From acbdf423eee28c22011c0699562fc7b51dd5ced0 Mon Sep 17 00:00:00 2001 From: Zach Bruggeman Date: Fri, 16 Aug 2013 17:40:20 -0700 Subject: [PATCH 001/157] Major refactor of Sheetsee (the Browserify boogie!) --- .gitignore | 2 + .npmignore | 5 + changelog.md | 9 + demo.html | 16 +- dist/sheetsee.full.js | 15 + dist/sheetsee.js | 1 + docs.md | 18 +- index.html | 13 +- js/ICanHaz.js | 542 --- js/components/d3.js | 327 ++ js/components/mapbox.js | 71 + js/d3.js | 7026 --------------------------------------- js/jquery.js | 2 - js/sheetsee.full.js | 20 + js/sheetsee.js | 906 ++--- js/tabletop.js | 414 --- makefile | 5 + package.json | 29 + readme.md | 17 +- 19 files changed, 756 insertions(+), 8682 deletions(-) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 dist/sheetsee.full.js create mode 100644 dist/sheetsee.js delete mode 100644 js/ICanHaz.js create mode 100644 js/components/d3.js create mode 100644 js/components/mapbox.js delete mode 100644 js/d3.js delete mode 100644 js/jquery.js create mode 100644 js/sheetsee.full.js delete mode 100644 js/tabletop.js create mode 100644 makefile create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..58b805fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +node_modules/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..83ba5f8b --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +css/ +img/ +dist/ +demo.html +index.html \ No newline at end of file diff --git a/changelog.md b/changelog.md index 6aba04ae..0af6e545 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,12 @@ +## August 16, 2013 +### The Browserify Boogie + +* Sheetsee is now built with Browserify and split up into components. By editing one line, you can remove the d3 and mapbox components, or add your own for great spreadsheeting. +* jQuery and Tabletop are no longer in the repository, so you must include them via your own means. Thankfully, both are available on major CDNs, which is what happens in both `index.html` and `demo.html`. The other libraries are included via the `package.json`, which means to populate the libraries, just run `npm install`. +* Sheetsee has been cleaned up, and exports like a good node module. jQuery is not included via npm because all the current packages are unofficial and outdated, and the official jQuery repository has yet to publish to npm. Tabletop is not included via npm due to it using `request` on Node, which is incompatible with Browserify. +* A makefile will handle the proper browserification and minifying. Just run `make` and look in the `dist` folder. +* Dependencies have been updated. Mapbox is now 1.3.1, icanhaz is now 0.10.3 and d3 is now 3.2.8. + ## August 13, 2013 ### Charting Intake diff --git a/demo.html b/demo.html index 84595e2f..e649beb4 100644 --- a/demo.html +++ b/demo.html @@ -1,15 +1,13 @@ Yo, yo, yo! - - - - - - + + + - - + + + @@ -479,7 +477,7 @@

Winner, Most Cuddlable

// more icanhas for most cuddlable var mostCuddleIs = Sheetsee.getMax(gData, "cuddlability") - var mostCuddle = ich.mostCuddle({ + var mostCuddle = Sheetsee.ich.mostCuddle({ rows: mostCuddleIs }) $('#mostCuddle').html(mostCuddle) diff --git a/dist/sheetsee.full.js b/dist/sheetsee.full.js new file mode 100644 index 00000000..30a77b41 --- /dev/null +++ b/dist/sheetsee.full.js @@ -0,0 +1,15 @@ +!function(e){if("function"==typeof bootstrap)bootstrap("sheetsee",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeSheetsee=e}else"undefined"!=typeof window?window.Sheetsee=e():global.Sheetsee=e()}(function(){var define,ses,bootstrap,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ob[sorter])return 1;return 0});if(sorted==="descending")data.reverse();Sheetsee.makeTable(data,tableDiv);var header;$(tableDiv+" .tHeader").each(function(i,el){var contents=Sheetsee.resolveDataTitle($(el).text());if(contents===sorter)header=el});$(header).attr("data-sorted",sorted)},resolveDataTitle:function(string){var adjusted=string.toLowerCase().replace(/\s/g,"").replace(/\W/g,"");return adjusted},sendToSort:function(event){var tableDiv="#"+$(event.target).closest("div").attr("id");console.log("came from this table",tableDiv);var sorted=$(event.target).attr("data-sorted");if(sorted){if(sorted==="descending")sorted="ascending";else sorted="descending"}else{sorted="ascending"}var sorter=Sheetsee.resolveDataTitle(event.target.innerHTML);Sheetsee.sortThings(gData,sorter,sorted,tableDiv)},makeTable:function(data,targetDiv){var templateID=targetDiv.replace("#","");var tableContents=ich[templateID]({rows:data});$(targetDiv).html(tableContents)},getKeywordCount:function(data,keyword){var group=[];data.forEach(function(d){for(var key in d){var value=d[key].toString().toLowerCase();if(value.match(keyword.toLowerCase()))group.push(d)}});return group.length;if(group=[])return"0"},getKeyword:function(data,keyword){var group=[];data.forEach(function(d){for(var key in d){var value=d[key].toString().toLowerCase();if(value.match(keyword.toLowerCase()))group.push(d)}});return group;if(group=[])return"no matches"},getColumnTotal:function(data,column){var total=[];data.forEach(function(d){if(d[column]==="")return;total.push(+d[column])});return total.reduce(function(a,b){return a+b})},getColumnAverage:function(data,column){var total=getColumnTotal(data,column);var average=total/data.length;return average},getMax:function(data,column){var result=[];data.forEach(function(element){if(result.length===0)return result.push(element);else{if(element[column].valueOf()>result[0][column].valueOf()){result.length=0;return result.push(element)}if(element[column].valueOf()===result[0][column].valueOf()){return result.push(element)}}});return result},getMin:function(data,column){var result=[];data.forEach(function(element){if(result.length===0)return result.push(element);else{if(element[column].valueOf()colors.length||keys.length<=colors.length){colorIndex=counter%colors.length}var h={units:data[key],hexcolor:colors[colorIndex]};h[category]=key;counter++;colorIndex=counter;return h})},makeArrayOfObject:function(data){var keys=Object.keys(data);return keys.map(function(key){var h={label:key,units:data[key]};return h})}};$(document).on("click",".tHeader",Sheetsee.sendToSort);Sheetsee.ich=ich;module.exports=Sheetsee},{icanhaz:7}],5:[function(require,module,exports){d3=function(){var d3={version:"3.2.8"};if(!Date.now)Date.now=function(){return+new Date};var d3_document=document,d3_documentElement=d3_document.documentElement,d3_window=window;try{d3_document.createElement("div").style.setProperty("opacity",0,"")}catch(error){var d3_element_prototype=d3_window.Element.prototype,d3_element_setAttribute=d3_element_prototype.setAttribute,d3_element_setAttributeNS=d3_element_prototype.setAttributeNS,d3_style_prototype=d3_window.CSSStyleDeclaration.prototype,d3_style_setProperty=d3_style_prototype.setProperty;d3_element_prototype.setAttribute=function(name,value){d3_element_setAttribute.call(this,name,value+"")};d3_element_prototype.setAttributeNS=function(space,local,value){d3_element_setAttributeNS.call(this,space,local,value+"")};d3_style_prototype.setProperty=function(name,value,priority){d3_style_setProperty.call(this,name,value+"",priority)}}d3.ascending=function(a,b){return ab?1:a>=b?0:NaN};d3.descending=function(a,b){return ba?1:b>=a?0:NaN};d3.min=function(array,f){var i=-1,n=array.length,a,b;if(arguments.length===1){while(++ib)a=b}else{while(++ib)a=b}return a};d3.max=function(array,f){var i=-1,n=array.length,a,b;if(arguments.length===1){while(++ia)a=b}else{while(++ia)a=b}return a};d3.extent=function(array,f){var i=-1,n=array.length,a,b,c;if(arguments.length===1){while(++ib)a=b;if(cb)a=b;if(c1)array=array.map(f);array=array.filter(d3_number);return array.length?d3.quantile(array.sort(d3.ascending),.5):undefined};d3.bisector=function(f){return{left:function(a,x,lo,hi){if(arguments.length<3)lo=0;if(arguments.length<4)hi=a.length;while(lo>>1;if(f.call(a,a[mid],mid)>>1;if(xstop)range.push(j/k);else while((j=start+step*++i)=keys.length)return rollup?rollup.call(nest,array):sortValues?array.sort(sortValues):array;var i=-1,n=array.length,key=keys[depth++],keyValue,object,setter,valuesByKey=new d3_Map,values;while(++i=keys.length)return map;var array=[],sortKey=sortKeys[depth++];map.forEach(function(key,keyMap){array.push({key:key,values:entries(keyMap,depth)})});return sortKey?array.sort(function(a,b){return sortKey(a.key,b.key)}):array}nest.map=function(array,mapType){return map(mapType,array,0)};nest.entries=function(array){return entries(map(d3.map,array,0),0)};nest.key=function(d){keys.push(d);return nest};nest.sortKeys=function(order){sortKeys[keys.length-1]=order;return nest};nest.sortValues=function(order){sortValues=order;return nest};nest.rollup=function(f){rollup=f;return nest};return nest};d3.set=function(array){var set=new d3_Set;if(array)for(var i=0,n=array.length;i=0){name=type.substring(i+1);type=type.substring(0,i)}if(type)return arguments.length<2?this[type].on(name):this[type].on(name,listener);if(arguments.length===2){if(listener==null)for(type in this){if(this.hasOwnProperty(type))this[type].on(name,null)}return this}};function d3_dispatch_event(dispatch){var listeners=[],listenerByName=new d3_Map;function event(){var z=listeners,i=-1,n=z.length,l;while(++i=0){prefix=name.substring(0,i);name=name.substring(i+1)}return d3_nsPrefix.hasOwnProperty(prefix)?{space:d3_nsPrefix[prefix],local:name}:name}};d3_selectionPrototype.attr=function(name,value){if(arguments.length<2){if(typeof name==="string"){var node=this.node();name=d3.ns.qualify(name);return name.local?node.getAttributeNS(name.space,name.local):node.getAttribute(name)}for(value in name)this.each(d3_selection_attr(value,name[value]));return this}return this.each(d3_selection_attr(name,value))};function d3_selection_attr(name,value){name=d3.ns.qualify(name);function attrNull(){this.removeAttribute(name)}function attrNullNS(){this.removeAttributeNS(name.space,name.local)}function attrConstant(){this.setAttribute(name,value)}function attrConstantNS(){this.setAttributeNS(name.space,name.local,value)}function attrFunction(){var x=value.apply(this,arguments);if(x==null)this.removeAttribute(name);else this.setAttribute(name,x)}function attrFunctionNS(){var x=value.apply(this,arguments);if(x==null)this.removeAttributeNS(name.space,name.local);else this.setAttributeNS(name.space,name.local,x)}return value==null?name.local?attrNullNS:attrNull:typeof value==="function"?name.local?attrFunctionNS:attrFunction:name.local?attrConstantNS:attrConstant}function d3_collapse(s){return s.trim().replace(/\s+/g," ")}d3_selectionPrototype.classed=function(name,value){if(arguments.length<2){if(typeof name==="string"){var node=this.node(),n=(name=name.trim().split(/^|\s+/g)).length,i=-1;if(value=node.classList){while(++i=0;){if(node=group[i]){if(next&&next!==node.nextSibling)next.parentNode.insertBefore(node,next);next=node}}}return this};d3_selectionPrototype.sort=function(comparator){comparator=d3_selection_sortComparator.apply(this,arguments);for(var j=-1,m=this.length;++j=i0)i0=i+1;while(!(node=group[i0])&&++i00)type=type.substring(0,i);var filter=d3_selection_onFilters.get(type);if(filter)type=filter,wrap=d3_selection_onFilter;function onRemove(){var l=this[name];if(l){this.removeEventListener(type,l,l.$);delete this[name]}}function onAdd(){var l=wrap(listener,d3_array(arguments));onRemove.call(this);this.addEventListener(type,this[name]=l,l.$=capture);l._=listener}function removeAll(){var re=new RegExp("^__on([^.]+)"+d3.requote(type)+"$"),match;for(var name in this){if(match=name.match(re)){var l=this[name];this.removeEventListener(match[1],l,l.$);delete this[name]}}}return i?listener?onAdd:onRemove:listener?d3_noop:removeAll}var d3_selection_onFilters=d3.map({mouseenter:"mouseover",mouseleave:"mouseout"});d3_selection_onFilters.forEach(function(k){if("on"+k in d3_document)d3_selection_onFilters.remove(k)});function d3_selection_onListener(listener,argumentz){return function(e){var o=d3.event;d3.event=e;argumentz[0]=this.__data__;try{listener.apply(this,argumentz)}finally{d3.event=o}}}function d3_selection_onFilter(listener,argumentz){var l=d3_selection_onListener(listener,argumentz);return function(e){var target=this,related=e.relatedTarget;if(!related||related!==target&&!(related.compareDocumentPosition(target)&8)){l.call(target,e)}}}var d3_event_dragSelect=d3_vendorSymbol(d3_documentElement.style,"userSelect"),d3_event_dragId=0;function d3_event_dragSuppress(){var name=".dragsuppress-"+ ++d3_event_dragId,touchmove="touchmove"+name,selectstart="selectstart"+name,dragstart="dragstart"+name,click="click"+name,w=d3.select(d3_window).on(touchmove,d3_eventPreventDefault).on(selectstart,d3_eventPreventDefault).on(dragstart,d3_eventPreventDefault),style=d3_documentElement.style,select=style[d3_event_dragSelect];style[d3_event_dragSelect]="none";return function(suppressClick){w.on(name,null);style[d3_event_dragSelect]=select;if(suppressClick){function off(){w.on(click,null)}w.on(click,function(){d3_eventPreventDefault();off()},true);setTimeout(off,0)}}}d3.mouse=function(container){return d3_mousePoint(container,d3_eventSource())};var d3_mouse_bug44083=/WebKit/.test(d3_window.navigator.userAgent)?-1:0;function d3_mousePoint(container,e){var svg=container.ownerSVGElement||container;if(svg.createSVGPoint){var point=svg.createSVGPoint();if(d3_mouse_bug44083<0&&(d3_window.scrollX||d3_window.scrollY)){svg=d3.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var ctm=svg[0][0].getScreenCTM();d3_mouse_bug44083=!(ctm.f||ctm.e);svg.remove()}if(d3_mouse_bug44083){point.x=e.pageX;point.y=e.pageY}else{point.x=e.clientX;point.y=e.clientY}point=point.matrixTransform(container.getScreenCTM().inverse());return[point.x,point.y]}var rect=container.getBoundingClientRect();return[e.clientX-rect.left-container.clientLeft,e.clientY-rect.top-container.clientTop]}d3.touches=function(container,touches){if(arguments.length<2)touches=d3_eventSource().touches;return touches?d3_array(touches).map(function(touch){var point=d3_mousePoint(container,touch);point.identifier=touch.identifier;return point}):[]};d3.behavior.drag=function(){var event=d3_eventDispatch(drag,"drag","dragstart","dragend"),origin=null,mousedown=dragstart(d3_noop,d3.mouse,"mousemove","mouseup"),touchstart=dragstart(touchid,touchposition,"touchmove","touchend");function drag(){this.on("mousedown.drag",mousedown).on("touchstart.drag",touchstart)}function touchid(){return d3.event.changedTouches[0].identifier}function touchposition(parent,id){return d3.touches(parent).filter(function(p){return p.identifier===id})[0]}function dragstart(id,position,move,end){return function(){var target=this,parent=target.parentNode,event_=event.of(target,arguments),eventTarget=d3.event.target,eventId=id(),drag=eventId==null?"drag":"drag-"+eventId,origin_=position(parent,eventId),dragged=0,offset,w=d3.select(d3_window).on(move+"."+drag,moved).on(end+"."+drag,ended),dragRestore=d3_event_dragSuppress();if(origin){offset=origin.apply(target,arguments);offset=[offset.x-origin_[0],offset.y-origin_[1]]}else{offset=[0,0]}event_({type:"dragstart"});function moved(){if(!parent)return ended();var p=position(parent,eventId),dx=p[0]-origin_[0],dy=p[1]-origin_[1];dragged|=dx|dy;origin_=p;event_({type:"drag",x:p[0]+offset[0],y:p[1]+offset[1],dx:dx,dy:dy})}function ended(){w.on(move+"."+drag,null).on(end+"."+drag,null);dragRestore(dragged&&d3.event.target===eventTarget);event_({type:"dragend"})}}}drag.origin=function(x){if(!arguments.length)return origin;origin=x;return drag};return d3.rebind(drag,event,"on")};d3.behavior.zoom=function(){var translate=[0,0],translate0,scale=1,scaleExtent=d3_behavior_zoomInfinity,mousedown="mousedown.zoom",mousemove="mousemove.zoom",mouseup="mouseup.zoom",touchstart="touchstart.zoom",touchmove="touchmove.zoom",touchend="touchend.zoom",touchtime,event=d3_eventDispatch(zoom,"zoom"),x0,x1,y0,y1;function zoom(){this.on(mousedown,mousedowned).on(d3_behavior_zoomWheel+".zoom",mousewheeled).on(mousemove,mousewheelreset).on("dblclick.zoom",dblclicked).on(touchstart,touchstarted)}zoom.translate=function(x){if(!arguments.length)return translate;translate=x.map(Number);rescale();return zoom};zoom.scale=function(x){if(!arguments.length)return scale;scale=+x;rescale();return zoom};zoom.scaleExtent=function(x){if(!arguments.length)return scaleExtent;scaleExtent=x==null?d3_behavior_zoomInfinity:x.map(Number);return zoom};zoom.x=function(z){if(!arguments.length)return x1;x1=z;x0=z.copy();translate=[0,0];scale=1;return zoom};zoom.y=function(z){if(!arguments.length)return y1;y1=z;y0=z.copy();translate=[0,0];scale=1;return zoom};function location(p){return[(p[0]-translate[0])/scale,(p[1]-translate[1])/scale]}function point(l){return[l[0]*scale+translate[0],l[1]*scale+translate[1]]}function scaleTo(s){scale=Math.max(scaleExtent[0],Math.min(scaleExtent[1],s))}function translateTo(p,l){l=point(l);translate[0]+=p[0]-l[0];translate[1]+=p[1]-l[1]}function rescale(){if(x1)x1.domain(x0.range().map(function(x){return(x-translate[0])/scale}).map(x0.invert));if(y1)y1.domain(y0.range().map(function(y){return(y-translate[1])/scale}).map(y0.invert))}function dispatch(event){rescale();event({type:"zoom",scale:scale,translate:translate})}function mousedowned(){var target=this,event_=event.of(target,arguments),eventTarget=d3.event.target,dragged=0,w=d3.select(d3_window).on(mousemove,moved).on(mouseup,ended),l=location(d3.mouse(target)),dragRestore=d3_event_dragSuppress();function moved(){dragged=1;translateTo(d3.mouse(target),l);dispatch(event_)}function ended(){w.on(mousemove,d3_window===target?mousewheelreset:null).on(mouseup,null);dragRestore(dragged&&d3.event.target===eventTarget)}}function touchstarted(){var target=this,event_=event.of(target,arguments),locations0,distance0=0,scale0,w=d3.select(d3_window).on(touchmove,moved).on(touchend,ended),t=d3.select(target).on(mousedown,null).on(touchstart,started),dragRestore=d3_event_dragSuppress();started();function relocate(){var touches=d3.touches(target);scale0=scale;locations0={};touches.forEach(function(t){locations0[t.identifier]=location(t)});return touches}function started(){var now=Date.now(),touches=relocate();if(touches.length===1){if(now-touchtime<500){var p=touches[0],l=locations0[p.identifier];scaleTo(scale*2);translateTo(p,l);d3_eventPreventDefault();dispatch(event_)}touchtime=now}else if(touches.length>1){var p=touches[0],q=touches[1],dx=p[0]-q[0],dy=p[1]-q[1];distance0=dx*dx+dy*dy}}function moved(){var touches=d3.touches(target),p0=touches[0],l0=locations0[p0.identifier];if(p1=touches[1]){var p1,l1=locations0[p1.identifier],scale1=d3.event.scale;if(scale1==null){var distance1=(distance1=p1[0]-p0[0])*distance1+(distance1=p1[1]-p0[1])*distance1;scale1=distance0&&Math.sqrt(distance1/distance0)}p0=[(p0[0]+p1[0])/2,(p0[1]+p1[1])/2];l0=[(l0[0]+l1[0])/2,(l0[1]+l1[1])/2];scaleTo(scale1*scale0)}touchtime=null;translateTo(p0,l0);dispatch(event_)}function ended(){if(d3.event.touches.length){relocate()}else{w.on(touchmove,null).on(touchend,null);t.on(mousedown,mousedowned).on(touchstart,touchstarted);dragRestore()}}}function mousewheeled(){d3_eventPreventDefault();if(!translate0)translate0=location(d3.mouse(this));scaleTo(Math.pow(2,d3_behavior_zoomDelta()*.002)*scale);translateTo(d3.mouse(this),translate0);dispatch(event.of(this,arguments))}function mousewheelreset(){translate0=null}function dblclicked(){var p=d3.mouse(this),l=location(p),k=Math.log(scale)/Math.LN2;scaleTo(Math.pow(2,d3.event.shiftKey?Math.ceil(k)-1:Math.floor(k)+1));translateTo(p,l);dispatch(event.of(this,arguments))}return d3.rebind(zoom,event,"on")};var d3_behavior_zoomInfinity=[0,Infinity];var d3_behavior_zoomDelta,d3_behavior_zoomWheel="onwheel"in d3_document?(d3_behavior_zoomDelta=function(){return-d3.event.deltaY*(d3.event.deltaMode?120:1)},"wheel"):"onmousewheel"in d3_document?(d3_behavior_zoomDelta=function(){return d3.event.wheelDelta},"mousewheel"):(d3_behavior_zoomDelta=function(){return-d3.event.detail},"MozMousePixelScroll");function d3_Color(){}d3_Color.prototype.toString=function(){return this.rgb()+""};d3.hsl=function(h,s,l){return arguments.length===1?h instanceof d3_Hsl?d3_hsl(h.h,h.s,h.l):d3_rgb_parse(""+h,d3_rgb_hsl,d3_hsl):d3_hsl(+h,+s,+l)};function d3_hsl(h,s,l){return new d3_Hsl(h,s,l)}function d3_Hsl(h,s,l){this.h=h;this.s=s;this.l=l}var d3_hslPrototype=d3_Hsl.prototype=new d3_Color;d3_hslPrototype.brighter=function(k){k=Math.pow(.7,arguments.length?k:1);return d3_hsl(this.h,this.s,this.l/k)};d3_hslPrototype.darker=function(k){k=Math.pow(.7,arguments.length?k:1);return d3_hsl(this.h,this.s,k*this.l)};d3_hslPrototype.rgb=function(){return d3_hsl_rgb(this.h,this.s,this.l)};function d3_hsl_rgb(h,s,l){var m1,m2;h=isNaN(h)?0:(h%=360)<0?h+360:h;s=isNaN(s)?0:s<0?0:s>1?1:s;l=l<0?0:l>1?1:l;m2=l<=.5?l*(1+s):l+s-l*s;m1=2*l-m2;function v(h){if(h>360)h-=360;else if(h<0)h+=360;if(h<60)return m1+(m2-m1)*h/60;if(h<180)return m2;if(h<240)return m1+(m2-m1)*(240-h)/60;return m1}function vv(h){return Math.round(v(h)*255)}return d3_rgb(vv(h+120),vv(h),vv(h-120))}var π=Math.PI,ε=1e-6,ε2=ε*ε,d3_radians=π/180,d3_degrees=180/π;function d3_sgn(x){return x>0?1:x<0?-1:0}function d3_acos(x){return x>1?0:x<-1?π:Math.acos(x)}function d3_asin(x){return x>1?π/2:x<-1?-π/2:Math.asin(x)}function d3_sinh(x){return(Math.exp(x)-Math.exp(-x))/2}function d3_cosh(x){return(Math.exp(x)+Math.exp(-x))/2}function d3_haversin(x){return(x=Math.sin(x/2))*x}d3.hcl=function(h,c,l){return arguments.length===1?h instanceof d3_Hcl?d3_hcl(h.h,h.c,h.l):h instanceof d3_Lab?d3_lab_hcl(h.l,h.a,h.b):d3_lab_hcl((h=d3_rgb_lab((h=d3.rgb(h)).r,h.g,h.b)).l,h.a,h.b):d3_hcl(+h,+c,+l)};function d3_hcl(h,c,l){return new d3_Hcl(h,c,l)}function d3_Hcl(h,c,l){this.h=h;this.c=c;this.l=l}var d3_hclPrototype=d3_Hcl.prototype=new d3_Color;d3_hclPrototype.brighter=function(k){return d3_hcl(this.h,this.c,Math.min(100,this.l+d3_lab_K*(arguments.length?k:1)))};d3_hclPrototype.darker=function(k){return d3_hcl(this.h,this.c,Math.max(0,this.l-d3_lab_K*(arguments.length?k:1)))};d3_hclPrototype.rgb=function(){return d3_hcl_lab(this.h,this.c,this.l).rgb()};function d3_hcl_lab(h,c,l){if(isNaN(h))h=0;if(isNaN(c))c=0;return d3_lab(l,Math.cos(h*=d3_radians)*c,Math.sin(h)*c)}d3.lab=function(l,a,b){return arguments.length===1?l instanceof d3_Lab?d3_lab(l.l,l.a,l.b):l instanceof d3_Hcl?d3_hcl_lab(l.l,l.c,l.h):d3_rgb_lab((l=d3.rgb(l)).r,l.g,l.b):d3_lab(+l,+a,+b)};function d3_lab(l,a,b){return new d3_Lab(l,a,b)}function d3_Lab(l,a,b){this.l=l;this.a=a;this.b=b}var d3_lab_K=18;var d3_lab_X=.95047,d3_lab_Y=1,d3_lab_Z=1.08883;var d3_labPrototype=d3_Lab.prototype=new d3_Color;d3_labPrototype.brighter=function(k){return d3_lab(Math.min(100,this.l+d3_lab_K*(arguments.length?k:1)),this.a,this.b)};d3_labPrototype.darker=function(k){return d3_lab(Math.max(0,this.l-d3_lab_K*(arguments.length?k:1)),this.a,this.b)};d3_labPrototype.rgb=function(){return d3_lab_rgb(this.l,this.a,this.b)};function d3_lab_rgb(l,a,b){var y=(l+16)/116,x=y+a/500,z=y-b/200;x=d3_lab_xyz(x)*d3_lab_X;y=d3_lab_xyz(y)*d3_lab_Y;z=d3_lab_xyz(z)*d3_lab_Z;return d3_rgb(d3_xyz_rgb(3.2404542*x-1.5371385*y-.4985314*z),d3_xyz_rgb(-.969266*x+1.8760108*y+.041556*z),d3_xyz_rgb(.0556434*x-.2040259*y+1.0572252*z))}function d3_lab_hcl(l,a,b){return l>0?d3_hcl(Math.atan2(b,a)*d3_degrees,Math.sqrt(a*a+b*b),l):d3_hcl(NaN,NaN,l)}function d3_lab_xyz(x){return x>.206893034?x*x*x:(x-4/29)/7.787037}function d3_xyz_lab(x){return x>.008856?Math.pow(x,1/3):7.787037*x+4/29}function d3_xyz_rgb(r){return Math.round(255*(r<=.00304?12.92*r:1.055*Math.pow(r,1/2.4)-.055))}d3.rgb=function(r,g,b){return arguments.length===1?r instanceof d3_Rgb?d3_rgb(r.r,r.g,r.b):d3_rgb_parse(""+r,d3_rgb,d3_hsl_rgb):d3_rgb(~~r,~~g,~~b)};function d3_rgbNumber(value){return d3_rgb(value>>16,value>>8&255,value&255)}function d3_rgbString(value){return d3_rgbNumber(value)+""}function d3_rgb(r,g,b){return new d3_Rgb(r,g,b)}function d3_Rgb(r,g,b){this.r=r;this.g=g;this.b=b}var d3_rgbPrototype=d3_Rgb.prototype=new d3_Color;d3_rgbPrototype.brighter=function(k){k=Math.pow(.7,arguments.length?k:1);var r=this.r,g=this.g,b=this.b,i=30;if(!r&&!g&&!b)return d3_rgb(i,i,i);if(r&&r0&&l<1?0:h}return d3_hsl(h,s,l)}function d3_rgb_lab(r,g,b){r=d3_rgb_xyz(r);g=d3_rgb_xyz(g);b=d3_rgb_xyz(b);var x=d3_xyz_lab((.4124564*r+.3575761*g+.1804375*b)/d3_lab_X),y=d3_xyz_lab((.2126729*r+.7151522*g+.072175*b)/d3_lab_Y),z=d3_xyz_lab((.0193339*r+.119192*g+.9503041*b)/d3_lab_Z);return d3_lab(116*y-16,500*(x-y),200*(y-z))}function d3_rgb_xyz(r){return(r/=255)<=.04045?r/12.92:Math.pow((r+.055)/1.055,2.4)}function d3_rgb_parseNumber(c){var f=parseFloat(c);return c.charAt(c.length-1)==="%"?Math.round(f*2.55):f}var d3_rgb_names=d3.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});d3_rgb_names.forEach(function(key,value){d3_rgb_names.set(key,d3_rgbNumber(value))});function d3_functor(v){return typeof v==="function"?v:function(){return v}}d3.functor=d3_functor;function d3_identity(d){return d}d3.xhr=d3_xhrType(d3_identity);function d3_xhrType(response){return function(url,mimeType,callback){if(arguments.length===2&&typeof mimeType==="function")callback=mimeType,mimeType=null;return d3_xhr(url,mimeType,response,callback)}}function d3_xhr(url,mimeType,response,callback){var xhr={},dispatch=d3.dispatch("progress","load","error"),headers={},request=new XMLHttpRequest,responseType=null;if(d3_window.XDomainRequest&&!("withCredentials"in request)&&/^(http(s)?:)?\/\//.test(url))request=new XDomainRequest;"onload"in request?request.onload=request.onerror=respond:request.onreadystatechange=function(){request.readyState>3&&respond()};function respond(){var status=request.status,result;if(!status&&request.responseText||status>=200&&status<300||status===304){try{result=response.call(xhr,request)}catch(e){dispatch.error.call(xhr,e);return}dispatch.load.call(xhr,result)}else{dispatch.error.call(xhr,request)}}request.onprogress=function(event){var o=d3.event;d3.event=event;try{dispatch.progress.call(xhr,request)}finally{d3.event=o}};xhr.header=function(name,value){name=(name+"").toLowerCase();if(arguments.length<2)return headers[name];if(value==null)delete headers[name];else headers[name]=value+"";return xhr};xhr.mimeType=function(value){if(!arguments.length)return mimeType;mimeType=value==null?null:value+"";return xhr};xhr.responseType=function(value){if(!arguments.length)return responseType;responseType=value;return xhr};xhr.response=function(value){response=value;return xhr};["get","post"].forEach(function(method){xhr[method]=function(){return xhr.send.apply(xhr,[method].concat(d3_array(arguments)))}});xhr.send=function(method,data,callback){if(arguments.length===2&&typeof data==="function")callback=data,data=null;request.open(method,url,true);if(mimeType!=null&&!("accept"in headers))headers["accept"]=mimeType+",*/*";if(request.setRequestHeader)for(var name in headers)request.setRequestHeader(name,headers[name]);if(mimeType!=null&&request.overrideMimeType)request.overrideMimeType(mimeType);if(responseType!=null)request.responseType=responseType;if(callback!=null)xhr.on("error",callback).on("load",function(request){callback(null,request)});request.send(data==null?null:data);return xhr};xhr.abort=function(){request.abort();return xhr};d3.rebind(xhr,dispatch,"on");return callback==null?xhr:xhr.get(d3_xhr_fixCallback(callback))}function d3_xhr_fixCallback(callback){return callback.length===1?function(error,request){callback(error==null?request:null)}:callback}d3.dsv=function(delimiter,mimeType){var reFormat=new RegExp('["'+delimiter+"\n]"),delimiterCode=delimiter.charCodeAt(0);function dsv(url,row,callback){if(arguments.length<3)callback=row,row=null;var xhr=d3.xhr(url,mimeType,callback);xhr.row=function(_){return arguments.length?xhr.response((row=_)==null?response:typedResponse(_)):row};return xhr.row(row)}function response(request){return dsv.parse(request.responseText)}function typedResponse(f){return function(request){return dsv.parse(request.responseText,f)}}dsv.parse=function(text,f){var o;return dsv.parseRows(text,function(row,i){if(o)return o(row,i-1);var a=new Function("d","return {"+row.map(function(name,i){return JSON.stringify(name)+": d["+i+"]"}).join(",")+"}");o=f?function(row,i){return f(a(row),i)}:a})};dsv.parseRows=function(text,f){var EOL={},EOF={},rows=[],N=text.length,I=0,n=0,t,eol;function token(){if(I>=N)return EOF;if(eol)return eol=false,EOL;var j=I;if(text.charCodeAt(j)===34){var i=j;while(i++24){if(isFinite(delay)){clearTimeout(d3_timer_timeout);d3_timer_timeout=setTimeout(d3_timer_step,delay)}d3_timer_interval=0}else{d3_timer_interval=1;d3_timer_frame(d3_timer_step)}}d3.timer.flush=function(){d3_timer_mark();d3_timer_sweep()};function d3_timer_replace(callback,delay,then){var n=arguments.length;if(n<2)delay=0;if(n<3)then=Date.now();d3_timer_active.callback=callback;d3_timer_active.time=then+delay}function d3_timer_mark(){var now=Date.now();d3_timer_active=d3_timer_queueHead;while(d3_timer_active){if(now>=d3_timer_active.time)d3_timer_active.flush=d3_timer_active.callback(now-d3_timer_active.time);d3_timer_active=d3_timer_active.next}return now}function d3_timer_sweep(){var t0,t1=d3_timer_queueHead,time=Infinity;while(t1){if(t1.flush){t1=t0?t0.next=t1.next:d3_timer_queueHead=t1.next +}else{if(t1.time8?function(d){return d/k}:function(d){return d*k},symbol:d}}d3.round=function(x,n){return n?Math.round(x*(n=Math.pow(10,n)))/n:Math.round(x)};d3.format=function(specifier){var match=d3_format_re.exec(specifier),fill=match[1]||" ",align=match[2]||">",sign=match[3]||"",symbol=match[4]||"",zfill=match[5],width=+match[6],comma=match[7],precision=match[8],type=match[9],scale=1,suffix="",integer=false;if(precision)precision=+precision.substring(1);if(zfill||fill==="0"&&align==="="){zfill=fill="0";align="=";if(comma)width-=Math.floor((width-1)/4)}switch(type){case"n":comma=true;type="g";break;case"%":scale=100;suffix="%";type="f";break;case"p":scale=100;suffix="%";type="r";break;case"b":case"o":case"x":case"X":if(symbol==="#")symbol="0"+type.toLowerCase();case"c":case"d":integer=true;precision=0;break;case"s":scale=-1;type="r";break}if(symbol==="#")symbol="";else if(symbol==="$")symbol=d3_format_currencySymbol;if(type=="r"&&!precision)type="g";if(precision!=null){if(type=="g")precision=Math.max(1,Math.min(21,precision));else if(type=="e"||type=="f")precision=Math.max(0,Math.min(20,precision))}type=d3_format_types.get(type)||d3_format_typeDefault;var zcomma=zfill&,return function(value){if(integer&&value%1)return"";var negative=value<0||value===0&&1/value<0?(value=-value,"-"):sign;if(scale<0){var prefix=d3.formatPrefix(value,precision);value=prefix.scale(value);suffix=prefix.symbol}else{value*=scale}value=type(value,precision);var i=value.lastIndexOf("."),before=i<0?value:value.substring(0,i),after=i<0?"":d3_format_decimalPoint+value.substring(i+1);if(!zfill&&comma)before=d3_format_group(before);var length=symbol.length+before.length+after.length+(zcomma?0:negative.length),padding=length"?padding+negative+value:align==="^"?padding.substring(0,length>>=1)+negative+value+padding.substring(length):negative+(zcomma?value:padding+value))+suffix}};var d3_format_re=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;var d3_format_types=d3.map({b:function(x){return x.toString(2)},c:function(x){return String.fromCharCode(x)},o:function(x){return x.toString(8)},x:function(x){return x.toString(16)},X:function(x){return x.toString(16).toUpperCase()},g:function(x,p){return x.toPrecision(p)},e:function(x,p){return x.toExponential(p)},f:function(x,p){return x.toFixed(p)},r:function(x,p){return(x=d3.round(x,d3_format_precision(x,p))).toFixed(Math.max(0,Math.min(20,d3_format_precision(x*(1+1e-15),p))))}});function d3_format_precision(x,p){return p-(x?Math.ceil(Math.log(x)/Math.LN10):1)}function d3_format_typeDefault(x){return x+""}var d3_format_group=d3_identity;if(d3_format_grouping){var d3_format_groupingLength=d3_format_grouping.length;d3_format_group=function(value){var i=value.length,t=[],j=0,g=d3_format_grouping[0];while(i>0&&g>0){t.push(value.substring(i-=g,i+g));g=d3_format_grouping[j=(j+1)%d3_format_groupingLength]}return t.reverse().join(d3_format_thousandsSeparator)}}d3.geo={};function d3_adder(){}d3_adder.prototype={s:0,t:0,add:function(y){d3_adderSum(y,this.t,d3_adderTemp);d3_adderSum(d3_adderTemp.s,this.s,this);if(this.s)this.t+=d3_adderTemp.t;else this.s=d3_adderTemp.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var d3_adderTemp=new d3_adder;function d3_adderSum(a,b,o){var x=o.s=a+b,bv=x-a,av=x-bv;o.t=a-av+(b-bv)}d3.geo.stream=function(object,listener){if(object&&d3_geo_streamObjectType.hasOwnProperty(object.type)){d3_geo_streamObjectType[object.type](object,listener)}else{d3_geo_streamGeometry(object,listener)}};function d3_geo_streamGeometry(geometry,listener){if(geometry&&d3_geo_streamGeometryType.hasOwnProperty(geometry.type)){d3_geo_streamGeometryType[geometry.type](geometry,listener)}}var d3_geo_streamObjectType={Feature:function(feature,listener){d3_geo_streamGeometry(feature.geometry,listener)},FeatureCollection:function(object,listener){var features=object.features,i=-1,n=features.length;while(++iε)φ1=90;else if(dλSum<-ε)φ0=-90;range[0]=λ0,range[1]=λ1}};function point(λ,φ){ranges.push(range=[λ0=λ,λ1=λ]);if(φ<φ0)φ0=φ;if(φ>φ1)φ1=φ}function linePoint(λ,φ){var p=d3_geo_cartesian([λ*d3_radians,φ*d3_radians]);if(p0){var normal=d3_geo_cartesianCross(p0,p),equatorial=[normal[1],-normal[0],0],inflection=d3_geo_cartesianCross(equatorial,normal);d3_geo_cartesianNormalize(inflection);inflection=d3_geo_spherical(inflection);var dλ=λ-λ_,s=dλ>0?1:-1,λi=inflection[0]*d3_degrees*s,antimeridian=Math.abs(dλ)>180;if(antimeridian^(s*λ_<λi&&λiφ1)φ1=φi}else if(λi=(λi+360)%360-180,antimeridian^(s*λ_<λi&&λiφ1)φ1=φ}if(antimeridian){if(λ<λ_){if(angle(λ0,λ)>angle(λ0,λ1))λ1=λ}else{if(angle(λ,λ1)>angle(λ0,λ1))λ0=λ}}else{if(λ1>=λ0){if(λ<λ0)λ0=λ;if(λ>λ1)λ1=λ}else{if(λ>λ_){if(angle(λ0,λ)>angle(λ0,λ1))λ1=λ}else{if(angle(λ,λ1)>angle(λ0,λ1))λ0=λ}}}}else{point(λ,φ)}p0=p,λ_=λ}function lineStart(){bound.point=linePoint}function lineEnd(){range[0]=λ0,range[1]=λ1;bound.point=point;p0=null}function ringPoint(λ,φ){if(p0){var dλ=λ-λ_;dλSum+=Math.abs(dλ)>180?dλ+(dλ>0?360:-360):dλ}else λ__=λ,φ__=φ;d3_geo_area.point(λ,φ);linePoint(λ,φ)}function ringStart(){d3_geo_area.lineStart()}function ringEnd(){ringPoint(λ__,φ__);d3_geo_area.lineEnd();if(Math.abs(dλSum)>ε)λ0=-(λ1=180);range[0]=λ0,range[1]=λ1;p0=null}function angle(λ0,λ1){return(λ1-=λ0)<0?λ1+360:λ1}function compareRanges(a,b){return a[0]-b[0]}function withinRange(x,range){return range[0]<=range[1]?range[0]<=x&&x<=range[1]:xangle(a[0],a[1]))a[1]=b[1];if(angle(b[0],a[1])>angle(a[0],a[1]))a[0]=b[0]}else{merged.push(a=b)}}var best=-Infinity,dλ;for(var n=merged.length-1,i=0,a=merged[n],b;i<=n;a=b,++i){b=merged[i];if((dλ=angle(a[1],b[0]))>best)best=dλ,λ0=b[0],λ1=a[1]}}ranges=range=null;return λ0===Infinity||φ0===Infinity?[[NaN,NaN],[NaN,NaN]]:[[λ0,φ0],[λ1,φ1]]}}();d3.geo.centroid=function(object){d3_geo_centroidW0=d3_geo_centroidW1=d3_geo_centroidX0=d3_geo_centroidY0=d3_geo_centroidZ0=d3_geo_centroidX1=d3_geo_centroidY1=d3_geo_centroidZ1=d3_geo_centroidX2=d3_geo_centroidY2=d3_geo_centroidZ2=0;d3.geo.stream(object,d3_geo_centroid);var x=d3_geo_centroidX2,y=d3_geo_centroidY2,z=d3_geo_centroidZ2,m=x*x+y*y+z*z;if(m<ε2){x=d3_geo_centroidX1,y=d3_geo_centroidY1,z=d3_geo_centroidZ1;if(d3_geo_centroidW1<ε)x=d3_geo_centroidX0,y=d3_geo_centroidY0,z=d3_geo_centroidZ0;m=x*x+y*y+z*z;if(m<ε2)return[NaN,NaN]}return[Math.atan2(y,x)*d3_degrees,d3_asin(z/Math.sqrt(m))*d3_degrees]};var d3_geo_centroidW0,d3_geo_centroidW1,d3_geo_centroidX0,d3_geo_centroidY0,d3_geo_centroidZ0,d3_geo_centroidX1,d3_geo_centroidY1,d3_geo_centroidZ1,d3_geo_centroidX2,d3_geo_centroidY2,d3_geo_centroidZ2;var d3_geo_centroid={sphere:d3_noop,point:d3_geo_centroidPoint,lineStart:d3_geo_centroidLineStart,lineEnd:d3_geo_centroidLineEnd,polygonStart:function(){d3_geo_centroid.lineStart=d3_geo_centroidRingStart},polygonEnd:function(){d3_geo_centroid.lineStart=d3_geo_centroidLineStart}};function d3_geo_centroidPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);d3_geo_centroidPointXYZ(cosφ*Math.cos(λ),cosφ*Math.sin(λ),Math.sin(φ))}function d3_geo_centroidPointXYZ(x,y,z){++d3_geo_centroidW0;d3_geo_centroidX0+=(x-d3_geo_centroidX0)/d3_geo_centroidW0;d3_geo_centroidY0+=(y-d3_geo_centroidY0)/d3_geo_centroidW0;d3_geo_centroidZ0+=(z-d3_geo_centroidZ0)/d3_geo_centroidW0}function d3_geo_centroidLineStart(){var x0,y0,z0;d3_geo_centroid.point=function(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);x0=cosφ*Math.cos(λ);y0=cosφ*Math.sin(λ);z0=Math.sin(φ);d3_geo_centroid.point=nextPoint;d3_geo_centroidPointXYZ(x0,y0,z0)};function nextPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians),x=cosφ*Math.cos(λ),y=cosφ*Math.sin(λ),z=Math.sin(φ),w=Math.atan2(Math.sqrt((w=y0*z-z0*y)*w+(w=z0*x-x0*z)*w+(w=x0*y-y0*x)*w),x0*x+y0*y+z0*z);d3_geo_centroidW1+=w;d3_geo_centroidX1+=w*(x0+(x0=x));d3_geo_centroidY1+=w*(y0+(y0=y));d3_geo_centroidZ1+=w*(z0+(z0=z));d3_geo_centroidPointXYZ(x0,y0,z0)}}function d3_geo_centroidLineEnd(){d3_geo_centroid.point=d3_geo_centroidPoint}function d3_geo_centroidRingStart(){var λ00,φ00,x0,y0,z0;d3_geo_centroid.point=function(λ,φ){λ00=λ,φ00=φ;d3_geo_centroid.point=nextPoint;λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);x0=cosφ*Math.cos(λ);y0=cosφ*Math.sin(λ);z0=Math.sin(φ);d3_geo_centroidPointXYZ(x0,y0,z0)};d3_geo_centroid.lineEnd=function(){nextPoint(λ00,φ00);d3_geo_centroid.lineEnd=d3_geo_centroidLineEnd;d3_geo_centroid.point=d3_geo_centroidPoint};function nextPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians),x=cosφ*Math.cos(λ),y=cosφ*Math.sin(λ),z=Math.sin(φ),cx=y0*z-z0*y,cy=z0*x-x0*z,cz=x0*y-y0*x,m=Math.sqrt(cx*cx+cy*cy+cz*cz),u=x0*x+y0*y+z0*z,v=m&&-d3_acos(u)/m,w=Math.atan2(m,u);d3_geo_centroidX2+=v*cx;d3_geo_centroidY2+=v*cy;d3_geo_centroidZ2+=v*cz;d3_geo_centroidW1+=w;d3_geo_centroidX1+=w*(x0+(x0=x));d3_geo_centroidY1+=w*(y0+(y0=y));d3_geo_centroidZ1+=w*(z0+(z0=z));d3_geo_centroidPointXYZ(x0,y0,z0)}}function d3_true(){return true}function d3_geo_clipPolygon(segments,compare,inside,interpolate,listener){var subject=[],clip=[];segments.forEach(function(segment){if((n=segment.length-1)<=0)return;var n,p0=segment[0],p1=segment[n];if(d3_geo_sphericalEqual(p0,p1)){listener.lineStart();for(var i=0;i=0;)listener.point((point=points[i])[0],point[1])}else{interpolate(current.point,current.prev.point,-1,listener)}current=current.prev}current=current.other;points=current.points}while(!current.visited);listener.lineEnd()}}function d3_geo_clipPolygonLinkCircular(array){if(!(n=array.length))return;var n,i=0,a=array[0],b;while(++i1&&clean&2)ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));segments.push(ringSegments.filter(d3_geo_clipSegmentLength1))}return clip}}function d3_geo_clipSegmentLength1(segment){return segment.length>1}function d3_geo_clipBufferListener(){var lines=[],line;return{lineStart:function(){lines.push(line=[])},point:function(λ,φ){line.push([λ,φ])},lineEnd:d3_noop,buffer:function(){var buffer=lines;lines=[];line=null;return buffer},rejoin:function(){if(lines.length>1)lines.push(lines.pop().concat(lines.shift()))}}}function d3_geo_clipSort(a,b){return((a=a.point)[0]<0?a[1]-π/2-ε:π/2-a[1])-((b=b.point)[0]<0?b[1]-π/2-ε:π/2-b[1])}function d3_geo_pointInPolygon(point,polygon){var meridian=point[0],parallel=point[1],meridianNormal=[Math.sin(meridian),-Math.cos(meridian),0],polarAngle=0,polar=false,southPole=false,winding=0;d3_geo_areaRingSum.reset();for(var i=0,n=polygon.length;iπ,k=sinφ0*sinφ;d3_geo_areaRingSum.add(Math.atan2(k*Math.sin(dλ),cosφ0*cosφ+k*Math.cos(dλ)));if(Math.abs(φ)<ε)southPole=true;polarAngle+=antimeridian?dλ+(dλ>=0?2:-2)*π:dλ;if(antimeridian^λ0>=meridian^λ>=meridian){var arc=d3_geo_cartesianCross(d3_geo_cartesian(point0),d3_geo_cartesian(point));d3_geo_cartesianNormalize(arc);var intersection=d3_geo_cartesianCross(meridianNormal,arc);d3_geo_cartesianNormalize(intersection);var φarc=(antimeridian^dλ>=0?-1:1)*d3_asin(intersection[2]);if(parallel>φarc){winding+=antimeridian^dλ>=0?1:-1}}if(!j++)break;λ0=λ,sinφ0=sinφ,cosφ0=cosφ,point0=point}if(Math.abs(polarAngle)>ε)polar=true}return(!southPole&&!polar&&d3_geo_areaRingSum<0||polarAngle<-ε)^winding&1}var d3_geo_clipAntimeridian=d3_geo_clip(d3_true,d3_geo_clipAntimeridianLine,d3_geo_clipAntimeridianInterpolate,d3_geo_clipAntimeridianPolygonContains);function d3_geo_clipAntimeridianLine(listener){var λ0=NaN,φ0=NaN,sλ0=NaN,clean;return{lineStart:function(){listener.lineStart();clean=1},point:function(λ1,φ1){var sλ1=λ1>0?π:-π,dλ=Math.abs(λ1-λ0);if(Math.abs(dλ-π)<ε){listener.point(λ0,φ0=(φ0+φ1)/2>0?π/2:-π/2);listener.point(sλ0,φ0);listener.lineEnd();listener.lineStart();listener.point(sλ1,φ0);listener.point(λ1,φ0);clean=0}else if(sλ0!==sλ1&&dλ>=π){if(Math.abs(λ0-sλ0)<ε)λ0-=sλ0*ε;if(Math.abs(λ1-sλ1)<ε)λ1-=sλ1*ε;φ0=d3_geo_clipAntimeridianIntersect(λ0,φ0,λ1,φ1);listener.point(sλ0,φ0);listener.lineEnd();listener.lineStart();listener.point(sλ1,φ0);clean=0}listener.point(λ0=λ1,φ0=φ1);sλ0=sλ1},lineEnd:function(){listener.lineEnd();λ0=φ0=NaN},clean:function(){return 2-clean}}}function d3_geo_clipAntimeridianIntersect(λ0,φ0,λ1,φ1){var cosφ0,cosφ1,sinλ0_λ1=Math.sin(λ0-λ1);return Math.abs(sinλ0_λ1)>ε?Math.atan((Math.sin(φ0)*(cosφ1=Math.cos(φ1))*Math.sin(λ1)-Math.sin(φ1)*(cosφ0=Math.cos(φ0))*Math.sin(λ0))/(cosφ0*cosφ1*sinλ0_λ1)):(φ0+φ1)/2}function d3_geo_clipAntimeridianInterpolate(from,to,direction,listener){var φ;if(from==null){φ=direction*π/2;listener.point(-π,φ);listener.point(0,φ);listener.point(π,φ);listener.point(π,0);listener.point(π,-φ);listener.point(0,-φ);listener.point(-π,-φ);listener.point(-π,0);listener.point(-π,φ)}else if(Math.abs(from[0]-to[0])>ε){var s=(from[0]0,point=[radius,0],notHemisphere=Math.abs(cr)>ε,interpolate=d3_geo_circleInterpolate(radius,6*d3_radians);return d3_geo_clip(visible,clipLine,interpolate,polygonContains);function visible(λ,φ){return Math.cos(λ)*Math.cos(φ)>cr}function clipLine(listener){var point0,c0,v0,v00,clean;return{lineStart:function(){v00=v0=false;clean=1},point:function(λ,φ){var point1=[λ,φ],point2,v=visible(λ,φ),c=smallRadius?v?0:code(λ,φ):v?code(λ+(λ<0?π:-π),φ):0;if(!point0&&(v00=v0=v))listener.lineStart();if(v!==v0){point2=intersect(point0,point1);if(d3_geo_sphericalEqual(point0,point2)||d3_geo_sphericalEqual(point1,point2)){point1[0]+=ε;point1[1]+=ε;v=visible(point1[0],point1[1])}}if(v!==v0){clean=0;if(v){listener.lineStart();point2=intersect(point1,point0);listener.point(point2[0],point2[1])}else{point2=intersect(point0,point1);listener.point(point2[0],point2[1]);listener.lineEnd()}point0=point2}else if(notHemisphere&&point0&&smallRadius^v){var t;if(!(c&c0)&&(t=intersect(point1,point0,true))){clean=0;if(smallRadius){listener.lineStart();listener.point(t[0][0],t[0][1]);listener.point(t[1][0],t[1][1]);listener.lineEnd()}else{listener.point(t[1][0],t[1][1]);listener.lineEnd();listener.lineStart();listener.point(t[0][0],t[0][1])}}}if(v&&(!point0||!d3_geo_sphericalEqual(point0,point1))){listener.point(point1[0],point1[1])}point0=point1,v0=v,c0=c},lineEnd:function(){if(v0)listener.lineEnd();point0=null},clean:function(){return clean|(v00&&v0)<<1}}}function intersect(a,b,two){var pa=d3_geo_cartesian(a),pb=d3_geo_cartesian(b);var n1=[1,0,0],n2=d3_geo_cartesianCross(pa,pb),n2n2=d3_geo_cartesianDot(n2,n2),n1n2=n2[0],determinant=n2n2-n1n2*n1n2;if(!determinant)return!two&&a;var c1=cr*n2n2/determinant,c2=-cr*n1n2/determinant,n1xn2=d3_geo_cartesianCross(n1,n2),A=d3_geo_cartesianScale(n1,c1),B=d3_geo_cartesianScale(n2,c2);d3_geo_cartesianAdd(A,B);var u=n1xn2,w=d3_geo_cartesianDot(A,u),uu=d3_geo_cartesianDot(u,u),t2=w*w-uu*(d3_geo_cartesianDot(A,A)-1);if(t2<0)return;var t=Math.sqrt(t2),q=d3_geo_cartesianScale(u,(-w-t)/uu);d3_geo_cartesianAdd(q,A);q=d3_geo_spherical(q);if(!two)return q;var λ0=a[0],λ1=b[0],φ0=a[1],φ1=b[1],z;if(λ1<λ0)z=λ0,λ0=λ1,λ1=z;var δλ=λ1-λ0,polar=Math.abs(δλ-π)<ε,meridian=polar||δλ<ε;if(!polar&&φ1<φ0)z=φ0,φ0=φ1,φ1=z;if(meridian?polar?φ0+φ1>0^q[1]<(Math.abs(q[0]-λ0)<ε?φ0:φ1):φ0<=q[1]&&q[1]<=φ1:δλ>π^(λ0<=q[0]&&q[0]<=λ1)){var q1=d3_geo_cartesianScale(u,(-w+t)/uu);d3_geo_cartesianAdd(q1,A);return[q,d3_geo_spherical(q1)]}}function code(λ,φ){var r=smallRadius?radius:π-radius,code=0;if(λ<-r)code|=1;else if(λ>r)code|=2;if(φ<-r)code|=4;else if(φ>r)code|=8;return code}function polygonContains(polygon){return d3_geo_pointInPolygon(point,polygon)}}var d3_geo_clipViewMAX=1e9;function d3_geo_clipView(x0,y0,x1,y1){return function(listener){var listener_=listener,bufferListener=d3_geo_clipBufferListener(),segments,polygon,ring;var clip={point:point,lineStart:lineStart,lineEnd:lineEnd,polygonStart:function(){listener=bufferListener;segments=[];polygon=[]},polygonEnd:function(){listener=listener_;if((segments=d3.merge(segments)).length){listener.polygonStart();d3_geo_clipPolygon(segments,compare,inside,interpolate,listener);listener.polygonEnd()}else if(insidePolygon([x0,y0])){listener.polygonStart(),listener.lineStart();interpolate(null,null,1,listener);listener.lineEnd(),listener.polygonEnd()}segments=polygon=ring=null}};function inside(point){var a=corner(point,-1),i=insidePolygon([a===0||a===3?x0:x1,a>1?y1:y0]);return i}function insidePolygon(p){var wn=0,n=polygon.length,y=p[1];for(var i=0;iy&&isLeft(a,b,p)>0)++wn}else{if(b[1]<=y&&isLeft(a,b,p)<0)--wn}a=b}}return wn!==0}function isLeft(a,b,c){return(b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])}function interpolate(from,to,direction,listener){var a=0,a1=0;if(from==null||(a=corner(from,direction))!==(a1=corner(to,direction))||comparePoints(from,to)<0^direction>0){do{listener.point(a===0||a===3?x0:x1,a>1?y1:y0)}while((a=(a+direction+4)%4)!==a1)}else{listener.point(to[0],to[1])}}function visible(x,y){return x0<=x&&x<=x1&&y0<=y&&y<=y1}function point(x,y){if(visible(x,y))listener.point(x,y)}var x__,y__,v__,x_,y_,v_,first;function lineStart(){clip.point=linePoint;if(polygon)polygon.push(ring=[]);first=true;v_=false;x_=y_=NaN}function lineEnd(){if(segments){linePoint(x__,y__);if(v__&&v_)bufferListener.rejoin();segments.push(bufferListener.buffer())}clip.point=point;if(v_)listener.lineEnd()}function linePoint(x,y){x=Math.max(-d3_geo_clipViewMAX,Math.min(d3_geo_clipViewMAX,x));y=Math.max(-d3_geo_clipViewMAX,Math.min(d3_geo_clipViewMAX,y));var v=visible(x,y);if(polygon)ring.push([x,y]);if(first){x__=x,y__=y,v__=v;first=false;if(v){listener.lineStart();listener.point(x,y)}}else{if(v&&v_)listener.point(x,y);else{var a=[x_,y_],b=[x,y];if(clipLine(a,b)){if(!v_){listener.lineStart();listener.point(a[0],a[1])}listener.point(b[0],b[1]);if(!v)listener.lineEnd()}else if(v){listener.lineStart();listener.point(x,y)}}}x_=x,y_=y,v_=v}return clip};function corner(p,direction){return Math.abs(p[0]-x0)<ε?direction>0?0:3:Math.abs(p[0]-x1)<ε?direction>0?2:1:Math.abs(p[1]-y0)<ε?direction>0?1:0:direction>0?3:2}function compare(a,b){return comparePoints(a.point,b.point)}function comparePoints(a,b){var ca=corner(a,1),cb=corner(b,1);return ca!==cb?ca-cb:ca===0?b[1]-a[1]:ca===1?a[0]-b[0]:ca===2?a[1]-b[1]:b[0]-a[0]}function clipLine(a,b){var dx=b[0]-a[0],dy=b[1]-a[1],t=[0,1];if(Math.abs(dx)<ε&&Math.abs(dy)<ε)return x0<=a[0]&&a[0]<=x1&&y0<=a[1]&&a[1]<=y1;if(d3_geo_clipViewT(x0-a[0],dx,t)&&d3_geo_clipViewT(a[0]-x1,-dx,t)&&d3_geo_clipViewT(y0-a[1],dy,t)&&d3_geo_clipViewT(a[1]-y1,-dy,t)){if(t[1]<1){b[0]=a[0]+t[1]*dx;b[1]=a[1]+t[1]*dy}if(t[0]>0){a[0]+=t[0]*dx;a[1]+=t[0]*dy}return true}return false}}function d3_geo_clipViewT(num,denominator,t){if(Math.abs(denominator)<ε)return num<=0;var u=num/denominator;if(denominator>0){if(u>t[1])return false;if(u>t[0])t[0]=u}else{if(u=.12&&y<.234&&x>=-.425&&x<-.214?alaska:y>=.166&&y<.234&&x>=-.214&&x<-.115?hawaii:lower48).invert(coordinates)};albersUsa.stream=function(stream){var lower48Stream=lower48.stream(stream),alaskaStream=alaska.stream(stream),hawaiiStream=hawaii.stream(stream);return{point:function(x,y){lower48Stream.point(x,y);alaskaStream.point(x,y);hawaiiStream.point(x,y)},sphere:function(){lower48Stream.sphere();alaskaStream.sphere();hawaiiStream.sphere()},lineStart:function(){lower48Stream.lineStart();alaskaStream.lineStart();hawaiiStream.lineStart()},lineEnd:function(){lower48Stream.lineEnd();alaskaStream.lineEnd();hawaiiStream.lineEnd()},polygonStart:function(){lower48Stream.polygonStart();alaskaStream.polygonStart();hawaiiStream.polygonStart()},polygonEnd:function(){lower48Stream.polygonEnd();alaskaStream.polygonEnd();hawaiiStream.polygonEnd()}}};albersUsa.precision=function(_){if(!arguments.length)return lower48.precision();lower48.precision(_);alaska.precision(_);hawaii.precision(_);return albersUsa};albersUsa.scale=function(_){if(!arguments.length)return lower48.scale();lower48.scale(_);alaska.scale(_*.35);hawaii.scale(_);return albersUsa.translate(lower48.translate())};albersUsa.translate=function(_){if(!arguments.length)return lower48.translate();var k=lower48.scale(),x=+_[0],y=+_[1];lower48Point=lower48.translate(_).clipExtent([[x-.455*k,y-.238*k],[x+.455*k,y+.238*k]]).stream(pointStream).point;alaskaPoint=alaska.translate([x-.307*k,y+.201*k]).clipExtent([[x-.425*k+ε,y+.12*k+ε],[x-.214*k-ε,y+.234*k-ε]]).stream(pointStream).point;hawaiiPoint=hawaii.translate([x-.205*k,y+.212*k]).clipExtent([[x-.214*k+ε,y+.166*k+ε],[x-.115*k-ε,y+.234*k-ε]]).stream(pointStream).point;return albersUsa};return albersUsa.scale(1070)};var d3_geo_pathAreaSum,d3_geo_pathAreaPolygon,d3_geo_pathArea={point:d3_noop,lineStart:d3_noop,lineEnd:d3_noop,polygonStart:function(){d3_geo_pathAreaPolygon=0;d3_geo_pathArea.lineStart=d3_geo_pathAreaRingStart},polygonEnd:function(){d3_geo_pathArea.lineStart=d3_geo_pathArea.lineEnd=d3_geo_pathArea.point=d3_noop;d3_geo_pathAreaSum+=Math.abs(d3_geo_pathAreaPolygon/2)}};function d3_geo_pathAreaRingStart(){var x00,y00,x0,y0;d3_geo_pathArea.point=function(x,y){d3_geo_pathArea.point=nextPoint;x00=x0=x,y00=y0=y};function nextPoint(x,y){d3_geo_pathAreaPolygon+=y0*x-x0*y;x0=x,y0=y}d3_geo_pathArea.lineEnd=function(){nextPoint(x00,y00)}}var d3_geo_pathBoundsX0,d3_geo_pathBoundsY0,d3_geo_pathBoundsX1,d3_geo_pathBoundsY1;var d3_geo_pathBounds={point:d3_geo_pathBoundsPoint,lineStart:d3_noop,lineEnd:d3_noop,polygonStart:d3_noop,polygonEnd:d3_noop};function d3_geo_pathBoundsPoint(x,y){if(xd3_geo_pathBoundsX1)d3_geo_pathBoundsX1=x;if(yd3_geo_pathBoundsY1)d3_geo_pathBoundsY1=y}function d3_geo_pathBuffer(){var pointCircle=d3_geo_pathBufferCircle(4.5),buffer=[];var stream={point:point,lineStart:function(){stream.point=pointLineStart},lineEnd:lineEnd,polygonStart:function(){stream.lineEnd=lineEndPolygon},polygonEnd:function(){stream.lineEnd=lineEnd;stream.point=point},pointRadius:function(_){pointCircle=d3_geo_pathBufferCircle(_);return stream},result:function(){if(buffer.length){var result=buffer.join("");buffer=[];return result}}};function point(x,y){buffer.push("M",x,",",y,pointCircle)}function pointLineStart(x,y){buffer.push("M",x,",",y); +stream.point=pointLine}function pointLine(x,y){buffer.push("L",x,",",y)}function lineEnd(){stream.point=point}function lineEndPolygon(){buffer.push("Z")}return stream}function d3_geo_pathBufferCircle(radius){return"m0,"+radius+"a"+radius+","+radius+" 0 1,1 0,"+-2*radius+"a"+radius+","+radius+" 0 1,1 0,"+2*radius+"z"}var d3_geo_pathCentroid={point:d3_geo_pathCentroidPoint,lineStart:d3_geo_pathCentroidLineStart,lineEnd:d3_geo_pathCentroidLineEnd,polygonStart:function(){d3_geo_pathCentroid.lineStart=d3_geo_pathCentroidRingStart},polygonEnd:function(){d3_geo_pathCentroid.point=d3_geo_pathCentroidPoint;d3_geo_pathCentroid.lineStart=d3_geo_pathCentroidLineStart;d3_geo_pathCentroid.lineEnd=d3_geo_pathCentroidLineEnd}};function d3_geo_pathCentroidPoint(x,y){d3_geo_centroidX0+=x;d3_geo_centroidY0+=y;++d3_geo_centroidZ0}function d3_geo_pathCentroidLineStart(){var x0,y0;d3_geo_pathCentroid.point=function(x,y){d3_geo_pathCentroid.point=nextPoint;d3_geo_pathCentroidPoint(x0=x,y0=y)};function nextPoint(x,y){var dx=x-x0,dy=y-y0,z=Math.sqrt(dx*dx+dy*dy);d3_geo_centroidX1+=z*(x0+x)/2;d3_geo_centroidY1+=z*(y0+y)/2;d3_geo_centroidZ1+=z;d3_geo_pathCentroidPoint(x0=x,y0=y)}}function d3_geo_pathCentroidLineEnd(){d3_geo_pathCentroid.point=d3_geo_pathCentroidPoint}function d3_geo_pathCentroidRingStart(){var x00,y00,x0,y0;d3_geo_pathCentroid.point=function(x,y){d3_geo_pathCentroid.point=nextPoint;d3_geo_pathCentroidPoint(x00=x0=x,y00=y0=y)};function nextPoint(x,y){var dx=x-x0,dy=y-y0,z=Math.sqrt(dx*dx+dy*dy);d3_geo_centroidX1+=z*(x0+x)/2;d3_geo_centroidY1+=z*(y0+y)/2;d3_geo_centroidZ1+=z;z=y0*x-x0*y;d3_geo_centroidX2+=z*(x0+x);d3_geo_centroidY2+=z*(y0+y);d3_geo_centroidZ2+=z*3;d3_geo_pathCentroidPoint(x0=x,y0=y)}d3_geo_pathCentroid.lineEnd=function(){nextPoint(x00,y00)}}function d3_geo_pathContext(context){var pointRadius=4.5;var stream={point:point,lineStart:function(){stream.point=pointLineStart},lineEnd:lineEnd,polygonStart:function(){stream.lineEnd=lineEndPolygon},polygonEnd:function(){stream.lineEnd=lineEnd;stream.point=point},pointRadius:function(_){pointRadius=_;return stream},result:d3_noop};function point(x,y){context.moveTo(x,y);context.arc(x,y,pointRadius,0,2*π)}function pointLineStart(x,y){context.moveTo(x,y);stream.point=pointLine}function pointLine(x,y){context.lineTo(x,y)}function lineEnd(){stream.point=point}function lineEndPolygon(){context.closePath()}return stream}function d3_geo_resample(project){var δ2=.5,cosMinDistance=Math.cos(30*d3_radians),maxDepth=16;function resample(stream){var λ00,φ00,x00,y00,a00,b00,c00,λ0,x0,y0,a0,b0,c0;var resample={point:point,lineStart:lineStart,lineEnd:lineEnd,polygonStart:function(){stream.polygonStart();resample.lineStart=ringStart},polygonEnd:function(){stream.polygonEnd();resample.lineStart=lineStart}};function point(x,y){x=project(x,y);stream.point(x[0],x[1])}function lineStart(){x0=NaN;resample.point=linePoint;stream.lineStart()}function linePoint(λ,φ){var c=d3_geo_cartesian([λ,φ]),p=project(λ,φ);resampleLineTo(x0,y0,λ0,a0,b0,c0,x0=p[0],y0=p[1],λ0=λ,a0=c[0],b0=c[1],c0=c[2],maxDepth,stream);stream.point(x0,y0)}function lineEnd(){resample.point=point;stream.lineEnd()}function ringStart(){lineStart();resample.point=ringPoint;resample.lineEnd=ringEnd}function ringPoint(λ,φ){linePoint(λ00=λ,φ00=φ),x00=x0,y00=y0,a00=a0,b00=b0,c00=c0;resample.point=linePoint}function ringEnd(){resampleLineTo(x0,y0,λ0,a0,b0,c0,x00,y00,λ00,a00,b00,c00,maxDepth,stream);resample.lineEnd=lineEnd;lineEnd()}return resample}function resampleLineTo(x0,y0,λ0,a0,b0,c0,x1,y1,λ1,a1,b1,c1,depth,stream){var dx=x1-x0,dy=y1-y0,d2=dx*dx+dy*dy;if(d2>4*δ2&&depth--){var a=a0+a1,b=b0+b1,c=c0+c1,m=Math.sqrt(a*a+b*b+c*c),φ2=Math.asin(c/=m),λ2=Math.abs(Math.abs(c)-1)<ε?(λ0+λ1)/2:Math.atan2(b,a),p=project(λ2,φ2),x2=p[0],y2=p[1],dx2=x2-x0,dy2=y2-y0,dz=dy*dx2-dx*dy2;if(dz*dz/d2>δ2||Math.abs((dx*dx2+dy*dy2)/d2-.5)>.3||a0*a1+b0*b1+c0*c10&&16;return resample};return resample}d3.geo.path=function(){var pointRadius=4.5,projection,context,projectStream,contextStream,cacheStream;function path(object){if(object){if(typeof pointRadius==="function")contextStream.pointRadius(+pointRadius.apply(this,arguments));if(!cacheStream||!cacheStream.valid)cacheStream=projectStream(contextStream);d3.geo.stream(object,cacheStream)}return contextStream.result()}path.area=function(object){d3_geo_pathAreaSum=0;d3.geo.stream(object,projectStream(d3_geo_pathArea));return d3_geo_pathAreaSum};path.centroid=function(object){d3_geo_centroidX0=d3_geo_centroidY0=d3_geo_centroidZ0=d3_geo_centroidX1=d3_geo_centroidY1=d3_geo_centroidZ1=d3_geo_centroidX2=d3_geo_centroidY2=d3_geo_centroidZ2=0;d3.geo.stream(object,projectStream(d3_geo_pathCentroid));return d3_geo_centroidZ2?[d3_geo_centroidX2/d3_geo_centroidZ2,d3_geo_centroidY2/d3_geo_centroidZ2]:d3_geo_centroidZ1?[d3_geo_centroidX1/d3_geo_centroidZ1,d3_geo_centroidY1/d3_geo_centroidZ1]:d3_geo_centroidZ0?[d3_geo_centroidX0/d3_geo_centroidZ0,d3_geo_centroidY0/d3_geo_centroidZ0]:[NaN,NaN]};path.bounds=function(object){d3_geo_pathBoundsX1=d3_geo_pathBoundsY1=-(d3_geo_pathBoundsX0=d3_geo_pathBoundsY0=Infinity);d3.geo.stream(object,projectStream(d3_geo_pathBounds));return[[d3_geo_pathBoundsX0,d3_geo_pathBoundsY0],[d3_geo_pathBoundsX1,d3_geo_pathBoundsY1]]};path.projection=function(_){if(!arguments.length)return projection;projectStream=(projection=_)?_.stream||d3_geo_pathProjectStream(_):d3_identity;return reset()};path.context=function(_){if(!arguments.length)return context;contextStream=(context=_)==null?new d3_geo_pathBuffer:new d3_geo_pathContext(_);if(typeof pointRadius!=="function")contextStream.pointRadius(pointRadius);return reset()};path.pointRadius=function(_){if(!arguments.length)return pointRadius;pointRadius=typeof _==="function"?_:(contextStream.pointRadius(+_),+_);return path};function reset(){cacheStream=null;return path}return path.projection(d3.geo.albersUsa()).context(null)};function d3_geo_pathProjectStream(project){var resample=d3_geo_resample(function(λ,φ){return project([λ*d3_degrees,φ*d3_degrees])});return function(stream){stream=resample(stream);return{point:function(λ,φ){stream.point(λ*d3_radians,φ*d3_radians)},sphere:function(){stream.sphere()},lineStart:function(){stream.lineStart()},lineEnd:function(){stream.lineEnd()},polygonStart:function(){stream.polygonStart()},polygonEnd:function(){stream.polygonEnd()}}}}d3.geo.projection=d3_geo_projection;d3.geo.projectionMutator=d3_geo_projectionMutator;function d3_geo_projection(project){return d3_geo_projectionMutator(function(){return project})()}function d3_geo_projectionMutator(projectAt){var project,rotate,projectRotate,projectResample=d3_geo_resample(function(x,y){x=project(x,y);return[x[0]*k+δx,δy-x[1]*k]}),k=150,x=480,y=250,λ=0,φ=0,δλ=0,δφ=0,δγ=0,δx,δy,preclip=d3_geo_clipAntimeridian,postclip=d3_identity,clipAngle=null,clipExtent=null,stream;function projection(point){point=projectRotate(point[0]*d3_radians,point[1]*d3_radians);return[point[0]*k+δx,δy-point[1]*k]}function invert(point){point=projectRotate.invert((point[0]-δx)/k,(δy-point[1])/k);return point&&[point[0]*d3_degrees,point[1]*d3_degrees]}projection.stream=function(output){if(stream)stream.valid=false;stream=d3_geo_projectionRadiansRotate(rotate,preclip(projectResample(postclip(output))));stream.valid=true;return stream};projection.clipAngle=function(_){if(!arguments.length)return clipAngle;preclip=_==null?(clipAngle=_,d3_geo_clipAntimeridian):d3_geo_clipCircle((clipAngle=+_)*d3_radians);return invalidate()};projection.clipExtent=function(_){if(!arguments.length)return clipExtent;clipExtent=_;postclip=_==null?d3_identity:d3_geo_clipView(_[0][0],_[0][1],_[1][0],_[1][1]);return invalidate()};projection.scale=function(_){if(!arguments.length)return k;k=+_;return reset()};projection.translate=function(_){if(!arguments.length)return[x,y];x=+_[0];y=+_[1];return reset()};projection.center=function(_){if(!arguments.length)return[λ*d3_degrees,φ*d3_degrees];λ=_[0]%360*d3_radians;φ=_[1]%360*d3_radians;return reset()};projection.rotate=function(_){if(!arguments.length)return[δλ*d3_degrees,δφ*d3_degrees,δγ*d3_degrees];δλ=_[0]%360*d3_radians;δφ=_[1]%360*d3_radians;δγ=_.length>2?_[2]%360*d3_radians:0;return reset()};d3.rebind(projection,projectResample,"precision");function reset(){projectRotate=d3_geo_compose(rotate=d3_geo_rotation(δλ,δφ,δγ),project);var center=project(λ,φ);δx=x-center[0]*k;δy=y+center[1]*k;return invalidate()}function invalidate(){if(stream){stream.valid=false;stream=null}return projection}return function(){project=projectAt.apply(this,arguments);projection.invert=project.invert&&invert;return reset()}}function d3_geo_projectionRadiansRotate(rotate,stream){return{point:function(x,y){y=rotate(x*d3_radians,y*d3_radians),x=y[0];stream.point(x>π?x-2*π:x<-π?x+2*π:x,y[1])},sphere:function(){stream.sphere()},lineStart:function(){stream.lineStart()},lineEnd:function(){stream.lineEnd()},polygonStart:function(){stream.polygonStart()},polygonEnd:function(){stream.polygonEnd()}}}function d3_geo_equirectangular(λ,φ){return[λ,φ]}(d3.geo.equirectangular=function(){return d3_geo_projection(d3_geo_equirectangular)}).raw=d3_geo_equirectangular.invert=d3_geo_equirectangular;d3.geo.rotation=function(rotate){rotate=d3_geo_rotation(rotate[0]%360*d3_radians,rotate[1]*d3_radians,rotate.length>2?rotate[2]*d3_radians:0);function forward(coordinates){coordinates=rotate(coordinates[0]*d3_radians,coordinates[1]*d3_radians);return coordinates[0]*=d3_degrees,coordinates[1]*=d3_degrees,coordinates}forward.invert=function(coordinates){coordinates=rotate.invert(coordinates[0]*d3_radians,coordinates[1]*d3_radians);return coordinates[0]*=d3_degrees,coordinates[1]*=d3_degrees,coordinates};return forward};function d3_geo_rotation(δλ,δφ,δγ){return δλ?δφ||δγ?d3_geo_compose(d3_geo_rotationλ(δλ),d3_geo_rotationφγ(δφ,δγ)):d3_geo_rotationλ(δλ):δφ||δγ?d3_geo_rotationφγ(δφ,δγ):d3_geo_equirectangular}function d3_geo_forwardRotationλ(δλ){return function(λ,φ){return λ+=δλ,[λ>π?λ-2*π:λ<-π?λ+2*π:λ,φ]}}function d3_geo_rotationλ(δλ){var rotation=d3_geo_forwardRotationλ(δλ);rotation.invert=d3_geo_forwardRotationλ(-δλ);return rotation}function d3_geo_rotationφγ(δφ,δγ){var cosδφ=Math.cos(δφ),sinδφ=Math.sin(δφ),cosδγ=Math.cos(δγ),sinδγ=Math.sin(δγ);function rotation(λ,φ){var cosφ=Math.cos(φ),x=Math.cos(λ)*cosφ,y=Math.sin(λ)*cosφ,z=Math.sin(φ),k=z*cosδφ+x*sinδφ;return[Math.atan2(y*cosδγ-k*sinδγ,x*cosδφ-z*sinδφ),d3_asin(k*cosδγ+y*sinδγ)]}rotation.invert=function(λ,φ){var cosφ=Math.cos(φ),x=Math.cos(λ)*cosφ,y=Math.sin(λ)*cosφ,z=Math.sin(φ),k=z*cosδγ-y*sinδγ;return[Math.atan2(y*cosδγ+z*sinδγ,x*cosδφ+k*sinδφ),d3_asin(k*cosδφ-x*sinδφ)]};return rotation}d3.geo.circle=function(){var origin=[0,0],angle,precision=6,interpolate;function circle(){var center=typeof origin==="function"?origin.apply(this,arguments):origin,rotate=d3_geo_rotation(-center[0]*d3_radians,-center[1]*d3_radians,0).invert,ring=[];interpolate(null,null,1,{point:function(x,y){ring.push(x=rotate(x,y));x[0]*=d3_degrees,x[1]*=d3_degrees}});return{type:"Polygon",coordinates:[ring]}}circle.origin=function(x){if(!arguments.length)return origin;origin=x;return circle};circle.angle=function(x){if(!arguments.length)return angle;interpolate=d3_geo_circleInterpolate((angle=+x)*d3_radians,precision*d3_radians);return circle};circle.precision=function(_){if(!arguments.length)return precision;interpolate=d3_geo_circleInterpolate(angle*d3_radians,(precision=+_)*d3_radians);return circle};return circle.angle(90)};function d3_geo_circleInterpolate(radius,precision){var cr=Math.cos(radius),sr=Math.sin(radius);return function(from,to,direction,listener){if(from!=null){from=d3_geo_circleAngle(cr,from);to=d3_geo_circleAngle(cr,to);if(direction>0?fromto)from+=direction*2*π}else{from=radius+direction*2*π;to=radius}var point;for(var step=direction*precision,t=from;direction>0?t>to:tε}).map(x)).concat(d3.range(Math.ceil(y0/dy)*dy,y1,dy).filter(function(y){return Math.abs(y%DY)>ε}).map(y))}graticule.lines=function(){return lines().map(function(coordinates){return{type:"LineString",coordinates:coordinates}})};graticule.outline=function(){return{type:"Polygon",coordinates:[X(X0).concat(Y(Y1).slice(1),X(X1).reverse().slice(1),Y(Y0).reverse().slice(1))]}};graticule.extent=function(_){if(!arguments.length)return graticule.minorExtent();return graticule.majorExtent(_).minorExtent(_)};graticule.majorExtent=function(_){if(!arguments.length)return[[X0,Y0],[X1,Y1]];X0=+_[0][0],X1=+_[1][0];Y0=+_[0][1],Y1=+_[1][1];if(X0>X1)_=X0,X0=X1,X1=_;if(Y0>Y1)_=Y0,Y0=Y1,Y1=_;return graticule.precision(precision)};graticule.minorExtent=function(_){if(!arguments.length)return[[x0,y0],[x1,y1]];x0=+_[0][0],x1=+_[1][0];y0=+_[0][1],y1=+_[1][1];if(x0>x1)_=x0,x0=x1,x1=_;if(y0>y1)_=y0,y0=y1,y1=_;return graticule.precision(precision)};graticule.step=function(_){if(!arguments.length)return graticule.minorStep();return graticule.majorStep(_).minorStep(_)};graticule.majorStep=function(_){if(!arguments.length)return[DX,DY];DX=+_[0],DY=+_[1];return graticule};graticule.minorStep=function(_){if(!arguments.length)return[dx,dy];dx=+_[0],dy=+_[1];return graticule};graticule.precision=function(_){if(!arguments.length)return precision;precision=+_;x=d3_geo_graticuleX(y0,y1,90);y=d3_geo_graticuleY(x0,x1,precision);X=d3_geo_graticuleX(Y0,Y1,90);Y=d3_geo_graticuleY(X0,X1,precision);return graticule};return graticule.majorExtent([[-180,-90+ε],[180,90-ε]]).minorExtent([[-180,-80-ε],[180,80+ε]])};function d3_geo_graticuleX(y0,y1,dy){var y=d3.range(y0,y1-ε,dy).concat(y1);return function(x){return y.map(function(y){return[x,y]})}}function d3_geo_graticuleY(x0,x1,dx){var x=d3.range(x0,x1-ε,dx).concat(x1);return function(y){return x.map(function(x){return[x,y]})}}function d3_source(d){return d.source}function d3_target(d){return d.target}d3.geo.greatArc=function(){var source=d3_source,source_,target=d3_target,target_;function greatArc(){return{type:"LineString",coordinates:[source_||source.apply(this,arguments),target_||target.apply(this,arguments)]}}greatArc.distance=function(){return d3.geo.distance(source_||source.apply(this,arguments),target_||target.apply(this,arguments))};greatArc.source=function(_){if(!arguments.length)return source;source=_,source_=typeof _==="function"?null:_;return greatArc};greatArc.target=function(_){if(!arguments.length)return target;target=_,target_=typeof _==="function"?null:_;return greatArc};greatArc.precision=function(){return arguments.length?greatArc:0};return greatArc};d3.geo.interpolate=function(source,target){return d3_geo_interpolate(source[0]*d3_radians,source[1]*d3_radians,target[0]*d3_radians,target[1]*d3_radians)};function d3_geo_interpolate(x0,y0,x1,y1){var cy0=Math.cos(y0),sy0=Math.sin(y0),cy1=Math.cos(y1),sy1=Math.sin(y1),kx0=cy0*Math.cos(x0),ky0=cy0*Math.sin(x0),kx1=cy1*Math.cos(x1),ky1=cy1*Math.sin(x1),d=2*Math.asin(Math.sqrt(d3_haversin(y1-y0)+cy0*cy1*d3_haversin(x1-x0))),k=1/Math.sin(d);var interpolate=d?function(t){var B=Math.sin(t*=d)*k,A=Math.sin(d-t)*k,x=A*kx0+B*kx1,y=A*ky0+B*ky1,z=A*sy0+B*sy1;return[Math.atan2(y,x)*d3_degrees,Math.atan2(z,Math.sqrt(x*x+y*y))*d3_degrees]}:function(){return[x0*d3_degrees,y0*d3_degrees]};interpolate.distance=d;return interpolate}d3.geo.length=function(object){d3_geo_lengthSum=0;d3.geo.stream(object,d3_geo_length);return d3_geo_lengthSum};var d3_geo_lengthSum;var d3_geo_length={sphere:d3_noop,point:d3_noop,lineStart:d3_geo_lengthLineStart,lineEnd:d3_noop,polygonStart:d3_noop,polygonEnd:d3_noop};function d3_geo_lengthLineStart(){var λ0,sinφ0,cosφ0;d3_geo_length.point=function(λ,φ){λ0=λ*d3_radians,sinφ0=Math.sin(φ*=d3_radians),cosφ0=Math.cos(φ);d3_geo_length.point=nextPoint};d3_geo_length.lineEnd=function(){d3_geo_length.point=d3_geo_length.lineEnd=d3_noop};function nextPoint(λ,φ){var sinφ=Math.sin(φ*=d3_radians),cosφ=Math.cos(φ),t=Math.abs((λ*=d3_radians)-λ0),cosΔλ=Math.cos(t);d3_geo_lengthSum+=Math.atan2(Math.sqrt((t=cosφ*Math.sin(t))*t+(t=cosφ0*sinφ-sinφ0*cosφ*cosΔλ)*t),sinφ0*sinφ+cosφ0*cosφ*cosΔλ);λ0=λ,sinφ0=sinφ,cosφ0=cosφ}}function d3_geo_azimuthal(scale,angle){function azimuthal(λ,φ){var cosλ=Math.cos(λ),cosφ=Math.cos(φ),k=scale(cosλ*cosφ);return[k*cosφ*Math.sin(λ),k*Math.sin(φ)]}azimuthal.invert=function(x,y){var ρ=Math.sqrt(x*x+y*y),c=angle(ρ),sinc=Math.sin(c),cosc=Math.cos(c);return[Math.atan2(x*sinc,ρ*cosc),Math.asin(ρ&&y*sinc/ρ)]};return azimuthal}var d3_geo_azimuthalEqualArea=d3_geo_azimuthal(function(cosλcosφ){return Math.sqrt(2/(1+cosλcosφ))},function(ρ){return 2*Math.asin(ρ/2)});(d3.geo.azimuthalEqualArea=function(){return d3_geo_projection(d3_geo_azimuthalEqualArea)}).raw=d3_geo_azimuthalEqualArea;var d3_geo_azimuthalEquidistant=d3_geo_azimuthal(function(cosλcosφ){var c=Math.acos(cosλcosφ);return c&&c/Math.sin(c)},d3_identity);(d3.geo.azimuthalEquidistant=function(){return d3_geo_projection(d3_geo_azimuthalEquidistant)}).raw=d3_geo_azimuthalEquidistant;function d3_geo_conicConformal(φ0,φ1){var cosφ0=Math.cos(φ0),t=function(φ){return Math.tan(π/4+φ/2)},n=φ0===φ1?Math.sin(φ0):Math.log(cosφ0/Math.cos(φ1))/Math.log(t(φ1)/t(φ0)),F=cosφ0*Math.pow(t(φ0),n)/n;if(!n)return d3_geo_mercator;function forward(λ,φ){var ρ=Math.abs(Math.abs(φ)-π/2)<ε?0:F/Math.pow(t(φ),n);return[ρ*Math.sin(n*λ),F-ρ*Math.cos(n*λ)]}forward.invert=function(x,y){var ρ0_y=F-y,ρ=d3_sgn(n)*Math.sqrt(x*x+ρ0_y*ρ0_y);return[Math.atan2(x,ρ0_y)/n,2*Math.atan(Math.pow(F/ρ,1/n))-π/2]};return forward}(d3.geo.conicConformal=function(){return d3_geo_conic(d3_geo_conicConformal)}).raw=d3_geo_conicConformal;function d3_geo_conicEquidistant(φ0,φ1){var cosφ0=Math.cos(φ0),n=φ0===φ1?Math.sin(φ0):(cosφ0-Math.cos(φ1))/(φ1-φ0),G=cosφ0/n+φ0;if(Math.abs(n)<ε)return d3_geo_equirectangular;function forward(λ,φ){var ρ=G-φ;return[ρ*Math.sin(n*λ),G-ρ*Math.cos(n*λ)]}forward.invert=function(x,y){var ρ0_y=G-y;return[Math.atan2(x,ρ0_y)/n,G-d3_sgn(n)*Math.sqrt(x*x+ρ0_y*ρ0_y)]};return forward}(d3.geo.conicEquidistant=function(){return d3_geo_conic(d3_geo_conicEquidistant)}).raw=d3_geo_conicEquidistant;var d3_geo_gnomonic=d3_geo_azimuthal(function(cosλcosφ){return 1/cosλcosφ},Math.atan);(d3.geo.gnomonic=function(){return d3_geo_projection(d3_geo_gnomonic)}).raw=d3_geo_gnomonic;function d3_geo_mercator(λ,φ){return[λ,Math.log(Math.tan(π/4+φ/2))]}d3_geo_mercator.invert=function(x,y){return[x,2*Math.atan(Math.exp(y))-π/2]};function d3_geo_mercatorProjection(project){var m=d3_geo_projection(project),scale=m.scale,translate=m.translate,clipExtent=m.clipExtent,clipAuto;m.scale=function(){var v=scale.apply(m,arguments);return v===m?clipAuto?m.clipExtent(null):m:v};m.translate=function(){var v=translate.apply(m,arguments);return v===m?clipAuto?m.clipExtent(null):m:v};m.clipExtent=function(_){var v=clipExtent.apply(m,arguments);if(v===m){if(clipAuto=_==null){var k=π*scale(),t=translate();clipExtent([[t[0]-k,t[1]-k],[t[0]+k,t[1]+k]])}}else if(clipAuto){v=null}return v};return m.clipExtent(null)}(d3.geo.mercator=function(){return d3_geo_mercatorProjection(d3_geo_mercator)}).raw=d3_geo_mercator;var d3_geo_orthographic=d3_geo_azimuthal(function(){return 1},Math.asin);(d3.geo.orthographic=function(){return d3_geo_projection(d3_geo_orthographic)}).raw=d3_geo_orthographic;var d3_geo_stereographic=d3_geo_azimuthal(function(cosλcosφ){return 1/(1+cosλcosφ)},function(ρ){return 2*Math.atan(ρ)});(d3.geo.stereographic=function(){return d3_geo_projection(d3_geo_stereographic)}).raw=d3_geo_stereographic;function d3_geo_transverseMercator(λ,φ){var B=Math.cos(φ)*Math.sin(λ);return[Math.log((1+B)/(1-B))/2,Math.atan2(Math.tan(φ),Math.cos(λ))]}d3_geo_transverseMercator.invert=function(x,y){return[Math.atan2(d3_sinh(x),Math.cos(y)),d3_asin(Math.sin(y)/d3_cosh(x))]};(d3.geo.transverseMercator=function(){return d3_geo_mercatorProjection(d3_geo_transverseMercator)}).raw=d3_geo_transverseMercator;d3.geom={};d3.svg={};function d3_svg_line(projection){var x=d3_svg_lineX,y=d3_svg_lineY,defined=d3_true,interpolate=d3_svg_lineLinear,interpolateKey=interpolate.key,tension=.7;function line(data){var segments=[],points=[],i=-1,n=data.length,d,fx=d3_functor(x),fy=d3_functor(y);function segment(){segments.push("M",interpolate(projection(points),tension))}while(++i1)path.push("H",p[0]);return path.join("")}function d3_svg_lineStepBefore(points){var i=0,n=points.length,p=points[0],path=[p[0],",",p[1]];while(++i1){t=tangents[1];p=points[pi];pi++;path+="C"+(p0[0]+t0[0])+","+(p0[1]+t0[1])+","+(p[0]-t[0])+","+(p[1]-t[1])+","+p[0]+","+p[1];for(var i=2;i9){s=d*3/Math.sqrt(s);m[i]=s*a;m[i+1]=s*b}}}i=-1;while(++i<=j){s=(points[Math.min(j,i+1)][0]-points[Math.max(0,i-1)][0])/(6*(1+m[i]*m[i]));tangents.push([s||0,m[i]*s||0])}return tangents}function d3_svg_lineMonotone(points){return points.length<3?d3_svg_lineLinear(points):points[0]+d3_svg_lineHermite(points,d3_svg_lineMonotoneTangents(points))}d3.geom.hull=function(vertices){var x=d3_svg_lineX,y=d3_svg_lineY;if(arguments.length)return hull(vertices);function hull(data){if(data.length<3)return[];var fx=d3_functor(x),fy=d3_functor(y),n=data.length,vertices,plen=n-1,points=[],stack=[],d,i,j,h=0,x1,y1,x2,y2,u,v,a,sp;if(fx===d3_svg_lineX&&y===d3_svg_lineY)vertices=data;else for(i=0,vertices=[];i=x2*x2+y2*y2){points[i].index=-1;continue}else{points[u].index=-1}}a=points[i].angle;u=i;v=j}stack.push(h);for(i=0,j=0;i<2;++j){if(points[j].index>-1){stack.push(points[j].index);i++}}sp=stack.length;for(;j=0;--i)poly.push(data[stack[i]]);return poly}hull.x=function(_){return arguments.length?(x=_,hull):x};hull.y=function(_){return arguments.length?(y=_,hull):y};return hull};function d3_geom_hullCCW(i1,i2,i3,v){var t,a,b,c,d,e,f;t=v[i1];a=t[0];b=t[1];t=v[i2];c=t[0];d=t[1];t=v[i3];e=t[0];f=t[1];return(f-b)*(c-a)-(d-b)*(e-a)>0}d3.geom.polygon=function(coordinates){d3_subclass(coordinates,d3_geom_polygonPrototype);return coordinates};var d3_geom_polygonPrototype=d3.geom.polygon.prototype=[];d3_geom_polygonPrototype.area=function(){var i=-1,n=this.length,a,b=this[n-1],area=0;while(++i=0){s1=e.ep.r;s2=e.ep.l}else{s1=e.ep.l;s2=e.ep.r}if(e.a===1){y1=s1?s1.y:-Z;x1=e.c-e.b*y1;y2=s2?s2.y:Z;x2=e.c-e.b*y2}else{x1=s1?s1.x:-Z;y1=e.c-e.a*x1;x2=s2?s2.x:Z;y2=e.c-e.a*x2}var v1=[x1,y1],v2=[x2,y2];polygons[e.region.l.index].push(v1,v2);polygons[e.region.r.index].push(v1,v2)});polygons=polygons.map(function(polygon,i){var cx=points[i][0],cy=points[i][1],angle=polygon.map(function(v){return Math.atan2(v[0]-cx,v[1]-cy)}),order=d3.range(polygon.length).sort(function(a,b){return angle[a]-angle[b]});return order.filter(function(d,i){return!i||angle[d]-angle[order[i-1]]>ε}).map(function(d){return polygon[d]})});polygons.forEach(function(polygon,i){var n=polygon.length;if(!n)return polygon.push([-Z,-Z],[-Z,Z],[Z,Z],[Z,-Z]);if(n>2)return;var p0=points[i],p1=polygon[0],p2=polygon[1],x0=p0[0],y0=p0[1],x1=p1[0],y1=p1[1],x2=p2[0],y2=p2[1],dx=Math.abs(x2-x1),dy=y2-y1;if(Math.abs(dy)<ε){var y=y00)y*=-1;polygon.push([-Z,y],[Z,y])}}});if(clipPolygon)for(i=0;ib.y?1:a.xb.x?1:0}),bottomSite:null};var EdgeList={list:[],leftEnd:null,rightEnd:null,init:function(){EdgeList.leftEnd=EdgeList.createHalfEdge(null,"l");EdgeList.rightEnd=EdgeList.createHalfEdge(null,"l");EdgeList.leftEnd.r=EdgeList.rightEnd;EdgeList.rightEnd.l=EdgeList.leftEnd;EdgeList.list.unshift(EdgeList.leftEnd,EdgeList.rightEnd)},createHalfEdge:function(edge,side){return{edge:edge,side:side,vertex:null,l:null,r:null}},insert:function(lb,he){he.l=lb;he.r=lb.r;lb.r.l=he;lb.r=he},leftBound:function(p){var he=EdgeList.leftEnd;do{he=he.r}while(he!=EdgeList.rightEnd&&Geom.rightOf(he,p));he=he.l;return he},del:function(he){he.l.r=he.r;he.r.l=he.l;he.edge=null},right:function(he){return he.r},left:function(he){return he.l},leftRegion:function(he){return he.edge==null?Sites.bottomSite:he.edge.region[he.side]},rightRegion:function(he){return he.edge==null?Sites.bottomSite:he.edge.region[d3_geom_voronoiOpposite[he.side]]}};var Geom={bisect:function(s1,s2){var newEdge={region:{l:s1,r:s2},ep:{l:null,r:null}};var dx=s2.x-s1.x,dy=s2.y-s1.y,adx=dx>0?dx:-dx,ady=dy>0?dy:-dy;newEdge.c=s1.x*dx+s1.y*dy+(dx*dx+dy*dy)*.5;if(adx>ady){newEdge.a=1;newEdge.b=dy/dx;newEdge.c/=dx}else{newEdge.b=1;newEdge.a=dx/dy;newEdge.c/=dy}return newEdge},intersect:function(el1,el2){var e1=el1.edge,e2=el2.edge;if(!e1||!e2||e1.region.r==e2.region.r){return null}var d=e1.a*e2.b-e1.b*e2.a;if(Math.abs(d)<1e-10){return null}var xint=(e1.c*e2.b-e2.c*e1.b)/d,yint=(e2.c*e1.a-e1.c*e2.a)/d,e1r=e1.region.r,e2r=e2.region.r,el,e;if(e1r.y=e.region.r.x;if(rightOfSite&&el.side==="l"||!rightOfSite&&el.side==="r"){return null}return{x:xint,y:yint}},rightOf:function(he,p){var e=he.edge,topsite=e.region.r,rightOfSite=p.x>topsite.x;if(rightOfSite&&he.side==="l"){return 1}if(!rightOfSite&&he.side==="r"){return 0}if(e.a===1){var dyp=p.y-topsite.y,dxp=p.x-topsite.x,fast=0,above=0;if(!rightOfSite&&e.b<0||rightOfSite&&e.b>=0){above=fast=dyp>=e.b*dxp}else{above=p.x+p.y*e.b>e.c;if(e.b<0){above=!above}if(!above){fast=1}}if(!fast){var dxs=topsite.x-e.region.l.x;above=e.b*(dxp*dxp-dyp*dyp)t2*t2+t3*t3}return he.side==="l"?above:!above},endPoint:function(edge,side,site){edge.ep[side]=site;if(!edge.ep[d3_geom_voronoiOpposite[side]])return;callback(edge)},distance:function(s,t){var dx=s.x-t.x,dy=s.y-t.y;return Math.sqrt(dx*dx+dy*dy)}};var EventQueue={list:[],insert:function(he,site,offset){he.vertex=site;he.ystar=site.y+offset;for(var i=0,list=EventQueue.list,l=list.length;inext.ystar||he.ystar==next.ystar&&site.x>next.vertex.x){continue}else{break}}list.splice(i,0,he)},del:function(he){for(var i=0,ls=EventQueue.list,l=ls.length;itop.y){temp=bot;bot=top;top=temp;pm="r"}e=Geom.bisect(bot,top);bisector=EdgeList.createHalfEdge(e,pm);EdgeList.insert(llbnd,bisector);Geom.endPoint(e,d3_geom_voronoiOpposite[pm],v);p=Geom.intersect(llbnd,bisector);if(p){EventQueue.del(llbnd);EventQueue.insert(llbnd,p,Geom.distance(p,bot))}p=Geom.intersect(bisector,rrbnd);if(p){EventQueue.insert(bisector,p,Geom.distance(p,bot))}}else{break}}for(lbnd=EdgeList.right(EdgeList.leftEnd);lbnd!=EdgeList.rightEnd;lbnd=EdgeList.right(lbnd)){callback(lbnd.edge)}}d3.geom.quadtree=function(points,x1,y1,x2,y2){var x=d3_svg_lineX,y=d3_svg_lineY,compat;if(compat=arguments.length){x=d3_geom_quadtreeCompatX;y=d3_geom_quadtreeCompatY;if(compat===3){y2=y1;x2=x1;y1=x1=0}return quadtree(points)}function quadtree(data){var d,fx=d3_functor(x),fy=d3_functor(y),xs,ys,i,n,x1_,y1_,x2_,y2_;if(x1!=null){x1_=x1,y1_=y1,x2_=x2,y2_=y2}else{x2_=y2_=-(x1_=y1_=Infinity);xs=[],ys=[];n=data.length;if(compat)for(i=0;ix2_)x2_=d.x;if(d.y>y2_)y2_=d.y;xs.push(d.x);ys.push(d.y)}else for(i=0;ix2_)x2_=x_;if(y_>y2_)y2_=y_;xs.push(x_);ys.push(y_)}}var dx=x2_-x1_,dy=y2_-y1_;if(dx>dy)y2_=y1_+dx;else x2_=x1_+dy;function insert(n,d,x,y,x1,y1,x2,y2){if(isNaN(x)||isNaN(y))return;if(n.leaf){var nx=n.x,ny=n.y;if(nx!=null){if(Math.abs(nx-x)+Math.abs(ny-y)<.01){insertChild(n,d,x,y,x1,y1,x2,y2)}else{var nPoint=n.point;n.x=n.y=n.point=null;insertChild(n,nPoint,nx,ny,x1,y1,x2,y2);insertChild(n,d,x,y,x1,y1,x2,y2)}}else{n.x=x,n.y=y,n.point=d}}else{insertChild(n,d,x,y,x1,y1,x2,y2)}}function insertChild(n,d,x,y,x1,y1,x2,y2){var sx=(x1+x2)*.5,sy=(y1+y2)*.5,right=x>=sx,bottom=y>=sy,i=(bottom<<1)+right;n.leaf=false;n=n.nodes[i]||(n.nodes[i]=d3_geom_quadtreeNode());if(right)x1=sx;else x2=sx;if(bottom)y1=sy;else y2=sy;insert(n,d,x,y,x1,y1,x2,y2)}var root=d3_geom_quadtreeNode();root.add=function(d){insert(root,d,+fx(d,++i),+fy(d,i),x1_,y1_,x2_,y2_)};root.visit=function(f){d3_geom_quadtreeVisit(f,root,x1_,y1_,x2_,y2_)};i=-1;if(x1==null){while(++i=0&&!(f=d3.interpolators[i](a,b)));return f}d3.interpolators=[function(a,b){var t=typeof b;return(t==="string"?d3_rgb_names.has(b)||/^(#|rgb\(|hsl\()/.test(b)?d3_interpolateRgb:d3_interpolateString:b instanceof d3_Color?d3_interpolateRgb:t==="object"?Array.isArray(b)?d3_interpolateArray:d3_interpolateObject:d3_interpolateNumber)(a,b)}];d3.interpolateArray=d3_interpolateArray;function d3_interpolateArray(a,b){var x=[],c=[],na=a.length,nb=b.length,n0=Math.min(a.length,b.length),i;for(i=0;i=0?name.substring(0,i):name,m=i>=0?name.substring(i+1):"in";t=d3_ease.get(t)||d3_ease_default;m=d3_ease_mode.get(m)||d3_identity;return d3_ease_clamp(m(t.apply(null,Array.prototype.slice.call(arguments,1))))};function d3_ease_clamp(f){return function(t){return t<=0?0:t>=1?1:f(t)}}function d3_ease_reverse(f){return function(t){return 1-f(1-t)}}function d3_ease_reflect(f){return function(t){return.5*(t<.5?f(2*t):2-f(2-2*t))}}function d3_ease_quad(t){return t*t}function d3_ease_cubic(t){return t*t*t}function d3_ease_cubicInOut(t){if(t<=0)return 0;if(t>=1)return 1;var t2=t*t,t3=t2*t;return 4*(t<.5?t3:3*(t-t2)+t3-.75)}function d3_ease_poly(e){return function(t){return Math.pow(t,e)}}function d3_ease_sin(t){return 1-Math.cos(t*π/2)}function d3_ease_exp(t){return Math.pow(2,10*(t-1))}function d3_ease_circle(t){return 1-Math.sqrt(1-t*t)}function d3_ease_elastic(a,p){var s;if(arguments.length<2)p=.45;if(arguments.length)s=p/(2*π)*Math.asin(1/a);else a=1,s=p/4;return function(t){return 1+a*Math.pow(2,10*-t)*Math.sin((t-s)*2*π/p)}}function d3_ease_back(s){if(!s)s=1.70158;return function(t){return t*t*((s+1)*t-s)}}function d3_ease_bounce(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}d3.interpolateHcl=d3_interpolateHcl;function d3_interpolateHcl(a,b){a=d3.hcl(a);b=d3.hcl(b);var ah=a.h,ac=a.c,al=a.l,bh=b.h-ah,bc=b.c-ac,bl=b.l-al;if(isNaN(bc))bc=0,ac=isNaN(ac)?b.c:ac;if(isNaN(bh))bh=0,ah=isNaN(ah)?b.h:ah;else if(bh>180)bh-=360;else if(bh<-180)bh+=360;return function(t){return d3_hcl_lab(ah+bh*t,ac+bc*t,al+bl*t)+""}}d3.interpolateHsl=d3_interpolateHsl;function d3_interpolateHsl(a,b){a=d3.hsl(a);b=d3.hsl(b);var ah=a.h,as=a.s,al=a.l,bh=b.h-ah,bs=b.s-as,bl=b.l-al;if(isNaN(bs))bs=0,as=isNaN(as)?b.s:as;if(isNaN(bh))bh=0,ah=isNaN(ah)?b.h:ah;else if(bh>180)bh-=360;else if(bh<-180)bh+=360;return function(t){return d3_hsl_rgb(ah+bh*t,as+bs*t,al+bl*t)+""}}d3.interpolateLab=d3_interpolateLab;function d3_interpolateLab(a,b){a=d3.lab(a);b=d3.lab(b);var al=a.l,aa=a.a,ab=a.b,bl=b.l-al,ba=b.a-aa,bb=b.b-ab;return function(t){return d3_lab_rgb(al+bl*t,aa+ba*t,ab+bb*t)+""}}d3.interpolateRound=d3_interpolateRound;function d3_interpolateRound(a,b){b-=a;return function(t){return Math.round(a+b*t)}}d3.transform=function(string){var g=d3_document.createElementNS(d3.ns.prefix.svg,"g");return(d3.transform=function(string){if(string!=null){g.setAttribute("transform",string);var t=g.transform.baseVal.consolidate()}return new d3_transform(t?t.matrix:d3_transformIdentity)})(string)};function d3_transform(m){var r0=[m.a,m.b],r1=[m.c,m.d],kx=d3_transformNormalize(r0),kz=d3_transformDot(r0,r1),ky=d3_transformNormalize(d3_transformCombine(r1,r0,-kz))||0;if(r0[0]*r1[1]180)rb+=360;else if(rb-ra>180)ra+=360;q.push({i:s.push(s.pop()+"rotate(",null,")")-2,x:d3_interpolateNumber(ra,rb)})}else if(rb){s.push(s.pop()+"rotate("+rb+")")}if(wa!=wb){q.push({i:s.push(s.pop()+"skewX(",null,")")-2,x:d3_interpolateNumber(wa,wb)})}else if(wb){s.push(s.pop()+"skewX("+wb+")")}if(ka[0]!=kb[0]||ka[1]!=kb[1]){n=s.push(s.pop()+"scale(",null,",",null,")");q.push({i:n-4,x:d3_interpolateNumber(ka[0],kb[0])},{i:n-2,x:d3_interpolateNumber(ka[1],kb[1])})}else if(kb[0]!=1||kb[1]!=1){s.push(s.pop()+"scale("+kb+")")}n=q.length;return function(t){var i=-1,o;while(++i0)alpha=x;else alpha=0}else if(x>0){event.start({type:"start",alpha:alpha=x});d3.timer(force.tick)}return force};force.start=function(){var i,j,n=nodes.length,m=links.length,w=size[0],h=size[1],neighbors,o;for(i=0;imax)max=o;sums.push(o)}for(j=0;jv){j=i;v=k}}return j}function d3_layout_stackReduceSum(d){return d.reduce(d3_layout_stackSum,0)}function d3_layout_stackSum(p,d){return p+d[1]}d3.layout.histogram=function(){var frequency=true,valuer=Number,ranger=d3_layout_histogramRange,binner=d3_layout_histogramBinSturges;function histogram(data,i){var bins=[],values=data.map(valuer,this),range=ranger.call(this,values,i),thresholds=binner.call(this,range,values,i),bin,i=-1,n=values.length,m=thresholds.length-1,k=frequency?1:1/n,x;while(++i0){i=-1;while(++i=range[0]&&x<=range[1]){bin=bins[d3.bisect(thresholds,x,1,m)-1];bin.y+=k;bin.push(data[i])}}}return bins}histogram.value=function(x){if(!arguments.length)return valuer;valuer=x;return histogram};histogram.range=function(x){if(!arguments.length)return ranger;ranger=d3_functor(x);return histogram};histogram.bins=function(x){if(!arguments.length)return binner;binner=typeof x==="number"?function(range){return d3_layout_histogramBinFixed(range,x)}:d3_functor(x);return histogram};histogram.frequency=function(x){if(!arguments.length)return frequency;frequency=!!x;return histogram};return histogram};function d3_layout_histogramBinSturges(range,values){return d3_layout_histogramBinFixed(range,Math.ceil(Math.log(values.length)/Math.LN2+1))}function d3_layout_histogramBinFixed(range,n){var x=-1,b=+range[0],m=(range[1]-b)/n,f=[];while(++x<=n)f[x]=m*x+b;return f}function d3_layout_histogramRange(values){return[d3.min(values),d3.max(values)]}d3.layout.tree=function(){var hierarchy=d3.layout.hierarchy().sort(null).value(null),separation=d3_layout_treeSeparation,size=[1,1],nodeSize=false;function tree(d,i){var nodes=hierarchy.call(this,d,i),root=nodes[0];function firstWalk(node,previousSibling){var children=node.children,layout=node._tree;if(children&&(n=children.length)){var n,firstChild=children[0],previousChild,ancestor=firstChild,child,i=-1;while(++i0){d3_layout_treeMove(d3_layout_treeAncestor(vim,node,ancestor),node,shift);sip+=shift;sop+=shift}sim+=vim._tree.mod;sip+=vip._tree.mod;som+=vom._tree.mod;sop+=vop._tree.mod}if(vim&&!d3_layout_treeRight(vop)){vop._tree.thread=vim;vop._tree.mod+=sim-sop}if(vip&&!d3_layout_treeLeft(vom)){vom._tree.thread=vip;vom._tree.mod+=sip-som;ancestor=node}}return ancestor}d3_layout_treeVisitAfter(root,function(node,previousSibling){node._tree={ancestor:node,prelim:0,mod:0,change:0,shift:0,number:previousSibling?previousSibling._tree.number+1:0}});firstWalk(root);secondWalk(root,-root._tree.prelim);var left=d3_layout_treeSearch(root,d3_layout_treeLeftmost),right=d3_layout_treeSearch(root,d3_layout_treeRightmost),deep=d3_layout_treeSearch(root,d3_layout_treeDeepest),x0=left.x-separation(left,right)/2,x1=right.x+separation(right,left)/2,y1=deep.depth||1;d3_layout_treeVisitAfter(root,nodeSize?function(node){node.x*=size[0];node.y=node.depth*size[1];delete node._tree}:function(node){node.x=(node.x-x0)/(x1-x0)*size[0];node.y=node.depth/y1*size[1];delete node._tree});return nodes}tree.separation=function(x){if(!arguments.length)return separation;separation=x;return tree};tree.size=function(x){if(!arguments.length)return nodeSize?null:size;nodeSize=(size=x)==null;return tree};tree.nodeSize=function(x){if(!arguments.length)return nodeSize?size:null;nodeSize=(size=x)!=null;return tree};return d3_layout_hierarchyRebind(tree,hierarchy)};function d3_layout_treeSeparation(a,b){return a.parent==b.parent?1:2}function d3_layout_treeLeft(node){var children=node.children;return children&&children.length?children[0]:node._tree.thread}function d3_layout_treeRight(node){var children=node.children,n;return children&&(n=children.length)?children[n-1]:node._tree.thread}function d3_layout_treeSearch(node,compare){var children=node.children;if(children&&(n=children.length)){var child,n,i=-1;while(++i0){node=child}}}return node}function d3_layout_treeRightmost(a,b){return a.x-b.x}function d3_layout_treeLeftmost(a,b){return b.x-a.x}function d3_layout_treeDeepest(a,b){return a.depth-b.depth}function d3_layout_treeVisitAfter(node,callback){function visit(node,previousSibling){var children=node.children;if(children&&(n=children.length)){var child,previousChild=null,i=-1,n;while(++i=0){child=children[i]._tree;child.prelim+=shift;child.mod+=shift;shift+=child.shift+(change+=child.change)}}function d3_layout_treeMove(ancestor,node,shift){ancestor=ancestor._tree;node=node._tree;var change=shift/(node.number-ancestor.number);ancestor.change+=change;node.change-=change;node.shift+=shift;node.prelim+=shift;node.mod+=shift}function d3_layout_treeAncestor(vim,node,ancestor){return vim._tree.ancestor.parent==node.parent?vim._tree.ancestor:ancestor}d3.layout.pack=function(){var hierarchy=d3.layout.hierarchy().sort(d3_layout_packSort),padding=0,size=[1,1],radius;function pack(d,i){var nodes=hierarchy.call(this,d,i),root=nodes[0],w=size[0],h=size[1],r=radius==null?Math.sqrt:typeof radius==="function"?radius:function(){return radius};root.x=root.y=0;d3_layout_treeVisitAfter(root,function(d){d.r=+r(d.value)});d3_layout_treeVisitAfter(root,d3_layout_packSiblings);if(padding){var dr=padding*(radius?1:Math.max(2*root.r/w,2*root.r/h))/2;d3_layout_treeVisitAfter(root,function(d){d.r+=dr});d3_layout_treeVisitAfter(root,d3_layout_packSiblings);d3_layout_treeVisitAfter(root,function(d){d.r-=dr})}d3_layout_packTransform(root,w/2,h/2,radius?1:1/Math.max(2*root.r/w,2*root.r/h));return nodes}pack.size=function(_){if(!arguments.length)return size;size=_;return pack};pack.radius=function(_){if(!arguments.length)return radius;radius=_==null||typeof _==="function"?_:+_;return pack};pack.padding=function(_){if(!arguments.length)return padding;padding=+_;return pack};return d3_layout_hierarchyRebind(pack,hierarchy)};function d3_layout_packSort(a,b){return a.value-b.value}function d3_layout_packInsert(a,b){var c=a._pack_next;a._pack_next=b;b._pack_prev=a;b._pack_next=c;c._pack_prev=b}function d3_layout_packSplice(a,b){a._pack_next=b;b._pack_prev=a}function d3_layout_packIntersects(a,b){var dx=b.x-a.x,dy=b.y-a.y,dr=a.r+b.r;return.999*dr*dr>dx*dx+dy*dy}function d3_layout_packSiblings(node){if(!(nodes=node.children)||!(n=nodes.length))return;var nodes,xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity,a,b,c,i,j,k,n;function bound(node){xMin=Math.min(node.x-node.r,xMin);xMax=Math.max(node.x+node.r,xMax);yMin=Math.min(node.y-node.r,yMin);yMax=Math.max(node.y+node.r,yMax)}nodes.forEach(d3_layout_packLink);a=nodes[0];a.x=-a.r;a.y=0;bound(a);if(n>1){b=nodes[1];b.x=b.r;b.y=0;bound(b);if(n>2){c=nodes[2];d3_layout_packPlace(a,b,c);bound(c);d3_layout_packInsert(a,c);a._pack_prev=c;d3_layout_packInsert(c,b);b=a._pack_next;for(i=3;i0){row.push(child=remaining[n-1]);row.area+=child.area;if(mode!=="squarify"||(score=worst(row,u))<=best){remaining.pop();best=score}else{row.area-=row.pop().area;position(row,u,rect,false);u=Math.min(rect.dx,rect.dy);row.length=row.area=0;best=Infinity}}if(row.length){position(row,u,rect,true);row.length=row.area=0}children.forEach(squarify)}}function stickify(node){var children=node.children;if(children&&children.length){var rect=pad(node),remaining=children.slice(),child,row=[];scale(remaining,rect.dx*rect.dy/node.value);row.area=0;while(child=remaining.pop()){row.push(child);row.area+=child.area;if(child.z!=null){position(row,child.z?rect.dx:rect.dy,rect,!remaining.length);row.length=row.area=0}}children.forEach(stickify)}}function worst(row,u){var s=row.area,r,rmax=0,rmin=Infinity,i=-1,n=row.length;while(++irmax)rmax=r}s*=s;u*=u;return s?Math.max(u*rmax*ratio/s,s/(u*rmin*ratio)):Infinity}function position(row,u,rect,flush){var i=-1,n=row.length,x=rect.x,y=rect.y,v=u?round(row.area/u):0,o;if(u==rect.dx){if(flush||v>rect.dy)v=rect.dy;while(++irect.dx)v=rect.dx;while(++i1);return µ+σ*x*Math.sqrt(-2*Math.log(r)/r)}},logNormal:function(){var random=d3.random.normal.apply(d3,arguments);return function(){return Math.exp(random())}},irwinHall:function(m){return function(){for(var s=0,j=0;j2?d3_scale_polylinear:d3_scale_bilinear,uninterpolate=clamp?d3_uninterpolateClamp:d3_uninterpolateNumber;output=linear(domain,range,uninterpolate,interpolate);input=linear(range,domain,uninterpolate,d3_interpolate);return scale}function scale(x){return output(x)}scale.invert=function(y){return input(y)};scale.domain=function(x){if(!arguments.length)return domain;domain=x.map(Number);return rescale()};scale.range=function(x){if(!arguments.length)return range;range=x;return rescale()};scale.rangeRound=function(x){return scale.range(x).interpolate(d3_interpolateRound)};scale.clamp=function(x){if(!arguments.length)return clamp;clamp=x;return rescale()};scale.interpolate=function(x){if(!arguments.length)return interpolate;interpolate=x;return rescale()};scale.ticks=function(m){return d3_scale_linearTicks(domain,m)};scale.tickFormat=function(m,format){return d3_scale_linearTickFormat(domain,m,format)};scale.nice=function(m){d3_scale_linearNice(domain,m);return rescale()};scale.copy=function(){return d3_scale_linear(domain,range,interpolate,clamp)};return rescale()}function d3_scale_linearRebind(scale,linear){return d3.rebind(scale,linear,"range","rangeRound","interpolate","clamp")}function d3_scale_linearNice(domain,m){return d3_scale_nice(domain,d3_scale_niceStep(m?d3_scale_linearTickRange(domain,m)[2]:d3_scale_linearNiceStep(domain)))}function d3_scale_linearNiceStep(domain){var extent=d3_scaleExtent(domain),span=extent[1]-extent[0];return Math.pow(10,Math.round(Math.log(span)/Math.LN10)-1)}function d3_scale_linearTickRange(domain,m){var extent=d3_scaleExtent(domain),span=extent[1]-extent[0],step=Math.pow(10,Math.floor(Math.log(span/m)/Math.LN10)),err=m/span*step;if(err<=.15)step*=10;else if(err<=.35)step*=5;else if(err<=.75)step*=2;extent[0]=Math.ceil(extent[0]/step)*step;extent[1]=Math.floor(extent[1]/step)*step+step*.5;extent[2]=step;return extent}function d3_scale_linearTicks(domain,m){return d3.range.apply(d3,d3_scale_linearTickRange(domain,m))}function d3_scale_linearTickFormat(domain,m,format){var precision=-Math.floor(Math.log(d3_scale_linearTickRange(domain,m)[2])/Math.LN10+.01);return d3.format(format?format.replace(d3_format_re,function(a,b,c,d,e,f,g,h,i,j){return[b,c,d,e,f,g,h,i||"."+(precision-(j==="%")*2),j].join("")}):",."+precision+"f")}d3.scale.log=function(){return d3_scale_log(d3.scale.linear().domain([0,1]),10,true,[1,10])};function d3_scale_log(linear,base,positive,domain){function log(x){return(positive?Math.log(x<0?0:x):-Math.log(x>0?0:-x))/Math.log(base)}function pow(x){return positive?Math.pow(base,x):-Math.pow(base,-x)}function scale(x){return linear(log(x))}scale.invert=function(x){return pow(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return domain;positive=x[0]>=0;linear.domain((domain=x.map(Number)).map(log));return scale};scale.base=function(_){if(!arguments.length)return base;base=+_;linear.domain(domain.map(log));return scale};scale.nice=function(){var niced=d3_scale_nice(domain.map(log),positive?Math:d3_scale_logNiceNegative);linear.domain(niced);domain=niced.map(pow);return scale};scale.ticks=function(){var extent=d3_scaleExtent(domain),ticks=[],u=extent[0],v=extent[1],i=Math.floor(log(u)),j=Math.ceil(log(v)),n=base%1?2:base;if(isFinite(j-i)){if(positive){for(;i0;k--)ticks.push(pow(i)*k)}for(i=0;ticks[i]v;j--){}ticks=ticks.slice(i,j)}return ticks};scale.tickFormat=function(n,format){if(!arguments.length)return d3_scale_logFormat;if(arguments.length<2)format=d3_scale_logFormat;else if(typeof format!=="function")format=d3.format(format);var k=Math.max(.1,n/scale.ticks().length),f=positive?(e=1e-12,Math.ceil):(e=-1e-12,Math.floor),e;return function(d){return d/pow(f(log(d)+e))<=k?format(d):""}};scale.copy=function(){return d3_scale_log(linear.copy(),base,positive,domain)};return d3_scale_linearRebind(scale,linear)}var d3_scale_logFormat=d3.format(".0e"),d3_scale_logNiceNegative={floor:function(x){return-Math.ceil(-x)},ceil:function(x){return-Math.floor(-x)}};d3.scale.pow=function(){return d3_scale_pow(d3.scale.linear(),1,[0,1])};function d3_scale_pow(linear,exponent,domain){var powp=d3_scale_powPow(exponent),powb=d3_scale_powPow(1/exponent);function scale(x){return linear(powp(x))}scale.invert=function(x){return powb(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return domain;linear.domain((domain=x.map(Number)).map(powp));return scale};scale.ticks=function(m){return d3_scale_linearTicks(domain,m)};scale.tickFormat=function(m,format){return d3_scale_linearTickFormat(domain,m,format)};scale.nice=function(m){return scale.domain(d3_scale_linearNice(domain,m))};scale.exponent=function(x){if(!arguments.length)return exponent;powp=d3_scale_powPow(exponent=x);powb=d3_scale_powPow(1/exponent);linear.domain(domain.map(powp));return scale};scale.copy=function(){return d3_scale_pow(linear.copy(),exponent,domain)};return d3_scale_linearRebind(scale,linear)}function d3_scale_powPow(e){return function(x){return x<0?-Math.pow(-x,e):Math.pow(x,e)}}d3.scale.sqrt=function(){return d3.scale.pow().exponent(.5)};d3.scale.ordinal=function(){return d3_scale_ordinal([],{t:"range",a:[[]]})};function d3_scale_ordinal(domain,ranger){var index,range,rangeBand;function scale(x){return range[((index.get(x)||index.set(x,domain.push(x)))-1)%range.length]}function steps(start,step){return d3.range(domain.length).map(function(i){return start+step*i})}scale.domain=function(x){if(!arguments.length)return domain;domain=[];index=new d3_Map;var i=-1,n=x.length,xi;while(++i0?thresholds[y-1]:domain[0],y=d3_svg_arcMax?r0?"M0,"+r1+"A"+r1+","+r1+" 0 1,1 0,"+-r1+"A"+r1+","+r1+" 0 1,1 0,"+r1+"M0,"+r0+"A"+r0+","+r0+" 0 1,0 0,"+-r0+"A"+r0+","+r0+" 0 1,0 0,"+r0+"Z":"M0,"+r1+"A"+r1+","+r1+" 0 1,1 0,"+-r1+"A"+r1+","+r1+" 0 1,1 0,"+r1+"Z":r0?"M"+r1*c0+","+r1*s0+"A"+r1+","+r1+" 0 "+df+",1 "+r1*c1+","+r1*s1+"L"+r0*c1+","+r0*s1+"A"+r0+","+r0+" 0 "+df+",0 "+r0*c0+","+r0*s0+"Z":"M"+r1*c0+","+r1*s0+"A"+r1+","+r1+" 0 "+df+",1 "+r1*c1+","+r1*s1+"L0,0"+"Z"}arc.innerRadius=function(v){if(!arguments.length)return innerRadius;innerRadius=d3_functor(v);return arc};arc.outerRadius=function(v){if(!arguments.length)return outerRadius;outerRadius=d3_functor(v);return arc};arc.startAngle=function(v){if(!arguments.length)return startAngle;startAngle=d3_functor(v);return arc};arc.endAngle=function(v){if(!arguments.length)return endAngle;endAngle=d3_functor(v);return arc};arc.centroid=function(){var r=(innerRadius.apply(this,arguments)+outerRadius.apply(this,arguments))/2,a=(startAngle.apply(this,arguments)+endAngle.apply(this,arguments))/2+d3_svg_arcOffset;return[Math.cos(a)*r,Math.sin(a)*r]};return arc};var d3_svg_arcOffset=-π/2,d3_svg_arcMax=2*π-1e-6;function d3_svg_arcInnerRadius(d){return d.innerRadius}function d3_svg_arcOuterRadius(d){return d.outerRadius}function d3_svg_arcStartAngle(d){return d.startAngle}function d3_svg_arcEndAngle(d){return d.endAngle}d3.svg.line.radial=function(){var line=d3_svg_line(d3_svg_lineRadial);line.radius=line.x,delete line.x;line.angle=line.y,delete line.y;return line};function d3_svg_lineRadial(points){var point,i=-1,n=points.length,r,a;while(++iπ)+",1 "+p}function curve(r0,p0,r1,p1){return"Q 0,0 "+p1}chord.radius=function(v){if(!arguments.length)return radius;radius=d3_functor(v);return chord};chord.source=function(v){if(!arguments.length)return source;source=d3_functor(v);return chord};chord.target=function(v){if(!arguments.length)return target;target=d3_functor(v);return chord};chord.startAngle=function(v){if(!arguments.length)return startAngle;startAngle=d3_functor(v);return chord};chord.endAngle=function(v){if(!arguments.length)return endAngle;endAngle=d3_functor(v);return chord};return chord};function d3_svg_chordRadius(d){return d.radius}d3.svg.diagonal=function(){var source=d3_source,target=d3_target,projection=d3_svg_diagonalProjection;function diagonal(d,i){var p0=source.call(this,d,i),p3=target.call(this,d,i),m=(p0.y+p3.y)/2,p=[p0,{x:p0.x,y:m},{x:p3.x,y:m},p3];p=p.map(projection);return"M"+p[0]+"C"+p[1]+" "+p[2]+" "+p[3]}diagonal.source=function(x){if(!arguments.length)return source;source=d3_functor(x);return diagonal};diagonal.target=function(x){if(!arguments.length)return target;target=d3_functor(x);return diagonal};diagonal.projection=function(x){if(!arguments.length)return projection;projection=x;return diagonal};return diagonal};function d3_svg_diagonalProjection(d){return[d.x,d.y]}d3.svg.diagonal.radial=function(){var diagonal=d3.svg.diagonal(),projection=d3_svg_diagonalProjection,projection_=diagonal.projection;diagonal.projection=function(x){return arguments.length?projection_(d3_svg_diagonalRadialProjection(projection=x)):projection};return diagonal};function d3_svg_diagonalRadialProjection(projection){return function(){var d=projection.apply(this,arguments),r=d[0],a=d[1]+d3_svg_arcOffset;return[r*Math.cos(a),r*Math.sin(a)]}}d3.svg.symbol=function(){var type=d3_svg_symbolType,size=d3_svg_symbolSize;function symbol(d,i){return(d3_svg_symbols.get(type.call(this,d,i))||d3_svg_symbolCircle)(size.call(this,d,i))}symbol.type=function(x){if(!arguments.length)return type;type=d3_functor(x);return symbol};symbol.size=function(x){if(!arguments.length)return size;size=d3_functor(x);return symbol};return symbol};function d3_svg_symbolSize(){return 64}function d3_svg_symbolType(){return"circle"}function d3_svg_symbolCircle(size){var r=Math.sqrt(size/π);return"M0,"+r+"A"+r+","+r+" 0 1,1 0,"+-r+"A"+r+","+r+" 0 1,1 0,"+r+"Z"}var d3_svg_symbols=d3.map({circle:d3_svg_symbolCircle,cross:function(size){var r=Math.sqrt(size/5)/2;return"M"+-3*r+","+-r+"H"+-r+"V"+-3*r+"H"+r+"V"+-r+"H"+3*r+"V"+r+"H"+r+"V"+3*r+"H"+-r+"V"+r+"H"+-3*r+"Z"},diamond:function(size){var ry=Math.sqrt(size/(2*d3_svg_symbolTan30)),rx=ry*d3_svg_symbolTan30;return"M0,"+-ry+"L"+rx+",0"+" 0,"+ry+" "+-rx+",0"+"Z"},square:function(size){var r=Math.sqrt(size)/2;return"M"+-r+","+-r+"L"+r+","+-r+" "+r+","+r+" "+-r+","+r+"Z"},"triangle-down":function(size){var rx=Math.sqrt(size/d3_svg_symbolSqrt3),ry=rx*d3_svg_symbolSqrt3/2;return"M0,"+ry+"L"+rx+","+-ry+" "+-rx+","+-ry+"Z"},"triangle-up":function(size){var rx=Math.sqrt(size/d3_svg_symbolSqrt3),ry=rx*d3_svg_symbolSqrt3/2;return"M0,"+-ry+"L"+rx+","+ry+" "+-rx+","+ry+"Z"}});d3.svg.symbolTypes=d3_svg_symbols.keys();var d3_svg_symbolSqrt3=Math.sqrt(3),d3_svg_symbolTan30=Math.tan(30*d3_radians);function d3_transition(groups,id){d3_subclass(groups,d3_transitionPrototype);groups.id=id;return groups}var d3_transitionPrototype=[],d3_transitionId=0,d3_transitionInheritId,d3_transitionInherit;d3_transitionPrototype.call=d3_selectionPrototype.call;d3_transitionPrototype.empty=d3_selectionPrototype.empty;d3_transitionPrototype.node=d3_selectionPrototype.node;d3_transitionPrototype.size=d3_selectionPrototype.size;d3.transition=function(selection){return arguments.length?d3_transitionInheritId?selection.transition():selection:d3_selectionRoot.transition()};d3.transition.prototype=d3_transitionPrototype;d3_transitionPrototype.select=function(selector){var id=this.id,subgroups=[],subgroup,subnode,node;selector=d3_selection_selector(selector);for(var j=-1,m=this.length;++jid)return stop();lock.active=id;transition.event&&transition.event.start.call(node,d,i);transition.tween.forEach(function(key,value){if(value=value.call(node,d,i)){tweened.push(value)}});if(tick(elapsed))return 1;d3_timer_replace(tick,0,time)}function tick(elapsed){if(lock.active!==id)return stop();var t=(elapsed-delay)/duration,e=ease(t),n=tweened.length;while(n>0){tweened[--n].call(node,e)}if(t>=1){stop();transition.event&&transition.event.end.call(node,d,i);return 1}}function stop(){if(--lock.count)delete lock[id];else delete node.__transition__;return 1}},0,time)}}d3.svg.axis=function(){var scale=d3.scale.linear(),orient=d3_svg_axisDefaultOrient,tickMajorSize=6,tickMinorSize=6,tickEndSize=6,tickPadding=3,tickArguments_=[10],tickValues=null,tickFormat_,tickSubdivide=0;function axis(g){g.each(function(){var g=d3.select(this);var ticks=tickValues==null?scale.ticks?scale.ticks.apply(scale,tickArguments_):scale.domain():tickValues,tickFormat=tickFormat_==null?scale.tickFormat?scale.tickFormat.apply(scale,tickArguments_):String:tickFormat_;var subticks=d3_svg_axisSubdivide(scale,ticks,tickSubdivide),subtick=g.selectAll(".tick.minor").data(subticks,String),subtickEnter=subtick.enter().insert("line",".tick").attr("class","tick minor").style("opacity",1e-6),subtickExit=d3.transition(subtick.exit()).style("opacity",1e-6).remove(),subtickUpdate=d3.transition(subtick).style("opacity",1);var tick=g.selectAll(".tick.major").data(ticks,String),tickEnter=tick.enter().insert("g",".domain").attr("class","tick major").style("opacity",1e-6),tickExit=d3.transition(tick.exit()).style("opacity",1e-6).remove(),tickUpdate=d3.transition(tick).style("opacity",1),tickTransform;var range=d3_scaleRange(scale),path=g.selectAll(".domain").data([0]),pathUpdate=(path.enter().append("path").attr("class","domain"),d3.transition(path));var scale1=scale.copy(),scale0=this.__chart__||scale1;this.__chart__=scale1;tickEnter.append("line");tickEnter.append("text");var lineEnter=tickEnter.select("line"),lineUpdate=tickUpdate.select("line"),text=tick.select("text").text(tickFormat),textEnter=tickEnter.select("text"),textUpdate=tickUpdate.select("text");switch(orient){case"bottom":{tickTransform=d3_svg_axisX;subtickEnter.attr("y2",tickMinorSize);subtickUpdate.attr("x2",0).attr("y2",tickMinorSize);lineEnter.attr("y2",tickMajorSize);textEnter.attr("y",Math.max(tickMajorSize,0)+tickPadding);lineUpdate.attr("x2",0).attr("y2",tickMajorSize);textUpdate.attr("x",0).attr("y",Math.max(tickMajorSize,0)+tickPadding);text.attr("dy",".71em").style("text-anchor","middle");pathUpdate.attr("d","M"+range[0]+","+tickEndSize+"V0H"+range[1]+"V"+tickEndSize);break}case"top":{tickTransform=d3_svg_axisX;subtickEnter.attr("y2",-tickMinorSize);subtickUpdate.attr("x2",0).attr("y2",-tickMinorSize);lineEnter.attr("y2",-tickMajorSize);textEnter.attr("y",-(Math.max(tickMajorSize,0)+tickPadding));lineUpdate.attr("x2",0).attr("y2",-tickMajorSize);textUpdate.attr("x",0).attr("y",-(Math.max(tickMajorSize,0)+tickPadding));text.attr("dy","0em").style("text-anchor","middle");pathUpdate.attr("d","M"+range[0]+","+-tickEndSize+"V0H"+range[1]+"V"+-tickEndSize);break}case"left":{tickTransform=d3_svg_axisY;subtickEnter.attr("x2",-tickMinorSize);subtickUpdate.attr("x2",-tickMinorSize).attr("y2",0);lineEnter.attr("x2",-tickMajorSize);textEnter.attr("x",-(Math.max(tickMajorSize,0)+tickPadding));lineUpdate.attr("x2",-tickMajorSize).attr("y2",0);textUpdate.attr("x",-(Math.max(tickMajorSize,0)+tickPadding)).attr("y",0);text.attr("dy",".32em").style("text-anchor","end");pathUpdate.attr("d","M"+-tickEndSize+","+range[0]+"H0V"+range[1]+"H"+-tickEndSize);break}case"right":{tickTransform=d3_svg_axisY;subtickEnter.attr("x2",tickMinorSize);subtickUpdate.attr("x2",tickMinorSize).attr("y2",0);lineEnter.attr("x2",tickMajorSize);textEnter.attr("x",Math.max(tickMajorSize,0)+tickPadding);lineUpdate.attr("x2",tickMajorSize).attr("y2",0);textUpdate.attr("x",Math.max(tickMajorSize,0)+tickPadding).attr("y",0);text.attr("dy",".32em").style("text-anchor","start");pathUpdate.attr("d","M"+tickEndSize+","+range[0]+"H0V"+range[1]+"H"+tickEndSize);break}}if(scale.rangeBand){var dx=scale1.rangeBand()/2,x=function(d){return scale1(d)+dx};tickEnter.call(tickTransform,x);tickUpdate.call(tickTransform,x)}else{tickEnter.call(tickTransform,scale0);tickUpdate.call(tickTransform,scale1);tickExit.call(tickTransform,scale1);subtickEnter.call(tickTransform,scale0);subtickUpdate.call(tickTransform,scale1);subtickExit.call(tickTransform,scale1)}})}axis.scale=function(x){if(!arguments.length)return scale;scale=x;return axis};axis.orient=function(x){if(!arguments.length)return orient;orient=x in d3_svg_axisOrients?x+"":d3_svg_axisDefaultOrient;return axis};axis.ticks=function(){if(!arguments.length)return tickArguments_;tickArguments_=arguments;return axis};axis.tickValues=function(x){if(!arguments.length)return tickValues;tickValues=x;return axis};axis.tickFormat=function(x){if(!arguments.length)return tickFormat_;tickFormat_=x;return axis};axis.tickSize=function(x,y){if(!arguments.length)return tickMajorSize;var n=arguments.length-1;tickMajorSize=+x;tickMinorSize=n>1?+y:tickMajorSize;tickEndSize=n>0?+arguments[n]:tickMajorSize;return axis};axis.tickPadding=function(x){if(!arguments.length)return tickPadding;tickPadding=+x;return axis};axis.tickSubdivide=function(x){if(!arguments.length)return tickSubdivide;tickSubdivide=+x;return axis};return axis};var d3_svg_axisDefaultOrient="bottom",d3_svg_axisOrients={top:1,right:1,bottom:1,left:1};function d3_svg_axisX(selection,x){selection.attr("transform",function(d){return"translate("+x(d)+",0)"})}function d3_svg_axisY(selection,y){selection.attr("transform",function(d){return"translate(0,"+y(d)+")"})}function d3_svg_axisSubdivide(scale,ticks,m){subticks=[];if(m&&ticks.length>1){var extent=d3_scaleExtent(scale.domain()),subticks,i=-1,n=ticks.length,d=(ticks[1]-ticks[0])/++m,j,v;while(++i0;){if((v=+ticks[i]-j*d)>=extent[0]){subticks.push(v)}}}for(--i,j=0;++jrect,.s>rect").attr("width",extent[1][0]-extent[0][0])}function redrawY(g){g.select(".extent").attr("y",extent[0][1]);g.selectAll(".extent,.e>rect,.w>rect").attr("height",extent[1][1]-extent[0][1])}function brushstart(){var target=this,eventTarget=d3.select(d3.event.target),event_=event.of(target,arguments),g=d3.select(target),resizing=eventTarget.datum(),resizingX=!/^(n|s)$/.test(resizing)&&x,resizingY=!/^(e|w)$/.test(resizing)&&y,dragging=eventTarget.classed("extent"),dragRestore=d3_event_dragSuppress(),center,origin=mouse(),offset;var w=d3.select(d3_window).on("keydown.brush",keydown).on("keyup.brush",keyup);if(d3.event.changedTouches){w.on("touchmove.brush",brushmove).on("touchend.brush",brushend)}else{w.on("mousemove.brush",brushmove).on("mouseup.brush",brushend)}if(dragging){origin[0]=extent[0][0]-origin[0];origin[1]=extent[0][1]-origin[1]}else if(resizing){var ex=+/w$/.test(resizing),ey=+/^n/.test(resizing);offset=[extent[1-ex][0]-origin[0],extent[1-ey][1]-origin[1]];origin[0]=extent[ex][0];origin[1]=extent[ey][1]}else if(d3.event.altKey)center=origin.slice();g.style("pointer-events","none").selectAll(".resize").style("display",null);d3.select("body").style("cursor",eventTarget.style("cursor"));event_({type:"brushstart"});brushmove();function mouse(){var touches=d3.event.changedTouches;return touches?d3.touches(target,touches)[0]:d3.mouse(target)}function keydown(){if(d3.event.keyCode==32){if(!dragging){center=null;origin[0]-=extent[1][0];origin[1]-=extent[1][1];dragging=2}d3_eventPreventDefault()}}function keyup(){if(d3.event.keyCode==32&&dragging==2){origin[0]+=extent[1][0];origin[1]+=extent[1][1];dragging=0;d3_eventPreventDefault()}}function brushmove(){var point=mouse(),moved=false;if(offset){point[0]+=offset[0];point[1]+=offset[1]}if(!dragging){if(d3.event.altKey){if(!center)center=[(extent[0][0]+extent[1][0])/2,(extent[0][1]+extent[1][1])/2];origin[0]=extent[+(point[0]1?Date.UTC.apply(this,arguments):arguments[0])}d3_time_utc.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){d3_time_prototype.setUTCDate.apply(this._,arguments)},setDay:function(){d3_time_prototype.setUTCDay.apply(this._,arguments)},setFullYear:function(){d3_time_prototype.setUTCFullYear.apply(this._,arguments)},setHours:function(){d3_time_prototype.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){d3_time_prototype.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){d3_time_prototype.setUTCMinutes.apply(this._,arguments)},setMonth:function(){d3_time_prototype.setUTCMonth.apply(this._,arguments)},setSeconds:function(){d3_time_prototype.setUTCSeconds.apply(this._,arguments)},setTime:function(){d3_time_prototype.setTime.apply(this._,arguments)}};var d3_time_prototype=Date.prototype;var d3_time_formatDateTime="%a %b %e %X %Y",d3_time_formatDate="%m/%d/%Y",d3_time_formatTime="%H:%M:%S";var d3_time_days=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],d3_time_dayAbbreviations=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d3_time_months=["January","February","March","April","May","June","July","August","September","October","November","December"],d3_time_monthAbbreviations=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function d3_time_interval(local,step,number){function round(date){var d0=local(date),d1=offset(d0,1);return date-d01){while(time=m)return-1;c=template.charCodeAt(i++);if(c===37){p=d3_time_parsers[template.charAt(i++)];if(!p||(j=p(date,string,j))<0)return-1}else if(c!=string.charCodeAt(j++)){return-1}}return j}function d3_time_formatRe(names){return new RegExp("^(?:"+names.map(d3.requote).join("|")+")","i")}function d3_time_formatLookup(names){var map=new d3_Map,i=-1,n=names.length;while(++i=12?"PM":"AM"},S:function(d,p){return d3_time_formatPad(d.getSeconds(),p,2)},U:function(d,p){return d3_time_formatPad(d3.time.sundayOfYear(d),p,2)},w:function(d){return d.getDay()},W:function(d,p){return d3_time_formatPad(d3.time.mondayOfYear(d),p,2)},x:d3.time.format(d3_time_formatDate),X:d3.time.format(d3_time_formatTime),y:function(d,p){return d3_time_formatPad(d.getFullYear()%100,p,2)},Y:function(d,p){return d3_time_formatPad(d.getFullYear()%1e4,p,4)},Z:d3_time_zone,"%":function(){return"%"}};var d3_time_parsers={a:d3_time_parseWeekdayAbbrev,A:d3_time_parseWeekday,b:d3_time_parseMonthAbbrev,B:d3_time_parseMonth,c:d3_time_parseLocaleFull,d:d3_time_parseDay,e:d3_time_parseDay,H:d3_time_parseHour24,I:d3_time_parseHour24,j:d3_time_parseDayOfYear,L:d3_time_parseMilliseconds,m:d3_time_parseMonthNumber,M:d3_time_parseMinutes,p:d3_time_parseAmPm,S:d3_time_parseSeconds,U:d3_time_parseWeekNumberSunday,w:d3_time_parseWeekdayNumber,W:d3_time_parseWeekNumberMonday,x:d3_time_parseLocaleDate,X:d3_time_parseLocaleTime,y:d3_time_parseYear,Y:d3_time_parseFullYear,"%":d3_time_parseLiteralPercent};function d3_time_parseWeekdayAbbrev(date,string,i){d3_time_dayAbbrevRe.lastIndex=0;var n=d3_time_dayAbbrevRe.exec(string.substring(i));return n?(date.w=d3_time_dayAbbrevLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseWeekday(date,string,i){d3_time_dayRe.lastIndex=0;var n=d3_time_dayRe.exec(string.substring(i));return n?(date.w=d3_time_dayLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseWeekdayNumber(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+1));return n?(date.w=+n[0],i+n[0].length):-1}function d3_time_parseWeekNumberSunday(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i));return n?(date.U=+n[0],i+n[0].length):-1}function d3_time_parseWeekNumberMonday(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i));return n?(date.W=+n[0],i+n[0].length):-1}function d3_time_parseMonthAbbrev(date,string,i){d3_time_monthAbbrevRe.lastIndex=0;var n=d3_time_monthAbbrevRe.exec(string.substring(i));return n?(date.m=d3_time_monthAbbrevLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseMonth(date,string,i){d3_time_monthRe.lastIndex=0;var n=d3_time_monthRe.exec(string.substring(i));return n?(date.m=d3_time_monthLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseLocaleFull(date,string,i){return d3_time_parse(date,d3_time_formats.c.toString(),string,i)}function d3_time_parseLocaleDate(date,string,i){return d3_time_parse(date,d3_time_formats.x.toString(),string,i)}function d3_time_parseLocaleTime(date,string,i){return d3_time_parse(date,d3_time_formats.X.toString(),string,i)}function d3_time_parseFullYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+4));return n?(date.y=+n[0],i+n[0].length):-1}function d3_time_parseYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.y=d3_time_expandYear(+n[0]),i+n[0].length):-1}function d3_time_expandYear(d){return d+(d>68?1900:2e3)}function d3_time_parseMonthNumber(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.m=n[0]-1,i+n[0].length):-1}function d3_time_parseDay(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.d=+n[0],i+n[0].length):-1}function d3_time_parseDayOfYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+3));return n?(date.j=+n[0],i+n[0].length):-1}function d3_time_parseHour24(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.H=+n[0],i+n[0].length):-1}function d3_time_parseMinutes(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.M=+n[0],i+n[0].length):-1}function d3_time_parseSeconds(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.S=+n[0],i+n[0].length):-1}function d3_time_parseMilliseconds(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+3));return n?(date.L=+n[0],i+n[0].length):-1}var d3_time_numberRe=/^\s*\d+/;function d3_time_parseAmPm(date,string,i){var n=d3_time_amPmLookup.get(string.substring(i,i+=2).toLowerCase());return n==null?-1:(date.p=n,i)}var d3_time_amPmLookup=d3.map({am:0,pm:1});function d3_time_zone(d){var z=d.getTimezoneOffset(),zs=z>0?"-":"+",zh=~~(Math.abs(z)/60),zm=Math.abs(z)%60;return zs+d3_time_formatPad(zh,"0",2)+d3_time_formatPad(zm,"0",2)}function d3_time_parseLiteralPercent(date,string,i){d3_time_percentRe.lastIndex=0;var n=d3_time_percentRe.exec(string.substring(i,i+1));return n?i+n[0].length:-1}d3.time.format.utc=function(template){var local=d3.time.format(template);function format(date){try{d3_time=d3_time_utc;var utc=new d3_time;utc._=date;return local(utc)}finally{d3_time=Date}}format.parse=function(string){try{d3_time=d3_time_utc;var date=local.parse(string);return date&&date._}finally{d3_time=Date}};format.toString=local.toString;return format};var d3_time_formatIso=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?d3_time_formatIsoNative:d3_time_formatIso;function d3_time_formatIsoNative(date){return date.toISOString()}d3_time_formatIsoNative.parse=function(string){var date=new Date(string);return isNaN(date)?null:date};d3_time_formatIsoNative.toString=d3_time_formatIso.toString;d3.time.second=d3_time_interval(function(date){return new d3_time(Math.floor(date/1e3)*1e3)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*1e3)},function(date){return date.getSeconds()});d3.time.seconds=d3.time.second.range;d3.time.seconds.utc=d3.time.second.utc.range;d3.time.minute=d3_time_interval(function(date){return new d3_time(Math.floor(date/6e4)*6e4)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*6e4)},function(date){return date.getMinutes()});d3.time.minutes=d3.time.minute.range;d3.time.minutes.utc=d3.time.minute.utc.range;d3.time.hour=d3_time_interval(function(date){var timezone=date.getTimezoneOffset()/60;return new d3_time((Math.floor(date/36e5-timezone)+timezone)*36e5)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*36e5)},function(date){return date.getHours()});d3.time.hours=d3.time.hour.range;d3.time.hours.utc=d3.time.hour.utc.range;d3.time.month=d3_time_interval(function(date){date=d3.time.day(date);date.setDate(1);return date},function(date,offset){date.setMonth(date.getMonth()+offset)},function(date){return date.getMonth()});d3.time.months=d3.time.month.range;d3.time.months.utc=d3.time.month.utc.range;function d3_time_scale(linear,methods,format){function scale(x){return linear(x)}scale.invert=function(x){return d3_time_scaleDate(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return linear.domain().map(d3_time_scaleDate);linear.domain(x);return scale};scale.nice=function(m){return scale.domain(d3_scale_nice(scale.domain(),m))};scale.ticks=function(m,k){var extent=d3_scaleExtent(scale.domain());if(typeof m!=="function"){var span=extent[1]-extent[0],target=span/m,i=d3.bisect(d3_time_scaleSteps,target);if(i==d3_time_scaleSteps.length)return methods.year(extent,m);if(!i)return linear.ticks(m).map(d3_time_scaleDate);if(target/d3_time_scaleSteps[i-1]":">",'"':""","'":"'"};function escapeHTML(string){return String(string).replace(/&(?!\w+;)|[<>"']/g,function(s){return escapeMap[s]||s})}var regexCache={};var Renderer=function(){};Renderer.prototype={otag:"{{",ctag:"}}",pragmas:{},buffer:[],pragmas_implemented:{"IMPLICIT-ITERATOR":true},context:{},render:function(template,context,partials,in_recursion){if(!in_recursion){this.context=context;this.buffer=[]}if(!this.includes("",template)){if(in_recursion){return template}else{this.send(template);return}}template=this.render_pragmas(template);var html=this.render_section(template,context,partials);if(html===false){html=this.render_tags(template,context,partials,in_recursion)}if(in_recursion){return html}else{this.sendLines(html)}},send:function(line){if(line!==""){this.buffer.push(line)}},sendLines:function(text){if(text){var lines=text.split("\n");for(var i=0;i|&|\\{|%)?([^#\\^]+?)\\1?"+ctag+"+","g")})};var regex=new_regex();var tag_replace_callback=function(match,operator,name){switch(operator){case"!":return"";case"=":that.set_delimiters(name);regex=new_regex();return"";case">":return that.render_partial(name,context,partials);case"{":case"&":return that.find(name,context);default:return escapeHTML(that.find(name,context))}};var lines=template.split("\n");for(var i=0;i0){value_context=value;value=value[path.shift()]}if(typeof value=="function"){return value.apply(value_context)}return value},includes:function(needle,haystack){return haystack.indexOf(this.otag+needle)!=-1},create_context:function(_context){if(this.is_object(_context)){return _context}else{var iterator=".";if(this.pragmas["IMPLICIT-ITERATOR"]){iterator=this.pragmas["IMPLICIT-ITERATOR"].iterator}var ctx={};ctx[iterator]=_context;return ctx}},is_object:function(a){return a&&typeof a=="object"},map:function(array,fn){if(typeof array.map=="function"){return array.map(fn)}else{var r=[];var l=array.length;for(var i=0;i0?port.toString():null,encodeIfExists2(path,URI_DISALLOWED_IN_PATH_),null,encodeIfExists(fragment));if(query){if("string"===typeof query){uri.setRawQuery(query.replace(/[^?&=0-9A-Za-z_\-~.%]/g,encodeOne))}else{uri.setAllParameters(query)}}return uri}function encodeIfExists(unescapedPart){if("string"==typeof unescapedPart){return encodeURIComponent(unescapedPart)}return null}function encodeIfExists2(unescapedPart,extra){if("string"==typeof unescapedPart){return encodeURI(unescapedPart).replace(extra,encodeOne)}return null}function encodeOne(ch){var n=ch.charCodeAt(0);return"%"+"0123456789ABCDEF".charAt(n>>4&15)+"0123456789ABCDEF".charAt(n&15)}function normPath(path){return path.replace(/(^|\/)\.(?:\/|$)/g,"$1").replace(/\/{2,}/g,"/")}var PARENT_DIRECTORY_HANDLER=new RegExp(""+"(/|^)"+"(?:[^./][^/]*|\\.{2,}(?:[^./][^/]*)|\\.{3,}[^/]*)"+"/\\.\\.(?:/|$)");var PARENT_DIRECTORY_HANDLER_RE=new RegExp(PARENT_DIRECTORY_HANDLER);var EXTRA_PARENT_PATHS_RE=/^(?:\.\.\/)*(?:\.\.$)?/;function collapse_dots(path){if(path===null){return null}var p=normPath(path);var r=PARENT_DIRECTORY_HANDLER_RE;for(var q;(q=p.replace(r,"$1"))!=p;p=q){}return p}function resolve(baseUri,relativeUri){var absoluteUri=baseUri.clone();var overridden=relativeUri.hasScheme();if(overridden){absoluteUri.setRawScheme(relativeUri.getRawScheme())}else{overridden=relativeUri.hasCredentials()}if(overridden){absoluteUri.setRawCredentials(relativeUri.getRawCredentials())}else{overridden=relativeUri.hasDomain()}if(overridden){absoluteUri.setRawDomain(relativeUri.getRawDomain())}else{overridden=relativeUri.hasPort()}var rawPath=relativeUri.getRawPath();var simplifiedPath=collapse_dots(rawPath);if(overridden){absoluteUri.setPort(relativeUri.getPort());simplifiedPath=simplifiedPath&&simplifiedPath.replace(EXTRA_PARENT_PATHS_RE,"")}else{overridden=!!rawPath;if(overridden){if(simplifiedPath.charCodeAt(0)!==47){var absRawPath=collapse_dots(absoluteUri.getRawPath()||"").replace(EXTRA_PARENT_PATHS_RE,"");var slash=absRawPath.lastIndexOf("/")+1;simplifiedPath=collapse_dots((slash?absRawPath.substring(0,slash):"")+collapse_dots(rawPath)).replace(EXTRA_PARENT_PATHS_RE,"")}}else{simplifiedPath=simplifiedPath&&simplifiedPath.replace(EXTRA_PARENT_PATHS_RE,"");if(simplifiedPath!==rawPath){absoluteUri.setRawPath(simplifiedPath)}}}if(overridden){absoluteUri.setRawPath(simplifiedPath)}else{overridden=relativeUri.hasQuery()}if(overridden){absoluteUri.setRawQuery(relativeUri.getRawQuery())}else{overridden=relativeUri.hasFragment()}if(overridden){absoluteUri.setRawFragment(relativeUri.getRawFragment())}return absoluteUri}function URI(rawScheme,rawCredentials,rawDomain,port,rawPath,rawQuery,rawFragment){this.scheme_=rawScheme;this.credentials_=rawCredentials;this.domain_=rawDomain;this.port_=port;this.path_=rawPath;this.query_=rawQuery;this.fragment_=rawFragment;this.paramCache_=null}URI.prototype.toString=function(){var out=[];if(null!==this.scheme_){out.push(this.scheme_,":")}if(null!==this.domain_){out.push("//");if(null!==this.credentials_){out.push(this.credentials_,"@")}out.push(this.domain_);if(null!==this.port_){out.push(":",this.port_.toString())}}if(null!==this.path_){out.push(this.path_)}if(null!==this.query_){out.push("?",this.query_)}if(null!==this.fragment_){out.push("#",this.fragment_)}return out.join("")};URI.prototype.clone=function(){return new URI(this.scheme_,this.credentials_,this.domain_,this.port_,this.path_,this.query_,this.fragment_)};URI.prototype.getScheme=function(){return this.scheme_&&decodeURIComponent(this.scheme_).toLowerCase()};URI.prototype.getRawScheme=function(){return this.scheme_};URI.prototype.setScheme=function(newScheme){this.scheme_=encodeIfExists2(newScheme,URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);return this};URI.prototype.setRawScheme=function(newScheme){this.scheme_=newScheme?newScheme:null;return this};URI.prototype.hasScheme=function(){return null!==this.scheme_};URI.prototype.getCredentials=function(){return this.credentials_&&decodeURIComponent(this.credentials_)};URI.prototype.getRawCredentials=function(){return this.credentials_};URI.prototype.setCredentials=function(newCredentials){this.credentials_=encodeIfExists2(newCredentials,URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);return this};URI.prototype.setRawCredentials=function(newCredentials){this.credentials_=newCredentials?newCredentials:null;return this};URI.prototype.hasCredentials=function(){return null!==this.credentials_};URI.prototype.getDomain=function(){return this.domain_&&decodeURIComponent(this.domain_)};URI.prototype.getRawDomain=function(){return this.domain_};URI.prototype.setDomain=function(newDomain){return this.setRawDomain(newDomain&&encodeURIComponent(newDomain))};URI.prototype.setRawDomain=function(newDomain){this.domain_=newDomain?newDomain:null;return this.setRawPath(this.path_)};URI.prototype.hasDomain=function(){return null!==this.domain_};URI.prototype.getPort=function(){return this.port_&&decodeURIComponent(this.port_)};URI.prototype.setPort=function(newPort){if(newPort){newPort=Number(newPort);if(newPort!==(newPort&65535)){throw new Error("Bad port number "+newPort)}this.port_=""+newPort}else{this.port_=null}return this};URI.prototype.hasPort=function(){return null!==this.port_};URI.prototype.getPath=function(){return this.path_&&decodeURIComponent(this.path_)};URI.prototype.getRawPath=function(){return this.path_};URI.prototype.setPath=function(newPath){return this.setRawPath(encodeIfExists2(newPath,URI_DISALLOWED_IN_PATH_))};URI.prototype.setRawPath=function(newPath){if(newPath){newPath=String(newPath);this.path_=!this.domain_||/^\//.test(newPath)?newPath:"/"+newPath}else{this.path_=null}return this};URI.prototype.hasPath=function(){return null!==this.path_};URI.prototype.getQuery=function(){return this.query_&&decodeURIComponent(this.query_).replace(/\+/g," ")};URI.prototype.getRawQuery=function(){return this.query_};URI.prototype.setQuery=function(newQuery){this.paramCache_=null;this.query_=encodeIfExists(newQuery);return this};URI.prototype.setRawQuery=function(newQuery){this.paramCache_=null;this.query_=newQuery?newQuery:null;return this};URI.prototype.hasQuery=function(){return null!==this.query_};URI.prototype.setAllParameters=function(params){if(typeof params==="object"){if(!(params instanceof Array)&&(params instanceof Object||Object.prototype.toString.call(params)!=="[object Array]")){var newParams=[];var i=-1;for(var k in params){var v=params[k];if("string"===typeof v){newParams[++i]=k;newParams[++i]=v}}params=newParams}}this.paramCache_=null;var queryBuf=[];var separator="";for(var j=0;j0?matchPart:null}var URI_RE_=new RegExp("^"+"(?:"+"([^:/?#]+)"+":)?"+"(?://"+"(?:([^/?#]*)@)?"+"([^/?#:@]*)"+"(?::([0-9]+))?"+")?"+"([^?#]+)?"+"(?:\\?([^#]*))?"+"(?:#(.*))?"+"$");var URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_=/[#\/\?@]/g;var URI_DISALLOWED_IN_PATH_=/[\#\?]/g;URI.parse=parse;URI.create=create;URI.resolve=resolve;URI.collapse_dots=collapse_dots;URI.utils={mimeTypeOf:function(uri){var uriObj=parse(uri);if(/\.html$/.test(uriObj.getPath())){return"text/html"}else{return"application/javascript"}},resolve:function(base,uri){if(base){return resolve(parse(base),parse(uri)).toString()}else{return""+uri}}};return URI}();var html4={};html4.atype={NONE:0,URI:1,URI_FRAGMENT:11,SCRIPT:2,STYLE:3,HTML:12,ID:4,IDREF:5,IDREFS:6,GLOBAL_NAME:7,LOCAL_NAME:8,CLASSES:9,FRAME_TARGET:10,MEDIA_QUERY:13};html4["atype"]=html4.atype;html4.ATTRIBS={"*::class":9,"*::dir":0,"*::draggable":0,"*::hidden":0,"*::id":4,"*::inert":0,"*::itemprop":0,"*::itemref":6,"*::itemscope":0,"*::lang":0,"*::onblur":2,"*::onchange":2,"*::onclick":2,"*::ondblclick":2,"*::onfocus":2,"*::onkeydown":2,"*::onkeypress":2,"*::onkeyup":2,"*::onload":2,"*::onmousedown":2,"*::onmousemove":2,"*::onmouseout":2,"*::onmouseover":2,"*::onmouseup":2,"*::onreset":2,"*::onscroll":2,"*::onselect":2,"*::onsubmit":2,"*::onunload":2,"*::spellcheck":0,"*::style":3,"*::title":0,"*::translate":0,"a::accesskey":0,"a::coords":0,"a::href":1,"a::hreflang":0,"a::name":7,"a::onblur":2,"a::onfocus":2,"a::shape":0,"a::tabindex":0,"a::target":10,"a::type":0,"area::accesskey":0,"area::alt":0,"area::coords":0,"area::href":1,"area::nohref":0,"area::onblur":2,"area::onfocus":2,"area::shape":0,"area::tabindex":0,"area::target":10,"audio::controls":0,"audio::loop":0,"audio::mediagroup":5,"audio::muted":0,"audio::preload":0,"bdo::dir":0,"blockquote::cite":1,"br::clear":0,"button::accesskey":0,"button::disabled":0,"button::name":8,"button::onblur":2,"button::onfocus":2,"button::tabindex":0,"button::type":0,"button::value":0,"canvas::height":0,"canvas::width":0,"caption::align":0,"col::align":0,"col::char":0,"col::charoff":0,"col::span":0,"col::valign":0,"col::width":0,"colgroup::align":0,"colgroup::char":0,"colgroup::charoff":0,"colgroup::span":0,"colgroup::valign":0,"colgroup::width":0,"command::checked":0,"command::command":5,"command::disabled":0,"command::icon":1,"command::label":0,"command::radiogroup":0,"command::type":0,"data::value":0,"del::cite":1,"del::datetime":0,"details::open":0,"dir::compact":0,"div::align":0,"dl::compact":0,"fieldset::disabled":0,"font::color":0,"font::face":0,"font::size":0,"form::accept":0,"form::action":1,"form::autocomplete":0,"form::enctype":0,"form::method":0,"form::name":7,"form::novalidate":0,"form::onreset":2,"form::onsubmit":2,"form::target":10,"h1::align":0,"h2::align":0,"h3::align":0,"h4::align":0,"h5::align":0,"h6::align":0,"hr::align":0,"hr::noshade":0,"hr::size":0,"hr::width":0,"iframe::align":0,"iframe::frameborder":0,"iframe::height":0,"iframe::marginheight":0,"iframe::marginwidth":0,"iframe::width":0,"img::align":0,"img::alt":0,"img::border":0,"img::height":0,"img::hspace":0,"img::ismap":0,"img::name":7,"img::src":1,"img::usemap":11,"img::vspace":0,"img::width":0,"input::accept":0,"input::accesskey":0,"input::align":0,"input::alt":0,"input::autocomplete":0,"input::checked":0,"input::disabled":0,"input::inputmode":0,"input::ismap":0,"input::list":5,"input::max":0,"input::maxlength":0,"input::min":0,"input::multiple":0,"input::name":8,"input::onblur":2,"input::onchange":2,"input::onfocus":2,"input::onselect":2,"input::placeholder":0,"input::readonly":0,"input::required":0,"input::size":0,"input::src":1,"input::step":0,"input::tabindex":0,"input::type":0,"input::usemap":11,"input::value":0,"ins::cite":1,"ins::datetime":0,"label::accesskey":0,"label::for":5,"label::onblur":2,"label::onfocus":2,"legend::accesskey":0,"legend::align":0,"li::type":0,"li::value":0,"map::name":7,"menu::compact":0,"menu::label":0,"menu::type":0,"meter::high":0,"meter::low":0,"meter::max":0,"meter::min":0,"meter::value":0,"ol::compact":0,"ol::reversed":0,"ol::start":0,"ol::type":0,"optgroup::disabled":0,"optgroup::label":0,"option::disabled":0,"option::label":0,"option::selected":0,"option::value":0,"output::for":6,"output::name":8,"p::align":0,"pre::width":0,"progress::max":0,"progress::min":0,"progress::value":0,"q::cite":1,"select::autocomplete":0,"select::disabled":0,"select::multiple":0,"select::name":8,"select::onblur":2,"select::onchange":2,"select::onfocus":2,"select::required":0,"select::size":0,"select::tabindex":0,"source::type":0,"table::align":0,"table::bgcolor":0,"table::border":0,"table::cellpadding":0,"table::cellspacing":0,"table::frame":0,"table::rules":0,"table::summary":0,"table::width":0,"tbody::align":0,"tbody::char":0,"tbody::charoff":0,"tbody::valign":0,"td::abbr":0,"td::align":0,"td::axis":0,"td::bgcolor":0,"td::char":0,"td::charoff":0,"td::colspan":0,"td::headers":6,"td::height":0,"td::nowrap":0,"td::rowspan":0,"td::scope":0,"td::valign":0,"td::width":0,"textarea::accesskey":0,"textarea::autocomplete":0,"textarea::cols":0,"textarea::disabled":0,"textarea::inputmode":0,"textarea::name":8,"textarea::onblur":2,"textarea::onchange":2,"textarea::onfocus":2,"textarea::onselect":2,"textarea::placeholder":0,"textarea::readonly":0,"textarea::required":0,"textarea::rows":0,"textarea::tabindex":0,"textarea::wrap":0,"tfoot::align":0,"tfoot::char":0,"tfoot::charoff":0,"tfoot::valign":0,"th::abbr":0,"th::align":0,"th::axis":0,"th::bgcolor":0,"th::char":0,"th::charoff":0,"th::colspan":0,"th::headers":6,"th::height":0,"th::nowrap":0,"th::rowspan":0,"th::scope":0,"th::valign":0,"th::width":0,"thead::align":0,"thead::char":0,"thead::charoff":0,"thead::valign":0,"tr::align":0,"tr::bgcolor":0,"tr::char":0,"tr::charoff":0,"tr::valign":0,"track::default":0,"track::kind":0,"track::label":0,"track::srclang":0,"ul::compact":0,"ul::type":0,"video::controls":0,"video::height":0,"video::loop":0,"video::mediagroup":5,"video::muted":0,"video::poster":1,"video::preload":0,"video::width":0}; +html4["ATTRIBS"]=html4.ATTRIBS;html4.eflags={OPTIONAL_ENDTAG:1,EMPTY:2,CDATA:4,RCDATA:8,UNSAFE:16,FOLDABLE:32,SCRIPT:64,STYLE:128,VIRTUALIZED:256};html4["eflags"]=html4.eflags;html4.ELEMENTS={a:0,abbr:0,acronym:0,address:0,applet:272,area:2,article:0,aside:0,audio:0,b:0,base:274,basefont:274,bdi:0,bdo:0,big:0,blockquote:0,body:305,br:2,button:0,canvas:0,caption:0,center:0,cite:0,code:0,col:2,colgroup:1,command:2,data:0,datalist:0,dd:1,del:0,details:0,dfn:0,dialog:272,dir:0,div:0,dl:0,dt:1,em:0,fieldset:0,figcaption:0,figure:0,font:0,footer:0,form:0,frame:274,frameset:272,h1:0,h2:0,h3:0,h4:0,h5:0,h6:0,head:305,header:0,hgroup:0,hr:2,html:305,i:0,iframe:4,img:2,input:2,ins:0,isindex:274,kbd:0,keygen:274,label:0,legend:0,li:1,link:274,map:0,mark:0,menu:0,meta:274,meter:0,nav:0,nobr:0,noembed:276,noframes:276,noscript:276,object:272,ol:0,optgroup:0,option:1,output:0,p:1,param:274,pre:0,progress:0,q:0,s:0,samp:0,script:84,section:0,select:0,small:0,source:2,span:0,strike:0,strong:0,style:148,sub:0,summary:0,sup:0,table:0,tbody:1,td:1,textarea:8,tfoot:1,th:1,thead:1,time:0,title:280,tr:1,track:2,tt:0,u:0,ul:0,"var":0,video:0,wbr:2};html4["ELEMENTS"]=html4.ELEMENTS;html4.ELEMENT_DOM_INTERFACES={a:"HTMLAnchorElement",abbr:"HTMLElement",acronym:"HTMLElement",address:"HTMLElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",article:"HTMLElement",aside:"HTMLElement",audio:"HTMLAudioElement",b:"HTMLElement",base:"HTMLBaseElement",basefont:"HTMLBaseFontElement",bdi:"HTMLElement",bdo:"HTMLElement",big:"HTMLElement",blockquote:"HTMLQuoteElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",center:"HTMLElement",cite:"HTMLElement",code:"HTMLElement",col:"HTMLTableColElement",colgroup:"HTMLTableColElement",command:"HTMLCommandElement",data:"HTMLElement",datalist:"HTMLDataListElement",dd:"HTMLElement",del:"HTMLModElement",details:"HTMLDetailsElement",dfn:"HTMLElement",dialog:"HTMLDialogElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",dt:"HTMLElement",em:"HTMLElement",fieldset:"HTMLFieldSetElement",figcaption:"HTMLElement",figure:"HTMLElement",font:"HTMLFontElement",footer:"HTMLElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",h2:"HTMLHeadingElement",h3:"HTMLHeadingElement",h4:"HTMLHeadingElement",h5:"HTMLHeadingElement",h6:"HTMLHeadingElement",head:"HTMLHeadElement",header:"HTMLElement",hgroup:"HTMLElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",i:"HTMLElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",ins:"HTMLModElement",isindex:"HTMLUnknownElement",kbd:"HTMLElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",mark:"HTMLElement",menu:"HTMLMenuElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",nav:"HTMLElement",nobr:"HTMLElement",noembed:"HTMLElement",noframes:"HTMLElement",noscript:"HTMLElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",s:"HTMLElement",samp:"HTMLElement",script:"HTMLScriptElement",section:"HTMLElement",select:"HTMLSelectElement",small:"HTMLElement",source:"HTMLSourceElement",span:"HTMLSpanElement",strike:"HTMLElement",strong:"HTMLElement",style:"HTMLStyleElement",sub:"HTMLElement",summary:"HTMLElement",sup:"HTMLElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",td:"HTMLTableDataCellElement",textarea:"HTMLTextAreaElement",tfoot:"HTMLTableSectionElement",th:"HTMLTableHeaderCellElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",tt:"HTMLElement",u:"HTMLElement",ul:"HTMLUListElement","var":"HTMLElement",video:"HTMLVideoElement",wbr:"HTMLElement"};html4["ELEMENT_DOM_INTERFACES"]=html4.ELEMENT_DOM_INTERFACES;html4.ueffects={NOT_LOADED:0,SAME_DOCUMENT:1,NEW_DOCUMENT:2};html4["ueffects"]=html4.ueffects;html4.URIEFFECTS={"a::href":2,"area::href":2,"blockquote::cite":0,"command::icon":1,"del::cite":0,"form::action":2,"img::src":1,"input::src":1,"ins::cite":0,"q::cite":0,"video::poster":1};html4["URIEFFECTS"]=html4.URIEFFECTS;html4.ltypes={UNSANDBOXED:2,SANDBOXED:1,DATA:0};html4["ltypes"]=html4.ltypes;html4.LOADERTYPES={"a::href":2,"area::href":2,"blockquote::cite":2,"command::icon":1,"del::cite":2,"form::action":2,"img::src":1,"input::src":1,"ins::cite":2,"q::cite":2,"video::poster":1};html4["LOADERTYPES"]=html4.LOADERTYPES;if("I".toLowerCase()!=="i"){throw"I/i problem"}var html=function(html4){var parseCssDeclarations,sanitizeCssProperty,cssSchema;if("undefined"!==typeof window){parseCssDeclarations=window["parseCssDeclarations"];sanitizeCssProperty=window["sanitizeCssProperty"];cssSchema=window["cssSchema"]}var ENTITIES={lt:"<",LT:"<",gt:">",GT:">",amp:"&",AMP:"&",quot:'"',apos:"'",nbsp:" "};var decimalEscapeRe=/^#(\d+)$/;var hexEscapeRe=/^#x([0-9A-Fa-f]+)$/;var safeEntityNameRe=/^[A-Za-z][A-za-z0-9]+$/;var entityLookupElement="undefined"!==typeof window&&window["document"]?window["document"].createElement("textarea"):null;function lookupEntity(name){if(ENTITIES.hasOwnProperty(name)){return ENTITIES[name]}var m=name.match(decimalEscapeRe);if(m){return String.fromCharCode(parseInt(m[1],10))}else if(!!(m=name.match(hexEscapeRe))){return String.fromCharCode(parseInt(m[1],16))}else if(entityLookupElement&&safeEntityNameRe.test(name)){entityLookupElement.innerHTML="&"+name+";";var text=entityLookupElement.textContent;ENTITIES[name]=text;return text}else{return"&"+name+";"}}function decodeOneEntity(_,name){return lookupEntity(name)}var nulRe=/\0/g;function stripNULs(s){return s.replace(nulRe,"")}var ENTITY_RE_1=/&(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/g;var ENTITY_RE_2=/^(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/;function unescapeEntities(s){return s.replace(ENTITY_RE_1,decodeOneEntity)}var ampRe=/&/g;var looseAmpRe=/&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;var ltRe=/[<]/g;var gtRe=/>/g;var quotRe=/\"/g;function escapeAttrib(s){return(""+s).replace(ampRe,"&").replace(ltRe,"<").replace(gtRe,">").replace(quotRe,""")}function normalizeRCData(rcdata){return rcdata.replace(looseAmpRe,"&$1").replace(ltRe,"<").replace(gtRe,">")}var ATTR_RE=new RegExp("^\\s*"+"([-.:\\w]+)"+"(?:"+("\\s*(=)\\s*"+"("+('(")[^"]*("|$)'+"|"+"(')[^']*('|$)"+"|"+"(?=[a-z][-\\w]*\\s*=)"+"|"+"[^\"'\\s]*")+")")+")?","i");var splitWillCapture="a,b".split(/(,)/).length===3;var EFLAGS_TEXT=html4.eflags["CDATA"]|html4.eflags["RCDATA"];function makeSaxParser(handler){var hcopy={cdata:handler.cdata||handler["cdata"],comment:handler.comment||handler["comment"],endDoc:handler.endDoc||handler["endDoc"],endTag:handler.endTag||handler["endTag"],pcdata:handler.pcdata||handler["pcdata"],rcdata:handler.rcdata||handler["rcdata"],startDoc:handler.startDoc||handler["startDoc"],startTag:handler.startTag||handler["startTag"]};return function(htmlText,param){return parse(htmlText,hcopy,param)}}var continuationMarker={};function parse(htmlText,handler,param){var m,p,tagName;var parts=htmlSplit(htmlText);var state={noMoreGT:false,noMoreEndComments:false};parseCPS(handler,parts,0,state,param)}function continuationMaker(h,parts,initial,state,param){return function(){parseCPS(h,parts,initial,state,param)}}function parseCPS(h,parts,initial,state,param){try{if(h.startDoc&&initial==0){h.startDoc(param)}var m,p,tagName;for(var pos=initial,end=parts.length;pos"){pos+=2;tagName=m[1].toLowerCase();if(h.endTag){h.endTag(tagName,param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}else{pos=parseEndTag(parts,pos,h,param,continuationMarker,state)}}else{if(h.pcdata){h.pcdata("</",param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}break;case"<":if(m=/^([-\w:]+)\s*\/?/.exec(next)){if(m[0].length===next.length&&parts[pos+1]===">"){pos+=2;tagName=m[1].toLowerCase();if(h.startTag){h.startTag(tagName,[],param,continuationMarker,continuationMaker(h,parts,pos,state,param))}var eflags=html4.ELEMENTS[tagName];if(eflags&EFLAGS_TEXT){var tag={name:tagName,next:pos,eflags:eflags};pos=parseText(parts,tag,h,param,continuationMarker,state)}}else{pos=parseStartTag(parts,pos,h,param,continuationMarker,state)}}else{if(h.pcdata){h.pcdata("<",param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}break;case"', and + // repeated failure to find '-->' is quadratic. We avoid that by + // remembering when search for '-->' fails. + if (!state.noMoreEndComments) { + // A comment <\!--x--> is split into three tokens: + // '<\!--', 'x--', '>' + // We want to find the next '>' token that has a preceding '--'. + // pos is at the 'x--'. + for (p = pos + 1; p < end; p++) { + if (parts[p] === '>' && /--$/.test(parts[p - 1])) { break; } + } + if (p < end) { + if (h.comment) { + var comment = parts.slice(pos, p).join(''); + h.comment( + comment.substr(0, comment.length - 2), param, + continuationMarker, + continuationMaker(h, parts, p + 1, state, param)); + } + pos = p + 1; + } else { + state.noMoreEndComments = true; + } + } + if (state.noMoreEndComments) { + if (h.pcdata) { + h.pcdata('<!--', param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + } + break; + case '<\!': + if (!/^\w/.test(next)) { + if (h.pcdata) { + h.pcdata('<!', param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + } else { + // similar to noMoreEndComment logic + if (!state.noMoreGT) { + for (p = pos + 1; p < end; p++) { + if (parts[p] === '>') { break; } + } + if (p < end) { + pos = p + 1; + } else { + state.noMoreGT = true; + } + } + if (state.noMoreGT) { + if (h.pcdata) { + h.pcdata('<!', param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + } + } + break; + case '') { break; } + } + if (p < end) { + pos = p + 1; + } else { + state.noMoreGT = true; + } + } + if (state.noMoreGT) { + if (h.pcdata) { + h.pcdata('<?', param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + } + break; + case '>': + if (h.pcdata) { + h.pcdata(">", param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + break; + case '': + break; + default: + if (h.pcdata) { + h.pcdata(current, param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + break; + } + } + if (h.endDoc) { h.endDoc(param); } + } catch (e) { + if (e !== continuationMarker) { throw e; } + } + } + + // Split str into parts for the html parser. + function htmlSplit(str) { + // can't hoist this out of the function because of the re.exec loop. + var re = /(<\/|<\!--|<[!?]|[&<>])/g; + str += ''; + if (splitWillCapture) { + return str.split(re); + } else { + var parts = []; + var lastPos = 0; + var m; + while ((m = re.exec(str)) !== null) { + parts.push(str.substring(lastPos, m.index)); + parts.push(m[0]); + lastPos = m.index + m[0].length; + } + parts.push(str.substring(lastPos)); + return parts; + } + } + + function parseEndTag(parts, pos, h, param, continuationMarker, state) { + var tag = parseTagAndAttrs(parts, pos); + // drop unclosed tags + if (!tag) { return parts.length; } + if (h.endTag) { + h.endTag(tag.name, param, continuationMarker, + continuationMaker(h, parts, pos, state, param)); + } + return tag.next; + } + + function parseStartTag(parts, pos, h, param, continuationMarker, state) { + var tag = parseTagAndAttrs(parts, pos); + // drop unclosed tags + if (!tag) { return parts.length; } + if (h.startTag) { + h.startTag(tag.name, tag.attrs, param, continuationMarker, + continuationMaker(h, parts, tag.next, state, param)); + } + // tags like - \ No newline at end of file + diff --git a/js/sheetsee.full.js b/js/sheetsee.full.js index cae3b9e8..c8d6cc9a 100644 --- a/js/sheetsee.full.js +++ b/js/sheetsee.full.js @@ -4,6 +4,6 @@ var extend = require('lodash.assign'); // consider this a "build file!" you can add/remove dependencies here, and the file will be created at dist/sheetsee.full.js. // creating these components are easy, just export an object, and things inside it will be extended to the main Sheetsee here. // in the future, these could be separate node modules. (for example: sheetsee-d3, sheetsee-mapbox, etc) -extend(Sheetsee, require('./components/d3'), require('./components/mapbox')) +extend(Sheetsee, require('./components/sheetsee-charts'), require('./components/sheetsee-maps'), require('./components/sheetsee-tables')) module.exports = Sheetsee; From eff0413e2ca671f44cc929c38d279e72a37d0a01 Mon Sep 17 00:00:00 2001 From: jlord Date: Mon, 21 Oct 2013 14:50:47 -0700 Subject: [PATCH 005/157] new build --- dist/sheetsee.full.js | 231 +++++++++++++++++--------------------- dist/sheetsee.full.min.js | 24 ++-- dist/sheetsee.js | 136 ++++------------------ dist/sheetsee.min.js | 2 +- 4 files changed, 141 insertions(+), 252 deletions(-) diff --git a/dist/sheetsee.full.js b/dist/sheetsee.full.js index a5987342..3e693410 100644 --- a/dist/sheetsee.full.js +++ b/dist/sheetsee.full.js @@ -327,7 +327,7 @@ module.exports = { }) } } -},{"d3":6}],2:[function(require,module,exports){ +},{"d3":7}],2:[function(require,module,exports){ var mapbox = require('mapbox.js') module.exports = { @@ -399,29 +399,14 @@ module.exports = { // }) // } } -},{"mapbox.js":34}],3:[function(require,module,exports){ -var Sheetsee = require('./sheetsee') -var extend = require('lodash.assign'); - -// consider this a "build file!" you can add/remove dependencies here, and the file will be created at dist/sheetsee.full.js. -// creating these components are easy, just export an object, and things inside it will be extended to the main Sheetsee here. -// in the future, these could be separate node modules. (for example: sheetsee-d3, sheetsee-mapbox, etc) -extend(Sheetsee, require('./components/d3'), require('./components/mapbox')) - -module.exports = Sheetsee; - -},{"./components/d3":1,"./components/mapbox":2,"./sheetsee":4,"lodash.assign":8}],4:[function(require,module,exports){ +},{"mapbox.js":35}],3:[function(require,module,exports){ var ich = require('icanhaz') -var Sheetsee = { - // // // // // // // // // // // // // // // // // // // // // // // // // // - // - // // // Make Table, Sort and Filter Interactions - // - // // // // // // // // // // // // // // // // // // // // // // // // // // +module.exports = { + // Make Table, Sort and Filter Interactions initiateTableFilter: function(data, filterDiv, tableDiv) { - $('.clear').on("click", function() { + $('.clear').on("click", function() { $(this.id + ".noMatches").css("visibility", "hidden") $(this.id + filterDiv).val("") Sheetsee.makeTable(data, tableDiv) @@ -444,8 +429,8 @@ var Sheetsee = { Sheetsee.makeTable("no matches", tableDiv) } else $(".noMatches").css("visibility", "hidden") - Sheetsee.makeTable(filteredList, tableDiv) - return filteredList + Sheetsee.makeTable(filteredList, tableDiv) + return filteredList }, sortThings: function(data, sorter, sorted, tableDiv) { @@ -456,12 +441,12 @@ var Sheetsee = { }) if (sorted === "descending") data.reverse() Sheetsee.makeTable(data, tableDiv) - var header + var header $(tableDiv + " .tHeader").each(function(i, el){ var contents = Sheetsee.resolveDataTitle($(el).text()) if (contents === sorter) header = el }) - $(header).attr("data-sorted", sorted) + $(header).attr("data-sorted", sorted) }, resolveDataTitle: function(string) { @@ -479,7 +464,7 @@ var Sheetsee = { } else { sorted = "ascending" } var sorter = Sheetsee.resolveDataTitle(event.target.innerHTML) - Sheetsee.sortThings(gData, sorter, sorted, tableDiv) + Sheetsee.sortThings(gData, sorter, sorted, tableDiv) }, makeTable: function(data, targetDiv) { @@ -487,14 +472,26 @@ var Sheetsee = { var tableContents = ich[templateID]({ rows: data }) - $(targetDiv).html(tableContents) - }, + $(targetDiv).html(tableContents) + } +} - // // // // // // // // // // // // // // // // // // // // // // // // // // - // - // // // Sorting, Ordering Data - // - // // // // // // // // // // // // // // // // // // // // // // // // // // +},{"icanhaz":8}],4:[function(require,module,exports){ +var Sheetsee = require('./sheetsee') +var extend = require('lodash.assign'); + +// consider this a "build file!" you can add/remove dependencies here, and the file will be created at dist/sheetsee.full.js. +// creating these components are easy, just export an object, and things inside it will be extended to the main Sheetsee here. +// in the future, these could be separate node modules. (for example: sheetsee-d3, sheetsee-mapbox, etc) +extend(Sheetsee, require('./components/sheetsee-charts'), require('./components/sheetsee-maps'), require('./components/sheetsee-tables')) + +module.exports = Sheetsee; + +},{"./components/sheetsee-charts":1,"./components/sheetsee-maps":2,"./components/sheetsee-tables":3,"./sheetsee":5,"lodash.assign":9}],5:[function(require,module,exports){ +var ich = require('icanhaz') + +var Sheetsee = { + // Sorting, Ordering Data getKeywordCount: function(data, keyword) { var group = [] @@ -502,10 +499,10 @@ var Sheetsee = { for(var key in d) { var value = d[key].toString().toLowerCase() if (value.match(keyword.toLowerCase())) group.push(d) - } + } }) return group.length - if (group = []) return "0" + if (group = []) return "0" }, getKeyword: function(data, keyword) { @@ -514,27 +511,27 @@ var Sheetsee = { for(var key in d) { var value = d[key].toString().toLowerCase() if (value.match(keyword.toLowerCase())) group.push(d) - } + } }) return group - if (group = []) return "no matches" + if (group = []) return "no matches" }, getColumnTotal: function(data, column) { var total = [] data.forEach(function (d) { - if (d[column] === "") return - total.push(+d[column]) + if (d[column] === "") return + total.push(+d[column]) }) return total.reduce(function(a,b) { return a + b - }) + }) }, getColumnAverage: function(data, column) { var total = getColumnTotal(data, column) var average = total / data.length - return average + return average }, getMax: function(data, column) { @@ -545,7 +542,7 @@ var Sheetsee = { if (element[column].valueOf() > result[0][column].valueOf()) { result.length = 0 return result.push(element) - } + } if (element[column].valueOf() === result[0][column].valueOf()) { return result.push(element) } @@ -562,13 +559,13 @@ var Sheetsee = { if (element[column].valueOf() < result[0][column].valueOf()) { result.length = 0 return result.push(element) - } + } if (element[column].valueOf() === result[0][column].valueOf()) { return result.push(element) } } }) - return result + return result }, // out of the data, filter something from a category @@ -595,7 +592,7 @@ var Sheetsee = { } sortable.sort(function(a, b) {return b[1] - a[1]}) return sortable - // returns array of arrays, in order + // returns array of arrays, in order }, // thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ @@ -614,21 +611,9 @@ var Sheetsee = { } return out; } - return obj; + return obj; }, - // no longer need this - // function addUnitsLabels(arrayObj, oldLabel, oldUnits) { - // var newArray = deepCopy(arrayObj) - // for (var i = 0; i < newArray.length; i++) { - // newArray[i].label = newArray[i][oldLabel] - // newArray[i].units = newArray[i][oldUnits] - // delete newArray[i][oldLabel] - // delete newArray[i][oldUnits] - // } - // return newArray - // } - getOccurance: function(data, category) { var occuranceCount = {} for (var i = 0; i < data.length; i++) { @@ -638,7 +623,7 @@ var Sheetsee = { occuranceCount[data[i][category]]++ } return occuranceCount - // returns object, keys alphabetical + // returns object, keys alphabetical }, makeColorArrayOfObject: function(data, colors, category) { @@ -646,23 +631,23 @@ var Sheetsee = { var keys = Object.keys(data) var counter = 1 var colorIndex - return keys.map(function(key){ + return keys.map(function(key){ if (keys.length > colors.length || keys.length <= colors.length ) { colorIndex = counter % colors.length } - var h = {units: data[key], hexcolor: colors[colorIndex]} + var h = {units: data[key], hexcolor: colors[colorIndex]} h[category] = key - counter++ - colorIndex = counter + counter++ + colorIndex = counter return h }) }, makeArrayOfObject: function(data) { var keys = Object.keys(data) - return keys.map(function(key){ - // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} - var h = {label: key, units: data[key]} + return keys.map(function(key){ + // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} + var h = {label: key, units: data[key]} return h }) } @@ -673,7 +658,7 @@ $(document).on("click", ".tHeader", Sheetsee.sendToSort) Sheetsee.ich = ich module.exports = Sheetsee -},{"icanhaz":7}],5:[function(require,module,exports){ +},{"icanhaz":8}],6:[function(require,module,exports){ d3 = function() { var d3 = { version: "3.2.8" @@ -9484,12 +9469,12 @@ d3 = function() { }); return d3; }(); -},{}],6:[function(require,module,exports){ +},{}],7:[function(require,module,exports){ require("./d3"); module.exports = d3; (function () { delete this.d3; })(); // unset global -},{"./d3":5}],7:[function(require,module,exports){ +},{"./d3":6}],8:[function(require,module,exports){ /*! ICanHaz.js version 0.10.2 -- by @HenrikJoreteg More info at: http://icanhazjs.com @@ -10043,7 +10028,7 @@ var Mustache = function () { })(); })(); -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10115,7 +10100,7 @@ var assign = function(object, source, guard) { module.exports = assign; -},{"lodash._basecreatecallback":9,"lodash._objecttypes":28,"lodash.keys":29}],9:[function(require,module,exports){ +},{"lodash._basecreatecallback":10,"lodash._objecttypes":29,"lodash.keys":30}],10:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10191,7 +10176,7 @@ function baseCreateCallback(func, thisArg, argCount) { module.exports = baseCreateCallback; -},{"lodash._setbinddata":10,"lodash.bind":18,"lodash.identity":25,"lodash.support":26}],10:[function(require,module,exports){ +},{"lodash._setbinddata":11,"lodash.bind":19,"lodash.identity":26,"lodash.support":27}],11:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10233,7 +10218,7 @@ var setBindData = !defineProperty ? noop : function(func, value) { module.exports = setBindData; -},{"lodash._getobject":11,"lodash._noop":13,"lodash._releaseobject":14,"lodash._renative":17}],11:[function(require,module,exports){ +},{"lodash._getobject":12,"lodash._noop":14,"lodash._releaseobject":15,"lodash._renative":18}],12:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10276,7 +10261,7 @@ function getObject() { module.exports = getObject; -},{"lodash._objectpool":12}],12:[function(require,module,exports){ +},{"lodash._objectpool":13}],13:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10291,7 +10276,7 @@ var objectPool = []; module.exports = objectPool; -},{}],13:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10312,7 +10297,7 @@ function noop() { module.exports = noop; -},{}],14:[function(require,module,exports){ +},{}],15:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10343,7 +10328,7 @@ function releaseObject(object) { module.exports = releaseObject; -},{"lodash._maxpoolsize":15,"lodash._objectpool":16}],15:[function(require,module,exports){ +},{"lodash._maxpoolsize":16,"lodash._objectpool":17}],16:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10358,7 +10343,7 @@ var maxPoolSize = 40; module.exports = maxPoolSize; -},{}],16:[function(require,module,exports){ +},{}],17:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10373,7 +10358,7 @@ var objectPool = []; module.exports = objectPool; -},{}],17:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10395,7 +10380,7 @@ var reNative = RegExp('^' + module.exports = reNative; -},{}],18:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10448,7 +10433,7 @@ function bind(func, thisArg) { module.exports = bind; -},{"lodash._createbound":19,"lodash._renative":24}],19:[function(require,module,exports){ +},{"lodash._createbound":20,"lodash._renative":25}],20:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10599,7 +10584,7 @@ function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arit module.exports = createBound; -},{"lodash._createobject":20,"lodash._renative":24,"lodash._setbinddata":10,"lodash.isfunction":22,"lodash.isobject":23,"lodash.support":26}],20:[function(require,module,exports){ +},{"lodash._createobject":21,"lodash._renative":25,"lodash._setbinddata":11,"lodash.isfunction":23,"lodash.isobject":24,"lodash.support":27}],21:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10631,7 +10616,7 @@ function createObject(prototype) { module.exports = createObject; -},{"lodash._noop":21,"lodash._renative":24,"lodash.isobject":23}],21:[function(require,module,exports){ +},{"lodash._noop":22,"lodash._renative":25,"lodash.isobject":24}],22:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10652,7 +10637,7 @@ function noop() { module.exports = noop; -},{}],22:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10681,7 +10666,7 @@ function isFunction(value) { module.exports = isFunction; -},{}],23:[function(require,module,exports){ +},{}],24:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10722,7 +10707,7 @@ function isObject(value) { module.exports = isObject; -},{"lodash._objecttypes":28}],24:[function(require,module,exports){ +},{"lodash._objecttypes":29}],25:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10744,7 +10729,7 @@ var reNative = RegExp('^' + module.exports = reNative; -},{}],25:[function(require,module,exports){ +},{}],26:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10774,7 +10759,7 @@ function identity(value) { module.exports = identity; -},{}],26:[function(require,module,exports){ +},{}],27:[function(require,module,exports){ var global=self;/** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10837,7 +10822,7 @@ support.funcNames = typeof Function.name == 'string'; module.exports = support; -},{"lodash._renative":27}],27:[function(require,module,exports){ +},{"lodash._renative":28}],28:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10859,7 +10844,7 @@ var reNative = RegExp('^' + module.exports = reNative; -},{}],28:[function(require,module,exports){ +},{}],29:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10881,7 +10866,7 @@ var objectTypes = { module.exports = objectTypes; -},{}],29:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10922,7 +10907,7 @@ var keys = !nativeKeys ? shimKeys : function(object) { module.exports = keys; -},{"lodash._renative":30,"lodash._shimkeys":31,"lodash.isobject":32}],30:[function(require,module,exports){ +},{"lodash._renative":31,"lodash._shimkeys":32,"lodash.isobject":33}],31:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10944,7 +10929,7 @@ var reNative = RegExp('^' + module.exports = reNative; -},{}],31:[function(require,module,exports){ +},{}],32:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -10984,7 +10969,7 @@ var shimKeys = function(object) { module.exports = shimKeys; -},{"lodash._objecttypes":28}],32:[function(require,module,exports){ +},{"lodash._objecttypes":29}],33:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) * Build: `lodash modularize modern exports="npm" -o ./npm` @@ -11025,7 +11010,7 @@ function isObject(value) { module.exports = isObject; -},{"lodash._objecttypes":28}],33:[function(require,module,exports){ +},{"lodash._objecttypes":29}],34:[function(require,module,exports){ // Copyright (C) 2010 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13472,14 +13457,14 @@ if (typeof module !== 'undefined') { module.exports = html_sanitize; } -},{}],34:[function(require,module,exports){ +},{}],35:[function(require,module,exports){ require('./leaflet'); require('./mapbox'); -},{"./leaflet":35,"./mapbox":36}],35:[function(require,module,exports){ +},{"./leaflet":36,"./mapbox":37}],36:[function(require,module,exports){ window.L = require('leaflet/dist/leaflet-src'); -},{"leaflet/dist/leaflet-src":39}],36:[function(require,module,exports){ +},{"leaflet/dist/leaflet-src":40}],37:[function(require,module,exports){ // Hardcode image path, because Leaflet's autodetection // fails, because mapbox.js is not named leaflet.js window.L.Icon.Default.imagePath = '//api.tiles.mapbox.com/mapbox.js/' + 'v' + @@ -13502,7 +13487,7 @@ L.mapbox = module.exports = { template: require('mustache').to_html }; -},{"./package.json":41,"./src/config":42,"./src/geocoder":43,"./src/geocoder_control":44,"./src/grid_control":46,"./src/grid_layer":47,"./src/legend_control":48,"./src/map":50,"./src/marker":51,"./src/marker_layer":52,"./src/sanitize":54,"./src/share_control":55,"./src/tile_layer":56,"mustache":40}],37:[function(require,module,exports){ +},{"./package.json":42,"./src/config":43,"./src/geocoder":44,"./src/geocoder_control":45,"./src/grid_control":47,"./src/grid_layer":48,"./src/legend_control":49,"./src/map":51,"./src/marker":52,"./src/marker_layer":53,"./src/sanitize":55,"./src/share_control":56,"./src/tile_layer":57,"mustache":41}],38:[function(require,module,exports){ function xhr(url, callback, cors) { if (typeof window.XMLHttpRequest === 'undefined') { @@ -13586,7 +13571,7 @@ function xhr(url, callback, cors) { if (typeof module !== 'undefined') module.exports = xhr; -},{}],38:[function(require,module,exports){ +},{}],39:[function(require,module,exports){ /*! JSON v3.2.5 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */ ;(function (window) { // Convenience aliases. @@ -14438,7 +14423,7 @@ if (typeof module !== 'undefined') module.exports = xhr; } }(this)); -},{}],39:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ /* Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com (c) 2010-2013, Vladimir Agafonkin @@ -23303,7 +23288,7 @@ L.Map.include({ }(window, document)); -},{}],40:[function(require,module,exports){ +},{}],41:[function(require,module,exports){ /*! * mustache.js - Logic-less {{mustache}} templates with JavaScript * http://github.com/janl/mustache.js @@ -23915,7 +23900,7 @@ L.Map.include({ }()))); -},{}],41:[function(require,module,exports){ +},{}],42:[function(require,module,exports){ module.exports={ "author": { "name": "MapBox" @@ -23959,14 +23944,10 @@ module.exports={ "url": "https://github.com/mapbox/mapbox.js/issues" }, "_id": "mapbox.js@1.3.1", - "dist": { - "shasum": "a6d144286157eecf7273b202782b31a695450f6a" - }, - "_from": "mapbox.js@", - "_resolved": "https://registry.npmjs.org/mapbox.js/-/mapbox.js-1.3.1.tgz" + "_from": "mapbox.js@~1.3.1" } -},{}],42:[function(require,module,exports){ +},{}],43:[function(require,module,exports){ 'use strict'; module.exports = { @@ -23986,7 +23967,7 @@ module.exports = { 'https://d.tiles.mapbox.com/v3/'] }; -},{}],43:[function(require,module,exports){ +},{}],44:[function(require,module,exports){ 'use strict'; var util = require('./util'), @@ -24078,7 +24059,7 @@ module.exports = function(_) { return geocoder; }; -},{"./request":53,"./url":57,"./util":58}],44:[function(require,module,exports){ +},{"./request":54,"./url":58,"./util":59}],45:[function(require,module,exports){ 'use strict'; var geocoder = require('./geocoder'); @@ -24211,7 +24192,7 @@ module.exports = function(options) { return new GeocoderControl(options); }; -},{"./geocoder":43}],45:[function(require,module,exports){ +},{"./geocoder":44}],46:[function(require,module,exports){ 'use strict'; function utfDecode(c) { @@ -24229,7 +24210,7 @@ module.exports = function(data) { }; }; -},{}],46:[function(require,module,exports){ +},{}],47:[function(require,module,exports){ 'use strict'; var util = require('./util'), @@ -24423,7 +24404,7 @@ module.exports = function(_, options) { return new GridControl(_, options); }; -},{"./sanitize":54,"./util":58,"mustache":40}],47:[function(require,module,exports){ +},{"./sanitize":55,"./util":59,"mustache":41}],48:[function(require,module,exports){ 'use strict'; var util = require('./util'), @@ -24651,7 +24632,7 @@ module.exports = function(_, options) { return new GridLayer(_, options); }; -},{"./grid":45,"./load_tilejson":49,"./request":53,"./url":57,"./util":58}],48:[function(require,module,exports){ +},{"./grid":46,"./load_tilejson":50,"./request":54,"./url":58,"./util":59}],49:[function(require,module,exports){ 'use strict'; var LegendControl = L.Control.extend({ @@ -24719,7 +24700,7 @@ module.exports = function(options) { return new LegendControl(options); }; -},{"./sanitize":54}],49:[function(require,module,exports){ +},{"./sanitize":55}],50:[function(require,module,exports){ 'use strict'; var request = require('./request'), @@ -24748,7 +24729,7 @@ module.exports = { } }; -},{"./request":53,"./url":57,"./util":58}],50:[function(require,module,exports){ +},{"./request":54,"./url":58,"./util":59}],51:[function(require,module,exports){ 'use strict'; var util = require('./util'), @@ -24870,7 +24851,7 @@ module.exports = function(element, _, options) { return new Map(element, _, options); }; -},{"./grid_control":46,"./grid_layer":47,"./legend_control":48,"./load_tilejson":49,"./marker_layer":52,"./tile_layer":56,"./util":58}],51:[function(require,module,exports){ +},{"./grid_control":47,"./grid_layer":48,"./legend_control":49,"./load_tilejson":50,"./marker_layer":53,"./tile_layer":57,"./util":59}],52:[function(require,module,exports){ 'use strict'; var url = require('./url'), @@ -24933,7 +24914,7 @@ module.exports = { createPopup: createPopup }; -},{"./sanitize":54,"./url":57}],52:[function(require,module,exports){ +},{"./sanitize":55,"./url":58}],53:[function(require,module,exports){ 'use strict'; var util = require('./util'); @@ -25038,7 +25019,7 @@ module.exports = function(_, options) { return new MarkerLayer(_, options); }; -},{"./marker":51,"./request":53,"./sanitize":54,"./url":57,"./util":58}],53:[function(require,module,exports){ +},{"./marker":52,"./request":54,"./sanitize":55,"./url":58,"./util":59}],54:[function(require,module,exports){ 'use strict'; var corslite = require('corslite'), @@ -25062,7 +25043,7 @@ module.exports = function(url, callback) { }); }; -},{"./util":58,"corslite":37,"json3":38}],54:[function(require,module,exports){ +},{"./util":59,"corslite":38,"json3":39}],55:[function(require,module,exports){ 'use strict'; var html_sanitize = require('../ext/sanitizer/html-sanitizer-bundle.js'); @@ -25084,7 +25065,7 @@ module.exports = function(_) { return html_sanitize(_, cleanUrl, cleanId); }; -},{"../ext/sanitizer/html-sanitizer-bundle.js":33}],55:[function(require,module,exports){ +},{"../ext/sanitizer/html-sanitizer-bundle.js":34}],56:[function(require,module,exports){ 'use strict'; var ShareControl = L.Control.extend({ @@ -25183,7 +25164,7 @@ module.exports = function(_, options) { return new ShareControl(_, options); }; -},{"./load_tilejson":49}],56:[function(require,module,exports){ +},{"./load_tilejson":50}],57:[function(require,module,exports){ 'use strict'; var util = require('./util'), @@ -25277,7 +25258,7 @@ module.exports = function(_, options) { return new TileLayer(_, options); }; -},{"./load_tilejson":49,"./url":57,"./util":58}],57:[function(require,module,exports){ +},{"./load_tilejson":50,"./url":58,"./util":59}],58:[function(require,module,exports){ 'use strict'; var config = require('./config'); @@ -25316,7 +25297,7 @@ module.exports = { } }; -},{"./config":42}],58:[function(require,module,exports){ +},{"./config":43}],59:[function(require,module,exports){ 'use strict'; module.exports = { @@ -25351,6 +25332,6 @@ module.exports = { } }; -},{}]},{},[3])(3) +},{}]},{},[4])(4) }); ; \ No newline at end of file diff --git a/dist/sheetsee.full.min.js b/dist/sheetsee.full.min.js index 0529ff06..4445dd46 100644 --- a/dist/sheetsee.full.min.js +++ b/dist/sheetsee.full.min.js @@ -1,16 +1,16 @@ -!function(e){if("function"==typeof bootstrap)bootstrap("sheetsee",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeSheetsee=e}else"undefined"!=typeof window?window.Sheetsee=e():global.Sheetsee=e()}(function(){var define,ses,bootstrap,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ob[sorter])return 1;return 0});if(sorted==="descending")data.reverse();Sheetsee.makeTable(data,tableDiv);var header;$(tableDiv+" .tHeader").each(function(i,el){var contents=Sheetsee.resolveDataTitle($(el).text());if(contents===sorter)header=el});$(header).attr("data-sorted",sorted)},resolveDataTitle:function(string){var adjusted=string.toLowerCase().replace(/\s/g,"").replace(/\W/g,"");return adjusted},sendToSort:function(event){var tableDiv="#"+$(event.target).closest("div").attr("id");console.log("came from this table",tableDiv);var sorted=$(event.target).attr("data-sorted");if(sorted){if(sorted==="descending")sorted="ascending";else sorted="descending"}else{sorted="ascending"}var sorter=Sheetsee.resolveDataTitle(event.target.innerHTML);Sheetsee.sortThings(gData,sorter,sorted,tableDiv)},makeTable:function(data,targetDiv){var templateID=targetDiv.replace("#","");var tableContents=ich[templateID]({rows:data});$(targetDiv).html(tableContents)},getKeywordCount:function(data,keyword){var group=[];data.forEach(function(d){for(var key in d){var value=d[key].toString().toLowerCase();if(value.match(keyword.toLowerCase()))group.push(d)}});return group.length;if(group=[])return"0"},getKeyword:function(data,keyword){var group=[];data.forEach(function(d){for(var key in d){var value=d[key].toString().toLowerCase();if(value.match(keyword.toLowerCase()))group.push(d)}});return group;if(group=[])return"no matches"},getColumnTotal:function(data,column){var total=[];data.forEach(function(d){if(d[column]==="")return;total.push(+d[column])});return total.reduce(function(a,b){return a+b})},getColumnAverage:function(data,column){var total=getColumnTotal(data,column);var average=total/data.length;return average},getMax:function(data,column){var result=[];data.forEach(function(element){if(result.length===0)return result.push(element);else{if(element[column].valueOf()>result[0][column].valueOf()){result.length=0;return result.push(element)}if(element[column].valueOf()===result[0][column].valueOf()){return result.push(element)}}});return result},getMin:function(data,column){var result=[];data.forEach(function(element){if(result.length===0)return result.push(element);else{if(element[column].valueOf()colors.length||keys.length<=colors.length){colorIndex=counter%colors.length}var h={units:data[key],hexcolor:colors[colorIndex]};h[category]=key;counter++;colorIndex=counter;return h})},makeArrayOfObject:function(data){var keys=Object.keys(data);return keys.map(function(key){var h={label:key,units:data[key]};return h})}};$(document).on("click",".tHeader",Sheetsee.sendToSort);Sheetsee.ich=ich;module.exports=Sheetsee},{icanhaz:7}],5:[function(require,module,exports){d3=function(){var d3={version:"3.2.8"};if(!Date.now)Date.now=function(){return+new Date};var d3_document=document,d3_documentElement=d3_document.documentElement,d3_window=window;try{d3_document.createElement("div").style.setProperty("opacity",0,"")}catch(error){var d3_element_prototype=d3_window.Element.prototype,d3_element_setAttribute=d3_element_prototype.setAttribute,d3_element_setAttributeNS=d3_element_prototype.setAttributeNS,d3_style_prototype=d3_window.CSSStyleDeclaration.prototype,d3_style_setProperty=d3_style_prototype.setProperty;d3_element_prototype.setAttribute=function(name,value){d3_element_setAttribute.call(this,name,value+"")};d3_element_prototype.setAttributeNS=function(space,local,value){d3_element_setAttributeNS.call(this,space,local,value+"")};d3_style_prototype.setProperty=function(name,value,priority){d3_style_setProperty.call(this,name,value+"",priority)}}d3.ascending=function(a,b){return ab?1:a>=b?0:NaN};d3.descending=function(a,b){return ba?1:b>=a?0:NaN};d3.min=function(array,f){var i=-1,n=array.length,a,b;if(arguments.length===1){while(++ib)a=b}else{while(++ib)a=b}return a};d3.max=function(array,f){var i=-1,n=array.length,a,b;if(arguments.length===1){while(++ia)a=b}else{while(++ia)a=b}return a};d3.extent=function(array,f){var i=-1,n=array.length,a,b,c;if(arguments.length===1){while(++ib)a=b;if(cb)a=b;if(c1)array=array.map(f);array=array.filter(d3_number);return array.length?d3.quantile(array.sort(d3.ascending),.5):undefined};d3.bisector=function(f){return{left:function(a,x,lo,hi){if(arguments.length<3)lo=0;if(arguments.length<4)hi=a.length;while(lo>>1;if(f.call(a,a[mid],mid)>>1;if(xstop)range.push(j/k);else while((j=start+step*++i)=keys.length)return rollup?rollup.call(nest,array):sortValues?array.sort(sortValues):array;var i=-1,n=array.length,key=keys[depth++],keyValue,object,setter,valuesByKey=new d3_Map,values;while(++i=keys.length)return map;var array=[],sortKey=sortKeys[depth++];map.forEach(function(key,keyMap){array.push({key:key,values:entries(keyMap,depth)})});return sortKey?array.sort(function(a,b){return sortKey(a.key,b.key)}):array}nest.map=function(array,mapType){return map(mapType,array,0)};nest.entries=function(array){return entries(map(d3.map,array,0),0)};nest.key=function(d){keys.push(d);return nest};nest.sortKeys=function(order){sortKeys[keys.length-1]=order;return nest};nest.sortValues=function(order){sortValues=order;return nest};nest.rollup=function(f){rollup=f;return nest};return nest};d3.set=function(array){var set=new d3_Set;if(array)for(var i=0,n=array.length;i=0){name=type.substring(i+1);type=type.substring(0,i)}if(type)return arguments.length<2?this[type].on(name):this[type].on(name,listener);if(arguments.length===2){if(listener==null)for(type in this){if(this.hasOwnProperty(type))this[type].on(name,null)}return this}};function d3_dispatch_event(dispatch){var listeners=[],listenerByName=new d3_Map;function event(){var z=listeners,i=-1,n=z.length,l;while(++i=0){prefix=name.substring(0,i);name=name.substring(i+1)}return d3_nsPrefix.hasOwnProperty(prefix)?{space:d3_nsPrefix[prefix],local:name}:name}};d3_selectionPrototype.attr=function(name,value){if(arguments.length<2){if(typeof name==="string"){var node=this.node();name=d3.ns.qualify(name);return name.local?node.getAttributeNS(name.space,name.local):node.getAttribute(name)}for(value in name)this.each(d3_selection_attr(value,name[value]));return this}return this.each(d3_selection_attr(name,value))};function d3_selection_attr(name,value){name=d3.ns.qualify(name);function attrNull(){this.removeAttribute(name)}function attrNullNS(){this.removeAttributeNS(name.space,name.local)}function attrConstant(){this.setAttribute(name,value)}function attrConstantNS(){this.setAttributeNS(name.space,name.local,value)}function attrFunction(){var x=value.apply(this,arguments);if(x==null)this.removeAttribute(name);else this.setAttribute(name,x)}function attrFunctionNS(){var x=value.apply(this,arguments);if(x==null)this.removeAttributeNS(name.space,name.local);else this.setAttributeNS(name.space,name.local,x)}return value==null?name.local?attrNullNS:attrNull:typeof value==="function"?name.local?attrFunctionNS:attrFunction:name.local?attrConstantNS:attrConstant}function d3_collapse(s){return s.trim().replace(/\s+/g," ")}d3_selectionPrototype.classed=function(name,value){if(arguments.length<2){if(typeof name==="string"){var node=this.node(),n=(name=name.trim().split(/^|\s+/g)).length,i=-1;if(value=node.classList){while(++i=0;){if(node=group[i]){if(next&&next!==node.nextSibling)next.parentNode.insertBefore(node,next);next=node}}}return this};d3_selectionPrototype.sort=function(comparator){comparator=d3_selection_sortComparator.apply(this,arguments);for(var j=-1,m=this.length;++j=i0)i0=i+1;while(!(node=group[i0])&&++i00)type=type.substring(0,i);var filter=d3_selection_onFilters.get(type);if(filter)type=filter,wrap=d3_selection_onFilter;function onRemove(){var l=this[name];if(l){this.removeEventListener(type,l,l.$);delete this[name]}}function onAdd(){var l=wrap(listener,d3_array(arguments));onRemove.call(this);this.addEventListener(type,this[name]=l,l.$=capture);l._=listener}function removeAll(){var re=new RegExp("^__on([^.]+)"+d3.requote(type)+"$"),match;for(var name in this){if(match=name.match(re)){var l=this[name];this.removeEventListener(match[1],l,l.$);delete this[name]}}}return i?listener?onAdd:onRemove:listener?d3_noop:removeAll}var d3_selection_onFilters=d3.map({mouseenter:"mouseover",mouseleave:"mouseout"});d3_selection_onFilters.forEach(function(k){if("on"+k in d3_document)d3_selection_onFilters.remove(k)});function d3_selection_onListener(listener,argumentz){return function(e){var o=d3.event;d3.event=e;argumentz[0]=this.__data__;try{listener.apply(this,argumentz)}finally{d3.event=o}}}function d3_selection_onFilter(listener,argumentz){var l=d3_selection_onListener(listener,argumentz);return function(e){var target=this,related=e.relatedTarget;if(!related||related!==target&&!(related.compareDocumentPosition(target)&8)){l.call(target,e)}}}var d3_event_dragSelect=d3_vendorSymbol(d3_documentElement.style,"userSelect"),d3_event_dragId=0;function d3_event_dragSuppress(){var name=".dragsuppress-"+ ++d3_event_dragId,touchmove="touchmove"+name,selectstart="selectstart"+name,dragstart="dragstart"+name,click="click"+name,w=d3.select(d3_window).on(touchmove,d3_eventPreventDefault).on(selectstart,d3_eventPreventDefault).on(dragstart,d3_eventPreventDefault),style=d3_documentElement.style,select=style[d3_event_dragSelect];style[d3_event_dragSelect]="none";return function(suppressClick){w.on(name,null);style[d3_event_dragSelect]=select;if(suppressClick){function off(){w.on(click,null)}w.on(click,function(){d3_eventPreventDefault();off()},true);setTimeout(off,0)}}}d3.mouse=function(container){return d3_mousePoint(container,d3_eventSource())};var d3_mouse_bug44083=/WebKit/.test(d3_window.navigator.userAgent)?-1:0;function d3_mousePoint(container,e){var svg=container.ownerSVGElement||container;if(svg.createSVGPoint){var point=svg.createSVGPoint();if(d3_mouse_bug44083<0&&(d3_window.scrollX||d3_window.scrollY)){svg=d3.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var ctm=svg[0][0].getScreenCTM();d3_mouse_bug44083=!(ctm.f||ctm.e);svg.remove()}if(d3_mouse_bug44083){point.x=e.pageX;point.y=e.pageY}else{point.x=e.clientX;point.y=e.clientY}point=point.matrixTransform(container.getScreenCTM().inverse());return[point.x,point.y]}var rect=container.getBoundingClientRect();return[e.clientX-rect.left-container.clientLeft,e.clientY-rect.top-container.clientTop]}d3.touches=function(container,touches){if(arguments.length<2)touches=d3_eventSource().touches;return touches?d3_array(touches).map(function(touch){var point=d3_mousePoint(container,touch);point.identifier=touch.identifier;return point}):[]};d3.behavior.drag=function(){var event=d3_eventDispatch(drag,"drag","dragstart","dragend"),origin=null,mousedown=dragstart(d3_noop,d3.mouse,"mousemove","mouseup"),touchstart=dragstart(touchid,touchposition,"touchmove","touchend");function drag(){this.on("mousedown.drag",mousedown).on("touchstart.drag",touchstart)}function touchid(){return d3.event.changedTouches[0].identifier}function touchposition(parent,id){return d3.touches(parent).filter(function(p){return p.identifier===id})[0]}function dragstart(id,position,move,end){return function(){var target=this,parent=target.parentNode,event_=event.of(target,arguments),eventTarget=d3.event.target,eventId=id(),drag=eventId==null?"drag":"drag-"+eventId,origin_=position(parent,eventId),dragged=0,offset,w=d3.select(d3_window).on(move+"."+drag,moved).on(end+"."+drag,ended),dragRestore=d3_event_dragSuppress();if(origin){offset=origin.apply(target,arguments);offset=[offset.x-origin_[0],offset.y-origin_[1]]}else{offset=[0,0]}event_({type:"dragstart"});function moved(){if(!parent)return ended();var p=position(parent,eventId),dx=p[0]-origin_[0],dy=p[1]-origin_[1];dragged|=dx|dy;origin_=p;event_({type:"drag",x:p[0]+offset[0],y:p[1]+offset[1],dx:dx,dy:dy})}function ended(){w.on(move+"."+drag,null).on(end+"."+drag,null);dragRestore(dragged&&d3.event.target===eventTarget);event_({type:"dragend"})}}}drag.origin=function(x){if(!arguments.length)return origin;origin=x;return drag};return d3.rebind(drag,event,"on")};d3.behavior.zoom=function(){var translate=[0,0],translate0,scale=1,scaleExtent=d3_behavior_zoomInfinity,mousedown="mousedown.zoom",mousemove="mousemove.zoom",mouseup="mouseup.zoom",touchstart="touchstart.zoom",touchmove="touchmove.zoom",touchend="touchend.zoom",touchtime,event=d3_eventDispatch(zoom,"zoom"),x0,x1,y0,y1;function zoom(){this.on(mousedown,mousedowned).on(d3_behavior_zoomWheel+".zoom",mousewheeled).on(mousemove,mousewheelreset).on("dblclick.zoom",dblclicked).on(touchstart,touchstarted)}zoom.translate=function(x){if(!arguments.length)return translate;translate=x.map(Number);rescale();return zoom};zoom.scale=function(x){if(!arguments.length)return scale;scale=+x;rescale();return zoom};zoom.scaleExtent=function(x){if(!arguments.length)return scaleExtent;scaleExtent=x==null?d3_behavior_zoomInfinity:x.map(Number);return zoom};zoom.x=function(z){if(!arguments.length)return x1;x1=z;x0=z.copy();translate=[0,0];scale=1;return zoom};zoom.y=function(z){if(!arguments.length)return y1;y1=z;y0=z.copy();translate=[0,0];scale=1;return zoom};function location(p){return[(p[0]-translate[0])/scale,(p[1]-translate[1])/scale]}function point(l){return[l[0]*scale+translate[0],l[1]*scale+translate[1]]}function scaleTo(s){scale=Math.max(scaleExtent[0],Math.min(scaleExtent[1],s))}function translateTo(p,l){l=point(l);translate[0]+=p[0]-l[0];translate[1]+=p[1]-l[1]}function rescale(){if(x1)x1.domain(x0.range().map(function(x){return(x-translate[0])/scale}).map(x0.invert));if(y1)y1.domain(y0.range().map(function(y){return(y-translate[1])/scale}).map(y0.invert))}function dispatch(event){rescale();event({type:"zoom",scale:scale,translate:translate})}function mousedowned(){var target=this,event_=event.of(target,arguments),eventTarget=d3.event.target,dragged=0,w=d3.select(d3_window).on(mousemove,moved).on(mouseup,ended),l=location(d3.mouse(target)),dragRestore=d3_event_dragSuppress();function moved(){dragged=1;translateTo(d3.mouse(target),l);dispatch(event_)}function ended(){w.on(mousemove,d3_window===target?mousewheelreset:null).on(mouseup,null);dragRestore(dragged&&d3.event.target===eventTarget)}}function touchstarted(){var target=this,event_=event.of(target,arguments),locations0,distance0=0,scale0,w=d3.select(d3_window).on(touchmove,moved).on(touchend,ended),t=d3.select(target).on(mousedown,null).on(touchstart,started),dragRestore=d3_event_dragSuppress();started();function relocate(){var touches=d3.touches(target);scale0=scale;locations0={};touches.forEach(function(t){locations0[t.identifier]=location(t)});return touches}function started(){var now=Date.now(),touches=relocate();if(touches.length===1){if(now-touchtime<500){var p=touches[0],l=locations0[p.identifier];scaleTo(scale*2);translateTo(p,l);d3_eventPreventDefault();dispatch(event_)}touchtime=now}else if(touches.length>1){var p=touches[0],q=touches[1],dx=p[0]-q[0],dy=p[1]-q[1];distance0=dx*dx+dy*dy}}function moved(){var touches=d3.touches(target),p0=touches[0],l0=locations0[p0.identifier];if(p1=touches[1]){var p1,l1=locations0[p1.identifier],scale1=d3.event.scale;if(scale1==null){var distance1=(distance1=p1[0]-p0[0])*distance1+(distance1=p1[1]-p0[1])*distance1;scale1=distance0&&Math.sqrt(distance1/distance0)}p0=[(p0[0]+p1[0])/2,(p0[1]+p1[1])/2];l0=[(l0[0]+l1[0])/2,(l0[1]+l1[1])/2];scaleTo(scale1*scale0)}touchtime=null;translateTo(p0,l0);dispatch(event_)}function ended(){if(d3.event.touches.length){relocate()}else{w.on(touchmove,null).on(touchend,null);t.on(mousedown,mousedowned).on(touchstart,touchstarted);dragRestore()}}}function mousewheeled(){d3_eventPreventDefault();if(!translate0)translate0=location(d3.mouse(this));scaleTo(Math.pow(2,d3_behavior_zoomDelta()*.002)*scale);translateTo(d3.mouse(this),translate0);dispatch(event.of(this,arguments))}function mousewheelreset(){translate0=null}function dblclicked(){var p=d3.mouse(this),l=location(p),k=Math.log(scale)/Math.LN2;scaleTo(Math.pow(2,d3.event.shiftKey?Math.ceil(k)-1:Math.floor(k)+1));translateTo(p,l);dispatch(event.of(this,arguments))}return d3.rebind(zoom,event,"on")};var d3_behavior_zoomInfinity=[0,Infinity];var d3_behavior_zoomDelta,d3_behavior_zoomWheel="onwheel"in d3_document?(d3_behavior_zoomDelta=function(){return-d3.event.deltaY*(d3.event.deltaMode?120:1)},"wheel"):"onmousewheel"in d3_document?(d3_behavior_zoomDelta=function(){return d3.event.wheelDelta},"mousewheel"):(d3_behavior_zoomDelta=function(){return-d3.event.detail},"MozMousePixelScroll");function d3_Color(){}d3_Color.prototype.toString=function(){return this.rgb()+""};d3.hsl=function(h,s,l){return arguments.length===1?h instanceof d3_Hsl?d3_hsl(h.h,h.s,h.l):d3_rgb_parse(""+h,d3_rgb_hsl,d3_hsl):d3_hsl(+h,+s,+l)};function d3_hsl(h,s,l){return new d3_Hsl(h,s,l)}function d3_Hsl(h,s,l){this.h=h;this.s=s;this.l=l}var d3_hslPrototype=d3_Hsl.prototype=new d3_Color;d3_hslPrototype.brighter=function(k){k=Math.pow(.7,arguments.length?k:1);return d3_hsl(this.h,this.s,this.l/k)};d3_hslPrototype.darker=function(k){k=Math.pow(.7,arguments.length?k:1);return d3_hsl(this.h,this.s,k*this.l)};d3_hslPrototype.rgb=function(){return d3_hsl_rgb(this.h,this.s,this.l)};function d3_hsl_rgb(h,s,l){var m1,m2;h=isNaN(h)?0:(h%=360)<0?h+360:h;s=isNaN(s)?0:s<0?0:s>1?1:s;l=l<0?0:l>1?1:l;m2=l<=.5?l*(1+s):l+s-l*s;m1=2*l-m2;function v(h){if(h>360)h-=360;else if(h<0)h+=360;if(h<60)return m1+(m2-m1)*h/60;if(h<180)return m2;if(h<240)return m1+(m2-m1)*(240-h)/60;return m1}function vv(h){return Math.round(v(h)*255)}return d3_rgb(vv(h+120),vv(h),vv(h-120))}var π=Math.PI,ε=1e-6,ε2=ε*ε,d3_radians=π/180,d3_degrees=180/π;function d3_sgn(x){return x>0?1:x<0?-1:0}function d3_acos(x){return x>1?0:x<-1?π:Math.acos(x)}function d3_asin(x){return x>1?π/2:x<-1?-π/2:Math.asin(x)}function d3_sinh(x){return(Math.exp(x)-Math.exp(-x))/2}function d3_cosh(x){return(Math.exp(x)+Math.exp(-x))/2}function d3_haversin(x){return(x=Math.sin(x/2))*x}d3.hcl=function(h,c,l){return arguments.length===1?h instanceof d3_Hcl?d3_hcl(h.h,h.c,h.l):h instanceof d3_Lab?d3_lab_hcl(h.l,h.a,h.b):d3_lab_hcl((h=d3_rgb_lab((h=d3.rgb(h)).r,h.g,h.b)).l,h.a,h.b):d3_hcl(+h,+c,+l)};function d3_hcl(h,c,l){return new d3_Hcl(h,c,l)}function d3_Hcl(h,c,l){this.h=h;this.c=c;this.l=l}var d3_hclPrototype=d3_Hcl.prototype=new d3_Color;d3_hclPrototype.brighter=function(k){return d3_hcl(this.h,this.c,Math.min(100,this.l+d3_lab_K*(arguments.length?k:1)))};d3_hclPrototype.darker=function(k){return d3_hcl(this.h,this.c,Math.max(0,this.l-d3_lab_K*(arguments.length?k:1)))};d3_hclPrototype.rgb=function(){return d3_hcl_lab(this.h,this.c,this.l).rgb()};function d3_hcl_lab(h,c,l){if(isNaN(h))h=0;if(isNaN(c))c=0;return d3_lab(l,Math.cos(h*=d3_radians)*c,Math.sin(h)*c)}d3.lab=function(l,a,b){return arguments.length===1?l instanceof d3_Lab?d3_lab(l.l,l.a,l.b):l instanceof d3_Hcl?d3_hcl_lab(l.l,l.c,l.h):d3_rgb_lab((l=d3.rgb(l)).r,l.g,l.b):d3_lab(+l,+a,+b)};function d3_lab(l,a,b){return new d3_Lab(l,a,b)}function d3_Lab(l,a,b){this.l=l;this.a=a;this.b=b}var d3_lab_K=18;var d3_lab_X=.95047,d3_lab_Y=1,d3_lab_Z=1.08883;var d3_labPrototype=d3_Lab.prototype=new d3_Color;d3_labPrototype.brighter=function(k){return d3_lab(Math.min(100,this.l+d3_lab_K*(arguments.length?k:1)),this.a,this.b)};d3_labPrototype.darker=function(k){return d3_lab(Math.max(0,this.l-d3_lab_K*(arguments.length?k:1)),this.a,this.b)};d3_labPrototype.rgb=function(){return d3_lab_rgb(this.l,this.a,this.b)};function d3_lab_rgb(l,a,b){var y=(l+16)/116,x=y+a/500,z=y-b/200;x=d3_lab_xyz(x)*d3_lab_X;y=d3_lab_xyz(y)*d3_lab_Y;z=d3_lab_xyz(z)*d3_lab_Z;return d3_rgb(d3_xyz_rgb(3.2404542*x-1.5371385*y-.4985314*z),d3_xyz_rgb(-.969266*x+1.8760108*y+.041556*z),d3_xyz_rgb(.0556434*x-.2040259*y+1.0572252*z))}function d3_lab_hcl(l,a,b){return l>0?d3_hcl(Math.atan2(b,a)*d3_degrees,Math.sqrt(a*a+b*b),l):d3_hcl(NaN,NaN,l)}function d3_lab_xyz(x){return x>.206893034?x*x*x:(x-4/29)/7.787037}function d3_xyz_lab(x){return x>.008856?Math.pow(x,1/3):7.787037*x+4/29}function d3_xyz_rgb(r){return Math.round(255*(r<=.00304?12.92*r:1.055*Math.pow(r,1/2.4)-.055))}d3.rgb=function(r,g,b){return arguments.length===1?r instanceof d3_Rgb?d3_rgb(r.r,r.g,r.b):d3_rgb_parse(""+r,d3_rgb,d3_hsl_rgb):d3_rgb(~~r,~~g,~~b)};function d3_rgbNumber(value){return d3_rgb(value>>16,value>>8&255,value&255)}function d3_rgbString(value){return d3_rgbNumber(value)+""}function d3_rgb(r,g,b){return new d3_Rgb(r,g,b)}function d3_Rgb(r,g,b){this.r=r;this.g=g;this.b=b}var d3_rgbPrototype=d3_Rgb.prototype=new d3_Color;d3_rgbPrototype.brighter=function(k){k=Math.pow(.7,arguments.length?k:1);var r=this.r,g=this.g,b=this.b,i=30;if(!r&&!g&&!b)return d3_rgb(i,i,i);if(r&&r0&&l<1?0:h}return d3_hsl(h,s,l)}function d3_rgb_lab(r,g,b){r=d3_rgb_xyz(r);g=d3_rgb_xyz(g);b=d3_rgb_xyz(b);var x=d3_xyz_lab((.4124564*r+.3575761*g+.1804375*b)/d3_lab_X),y=d3_xyz_lab((.2126729*r+.7151522*g+.072175*b)/d3_lab_Y),z=d3_xyz_lab((.0193339*r+.119192*g+.9503041*b)/d3_lab_Z);return d3_lab(116*y-16,500*(x-y),200*(y-z))}function d3_rgb_xyz(r){return(r/=255)<=.04045?r/12.92:Math.pow((r+.055)/1.055,2.4)}function d3_rgb_parseNumber(c){var f=parseFloat(c);return c.charAt(c.length-1)==="%"?Math.round(f*2.55):f}var d3_rgb_names=d3.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});d3_rgb_names.forEach(function(key,value){d3_rgb_names.set(key,d3_rgbNumber(value))});function d3_functor(v){return typeof v==="function"?v:function(){return v}}d3.functor=d3_functor;function d3_identity(d){return d}d3.xhr=d3_xhrType(d3_identity);function d3_xhrType(response){return function(url,mimeType,callback){if(arguments.length===2&&typeof mimeType==="function")callback=mimeType,mimeType=null;return d3_xhr(url,mimeType,response,callback)}}function d3_xhr(url,mimeType,response,callback){var xhr={},dispatch=d3.dispatch("progress","load","error"),headers={},request=new XMLHttpRequest,responseType=null;if(d3_window.XDomainRequest&&!("withCredentials"in request)&&/^(http(s)?:)?\/\//.test(url))request=new XDomainRequest;"onload"in request?request.onload=request.onerror=respond:request.onreadystatechange=function(){request.readyState>3&&respond()};function respond(){var status=request.status,result;if(!status&&request.responseText||status>=200&&status<300||status===304){try{result=response.call(xhr,request)}catch(e){dispatch.error.call(xhr,e);return}dispatch.load.call(xhr,result)}else{dispatch.error.call(xhr,request)}}request.onprogress=function(event){var o=d3.event;d3.event=event;try{dispatch.progress.call(xhr,request)}finally{d3.event=o}};xhr.header=function(name,value){name=(name+"").toLowerCase();if(arguments.length<2)return headers[name];if(value==null)delete headers[name];else headers[name]=value+"";return xhr};xhr.mimeType=function(value){if(!arguments.length)return mimeType;mimeType=value==null?null:value+"";return xhr};xhr.responseType=function(value){if(!arguments.length)return responseType;responseType=value;return xhr};xhr.response=function(value){response=value;return xhr};["get","post"].forEach(function(method){xhr[method]=function(){return xhr.send.apply(xhr,[method].concat(d3_array(arguments)))}});xhr.send=function(method,data,callback){if(arguments.length===2&&typeof data==="function")callback=data,data=null;request.open(method,url,true);if(mimeType!=null&&!("accept"in headers))headers["accept"]=mimeType+",*/*";if(request.setRequestHeader)for(var name in headers)request.setRequestHeader(name,headers[name]);if(mimeType!=null&&request.overrideMimeType)request.overrideMimeType(mimeType);if(responseType!=null)request.responseType=responseType;if(callback!=null)xhr.on("error",callback).on("load",function(request){callback(null,request)});request.send(data==null?null:data);return xhr};xhr.abort=function(){request.abort();return xhr};d3.rebind(xhr,dispatch,"on");return callback==null?xhr:xhr.get(d3_xhr_fixCallback(callback))}function d3_xhr_fixCallback(callback){return callback.length===1?function(error,request){callback(error==null?request:null)}:callback}d3.dsv=function(delimiter,mimeType){var reFormat=new RegExp('["'+delimiter+"\n]"),delimiterCode=delimiter.charCodeAt(0);function dsv(url,row,callback){if(arguments.length<3)callback=row,row=null;var xhr=d3.xhr(url,mimeType,callback);xhr.row=function(_){return arguments.length?xhr.response((row=_)==null?response:typedResponse(_)):row};return xhr.row(row)}function response(request){return dsv.parse(request.responseText)}function typedResponse(f){return function(request){return dsv.parse(request.responseText,f)}}dsv.parse=function(text,f){var o;return dsv.parseRows(text,function(row,i){if(o)return o(row,i-1);var a=new Function("d","return {"+row.map(function(name,i){return JSON.stringify(name)+": d["+i+"]"}).join(",")+"}");o=f?function(row,i){return f(a(row),i)}:a})};dsv.parseRows=function(text,f){var EOL={},EOF={},rows=[],N=text.length,I=0,n=0,t,eol;function token(){if(I>=N)return EOF;if(eol)return eol=false,EOL;var j=I;if(text.charCodeAt(j)===34){var i=j;while(i++24){if(isFinite(delay)){clearTimeout(d3_timer_timeout);d3_timer_timeout=setTimeout(d3_timer_step,delay)}d3_timer_interval=0}else{d3_timer_interval=1;d3_timer_frame(d3_timer_step)}}d3.timer.flush=function(){d3_timer_mark();d3_timer_sweep()};function d3_timer_replace(callback,delay,then){var n=arguments.length;if(n<2)delay=0;if(n<3)then=Date.now();d3_timer_active.callback=callback;d3_timer_active.time=then+delay}function d3_timer_mark(){var now=Date.now();d3_timer_active=d3_timer_queueHead;while(d3_timer_active){if(now>=d3_timer_active.time)d3_timer_active.flush=d3_timer_active.callback(now-d3_timer_active.time);d3_timer_active=d3_timer_active.next}return now}function d3_timer_sweep(){var t0,t1=d3_timer_queueHead,time=Infinity;while(t1){if(t1.flush){t1=t0?t0.next=t1.next:d3_timer_queueHead=t1.next}else{if(t1.time8?function(d){return d/k}:function(d){return d*k},symbol:d}}d3.round=function(x,n){return n?Math.round(x*(n=Math.pow(10,n)))/n:Math.round(x)};d3.format=function(specifier){var match=d3_format_re.exec(specifier),fill=match[1]||" ",align=match[2]||">",sign=match[3]||"",symbol=match[4]||"",zfill=match[5],width=+match[6],comma=match[7],precision=match[8],type=match[9],scale=1,suffix="",integer=false;if(precision)precision=+precision.substring(1);if(zfill||fill==="0"&&align==="="){zfill=fill="0";align="=";if(comma)width-=Math.floor((width-1)/4)}switch(type){case"n":comma=true;type="g";break;case"%":scale=100;suffix="%";type="f";break;case"p":scale=100;suffix="%";type="r";break;case"b":case"o":case"x":case"X":if(symbol==="#")symbol="0"+type.toLowerCase();case"c":case"d":integer=true;precision=0;break;case"s":scale=-1;type="r";break}if(symbol==="#")symbol="";else if(symbol==="$")symbol=d3_format_currencySymbol;if(type=="r"&&!precision)type="g";if(precision!=null){if(type=="g")precision=Math.max(1,Math.min(21,precision));else if(type=="e"||type=="f")precision=Math.max(0,Math.min(20,precision))}type=d3_format_types.get(type)||d3_format_typeDefault;var zcomma=zfill&,return function(value){if(integer&&value%1)return"";var negative=value<0||value===0&&1/value<0?(value=-value,"-"):sign;if(scale<0){var prefix=d3.formatPrefix(value,precision);value=prefix.scale(value);suffix=prefix.symbol}else{value*=scale}value=type(value,precision);var i=value.lastIndexOf("."),before=i<0?value:value.substring(0,i),after=i<0?"":d3_format_decimalPoint+value.substring(i+1);if(!zfill&&comma)before=d3_format_group(before);var length=symbol.length+before.length+after.length+(zcomma?0:negative.length),padding=length"?padding+negative+value:align==="^"?padding.substring(0,length>>=1)+negative+value+padding.substring(length):negative+(zcomma?value:padding+value))+suffix}};var d3_format_re=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;var d3_format_types=d3.map({b:function(x){return x.toString(2)},c:function(x){return String.fromCharCode(x)},o:function(x){return x.toString(8)},x:function(x){return x.toString(16)},X:function(x){return x.toString(16).toUpperCase()},g:function(x,p){return x.toPrecision(p)},e:function(x,p){return x.toExponential(p)},f:function(x,p){return x.toFixed(p)},r:function(x,p){return(x=d3.round(x,d3_format_precision(x,p))).toFixed(Math.max(0,Math.min(20,d3_format_precision(x*(1+1e-15),p))))}});function d3_format_precision(x,p){return p-(x?Math.ceil(Math.log(x)/Math.LN10):1)}function d3_format_typeDefault(x){return x+""}var d3_format_group=d3_identity;if(d3_format_grouping){var d3_format_groupingLength=d3_format_grouping.length;d3_format_group=function(value){var i=value.length,t=[],j=0,g=d3_format_grouping[0];while(i>0&&g>0){t.push(value.substring(i-=g,i+g));g=d3_format_grouping[j=(j+1)%d3_format_groupingLength]}return t.reverse().join(d3_format_thousandsSeparator)}}d3.geo={};function d3_adder(){}d3_adder.prototype={s:0,t:0,add:function(y){d3_adderSum(y,this.t,d3_adderTemp);d3_adderSum(d3_adderTemp.s,this.s,this);if(this.s)this.t+=d3_adderTemp.t;else this.s=d3_adderTemp.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var d3_adderTemp=new d3_adder;function d3_adderSum(a,b,o){var x=o.s=a+b,bv=x-a,av=x-bv;o.t=a-av+(b-bv)}d3.geo.stream=function(object,listener){if(object&&d3_geo_streamObjectType.hasOwnProperty(object.type)){d3_geo_streamObjectType[object.type](object,listener)}else{d3_geo_streamGeometry(object,listener)}};function d3_geo_streamGeometry(geometry,listener){if(geometry&&d3_geo_streamGeometryType.hasOwnProperty(geometry.type)){d3_geo_streamGeometryType[geometry.type](geometry,listener)}}var d3_geo_streamObjectType={Feature:function(feature,listener){d3_geo_streamGeometry(feature.geometry,listener)},FeatureCollection:function(object,listener){var features=object.features,i=-1,n=features.length;while(++iε)φ1=90;else if(dλSum<-ε)φ0=-90;range[0]=λ0,range[1]=λ1}};function point(λ,φ){ranges.push(range=[λ0=λ,λ1=λ]);if(φ<φ0)φ0=φ;if(φ>φ1)φ1=φ}function linePoint(λ,φ){var p=d3_geo_cartesian([λ*d3_radians,φ*d3_radians]);if(p0){var normal=d3_geo_cartesianCross(p0,p),equatorial=[normal[1],-normal[0],0],inflection=d3_geo_cartesianCross(equatorial,normal);d3_geo_cartesianNormalize(inflection);inflection=d3_geo_spherical(inflection);var dλ=λ-λ_,s=dλ>0?1:-1,λi=inflection[0]*d3_degrees*s,antimeridian=Math.abs(dλ)>180;if(antimeridian^(s*λ_<λi&&λiφ1)φ1=φi}else if(λi=(λi+360)%360-180,antimeridian^(s*λ_<λi&&λiφ1)φ1=φ}if(antimeridian){if(λ<λ_){if(angle(λ0,λ)>angle(λ0,λ1))λ1=λ}else{if(angle(λ,λ1)>angle(λ0,λ1))λ0=λ}}else{if(λ1>=λ0){if(λ<λ0)λ0=λ;if(λ>λ1)λ1=λ}else{if(λ>λ_){if(angle(λ0,λ)>angle(λ0,λ1))λ1=λ}else{if(angle(λ,λ1)>angle(λ0,λ1))λ0=λ}}}}else{point(λ,φ)}p0=p,λ_=λ}function lineStart(){bound.point=linePoint}function lineEnd(){range[0]=λ0,range[1]=λ1;bound.point=point;p0=null}function ringPoint(λ,φ){if(p0){var dλ=λ-λ_;dλSum+=Math.abs(dλ)>180?dλ+(dλ>0?360:-360):dλ}else λ__=λ,φ__=φ;d3_geo_area.point(λ,φ);linePoint(λ,φ)}function ringStart(){d3_geo_area.lineStart()}function ringEnd(){ringPoint(λ__,φ__);d3_geo_area.lineEnd();if(Math.abs(dλSum)>ε)λ0=-(λ1=180);range[0]=λ0,range[1]=λ1;p0=null}function angle(λ0,λ1){return(λ1-=λ0)<0?λ1+360:λ1}function compareRanges(a,b){return a[0]-b[0]}function withinRange(x,range){return range[0]<=range[1]?range[0]<=x&&x<=range[1]:xangle(a[0],a[1]))a[1]=b[1];if(angle(b[0],a[1])>angle(a[0],a[1]))a[0]=b[0]}else{merged.push(a=b)}}var best=-Infinity,dλ;for(var n=merged.length-1,i=0,a=merged[n],b;i<=n;a=b,++i){b=merged[i];if((dλ=angle(a[1],b[0]))>best)best=dλ,λ0=b[0],λ1=a[1]}}ranges=range=null;return λ0===Infinity||φ0===Infinity?[[NaN,NaN],[NaN,NaN]]:[[λ0,φ0],[λ1,φ1]]}}();d3.geo.centroid=function(object){d3_geo_centroidW0=d3_geo_centroidW1=d3_geo_centroidX0=d3_geo_centroidY0=d3_geo_centroidZ0=d3_geo_centroidX1=d3_geo_centroidY1=d3_geo_centroidZ1=d3_geo_centroidX2=d3_geo_centroidY2=d3_geo_centroidZ2=0;d3.geo.stream(object,d3_geo_centroid);var x=d3_geo_centroidX2,y=d3_geo_centroidY2,z=d3_geo_centroidZ2,m=x*x+y*y+z*z;if(m<ε2){x=d3_geo_centroidX1,y=d3_geo_centroidY1,z=d3_geo_centroidZ1;if(d3_geo_centroidW1<ε)x=d3_geo_centroidX0,y=d3_geo_centroidY0,z=d3_geo_centroidZ0;m=x*x+y*y+z*z;if(m<ε2)return[NaN,NaN]}return[Math.atan2(y,x)*d3_degrees,d3_asin(z/Math.sqrt(m))*d3_degrees]};var d3_geo_centroidW0,d3_geo_centroidW1,d3_geo_centroidX0,d3_geo_centroidY0,d3_geo_centroidZ0,d3_geo_centroidX1,d3_geo_centroidY1,d3_geo_centroidZ1,d3_geo_centroidX2,d3_geo_centroidY2,d3_geo_centroidZ2;var d3_geo_centroid={sphere:d3_noop,point:d3_geo_centroidPoint,lineStart:d3_geo_centroidLineStart,lineEnd:d3_geo_centroidLineEnd,polygonStart:function(){d3_geo_centroid.lineStart=d3_geo_centroidRingStart},polygonEnd:function(){d3_geo_centroid.lineStart=d3_geo_centroidLineStart}};function d3_geo_centroidPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);d3_geo_centroidPointXYZ(cosφ*Math.cos(λ),cosφ*Math.sin(λ),Math.sin(φ))}function d3_geo_centroidPointXYZ(x,y,z){++d3_geo_centroidW0;d3_geo_centroidX0+=(x-d3_geo_centroidX0)/d3_geo_centroidW0;d3_geo_centroidY0+=(y-d3_geo_centroidY0)/d3_geo_centroidW0;d3_geo_centroidZ0+=(z-d3_geo_centroidZ0)/d3_geo_centroidW0}function d3_geo_centroidLineStart(){var x0,y0,z0;d3_geo_centroid.point=function(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);x0=cosφ*Math.cos(λ);y0=cosφ*Math.sin(λ);z0=Math.sin(φ);d3_geo_centroid.point=nextPoint;d3_geo_centroidPointXYZ(x0,y0,z0)};function nextPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians),x=cosφ*Math.cos(λ),y=cosφ*Math.sin(λ),z=Math.sin(φ),w=Math.atan2(Math.sqrt((w=y0*z-z0*y)*w+(w=z0*x-x0*z)*w+(w=x0*y-y0*x)*w),x0*x+y0*y+z0*z);d3_geo_centroidW1+=w;d3_geo_centroidX1+=w*(x0+(x0=x));d3_geo_centroidY1+=w*(y0+(y0=y));d3_geo_centroidZ1+=w*(z0+(z0=z));d3_geo_centroidPointXYZ(x0,y0,z0)}}function d3_geo_centroidLineEnd(){d3_geo_centroid.point=d3_geo_centroidPoint}function d3_geo_centroidRingStart(){var λ00,φ00,x0,y0,z0;d3_geo_centroid.point=function(λ,φ){λ00=λ,φ00=φ;d3_geo_centroid.point=nextPoint;λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians);x0=cosφ*Math.cos(λ);y0=cosφ*Math.sin(λ);z0=Math.sin(φ);d3_geo_centroidPointXYZ(x0,y0,z0)};d3_geo_centroid.lineEnd=function(){nextPoint(λ00,φ00);d3_geo_centroid.lineEnd=d3_geo_centroidLineEnd;d3_geo_centroid.point=d3_geo_centroidPoint};function nextPoint(λ,φ){λ*=d3_radians;var cosφ=Math.cos(φ*=d3_radians),x=cosφ*Math.cos(λ),y=cosφ*Math.sin(λ),z=Math.sin(φ),cx=y0*z-z0*y,cy=z0*x-x0*z,cz=x0*y-y0*x,m=Math.sqrt(cx*cx+cy*cy+cz*cz),u=x0*x+y0*y+z0*z,v=m&&-d3_acos(u)/m,w=Math.atan2(m,u);d3_geo_centroidX2+=v*cx;d3_geo_centroidY2+=v*cy;d3_geo_centroidZ2+=v*cz;d3_geo_centroidW1+=w;d3_geo_centroidX1+=w*(x0+(x0=x));d3_geo_centroidY1+=w*(y0+(y0=y));d3_geo_centroidZ1+=w*(z0+(z0=z));d3_geo_centroidPointXYZ(x0,y0,z0)}}function d3_true(){return true}function d3_geo_clipPolygon(segments,compare,inside,interpolate,listener){var subject=[],clip=[];segments.forEach(function(segment){if((n=segment.length-1)<=0)return;var n,p0=segment[0],p1=segment[n];if(d3_geo_sphericalEqual(p0,p1)){listener.lineStart();for(var i=0;i=0;)listener.point((point=points[i])[0],point[1])}else{interpolate(current.point,current.prev.point,-1,listener)}current=current.prev}current=current.other;points=current.points}while(!current.visited);listener.lineEnd()}}function d3_geo_clipPolygonLinkCircular(array){if(!(n=array.length))return;var n,i=0,a=array[0],b;while(++i1&&clean&2)ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));segments.push(ringSegments.filter(d3_geo_clipSegmentLength1))}return clip}}function d3_geo_clipSegmentLength1(segment){return segment.length>1}function d3_geo_clipBufferListener(){var lines=[],line;return{lineStart:function(){lines.push(line=[])},point:function(λ,φ){line.push([λ,φ])},lineEnd:d3_noop,buffer:function(){var buffer=lines;lines=[];line=null;return buffer},rejoin:function(){if(lines.length>1)lines.push(lines.pop().concat(lines.shift()))}}}function d3_geo_clipSort(a,b){return((a=a.point)[0]<0?a[1]-π/2-ε:π/2-a[1])-((b=b.point)[0]<0?b[1]-π/2-ε:π/2-b[1])}function d3_geo_pointInPolygon(point,polygon){var meridian=point[0],parallel=point[1],meridianNormal=[Math.sin(meridian),-Math.cos(meridian),0],polarAngle=0,polar=false,southPole=false,winding=0;d3_geo_areaRingSum.reset();for(var i=0,n=polygon.length;iπ,k=sinφ0*sinφ;d3_geo_areaRingSum.add(Math.atan2(k*Math.sin(dλ),cosφ0*cosφ+k*Math.cos(dλ)));if(Math.abs(φ)<ε)southPole=true;polarAngle+=antimeridian?dλ+(dλ>=0?2:-2)*π:dλ;if(antimeridian^λ0>=meridian^λ>=meridian){var arc=d3_geo_cartesianCross(d3_geo_cartesian(point0),d3_geo_cartesian(point));d3_geo_cartesianNormalize(arc);var intersection=d3_geo_cartesianCross(meridianNormal,arc);d3_geo_cartesianNormalize(intersection);var φarc=(antimeridian^dλ>=0?-1:1)*d3_asin(intersection[2]);if(parallel>φarc){winding+=antimeridian^dλ>=0?1:-1}}if(!j++)break;λ0=λ,sinφ0=sinφ,cosφ0=cosφ,point0=point}if(Math.abs(polarAngle)>ε)polar=true}return(!southPole&&!polar&&d3_geo_areaRingSum<0||polarAngle<-ε)^winding&1}var d3_geo_clipAntimeridian=d3_geo_clip(d3_true,d3_geo_clipAntimeridianLine,d3_geo_clipAntimeridianInterpolate,d3_geo_clipAntimeridianPolygonContains);function d3_geo_clipAntimeridianLine(listener){var λ0=NaN,φ0=NaN,sλ0=NaN,clean;return{lineStart:function(){listener.lineStart();clean=1},point:function(λ1,φ1){var sλ1=λ1>0?π:-π,dλ=Math.abs(λ1-λ0);if(Math.abs(dλ-π)<ε){listener.point(λ0,φ0=(φ0+φ1)/2>0?π/2:-π/2);listener.point(sλ0,φ0);listener.lineEnd();listener.lineStart();listener.point(sλ1,φ0);listener.point(λ1,φ0);clean=0}else if(sλ0!==sλ1&&dλ>=π){if(Math.abs(λ0-sλ0)<ε)λ0-=sλ0*ε;if(Math.abs(λ1-sλ1)<ε)λ1-=sλ1*ε;φ0=d3_geo_clipAntimeridianIntersect(λ0,φ0,λ1,φ1);listener.point(sλ0,φ0);listener.lineEnd();listener.lineStart();listener.point(sλ1,φ0);clean=0}listener.point(λ0=λ1,φ0=φ1);sλ0=sλ1},lineEnd:function(){listener.lineEnd();λ0=φ0=NaN},clean:function(){return 2-clean}}}function d3_geo_clipAntimeridianIntersect(λ0,φ0,λ1,φ1){var cosφ0,cosφ1,sinλ0_λ1=Math.sin(λ0-λ1);return Math.abs(sinλ0_λ1)>ε?Math.atan((Math.sin(φ0)*(cosφ1=Math.cos(φ1))*Math.sin(λ1)-Math.sin(φ1)*(cosφ0=Math.cos(φ0))*Math.sin(λ0))/(cosφ0*cosφ1*sinλ0_λ1)):(φ0+φ1)/2}function d3_geo_clipAntimeridianInterpolate(from,to,direction,listener){var φ;if(from==null){φ=direction*π/2;listener.point(-π,φ);listener.point(0,φ);listener.point(π,φ);listener.point(π,0);listener.point(π,-φ);listener.point(0,-φ);listener.point(-π,-φ);listener.point(-π,0);listener.point(-π,φ)}else if(Math.abs(from[0]-to[0])>ε){var s=(from[0]0,point=[radius,0],notHemisphere=Math.abs(cr)>ε,interpolate=d3_geo_circleInterpolate(radius,6*d3_radians);return d3_geo_clip(visible,clipLine,interpolate,polygonContains);function visible(λ,φ){return Math.cos(λ)*Math.cos(φ)>cr}function clipLine(listener){var point0,c0,v0,v00,clean;return{lineStart:function(){v00=v0=false;clean=1},point:function(λ,φ){var point1=[λ,φ],point2,v=visible(λ,φ),c=smallRadius?v?0:code(λ,φ):v?code(λ+(λ<0?π:-π),φ):0;if(!point0&&(v00=v0=v))listener.lineStart();if(v!==v0){point2=intersect(point0,point1);if(d3_geo_sphericalEqual(point0,point2)||d3_geo_sphericalEqual(point1,point2)){point1[0]+=ε;point1[1]+=ε;v=visible(point1[0],point1[1])}}if(v!==v0){clean=0;if(v){listener.lineStart();point2=intersect(point1,point0);listener.point(point2[0],point2[1])}else{point2=intersect(point0,point1);listener.point(point2[0],point2[1]);listener.lineEnd()}point0=point2}else if(notHemisphere&&point0&&smallRadius^v){var t;if(!(c&c0)&&(t=intersect(point1,point0,true))){clean=0;if(smallRadius){listener.lineStart();listener.point(t[0][0],t[0][1]);listener.point(t[1][0],t[1][1]);listener.lineEnd()}else{listener.point(t[1][0],t[1][1]);listener.lineEnd();listener.lineStart();listener.point(t[0][0],t[0][1])}}}if(v&&(!point0||!d3_geo_sphericalEqual(point0,point1))){listener.point(point1[0],point1[1])}point0=point1,v0=v,c0=c},lineEnd:function(){if(v0)listener.lineEnd();point0=null},clean:function(){return clean|(v00&&v0)<<1}}}function intersect(a,b,two){var pa=d3_geo_cartesian(a),pb=d3_geo_cartesian(b);var n1=[1,0,0],n2=d3_geo_cartesianCross(pa,pb),n2n2=d3_geo_cartesianDot(n2,n2),n1n2=n2[0],determinant=n2n2-n1n2*n1n2;if(!determinant)return!two&&a;var c1=cr*n2n2/determinant,c2=-cr*n1n2/determinant,n1xn2=d3_geo_cartesianCross(n1,n2),A=d3_geo_cartesianScale(n1,c1),B=d3_geo_cartesianScale(n2,c2);d3_geo_cartesianAdd(A,B);var u=n1xn2,w=d3_geo_cartesianDot(A,u),uu=d3_geo_cartesianDot(u,u),t2=w*w-uu*(d3_geo_cartesianDot(A,A)-1);if(t2<0)return;var t=Math.sqrt(t2),q=d3_geo_cartesianScale(u,(-w-t)/uu);d3_geo_cartesianAdd(q,A);q=d3_geo_spherical(q);if(!two)return q;var λ0=a[0],λ1=b[0],φ0=a[1],φ1=b[1],z;if(λ1<λ0)z=λ0,λ0=λ1,λ1=z;var δλ=λ1-λ0,polar=Math.abs(δλ-π)<ε,meridian=polar||δλ<ε;if(!polar&&φ1<φ0)z=φ0,φ0=φ1,φ1=z;if(meridian?polar?φ0+φ1>0^q[1]<(Math.abs(q[0]-λ0)<ε?φ0:φ1):φ0<=q[1]&&q[1]<=φ1:δλ>π^(λ0<=q[0]&&q[0]<=λ1)){var q1=d3_geo_cartesianScale(u,(-w+t)/uu);d3_geo_cartesianAdd(q1,A);return[q,d3_geo_spherical(q1)]}}function code(λ,φ){var r=smallRadius?radius:π-radius,code=0;if(λ<-r)code|=1;else if(λ>r)code|=2;if(φ<-r)code|=4;else if(φ>r)code|=8;return code}function polygonContains(polygon){return d3_geo_pointInPolygon(point,polygon)}}var d3_geo_clipViewMAX=1e9;function d3_geo_clipView(x0,y0,x1,y1){return function(listener){var listener_=listener,bufferListener=d3_geo_clipBufferListener(),segments,polygon,ring;var clip={point:point,lineStart:lineStart,lineEnd:lineEnd,polygonStart:function(){listener=bufferListener;segments=[];polygon=[]},polygonEnd:function(){listener=listener_;if((segments=d3.merge(segments)).length){listener.polygonStart();d3_geo_clipPolygon(segments,compare,inside,interpolate,listener);listener.polygonEnd()}else if(insidePolygon([x0,y0])){listener.polygonStart(),listener.lineStart();interpolate(null,null,1,listener);listener.lineEnd(),listener.polygonEnd()}segments=polygon=ring=null}};function inside(point){var a=corner(point,-1),i=insidePolygon([a===0||a===3?x0:x1,a>1?y1:y0]);return i}function insidePolygon(p){var wn=0,n=polygon.length,y=p[1];for(var i=0;iy&&isLeft(a,b,p)>0)++wn}else{if(b[1]<=y&&isLeft(a,b,p)<0)--wn}a=b}}return wn!==0}function isLeft(a,b,c){return(b[0]-a[0])*(c[1]-a[1])-(c[0]-a[0])*(b[1]-a[1])}function interpolate(from,to,direction,listener){var a=0,a1=0;if(from==null||(a=corner(from,direction))!==(a1=corner(to,direction))||comparePoints(from,to)<0^direction>0){do{listener.point(a===0||a===3?x0:x1,a>1?y1:y0)}while((a=(a+direction+4)%4)!==a1)}else{listener.point(to[0],to[1])}}function visible(x,y){return x0<=x&&x<=x1&&y0<=y&&y<=y1}function point(x,y){if(visible(x,y))listener.point(x,y)}var x__,y__,v__,x_,y_,v_,first;function lineStart(){clip.point=linePoint;if(polygon)polygon.push(ring=[]);first=true;v_=false;x_=y_=NaN}function lineEnd(){if(segments){linePoint(x__,y__);if(v__&&v_)bufferListener.rejoin();segments.push(bufferListener.buffer())}clip.point=point;if(v_)listener.lineEnd()}function linePoint(x,y){x=Math.max(-d3_geo_clipViewMAX,Math.min(d3_geo_clipViewMAX,x));y=Math.max(-d3_geo_clipViewMAX,Math.min(d3_geo_clipViewMAX,y));var v=visible(x,y);if(polygon)ring.push([x,y]);if(first){x__=x,y__=y,v__=v;first=false;if(v){listener.lineStart();listener.point(x,y)}}else{if(v&&v_)listener.point(x,y);else{var a=[x_,y_],b=[x,y];if(clipLine(a,b)){if(!v_){listener.lineStart();listener.point(a[0],a[1])}listener.point(b[0],b[1]);if(!v)listener.lineEnd()}else if(v){listener.lineStart();listener.point(x,y)}}}x_=x,y_=y,v_=v}return clip};function corner(p,direction){return Math.abs(p[0]-x0)<ε?direction>0?0:3:Math.abs(p[0]-x1)<ε?direction>0?2:1:Math.abs(p[1]-y0)<ε?direction>0?1:0:direction>0?3:2}function compare(a,b){return comparePoints(a.point,b.point)}function comparePoints(a,b){var ca=corner(a,1),cb=corner(b,1);return ca!==cb?ca-cb:ca===0?b[1]-a[1]:ca===1?a[0]-b[0]:ca===2?a[1]-b[1]:b[0]-a[0]}function clipLine(a,b){var dx=b[0]-a[0],dy=b[1]-a[1],t=[0,1];if(Math.abs(dx)<ε&&Math.abs(dy)<ε)return x0<=a[0]&&a[0]<=x1&&y0<=a[1]&&a[1]<=y1;if(d3_geo_clipViewT(x0-a[0],dx,t)&&d3_geo_clipViewT(a[0]-x1,-dx,t)&&d3_geo_clipViewT(y0-a[1],dy,t)&&d3_geo_clipViewT(a[1]-y1,-dy,t)){if(t[1]<1){b[0]=a[0]+t[1]*dx;b[1]=a[1]+t[1]*dy}if(t[0]>0){a[0]+=t[0]*dx;a[1]+=t[0]*dy}return true}return false}}function d3_geo_clipViewT(num,denominator,t){if(Math.abs(denominator)<ε)return num<=0;var u=num/denominator;if(denominator>0){if(u>t[1])return false;if(u>t[0])t[0]=u}else{if(u=.12&&y<.234&&x>=-.425&&x<-.214?alaska:y>=.166&&y<.234&&x>=-.214&&x<-.115?hawaii:lower48).invert(coordinates)};albersUsa.stream=function(stream){var lower48Stream=lower48.stream(stream),alaskaStream=alaska.stream(stream),hawaiiStream=hawaii.stream(stream);return{point:function(x,y){lower48Stream.point(x,y);alaskaStream.point(x,y);hawaiiStream.point(x,y)},sphere:function(){lower48Stream.sphere();alaskaStream.sphere();hawaiiStream.sphere()},lineStart:function(){lower48Stream.lineStart();alaskaStream.lineStart();hawaiiStream.lineStart()},lineEnd:function(){lower48Stream.lineEnd();alaskaStream.lineEnd();hawaiiStream.lineEnd()},polygonStart:function(){lower48Stream.polygonStart();alaskaStream.polygonStart();hawaiiStream.polygonStart()},polygonEnd:function(){lower48Stream.polygonEnd();alaskaStream.polygonEnd();hawaiiStream.polygonEnd()}}};albersUsa.precision=function(_){if(!arguments.length)return lower48.precision();lower48.precision(_);alaska.precision(_);hawaii.precision(_);return albersUsa};albersUsa.scale=function(_){if(!arguments.length)return lower48.scale();lower48.scale(_);alaska.scale(_*.35);hawaii.scale(_);return albersUsa.translate(lower48.translate())};albersUsa.translate=function(_){if(!arguments.length)return lower48.translate();var k=lower48.scale(),x=+_[0],y=+_[1];lower48Point=lower48.translate(_).clipExtent([[x-.455*k,y-.238*k],[x+.455*k,y+.238*k]]).stream(pointStream).point;alaskaPoint=alaska.translate([x-.307*k,y+.201*k]).clipExtent([[x-.425*k+ε,y+.12*k+ε],[x-.214*k-ε,y+.234*k-ε]]).stream(pointStream).point;hawaiiPoint=hawaii.translate([x-.205*k,y+.212*k]).clipExtent([[x-.214*k+ε,y+.166*k+ε],[x-.115*k-ε,y+.234*k-ε]]).stream(pointStream).point;return albersUsa};return albersUsa.scale(1070)};var d3_geo_pathAreaSum,d3_geo_pathAreaPolygon,d3_geo_pathArea={point:d3_noop,lineStart:d3_noop,lineEnd:d3_noop,polygonStart:function(){d3_geo_pathAreaPolygon=0;d3_geo_pathArea.lineStart=d3_geo_pathAreaRingStart},polygonEnd:function(){d3_geo_pathArea.lineStart=d3_geo_pathArea.lineEnd=d3_geo_pathArea.point=d3_noop;d3_geo_pathAreaSum+=Math.abs(d3_geo_pathAreaPolygon/2)}};function d3_geo_pathAreaRingStart(){var x00,y00,x0,y0;d3_geo_pathArea.point=function(x,y){d3_geo_pathArea.point=nextPoint;x00=x0=x,y00=y0=y};function nextPoint(x,y){d3_geo_pathAreaPolygon+=y0*x-x0*y;x0=x,y0=y}d3_geo_pathArea.lineEnd=function(){nextPoint(x00,y00)}}var d3_geo_pathBoundsX0,d3_geo_pathBoundsY0,d3_geo_pathBoundsX1,d3_geo_pathBoundsY1;var d3_geo_pathBounds={point:d3_geo_pathBoundsPoint,lineStart:d3_noop,lineEnd:d3_noop,polygonStart:d3_noop,polygonEnd:d3_noop};function d3_geo_pathBoundsPoint(x,y){if(xd3_geo_pathBoundsX1)d3_geo_pathBoundsX1=x;if(yd3_geo_pathBoundsY1)d3_geo_pathBoundsY1=y}function d3_geo_pathBuffer(){var pointCircle=d3_geo_pathBufferCircle(4.5),buffer=[];var stream={point:point,lineStart:function(){stream.point=pointLineStart},lineEnd:lineEnd,polygonStart:function(){stream.lineEnd=lineEndPolygon},polygonEnd:function(){stream.lineEnd=lineEnd;stream.point=point},pointRadius:function(_){pointCircle=d3_geo_pathBufferCircle(_);return stream},result:function(){if(buffer.length){var result=buffer.join("");buffer=[];return result}}};function point(x,y){buffer.push("M",x,",",y,pointCircle)}function pointLineStart(x,y){buffer.push("M",x,",",y); -stream.point=pointLine}function pointLine(x,y){buffer.push("L",x,",",y)}function lineEnd(){stream.point=point}function lineEndPolygon(){buffer.push("Z")}return stream}function d3_geo_pathBufferCircle(radius){return"m0,"+radius+"a"+radius+","+radius+" 0 1,1 0,"+-2*radius+"a"+radius+","+radius+" 0 1,1 0,"+2*radius+"z"}var d3_geo_pathCentroid={point:d3_geo_pathCentroidPoint,lineStart:d3_geo_pathCentroidLineStart,lineEnd:d3_geo_pathCentroidLineEnd,polygonStart:function(){d3_geo_pathCentroid.lineStart=d3_geo_pathCentroidRingStart},polygonEnd:function(){d3_geo_pathCentroid.point=d3_geo_pathCentroidPoint;d3_geo_pathCentroid.lineStart=d3_geo_pathCentroidLineStart;d3_geo_pathCentroid.lineEnd=d3_geo_pathCentroidLineEnd}};function d3_geo_pathCentroidPoint(x,y){d3_geo_centroidX0+=x;d3_geo_centroidY0+=y;++d3_geo_centroidZ0}function d3_geo_pathCentroidLineStart(){var x0,y0;d3_geo_pathCentroid.point=function(x,y){d3_geo_pathCentroid.point=nextPoint;d3_geo_pathCentroidPoint(x0=x,y0=y)};function nextPoint(x,y){var dx=x-x0,dy=y-y0,z=Math.sqrt(dx*dx+dy*dy);d3_geo_centroidX1+=z*(x0+x)/2;d3_geo_centroidY1+=z*(y0+y)/2;d3_geo_centroidZ1+=z;d3_geo_pathCentroidPoint(x0=x,y0=y)}}function d3_geo_pathCentroidLineEnd(){d3_geo_pathCentroid.point=d3_geo_pathCentroidPoint}function d3_geo_pathCentroidRingStart(){var x00,y00,x0,y0;d3_geo_pathCentroid.point=function(x,y){d3_geo_pathCentroid.point=nextPoint;d3_geo_pathCentroidPoint(x00=x0=x,y00=y0=y)};function nextPoint(x,y){var dx=x-x0,dy=y-y0,z=Math.sqrt(dx*dx+dy*dy);d3_geo_centroidX1+=z*(x0+x)/2;d3_geo_centroidY1+=z*(y0+y)/2;d3_geo_centroidZ1+=z;z=y0*x-x0*y;d3_geo_centroidX2+=z*(x0+x);d3_geo_centroidY2+=z*(y0+y);d3_geo_centroidZ2+=z*3;d3_geo_pathCentroidPoint(x0=x,y0=y)}d3_geo_pathCentroid.lineEnd=function(){nextPoint(x00,y00)}}function d3_geo_pathContext(context){var pointRadius=4.5;var stream={point:point,lineStart:function(){stream.point=pointLineStart},lineEnd:lineEnd,polygonStart:function(){stream.lineEnd=lineEndPolygon},polygonEnd:function(){stream.lineEnd=lineEnd;stream.point=point},pointRadius:function(_){pointRadius=_;return stream},result:d3_noop};function point(x,y){context.moveTo(x,y);context.arc(x,y,pointRadius,0,2*π)}function pointLineStart(x,y){context.moveTo(x,y);stream.point=pointLine}function pointLine(x,y){context.lineTo(x,y)}function lineEnd(){stream.point=point}function lineEndPolygon(){context.closePath()}return stream}function d3_geo_resample(project){var δ2=.5,cosMinDistance=Math.cos(30*d3_radians),maxDepth=16;function resample(stream){var λ00,φ00,x00,y00,a00,b00,c00,λ0,x0,y0,a0,b0,c0;var resample={point:point,lineStart:lineStart,lineEnd:lineEnd,polygonStart:function(){stream.polygonStart();resample.lineStart=ringStart},polygonEnd:function(){stream.polygonEnd();resample.lineStart=lineStart}};function point(x,y){x=project(x,y);stream.point(x[0],x[1])}function lineStart(){x0=NaN;resample.point=linePoint;stream.lineStart()}function linePoint(λ,φ){var c=d3_geo_cartesian([λ,φ]),p=project(λ,φ);resampleLineTo(x0,y0,λ0,a0,b0,c0,x0=p[0],y0=p[1],λ0=λ,a0=c[0],b0=c[1],c0=c[2],maxDepth,stream);stream.point(x0,y0)}function lineEnd(){resample.point=point;stream.lineEnd()}function ringStart(){lineStart();resample.point=ringPoint;resample.lineEnd=ringEnd}function ringPoint(λ,φ){linePoint(λ00=λ,φ00=φ),x00=x0,y00=y0,a00=a0,b00=b0,c00=c0;resample.point=linePoint}function ringEnd(){resampleLineTo(x0,y0,λ0,a0,b0,c0,x00,y00,λ00,a00,b00,c00,maxDepth,stream);resample.lineEnd=lineEnd;lineEnd()}return resample}function resampleLineTo(x0,y0,λ0,a0,b0,c0,x1,y1,λ1,a1,b1,c1,depth,stream){var dx=x1-x0,dy=y1-y0,d2=dx*dx+dy*dy;if(d2>4*δ2&&depth--){var a=a0+a1,b=b0+b1,c=c0+c1,m=Math.sqrt(a*a+b*b+c*c),φ2=Math.asin(c/=m),λ2=Math.abs(Math.abs(c)-1)<ε?(λ0+λ1)/2:Math.atan2(b,a),p=project(λ2,φ2),x2=p[0],y2=p[1],dx2=x2-x0,dy2=y2-y0,dz=dy*dx2-dx*dy2;if(dz*dz/d2>δ2||Math.abs((dx*dx2+dy*dy2)/d2-.5)>.3||a0*a1+b0*b1+c0*c10&&16;return resample};return resample}d3.geo.path=function(){var pointRadius=4.5,projection,context,projectStream,contextStream,cacheStream;function path(object){if(object){if(typeof pointRadius==="function")contextStream.pointRadius(+pointRadius.apply(this,arguments));if(!cacheStream||!cacheStream.valid)cacheStream=projectStream(contextStream);d3.geo.stream(object,cacheStream)}return contextStream.result()}path.area=function(object){d3_geo_pathAreaSum=0;d3.geo.stream(object,projectStream(d3_geo_pathArea));return d3_geo_pathAreaSum};path.centroid=function(object){d3_geo_centroidX0=d3_geo_centroidY0=d3_geo_centroidZ0=d3_geo_centroidX1=d3_geo_centroidY1=d3_geo_centroidZ1=d3_geo_centroidX2=d3_geo_centroidY2=d3_geo_centroidZ2=0;d3.geo.stream(object,projectStream(d3_geo_pathCentroid));return d3_geo_centroidZ2?[d3_geo_centroidX2/d3_geo_centroidZ2,d3_geo_centroidY2/d3_geo_centroidZ2]:d3_geo_centroidZ1?[d3_geo_centroidX1/d3_geo_centroidZ1,d3_geo_centroidY1/d3_geo_centroidZ1]:d3_geo_centroidZ0?[d3_geo_centroidX0/d3_geo_centroidZ0,d3_geo_centroidY0/d3_geo_centroidZ0]:[NaN,NaN]};path.bounds=function(object){d3_geo_pathBoundsX1=d3_geo_pathBoundsY1=-(d3_geo_pathBoundsX0=d3_geo_pathBoundsY0=Infinity);d3.geo.stream(object,projectStream(d3_geo_pathBounds));return[[d3_geo_pathBoundsX0,d3_geo_pathBoundsY0],[d3_geo_pathBoundsX1,d3_geo_pathBoundsY1]]};path.projection=function(_){if(!arguments.length)return projection;projectStream=(projection=_)?_.stream||d3_geo_pathProjectStream(_):d3_identity;return reset()};path.context=function(_){if(!arguments.length)return context;contextStream=(context=_)==null?new d3_geo_pathBuffer:new d3_geo_pathContext(_);if(typeof pointRadius!=="function")contextStream.pointRadius(pointRadius);return reset()};path.pointRadius=function(_){if(!arguments.length)return pointRadius;pointRadius=typeof _==="function"?_:(contextStream.pointRadius(+_),+_);return path};function reset(){cacheStream=null;return path}return path.projection(d3.geo.albersUsa()).context(null)};function d3_geo_pathProjectStream(project){var resample=d3_geo_resample(function(λ,φ){return project([λ*d3_degrees,φ*d3_degrees])});return function(stream){stream=resample(stream);return{point:function(λ,φ){stream.point(λ*d3_radians,φ*d3_radians)},sphere:function(){stream.sphere()},lineStart:function(){stream.lineStart()},lineEnd:function(){stream.lineEnd()},polygonStart:function(){stream.polygonStart()},polygonEnd:function(){stream.polygonEnd()}}}}d3.geo.projection=d3_geo_projection;d3.geo.projectionMutator=d3_geo_projectionMutator;function d3_geo_projection(project){return d3_geo_projectionMutator(function(){return project})()}function d3_geo_projectionMutator(projectAt){var project,rotate,projectRotate,projectResample=d3_geo_resample(function(x,y){x=project(x,y);return[x[0]*k+δx,δy-x[1]*k]}),k=150,x=480,y=250,λ=0,φ=0,δλ=0,δφ=0,δγ=0,δx,δy,preclip=d3_geo_clipAntimeridian,postclip=d3_identity,clipAngle=null,clipExtent=null,stream;function projection(point){point=projectRotate(point[0]*d3_radians,point[1]*d3_radians);return[point[0]*k+δx,δy-point[1]*k]}function invert(point){point=projectRotate.invert((point[0]-δx)/k,(δy-point[1])/k);return point&&[point[0]*d3_degrees,point[1]*d3_degrees]}projection.stream=function(output){if(stream)stream.valid=false;stream=d3_geo_projectionRadiansRotate(rotate,preclip(projectResample(postclip(output))));stream.valid=true;return stream};projection.clipAngle=function(_){if(!arguments.length)return clipAngle;preclip=_==null?(clipAngle=_,d3_geo_clipAntimeridian):d3_geo_clipCircle((clipAngle=+_)*d3_radians);return invalidate()};projection.clipExtent=function(_){if(!arguments.length)return clipExtent;clipExtent=_;postclip=_==null?d3_identity:d3_geo_clipView(_[0][0],_[0][1],_[1][0],_[1][1]);return invalidate()};projection.scale=function(_){if(!arguments.length)return k;k=+_;return reset()};projection.translate=function(_){if(!arguments.length)return[x,y];x=+_[0];y=+_[1];return reset()};projection.center=function(_){if(!arguments.length)return[λ*d3_degrees,φ*d3_degrees];λ=_[0]%360*d3_radians;φ=_[1]%360*d3_radians;return reset()};projection.rotate=function(_){if(!arguments.length)return[δλ*d3_degrees,δφ*d3_degrees,δγ*d3_degrees];δλ=_[0]%360*d3_radians;δφ=_[1]%360*d3_radians;δγ=_.length>2?_[2]%360*d3_radians:0;return reset()};d3.rebind(projection,projectResample,"precision");function reset(){projectRotate=d3_geo_compose(rotate=d3_geo_rotation(δλ,δφ,δγ),project);var center=project(λ,φ);δx=x-center[0]*k;δy=y+center[1]*k;return invalidate()}function invalidate(){if(stream){stream.valid=false;stream=null}return projection}return function(){project=projectAt.apply(this,arguments);projection.invert=project.invert&&invert;return reset()}}function d3_geo_projectionRadiansRotate(rotate,stream){return{point:function(x,y){y=rotate(x*d3_radians,y*d3_radians),x=y[0];stream.point(x>π?x-2*π:x<-π?x+2*π:x,y[1])},sphere:function(){stream.sphere()},lineStart:function(){stream.lineStart()},lineEnd:function(){stream.lineEnd()},polygonStart:function(){stream.polygonStart()},polygonEnd:function(){stream.polygonEnd()}}}function d3_geo_equirectangular(λ,φ){return[λ,φ]}(d3.geo.equirectangular=function(){return d3_geo_projection(d3_geo_equirectangular)}).raw=d3_geo_equirectangular.invert=d3_geo_equirectangular;d3.geo.rotation=function(rotate){rotate=d3_geo_rotation(rotate[0]%360*d3_radians,rotate[1]*d3_radians,rotate.length>2?rotate[2]*d3_radians:0);function forward(coordinates){coordinates=rotate(coordinates[0]*d3_radians,coordinates[1]*d3_radians);return coordinates[0]*=d3_degrees,coordinates[1]*=d3_degrees,coordinates}forward.invert=function(coordinates){coordinates=rotate.invert(coordinates[0]*d3_radians,coordinates[1]*d3_radians);return coordinates[0]*=d3_degrees,coordinates[1]*=d3_degrees,coordinates};return forward};function d3_geo_rotation(δλ,δφ,δγ){return δλ?δφ||δγ?d3_geo_compose(d3_geo_rotationλ(δλ),d3_geo_rotationφγ(δφ,δγ)):d3_geo_rotationλ(δλ):δφ||δγ?d3_geo_rotationφγ(δφ,δγ):d3_geo_equirectangular}function d3_geo_forwardRotationλ(δλ){return function(λ,φ){return λ+=δλ,[λ>π?λ-2*π:λ<-π?λ+2*π:λ,φ]}}function d3_geo_rotationλ(δλ){var rotation=d3_geo_forwardRotationλ(δλ);rotation.invert=d3_geo_forwardRotationλ(-δλ);return rotation}function d3_geo_rotationφγ(δφ,δγ){var cosδφ=Math.cos(δφ),sinδφ=Math.sin(δφ),cosδγ=Math.cos(δγ),sinδγ=Math.sin(δγ);function rotation(λ,φ){var cosφ=Math.cos(φ),x=Math.cos(λ)*cosφ,y=Math.sin(λ)*cosφ,z=Math.sin(φ),k=z*cosδφ+x*sinδφ;return[Math.atan2(y*cosδγ-k*sinδγ,x*cosδφ-z*sinδφ),d3_asin(k*cosδγ+y*sinδγ)]}rotation.invert=function(λ,φ){var cosφ=Math.cos(φ),x=Math.cos(λ)*cosφ,y=Math.sin(λ)*cosφ,z=Math.sin(φ),k=z*cosδγ-y*sinδγ;return[Math.atan2(y*cosδγ+z*sinδγ,x*cosδφ+k*sinδφ),d3_asin(k*cosδφ-x*sinδφ)]};return rotation}d3.geo.circle=function(){var origin=[0,0],angle,precision=6,interpolate;function circle(){var center=typeof origin==="function"?origin.apply(this,arguments):origin,rotate=d3_geo_rotation(-center[0]*d3_radians,-center[1]*d3_radians,0).invert,ring=[];interpolate(null,null,1,{point:function(x,y){ring.push(x=rotate(x,y));x[0]*=d3_degrees,x[1]*=d3_degrees}});return{type:"Polygon",coordinates:[ring]}}circle.origin=function(x){if(!arguments.length)return origin;origin=x;return circle};circle.angle=function(x){if(!arguments.length)return angle;interpolate=d3_geo_circleInterpolate((angle=+x)*d3_radians,precision*d3_radians);return circle};circle.precision=function(_){if(!arguments.length)return precision;interpolate=d3_geo_circleInterpolate(angle*d3_radians,(precision=+_)*d3_radians);return circle};return circle.angle(90)};function d3_geo_circleInterpolate(radius,precision){var cr=Math.cos(radius),sr=Math.sin(radius);return function(from,to,direction,listener){if(from!=null){from=d3_geo_circleAngle(cr,from);to=d3_geo_circleAngle(cr,to);if(direction>0?fromto)from+=direction*2*π}else{from=radius+direction*2*π;to=radius}var point;for(var step=direction*precision,t=from;direction>0?t>to:tε}).map(x)).concat(d3.range(Math.ceil(y0/dy)*dy,y1,dy).filter(function(y){return Math.abs(y%DY)>ε}).map(y))}graticule.lines=function(){return lines().map(function(coordinates){return{type:"LineString",coordinates:coordinates}})};graticule.outline=function(){return{type:"Polygon",coordinates:[X(X0).concat(Y(Y1).slice(1),X(X1).reverse().slice(1),Y(Y0).reverse().slice(1))]}};graticule.extent=function(_){if(!arguments.length)return graticule.minorExtent();return graticule.majorExtent(_).minorExtent(_)};graticule.majorExtent=function(_){if(!arguments.length)return[[X0,Y0],[X1,Y1]];X0=+_[0][0],X1=+_[1][0];Y0=+_[0][1],Y1=+_[1][1];if(X0>X1)_=X0,X0=X1,X1=_;if(Y0>Y1)_=Y0,Y0=Y1,Y1=_;return graticule.precision(precision)};graticule.minorExtent=function(_){if(!arguments.length)return[[x0,y0],[x1,y1]];x0=+_[0][0],x1=+_[1][0];y0=+_[0][1],y1=+_[1][1];if(x0>x1)_=x0,x0=x1,x1=_;if(y0>y1)_=y0,y0=y1,y1=_;return graticule.precision(precision)};graticule.step=function(_){if(!arguments.length)return graticule.minorStep();return graticule.majorStep(_).minorStep(_)};graticule.majorStep=function(_){if(!arguments.length)return[DX,DY];DX=+_[0],DY=+_[1];return graticule};graticule.minorStep=function(_){if(!arguments.length)return[dx,dy];dx=+_[0],dy=+_[1];return graticule};graticule.precision=function(_){if(!arguments.length)return precision;precision=+_;x=d3_geo_graticuleX(y0,y1,90);y=d3_geo_graticuleY(x0,x1,precision);X=d3_geo_graticuleX(Y0,Y1,90);Y=d3_geo_graticuleY(X0,X1,precision);return graticule};return graticule.majorExtent([[-180,-90+ε],[180,90-ε]]).minorExtent([[-180,-80-ε],[180,80+ε]])};function d3_geo_graticuleX(y0,y1,dy){var y=d3.range(y0,y1-ε,dy).concat(y1);return function(x){return y.map(function(y){return[x,y]})}}function d3_geo_graticuleY(x0,x1,dx){var x=d3.range(x0,x1-ε,dx).concat(x1);return function(y){return x.map(function(x){return[x,y]})}}function d3_source(d){return d.source}function d3_target(d){return d.target}d3.geo.greatArc=function(){var source=d3_source,source_,target=d3_target,target_;function greatArc(){return{type:"LineString",coordinates:[source_||source.apply(this,arguments),target_||target.apply(this,arguments)]}}greatArc.distance=function(){return d3.geo.distance(source_||source.apply(this,arguments),target_||target.apply(this,arguments))};greatArc.source=function(_){if(!arguments.length)return source;source=_,source_=typeof _==="function"?null:_;return greatArc};greatArc.target=function(_){if(!arguments.length)return target;target=_,target_=typeof _==="function"?null:_;return greatArc};greatArc.precision=function(){return arguments.length?greatArc:0};return greatArc};d3.geo.interpolate=function(source,target){return d3_geo_interpolate(source[0]*d3_radians,source[1]*d3_radians,target[0]*d3_radians,target[1]*d3_radians)};function d3_geo_interpolate(x0,y0,x1,y1){var cy0=Math.cos(y0),sy0=Math.sin(y0),cy1=Math.cos(y1),sy1=Math.sin(y1),kx0=cy0*Math.cos(x0),ky0=cy0*Math.sin(x0),kx1=cy1*Math.cos(x1),ky1=cy1*Math.sin(x1),d=2*Math.asin(Math.sqrt(d3_haversin(y1-y0)+cy0*cy1*d3_haversin(x1-x0))),k=1/Math.sin(d);var interpolate=d?function(t){var B=Math.sin(t*=d)*k,A=Math.sin(d-t)*k,x=A*kx0+B*kx1,y=A*ky0+B*ky1,z=A*sy0+B*sy1;return[Math.atan2(y,x)*d3_degrees,Math.atan2(z,Math.sqrt(x*x+y*y))*d3_degrees]}:function(){return[x0*d3_degrees,y0*d3_degrees]};interpolate.distance=d;return interpolate}d3.geo.length=function(object){d3_geo_lengthSum=0;d3.geo.stream(object,d3_geo_length);return d3_geo_lengthSum};var d3_geo_lengthSum;var d3_geo_length={sphere:d3_noop,point:d3_noop,lineStart:d3_geo_lengthLineStart,lineEnd:d3_noop,polygonStart:d3_noop,polygonEnd:d3_noop};function d3_geo_lengthLineStart(){var λ0,sinφ0,cosφ0;d3_geo_length.point=function(λ,φ){λ0=λ*d3_radians,sinφ0=Math.sin(φ*=d3_radians),cosφ0=Math.cos(φ);d3_geo_length.point=nextPoint};d3_geo_length.lineEnd=function(){d3_geo_length.point=d3_geo_length.lineEnd=d3_noop};function nextPoint(λ,φ){var sinφ=Math.sin(φ*=d3_radians),cosφ=Math.cos(φ),t=Math.abs((λ*=d3_radians)-λ0),cosΔλ=Math.cos(t);d3_geo_lengthSum+=Math.atan2(Math.sqrt((t=cosφ*Math.sin(t))*t+(t=cosφ0*sinφ-sinφ0*cosφ*cosΔλ)*t),sinφ0*sinφ+cosφ0*cosφ*cosΔλ);λ0=λ,sinφ0=sinφ,cosφ0=cosφ}}function d3_geo_azimuthal(scale,angle){function azimuthal(λ,φ){var cosλ=Math.cos(λ),cosφ=Math.cos(φ),k=scale(cosλ*cosφ);return[k*cosφ*Math.sin(λ),k*Math.sin(φ)]}azimuthal.invert=function(x,y){var ρ=Math.sqrt(x*x+y*y),c=angle(ρ),sinc=Math.sin(c),cosc=Math.cos(c);return[Math.atan2(x*sinc,ρ*cosc),Math.asin(ρ&&y*sinc/ρ)]};return azimuthal}var d3_geo_azimuthalEqualArea=d3_geo_azimuthal(function(cosλcosφ){return Math.sqrt(2/(1+cosλcosφ))},function(ρ){return 2*Math.asin(ρ/2)});(d3.geo.azimuthalEqualArea=function(){return d3_geo_projection(d3_geo_azimuthalEqualArea)}).raw=d3_geo_azimuthalEqualArea;var d3_geo_azimuthalEquidistant=d3_geo_azimuthal(function(cosλcosφ){var c=Math.acos(cosλcosφ);return c&&c/Math.sin(c)},d3_identity);(d3.geo.azimuthalEquidistant=function(){return d3_geo_projection(d3_geo_azimuthalEquidistant)}).raw=d3_geo_azimuthalEquidistant;function d3_geo_conicConformal(φ0,φ1){var cosφ0=Math.cos(φ0),t=function(φ){return Math.tan(π/4+φ/2)},n=φ0===φ1?Math.sin(φ0):Math.log(cosφ0/Math.cos(φ1))/Math.log(t(φ1)/t(φ0)),F=cosφ0*Math.pow(t(φ0),n)/n;if(!n)return d3_geo_mercator;function forward(λ,φ){var ρ=Math.abs(Math.abs(φ)-π/2)<ε?0:F/Math.pow(t(φ),n);return[ρ*Math.sin(n*λ),F-ρ*Math.cos(n*λ)]}forward.invert=function(x,y){var ρ0_y=F-y,ρ=d3_sgn(n)*Math.sqrt(x*x+ρ0_y*ρ0_y);return[Math.atan2(x,ρ0_y)/n,2*Math.atan(Math.pow(F/ρ,1/n))-π/2]};return forward}(d3.geo.conicConformal=function(){return d3_geo_conic(d3_geo_conicConformal)}).raw=d3_geo_conicConformal;function d3_geo_conicEquidistant(φ0,φ1){var cosφ0=Math.cos(φ0),n=φ0===φ1?Math.sin(φ0):(cosφ0-Math.cos(φ1))/(φ1-φ0),G=cosφ0/n+φ0;if(Math.abs(n)<ε)return d3_geo_equirectangular;function forward(λ,φ){var ρ=G-φ;return[ρ*Math.sin(n*λ),G-ρ*Math.cos(n*λ)]}forward.invert=function(x,y){var ρ0_y=G-y;return[Math.atan2(x,ρ0_y)/n,G-d3_sgn(n)*Math.sqrt(x*x+ρ0_y*ρ0_y)]};return forward}(d3.geo.conicEquidistant=function(){return d3_geo_conic(d3_geo_conicEquidistant)}).raw=d3_geo_conicEquidistant;var d3_geo_gnomonic=d3_geo_azimuthal(function(cosλcosφ){return 1/cosλcosφ},Math.atan);(d3.geo.gnomonic=function(){return d3_geo_projection(d3_geo_gnomonic)}).raw=d3_geo_gnomonic;function d3_geo_mercator(λ,φ){return[λ,Math.log(Math.tan(π/4+φ/2))]}d3_geo_mercator.invert=function(x,y){return[x,2*Math.atan(Math.exp(y))-π/2]};function d3_geo_mercatorProjection(project){var m=d3_geo_projection(project),scale=m.scale,translate=m.translate,clipExtent=m.clipExtent,clipAuto;m.scale=function(){var v=scale.apply(m,arguments);return v===m?clipAuto?m.clipExtent(null):m:v};m.translate=function(){var v=translate.apply(m,arguments);return v===m?clipAuto?m.clipExtent(null):m:v};m.clipExtent=function(_){var v=clipExtent.apply(m,arguments);if(v===m){if(clipAuto=_==null){var k=π*scale(),t=translate();clipExtent([[t[0]-k,t[1]-k],[t[0]+k,t[1]+k]])}}else if(clipAuto){v=null}return v};return m.clipExtent(null)}(d3.geo.mercator=function(){return d3_geo_mercatorProjection(d3_geo_mercator)}).raw=d3_geo_mercator;var d3_geo_orthographic=d3_geo_azimuthal(function(){return 1},Math.asin);(d3.geo.orthographic=function(){return d3_geo_projection(d3_geo_orthographic)}).raw=d3_geo_orthographic;var d3_geo_stereographic=d3_geo_azimuthal(function(cosλcosφ){return 1/(1+cosλcosφ)},function(ρ){return 2*Math.atan(ρ)});(d3.geo.stereographic=function(){return d3_geo_projection(d3_geo_stereographic)}).raw=d3_geo_stereographic;function d3_geo_transverseMercator(λ,φ){var B=Math.cos(φ)*Math.sin(λ);return[Math.log((1+B)/(1-B))/2,Math.atan2(Math.tan(φ),Math.cos(λ))]}d3_geo_transverseMercator.invert=function(x,y){return[Math.atan2(d3_sinh(x),Math.cos(y)),d3_asin(Math.sin(y)/d3_cosh(x))]};(d3.geo.transverseMercator=function(){return d3_geo_mercatorProjection(d3_geo_transverseMercator)}).raw=d3_geo_transverseMercator;d3.geom={};d3.svg={};function d3_svg_line(projection){var x=d3_svg_lineX,y=d3_svg_lineY,defined=d3_true,interpolate=d3_svg_lineLinear,interpolateKey=interpolate.key,tension=.7;function line(data){var segments=[],points=[],i=-1,n=data.length,d,fx=d3_functor(x),fy=d3_functor(y);function segment(){segments.push("M",interpolate(projection(points),tension))}while(++i1)path.push("H",p[0]);return path.join("")}function d3_svg_lineStepBefore(points){var i=0,n=points.length,p=points[0],path=[p[0],",",p[1]];while(++i1){t=tangents[1];p=points[pi];pi++;path+="C"+(p0[0]+t0[0])+","+(p0[1]+t0[1])+","+(p[0]-t[0])+","+(p[1]-t[1])+","+p[0]+","+p[1];for(var i=2;i9){s=d*3/Math.sqrt(s);m[i]=s*a;m[i+1]=s*b}}}i=-1;while(++i<=j){s=(points[Math.min(j,i+1)][0]-points[Math.max(0,i-1)][0])/(6*(1+m[i]*m[i]));tangents.push([s||0,m[i]*s||0])}return tangents}function d3_svg_lineMonotone(points){return points.length<3?d3_svg_lineLinear(points):points[0]+d3_svg_lineHermite(points,d3_svg_lineMonotoneTangents(points))}d3.geom.hull=function(vertices){var x=d3_svg_lineX,y=d3_svg_lineY;if(arguments.length)return hull(vertices);function hull(data){if(data.length<3)return[];var fx=d3_functor(x),fy=d3_functor(y),n=data.length,vertices,plen=n-1,points=[],stack=[],d,i,j,h=0,x1,y1,x2,y2,u,v,a,sp;if(fx===d3_svg_lineX&&y===d3_svg_lineY)vertices=data;else for(i=0,vertices=[];i=x2*x2+y2*y2){points[i].index=-1;continue}else{points[u].index=-1}}a=points[i].angle;u=i;v=j}stack.push(h);for(i=0,j=0;i<2;++j){if(points[j].index>-1){stack.push(points[j].index);i++}}sp=stack.length;for(;j=0;--i)poly.push(data[stack[i]]);return poly}hull.x=function(_){return arguments.length?(x=_,hull):x};hull.y=function(_){return arguments.length?(y=_,hull):y};return hull};function d3_geom_hullCCW(i1,i2,i3,v){var t,a,b,c,d,e,f;t=v[i1];a=t[0];b=t[1];t=v[i2];c=t[0];d=t[1];t=v[i3];e=t[0];f=t[1];return(f-b)*(c-a)-(d-b)*(e-a)>0}d3.geom.polygon=function(coordinates){d3_subclass(coordinates,d3_geom_polygonPrototype);return coordinates};var d3_geom_polygonPrototype=d3.geom.polygon.prototype=[];d3_geom_polygonPrototype.area=function(){var i=-1,n=this.length,a,b=this[n-1],area=0;while(++i=0){s1=e.ep.r;s2=e.ep.l}else{s1=e.ep.l;s2=e.ep.r}if(e.a===1){y1=s1?s1.y:-Z;x1=e.c-e.b*y1;y2=s2?s2.y:Z;x2=e.c-e.b*y2}else{x1=s1?s1.x:-Z;y1=e.c-e.a*x1;x2=s2?s2.x:Z;y2=e.c-e.a*x2}var v1=[x1,y1],v2=[x2,y2];polygons[e.region.l.index].push(v1,v2);polygons[e.region.r.index].push(v1,v2)});polygons=polygons.map(function(polygon,i){var cx=points[i][0],cy=points[i][1],angle=polygon.map(function(v){return Math.atan2(v[0]-cx,v[1]-cy)}),order=d3.range(polygon.length).sort(function(a,b){return angle[a]-angle[b]});return order.filter(function(d,i){return!i||angle[d]-angle[order[i-1]]>ε}).map(function(d){return polygon[d]})});polygons.forEach(function(polygon,i){var n=polygon.length;if(!n)return polygon.push([-Z,-Z],[-Z,Z],[Z,Z],[Z,-Z]);if(n>2)return;var p0=points[i],p1=polygon[0],p2=polygon[1],x0=p0[0],y0=p0[1],x1=p1[0],y1=p1[1],x2=p2[0],y2=p2[1],dx=Math.abs(x2-x1),dy=y2-y1;if(Math.abs(dy)<ε){var y=y00)y*=-1;polygon.push([-Z,y],[Z,y])}}});if(clipPolygon)for(i=0;ib.y?1:a.xb.x?1:0}),bottomSite:null};var EdgeList={list:[],leftEnd:null,rightEnd:null,init:function(){EdgeList.leftEnd=EdgeList.createHalfEdge(null,"l");EdgeList.rightEnd=EdgeList.createHalfEdge(null,"l");EdgeList.leftEnd.r=EdgeList.rightEnd;EdgeList.rightEnd.l=EdgeList.leftEnd;EdgeList.list.unshift(EdgeList.leftEnd,EdgeList.rightEnd)},createHalfEdge:function(edge,side){return{edge:edge,side:side,vertex:null,l:null,r:null}},insert:function(lb,he){he.l=lb;he.r=lb.r;lb.r.l=he;lb.r=he},leftBound:function(p){var he=EdgeList.leftEnd;do{he=he.r}while(he!=EdgeList.rightEnd&&Geom.rightOf(he,p));he=he.l;return he},del:function(he){he.l.r=he.r;he.r.l=he.l;he.edge=null},right:function(he){return he.r},left:function(he){return he.l},leftRegion:function(he){return he.edge==null?Sites.bottomSite:he.edge.region[he.side]},rightRegion:function(he){return he.edge==null?Sites.bottomSite:he.edge.region[d3_geom_voronoiOpposite[he.side]]}};var Geom={bisect:function(s1,s2){var newEdge={region:{l:s1,r:s2},ep:{l:null,r:null}};var dx=s2.x-s1.x,dy=s2.y-s1.y,adx=dx>0?dx:-dx,ady=dy>0?dy:-dy;newEdge.c=s1.x*dx+s1.y*dy+(dx*dx+dy*dy)*.5;if(adx>ady){newEdge.a=1;newEdge.b=dy/dx;newEdge.c/=dx}else{newEdge.b=1;newEdge.a=dx/dy;newEdge.c/=dy}return newEdge},intersect:function(el1,el2){var e1=el1.edge,e2=el2.edge;if(!e1||!e2||e1.region.r==e2.region.r){return null}var d=e1.a*e2.b-e1.b*e2.a;if(Math.abs(d)<1e-10){return null}var xint=(e1.c*e2.b-e2.c*e1.b)/d,yint=(e2.c*e1.a-e1.c*e2.a)/d,e1r=e1.region.r,e2r=e2.region.r,el,e;if(e1r.y=e.region.r.x;if(rightOfSite&&el.side==="l"||!rightOfSite&&el.side==="r"){return null}return{x:xint,y:yint}},rightOf:function(he,p){var e=he.edge,topsite=e.region.r,rightOfSite=p.x>topsite.x;if(rightOfSite&&he.side==="l"){return 1}if(!rightOfSite&&he.side==="r"){return 0}if(e.a===1){var dyp=p.y-topsite.y,dxp=p.x-topsite.x,fast=0,above=0;if(!rightOfSite&&e.b<0||rightOfSite&&e.b>=0){above=fast=dyp>=e.b*dxp}else{above=p.x+p.y*e.b>e.c;if(e.b<0){above=!above}if(!above){fast=1}}if(!fast){var dxs=topsite.x-e.region.l.x;above=e.b*(dxp*dxp-dyp*dyp)t2*t2+t3*t3}return he.side==="l"?above:!above},endPoint:function(edge,side,site){edge.ep[side]=site;if(!edge.ep[d3_geom_voronoiOpposite[side]])return;callback(edge)},distance:function(s,t){var dx=s.x-t.x,dy=s.y-t.y;return Math.sqrt(dx*dx+dy*dy)}};var EventQueue={list:[],insert:function(he,site,offset){he.vertex=site;he.ystar=site.y+offset;for(var i=0,list=EventQueue.list,l=list.length;inext.ystar||he.ystar==next.ystar&&site.x>next.vertex.x){continue}else{break}}list.splice(i,0,he)},del:function(he){for(var i=0,ls=EventQueue.list,l=ls.length;itop.y){temp=bot;bot=top;top=temp;pm="r"}e=Geom.bisect(bot,top);bisector=EdgeList.createHalfEdge(e,pm);EdgeList.insert(llbnd,bisector);Geom.endPoint(e,d3_geom_voronoiOpposite[pm],v);p=Geom.intersect(llbnd,bisector);if(p){EventQueue.del(llbnd);EventQueue.insert(llbnd,p,Geom.distance(p,bot))}p=Geom.intersect(bisector,rrbnd);if(p){EventQueue.insert(bisector,p,Geom.distance(p,bot))}}else{break}}for(lbnd=EdgeList.right(EdgeList.leftEnd);lbnd!=EdgeList.rightEnd;lbnd=EdgeList.right(lbnd)){callback(lbnd.edge)}}d3.geom.quadtree=function(points,x1,y1,x2,y2){var x=d3_svg_lineX,y=d3_svg_lineY,compat;if(compat=arguments.length){x=d3_geom_quadtreeCompatX;y=d3_geom_quadtreeCompatY;if(compat===3){y2=y1;x2=x1;y1=x1=0}return quadtree(points)}function quadtree(data){var d,fx=d3_functor(x),fy=d3_functor(y),xs,ys,i,n,x1_,y1_,x2_,y2_;if(x1!=null){x1_=x1,y1_=y1,x2_=x2,y2_=y2}else{x2_=y2_=-(x1_=y1_=Infinity);xs=[],ys=[];n=data.length;if(compat)for(i=0;ix2_)x2_=d.x;if(d.y>y2_)y2_=d.y;xs.push(d.x);ys.push(d.y)}else for(i=0;ix2_)x2_=x_;if(y_>y2_)y2_=y_;xs.push(x_);ys.push(y_)}}var dx=x2_-x1_,dy=y2_-y1_;if(dx>dy)y2_=y1_+dx;else x2_=x1_+dy;function insert(n,d,x,y,x1,y1,x2,y2){if(isNaN(x)||isNaN(y))return;if(n.leaf){var nx=n.x,ny=n.y;if(nx!=null){if(Math.abs(nx-x)+Math.abs(ny-y)<.01){insertChild(n,d,x,y,x1,y1,x2,y2)}else{var nPoint=n.point;n.x=n.y=n.point=null;insertChild(n,nPoint,nx,ny,x1,y1,x2,y2);insertChild(n,d,x,y,x1,y1,x2,y2)}}else{n.x=x,n.y=y,n.point=d}}else{insertChild(n,d,x,y,x1,y1,x2,y2)}}function insertChild(n,d,x,y,x1,y1,x2,y2){var sx=(x1+x2)*.5,sy=(y1+y2)*.5,right=x>=sx,bottom=y>=sy,i=(bottom<<1)+right;n.leaf=false;n=n.nodes[i]||(n.nodes[i]=d3_geom_quadtreeNode());if(right)x1=sx;else x2=sx;if(bottom)y1=sy;else y2=sy;insert(n,d,x,y,x1,y1,x2,y2)}var root=d3_geom_quadtreeNode();root.add=function(d){insert(root,d,+fx(d,++i),+fy(d,i),x1_,y1_,x2_,y2_)};root.visit=function(f){d3_geom_quadtreeVisit(f,root,x1_,y1_,x2_,y2_)};i=-1;if(x1==null){while(++i=0&&!(f=d3.interpolators[i](a,b)));return f}d3.interpolators=[function(a,b){var t=typeof b;return(t==="string"?d3_rgb_names.has(b)||/^(#|rgb\(|hsl\()/.test(b)?d3_interpolateRgb:d3_interpolateString:b instanceof d3_Color?d3_interpolateRgb:t==="object"?Array.isArray(b)?d3_interpolateArray:d3_interpolateObject:d3_interpolateNumber)(a,b)}];d3.interpolateArray=d3_interpolateArray;function d3_interpolateArray(a,b){var x=[],c=[],na=a.length,nb=b.length,n0=Math.min(a.length,b.length),i;for(i=0;i=0?name.substring(0,i):name,m=i>=0?name.substring(i+1):"in";t=d3_ease.get(t)||d3_ease_default;m=d3_ease_mode.get(m)||d3_identity;return d3_ease_clamp(m(t.apply(null,Array.prototype.slice.call(arguments,1))))};function d3_ease_clamp(f){return function(t){return t<=0?0:t>=1?1:f(t)}}function d3_ease_reverse(f){return function(t){return 1-f(1-t)}}function d3_ease_reflect(f){return function(t){return.5*(t<.5?f(2*t):2-f(2-2*t))}}function d3_ease_quad(t){return t*t}function d3_ease_cubic(t){return t*t*t}function d3_ease_cubicInOut(t){if(t<=0)return 0;if(t>=1)return 1;var t2=t*t,t3=t2*t;return 4*(t<.5?t3:3*(t-t2)+t3-.75)}function d3_ease_poly(e){return function(t){return Math.pow(t,e)}}function d3_ease_sin(t){return 1-Math.cos(t*π/2)}function d3_ease_exp(t){return Math.pow(2,10*(t-1))}function d3_ease_circle(t){return 1-Math.sqrt(1-t*t)}function d3_ease_elastic(a,p){var s;if(arguments.length<2)p=.45;if(arguments.length)s=p/(2*π)*Math.asin(1/a);else a=1,s=p/4;return function(t){return 1+a*Math.pow(2,10*-t)*Math.sin((t-s)*2*π/p)}}function d3_ease_back(s){if(!s)s=1.70158;return function(t){return t*t*((s+1)*t-s)}}function d3_ease_bounce(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}d3.interpolateHcl=d3_interpolateHcl;function d3_interpolateHcl(a,b){a=d3.hcl(a);b=d3.hcl(b);var ah=a.h,ac=a.c,al=a.l,bh=b.h-ah,bc=b.c-ac,bl=b.l-al;if(isNaN(bc))bc=0,ac=isNaN(ac)?b.c:ac;if(isNaN(bh))bh=0,ah=isNaN(ah)?b.h:ah;else if(bh>180)bh-=360;else if(bh<-180)bh+=360;return function(t){return d3_hcl_lab(ah+bh*t,ac+bc*t,al+bl*t)+""}}d3.interpolateHsl=d3_interpolateHsl;function d3_interpolateHsl(a,b){a=d3.hsl(a);b=d3.hsl(b);var ah=a.h,as=a.s,al=a.l,bh=b.h-ah,bs=b.s-as,bl=b.l-al;if(isNaN(bs))bs=0,as=isNaN(as)?b.s:as;if(isNaN(bh))bh=0,ah=isNaN(ah)?b.h:ah;else if(bh>180)bh-=360;else if(bh<-180)bh+=360;return function(t){return d3_hsl_rgb(ah+bh*t,as+bs*t,al+bl*t)+""}}d3.interpolateLab=d3_interpolateLab;function d3_interpolateLab(a,b){a=d3.lab(a);b=d3.lab(b);var al=a.l,aa=a.a,ab=a.b,bl=b.l-al,ba=b.a-aa,bb=b.b-ab;return function(t){return d3_lab_rgb(al+bl*t,aa+ba*t,ab+bb*t)+""}}d3.interpolateRound=d3_interpolateRound;function d3_interpolateRound(a,b){b-=a;return function(t){return Math.round(a+b*t)}}d3.transform=function(string){var g=d3_document.createElementNS(d3.ns.prefix.svg,"g");return(d3.transform=function(string){if(string!=null){g.setAttribute("transform",string);var t=g.transform.baseVal.consolidate()}return new d3_transform(t?t.matrix:d3_transformIdentity)})(string)};function d3_transform(m){var r0=[m.a,m.b],r1=[m.c,m.d],kx=d3_transformNormalize(r0),kz=d3_transformDot(r0,r1),ky=d3_transformNormalize(d3_transformCombine(r1,r0,-kz))||0;if(r0[0]*r1[1]180)rb+=360;else if(rb-ra>180)ra+=360;q.push({i:s.push(s.pop()+"rotate(",null,")")-2,x:d3_interpolateNumber(ra,rb)})}else if(rb){s.push(s.pop()+"rotate("+rb+")")}if(wa!=wb){q.push({i:s.push(s.pop()+"skewX(",null,")")-2,x:d3_interpolateNumber(wa,wb)})}else if(wb){s.push(s.pop()+"skewX("+wb+")")}if(ka[0]!=kb[0]||ka[1]!=kb[1]){n=s.push(s.pop()+"scale(",null,",",null,")");q.push({i:n-4,x:d3_interpolateNumber(ka[0],kb[0])},{i:n-2,x:d3_interpolateNumber(ka[1],kb[1])})}else if(kb[0]!=1||kb[1]!=1){s.push(s.pop()+"scale("+kb+")")}n=q.length;return function(t){var i=-1,o;while(++i0)alpha=x;else alpha=0}else if(x>0){event.start({type:"start",alpha:alpha=x});d3.timer(force.tick)}return force};force.start=function(){var i,j,n=nodes.length,m=links.length,w=size[0],h=size[1],neighbors,o;for(i=0;imax)max=o;sums.push(o)}for(j=0;jv){j=i;v=k}}return j}function d3_layout_stackReduceSum(d){return d.reduce(d3_layout_stackSum,0)}function d3_layout_stackSum(p,d){return p+d[1]}d3.layout.histogram=function(){var frequency=true,valuer=Number,ranger=d3_layout_histogramRange,binner=d3_layout_histogramBinSturges;function histogram(data,i){var bins=[],values=data.map(valuer,this),range=ranger.call(this,values,i),thresholds=binner.call(this,range,values,i),bin,i=-1,n=values.length,m=thresholds.length-1,k=frequency?1:1/n,x;while(++i0){i=-1;while(++i=range[0]&&x<=range[1]){bin=bins[d3.bisect(thresholds,x,1,m)-1];bin.y+=k;bin.push(data[i])}}}return bins}histogram.value=function(x){if(!arguments.length)return valuer;valuer=x;return histogram};histogram.range=function(x){if(!arguments.length)return ranger;ranger=d3_functor(x);return histogram};histogram.bins=function(x){if(!arguments.length)return binner;binner=typeof x==="number"?function(range){return d3_layout_histogramBinFixed(range,x)}:d3_functor(x);return histogram};histogram.frequency=function(x){if(!arguments.length)return frequency;frequency=!!x;return histogram};return histogram};function d3_layout_histogramBinSturges(range,values){return d3_layout_histogramBinFixed(range,Math.ceil(Math.log(values.length)/Math.LN2+1))}function d3_layout_histogramBinFixed(range,n){var x=-1,b=+range[0],m=(range[1]-b)/n,f=[];while(++x<=n)f[x]=m*x+b;return f}function d3_layout_histogramRange(values){return[d3.min(values),d3.max(values)]}d3.layout.tree=function(){var hierarchy=d3.layout.hierarchy().sort(null).value(null),separation=d3_layout_treeSeparation,size=[1,1],nodeSize=false;function tree(d,i){var nodes=hierarchy.call(this,d,i),root=nodes[0];function firstWalk(node,previousSibling){var children=node.children,layout=node._tree;if(children&&(n=children.length)){var n,firstChild=children[0],previousChild,ancestor=firstChild,child,i=-1;while(++i0){d3_layout_treeMove(d3_layout_treeAncestor(vim,node,ancestor),node,shift);sip+=shift;sop+=shift}sim+=vim._tree.mod;sip+=vip._tree.mod;som+=vom._tree.mod;sop+=vop._tree.mod}if(vim&&!d3_layout_treeRight(vop)){vop._tree.thread=vim;vop._tree.mod+=sim-sop}if(vip&&!d3_layout_treeLeft(vom)){vom._tree.thread=vip;vom._tree.mod+=sip-som;ancestor=node}}return ancestor}d3_layout_treeVisitAfter(root,function(node,previousSibling){node._tree={ancestor:node,prelim:0,mod:0,change:0,shift:0,number:previousSibling?previousSibling._tree.number+1:0}});firstWalk(root);secondWalk(root,-root._tree.prelim);var left=d3_layout_treeSearch(root,d3_layout_treeLeftmost),right=d3_layout_treeSearch(root,d3_layout_treeRightmost),deep=d3_layout_treeSearch(root,d3_layout_treeDeepest),x0=left.x-separation(left,right)/2,x1=right.x+separation(right,left)/2,y1=deep.depth||1;d3_layout_treeVisitAfter(root,nodeSize?function(node){node.x*=size[0];node.y=node.depth*size[1];delete node._tree}:function(node){node.x=(node.x-x0)/(x1-x0)*size[0];node.y=node.depth/y1*size[1];delete node._tree});return nodes}tree.separation=function(x){if(!arguments.length)return separation;separation=x;return tree};tree.size=function(x){if(!arguments.length)return nodeSize?null:size;nodeSize=(size=x)==null;return tree};tree.nodeSize=function(x){if(!arguments.length)return nodeSize?size:null;nodeSize=(size=x)!=null;return tree};return d3_layout_hierarchyRebind(tree,hierarchy)};function d3_layout_treeSeparation(a,b){return a.parent==b.parent?1:2}function d3_layout_treeLeft(node){var children=node.children;return children&&children.length?children[0]:node._tree.thread}function d3_layout_treeRight(node){var children=node.children,n;return children&&(n=children.length)?children[n-1]:node._tree.thread}function d3_layout_treeSearch(node,compare){var children=node.children;if(children&&(n=children.length)){var child,n,i=-1;while(++i0){node=child}}}return node}function d3_layout_treeRightmost(a,b){return a.x-b.x}function d3_layout_treeLeftmost(a,b){return b.x-a.x}function d3_layout_treeDeepest(a,b){return a.depth-b.depth}function d3_layout_treeVisitAfter(node,callback){function visit(node,previousSibling){var children=node.children;if(children&&(n=children.length)){var child,previousChild=null,i=-1,n;while(++i=0){child=children[i]._tree;child.prelim+=shift;child.mod+=shift;shift+=child.shift+(change+=child.change)}}function d3_layout_treeMove(ancestor,node,shift){ancestor=ancestor._tree;node=node._tree;var change=shift/(node.number-ancestor.number);ancestor.change+=change;node.change-=change;node.shift+=shift;node.prelim+=shift;node.mod+=shift}function d3_layout_treeAncestor(vim,node,ancestor){return vim._tree.ancestor.parent==node.parent?vim._tree.ancestor:ancestor}d3.layout.pack=function(){var hierarchy=d3.layout.hierarchy().sort(d3_layout_packSort),padding=0,size=[1,1],radius;function pack(d,i){var nodes=hierarchy.call(this,d,i),root=nodes[0],w=size[0],h=size[1],r=radius==null?Math.sqrt:typeof radius==="function"?radius:function(){return radius};root.x=root.y=0;d3_layout_treeVisitAfter(root,function(d){d.r=+r(d.value)});d3_layout_treeVisitAfter(root,d3_layout_packSiblings);if(padding){var dr=padding*(radius?1:Math.max(2*root.r/w,2*root.r/h))/2;d3_layout_treeVisitAfter(root,function(d){d.r+=dr});d3_layout_treeVisitAfter(root,d3_layout_packSiblings);d3_layout_treeVisitAfter(root,function(d){d.r-=dr})}d3_layout_packTransform(root,w/2,h/2,radius?1:1/Math.max(2*root.r/w,2*root.r/h));return nodes}pack.size=function(_){if(!arguments.length)return size;size=_;return pack};pack.radius=function(_){if(!arguments.length)return radius;radius=_==null||typeof _==="function"?_:+_;return pack};pack.padding=function(_){if(!arguments.length)return padding;padding=+_;return pack};return d3_layout_hierarchyRebind(pack,hierarchy)};function d3_layout_packSort(a,b){return a.value-b.value}function d3_layout_packInsert(a,b){var c=a._pack_next;a._pack_next=b;b._pack_prev=a;b._pack_next=c;c._pack_prev=b}function d3_layout_packSplice(a,b){a._pack_next=b;b._pack_prev=a}function d3_layout_packIntersects(a,b){var dx=b.x-a.x,dy=b.y-a.y,dr=a.r+b.r;return.999*dr*dr>dx*dx+dy*dy}function d3_layout_packSiblings(node){if(!(nodes=node.children)||!(n=nodes.length))return;var nodes,xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity,a,b,c,i,j,k,n;function bound(node){xMin=Math.min(node.x-node.r,xMin);xMax=Math.max(node.x+node.r,xMax);yMin=Math.min(node.y-node.r,yMin);yMax=Math.max(node.y+node.r,yMax)}nodes.forEach(d3_layout_packLink);a=nodes[0];a.x=-a.r;a.y=0;bound(a);if(n>1){b=nodes[1];b.x=b.r;b.y=0;bound(b);if(n>2){c=nodes[2];d3_layout_packPlace(a,b,c);bound(c);d3_layout_packInsert(a,c);a._pack_prev=c;d3_layout_packInsert(c,b);b=a._pack_next;for(i=3;i0){row.push(child=remaining[n-1]);row.area+=child.area;if(mode!=="squarify"||(score=worst(row,u))<=best){remaining.pop();best=score}else{row.area-=row.pop().area;position(row,u,rect,false);u=Math.min(rect.dx,rect.dy);row.length=row.area=0;best=Infinity}}if(row.length){position(row,u,rect,true);row.length=row.area=0}children.forEach(squarify)}}function stickify(node){var children=node.children;if(children&&children.length){var rect=pad(node),remaining=children.slice(),child,row=[];scale(remaining,rect.dx*rect.dy/node.value);row.area=0;while(child=remaining.pop()){row.push(child);row.area+=child.area;if(child.z!=null){position(row,child.z?rect.dx:rect.dy,rect,!remaining.length);row.length=row.area=0}}children.forEach(stickify)}}function worst(row,u){var s=row.area,r,rmax=0,rmin=Infinity,i=-1,n=row.length;while(++irmax)rmax=r}s*=s;u*=u;return s?Math.max(u*rmax*ratio/s,s/(u*rmin*ratio)):Infinity}function position(row,u,rect,flush){var i=-1,n=row.length,x=rect.x,y=rect.y,v=u?round(row.area/u):0,o;if(u==rect.dx){if(flush||v>rect.dy)v=rect.dy;while(++irect.dx)v=rect.dx;while(++i1);return µ+σ*x*Math.sqrt(-2*Math.log(r)/r)}},logNormal:function(){var random=d3.random.normal.apply(d3,arguments);return function(){return Math.exp(random())}},irwinHall:function(m){return function(){for(var s=0,j=0;j2?d3_scale_polylinear:d3_scale_bilinear,uninterpolate=clamp?d3_uninterpolateClamp:d3_uninterpolateNumber;output=linear(domain,range,uninterpolate,interpolate);input=linear(range,domain,uninterpolate,d3_interpolate);return scale}function scale(x){return output(x)}scale.invert=function(y){return input(y)};scale.domain=function(x){if(!arguments.length)return domain;domain=x.map(Number);return rescale()};scale.range=function(x){if(!arguments.length)return range;range=x;return rescale()};scale.rangeRound=function(x){return scale.range(x).interpolate(d3_interpolateRound)};scale.clamp=function(x){if(!arguments.length)return clamp;clamp=x;return rescale()};scale.interpolate=function(x){if(!arguments.length)return interpolate;interpolate=x;return rescale()};scale.ticks=function(m){return d3_scale_linearTicks(domain,m)};scale.tickFormat=function(m,format){return d3_scale_linearTickFormat(domain,m,format)};scale.nice=function(m){d3_scale_linearNice(domain,m);return rescale()};scale.copy=function(){return d3_scale_linear(domain,range,interpolate,clamp)};return rescale()}function d3_scale_linearRebind(scale,linear){return d3.rebind(scale,linear,"range","rangeRound","interpolate","clamp")}function d3_scale_linearNice(domain,m){return d3_scale_nice(domain,d3_scale_niceStep(m?d3_scale_linearTickRange(domain,m)[2]:d3_scale_linearNiceStep(domain)))}function d3_scale_linearNiceStep(domain){var extent=d3_scaleExtent(domain),span=extent[1]-extent[0];return Math.pow(10,Math.round(Math.log(span)/Math.LN10)-1)}function d3_scale_linearTickRange(domain,m){var extent=d3_scaleExtent(domain),span=extent[1]-extent[0],step=Math.pow(10,Math.floor(Math.log(span/m)/Math.LN10)),err=m/span*step;if(err<=.15)step*=10;else if(err<=.35)step*=5;else if(err<=.75)step*=2;extent[0]=Math.ceil(extent[0]/step)*step;extent[1]=Math.floor(extent[1]/step)*step+step*.5;extent[2]=step;return extent}function d3_scale_linearTicks(domain,m){return d3.range.apply(d3,d3_scale_linearTickRange(domain,m))}function d3_scale_linearTickFormat(domain,m,format){var precision=-Math.floor(Math.log(d3_scale_linearTickRange(domain,m)[2])/Math.LN10+.01);return d3.format(format?format.replace(d3_format_re,function(a,b,c,d,e,f,g,h,i,j){return[b,c,d,e,f,g,h,i||"."+(precision-(j==="%")*2),j].join("")}):",."+precision+"f")}d3.scale.log=function(){return d3_scale_log(d3.scale.linear().domain([0,1]),10,true,[1,10])};function d3_scale_log(linear,base,positive,domain){function log(x){return(positive?Math.log(x<0?0:x):-Math.log(x>0?0:-x))/Math.log(base)}function pow(x){return positive?Math.pow(base,x):-Math.pow(base,-x)}function scale(x){return linear(log(x))}scale.invert=function(x){return pow(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return domain;positive=x[0]>=0;linear.domain((domain=x.map(Number)).map(log));return scale};scale.base=function(_){if(!arguments.length)return base;base=+_;linear.domain(domain.map(log));return scale};scale.nice=function(){var niced=d3_scale_nice(domain.map(log),positive?Math:d3_scale_logNiceNegative);linear.domain(niced);domain=niced.map(pow);return scale};scale.ticks=function(){var extent=d3_scaleExtent(domain),ticks=[],u=extent[0],v=extent[1],i=Math.floor(log(u)),j=Math.ceil(log(v)),n=base%1?2:base;if(isFinite(j-i)){if(positive){for(;i0;k--)ticks.push(pow(i)*k)}for(i=0;ticks[i]v;j--){}ticks=ticks.slice(i,j)}return ticks};scale.tickFormat=function(n,format){if(!arguments.length)return d3_scale_logFormat;if(arguments.length<2)format=d3_scale_logFormat;else if(typeof format!=="function")format=d3.format(format);var k=Math.max(.1,n/scale.ticks().length),f=positive?(e=1e-12,Math.ceil):(e=-1e-12,Math.floor),e;return function(d){return d/pow(f(log(d)+e))<=k?format(d):""}};scale.copy=function(){return d3_scale_log(linear.copy(),base,positive,domain)};return d3_scale_linearRebind(scale,linear)}var d3_scale_logFormat=d3.format(".0e"),d3_scale_logNiceNegative={floor:function(x){return-Math.ceil(-x)},ceil:function(x){return-Math.floor(-x)}};d3.scale.pow=function(){return d3_scale_pow(d3.scale.linear(),1,[0,1])};function d3_scale_pow(linear,exponent,domain){var powp=d3_scale_powPow(exponent),powb=d3_scale_powPow(1/exponent);function scale(x){return linear(powp(x))}scale.invert=function(x){return powb(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return domain;linear.domain((domain=x.map(Number)).map(powp));return scale};scale.ticks=function(m){return d3_scale_linearTicks(domain,m)};scale.tickFormat=function(m,format){return d3_scale_linearTickFormat(domain,m,format)};scale.nice=function(m){return scale.domain(d3_scale_linearNice(domain,m))};scale.exponent=function(x){if(!arguments.length)return exponent;powp=d3_scale_powPow(exponent=x);powb=d3_scale_powPow(1/exponent);linear.domain(domain.map(powp));return scale};scale.copy=function(){return d3_scale_pow(linear.copy(),exponent,domain)};return d3_scale_linearRebind(scale,linear)}function d3_scale_powPow(e){return function(x){return x<0?-Math.pow(-x,e):Math.pow(x,e)}}d3.scale.sqrt=function(){return d3.scale.pow().exponent(.5)};d3.scale.ordinal=function(){return d3_scale_ordinal([],{t:"range",a:[[]]})};function d3_scale_ordinal(domain,ranger){var index,range,rangeBand;function scale(x){return range[((index.get(x)||index.set(x,domain.push(x)))-1)%range.length]}function steps(start,step){return d3.range(domain.length).map(function(i){return start+step*i})}scale.domain=function(x){if(!arguments.length)return domain;domain=[];index=new d3_Map;var i=-1,n=x.length,xi;while(++i0?thresholds[y-1]:domain[0],y=d3_svg_arcMax?r0?"M0,"+r1+"A"+r1+","+r1+" 0 1,1 0,"+-r1+"A"+r1+","+r1+" 0 1,1 0,"+r1+"M0,"+r0+"A"+r0+","+r0+" 0 1,0 0,"+-r0+"A"+r0+","+r0+" 0 1,0 0,"+r0+"Z":"M0,"+r1+"A"+r1+","+r1+" 0 1,1 0,"+-r1+"A"+r1+","+r1+" 0 1,1 0,"+r1+"Z":r0?"M"+r1*c0+","+r1*s0+"A"+r1+","+r1+" 0 "+df+",1 "+r1*c1+","+r1*s1+"L"+r0*c1+","+r0*s1+"A"+r0+","+r0+" 0 "+df+",0 "+r0*c0+","+r0*s0+"Z":"M"+r1*c0+","+r1*s0+"A"+r1+","+r1+" 0 "+df+",1 "+r1*c1+","+r1*s1+"L0,0"+"Z"}arc.innerRadius=function(v){if(!arguments.length)return innerRadius;innerRadius=d3_functor(v);return arc};arc.outerRadius=function(v){if(!arguments.length)return outerRadius;outerRadius=d3_functor(v);return arc};arc.startAngle=function(v){if(!arguments.length)return startAngle;startAngle=d3_functor(v);return arc};arc.endAngle=function(v){if(!arguments.length)return endAngle;endAngle=d3_functor(v);return arc};arc.centroid=function(){var r=(innerRadius.apply(this,arguments)+outerRadius.apply(this,arguments))/2,a=(startAngle.apply(this,arguments)+endAngle.apply(this,arguments))/2+d3_svg_arcOffset;return[Math.cos(a)*r,Math.sin(a)*r]};return arc};var d3_svg_arcOffset=-π/2,d3_svg_arcMax=2*π-1e-6;function d3_svg_arcInnerRadius(d){return d.innerRadius}function d3_svg_arcOuterRadius(d){return d.outerRadius}function d3_svg_arcStartAngle(d){return d.startAngle}function d3_svg_arcEndAngle(d){return d.endAngle}d3.svg.line.radial=function(){var line=d3_svg_line(d3_svg_lineRadial);line.radius=line.x,delete line.x;line.angle=line.y,delete line.y;return line};function d3_svg_lineRadial(points){var point,i=-1,n=points.length,r,a;while(++iπ)+",1 "+p}function curve(r0,p0,r1,p1){return"Q 0,0 "+p1}chord.radius=function(v){if(!arguments.length)return radius;radius=d3_functor(v);return chord};chord.source=function(v){if(!arguments.length)return source;source=d3_functor(v);return chord};chord.target=function(v){if(!arguments.length)return target;target=d3_functor(v);return chord};chord.startAngle=function(v){if(!arguments.length)return startAngle;startAngle=d3_functor(v);return chord};chord.endAngle=function(v){if(!arguments.length)return endAngle;endAngle=d3_functor(v);return chord};return chord};function d3_svg_chordRadius(d){return d.radius}d3.svg.diagonal=function(){var source=d3_source,target=d3_target,projection=d3_svg_diagonalProjection;function diagonal(d,i){var p0=source.call(this,d,i),p3=target.call(this,d,i),m=(p0.y+p3.y)/2,p=[p0,{x:p0.x,y:m},{x:p3.x,y:m},p3];p=p.map(projection);return"M"+p[0]+"C"+p[1]+" "+p[2]+" "+p[3]}diagonal.source=function(x){if(!arguments.length)return source;source=d3_functor(x);return diagonal};diagonal.target=function(x){if(!arguments.length)return target;target=d3_functor(x);return diagonal};diagonal.projection=function(x){if(!arguments.length)return projection;projection=x;return diagonal};return diagonal};function d3_svg_diagonalProjection(d){return[d.x,d.y]}d3.svg.diagonal.radial=function(){var diagonal=d3.svg.diagonal(),projection=d3_svg_diagonalProjection,projection_=diagonal.projection;diagonal.projection=function(x){return arguments.length?projection_(d3_svg_diagonalRadialProjection(projection=x)):projection};return diagonal};function d3_svg_diagonalRadialProjection(projection){return function(){var d=projection.apply(this,arguments),r=d[0],a=d[1]+d3_svg_arcOffset;return[r*Math.cos(a),r*Math.sin(a)]}}d3.svg.symbol=function(){var type=d3_svg_symbolType,size=d3_svg_symbolSize;function symbol(d,i){return(d3_svg_symbols.get(type.call(this,d,i))||d3_svg_symbolCircle)(size.call(this,d,i))}symbol.type=function(x){if(!arguments.length)return type;type=d3_functor(x);return symbol};symbol.size=function(x){if(!arguments.length)return size;size=d3_functor(x);return symbol};return symbol};function d3_svg_symbolSize(){return 64}function d3_svg_symbolType(){return"circle"}function d3_svg_symbolCircle(size){var r=Math.sqrt(size/π);return"M0,"+r+"A"+r+","+r+" 0 1,1 0,"+-r+"A"+r+","+r+" 0 1,1 0,"+r+"Z"}var d3_svg_symbols=d3.map({circle:d3_svg_symbolCircle,cross:function(size){var r=Math.sqrt(size/5)/2;return"M"+-3*r+","+-r+"H"+-r+"V"+-3*r+"H"+r+"V"+-r+"H"+3*r+"V"+r+"H"+r+"V"+3*r+"H"+-r+"V"+r+"H"+-3*r+"Z"},diamond:function(size){var ry=Math.sqrt(size/(2*d3_svg_symbolTan30)),rx=ry*d3_svg_symbolTan30;return"M0,"+-ry+"L"+rx+",0"+" 0,"+ry+" "+-rx+",0"+"Z"},square:function(size){var r=Math.sqrt(size)/2;return"M"+-r+","+-r+"L"+r+","+-r+" "+r+","+r+" "+-r+","+r+"Z"},"triangle-down":function(size){var rx=Math.sqrt(size/d3_svg_symbolSqrt3),ry=rx*d3_svg_symbolSqrt3/2;return"M0,"+ry+"L"+rx+","+-ry+" "+-rx+","+-ry+"Z"},"triangle-up":function(size){var rx=Math.sqrt(size/d3_svg_symbolSqrt3),ry=rx*d3_svg_symbolSqrt3/2;return"M0,"+-ry+"L"+rx+","+ry+" "+-rx+","+ry+"Z"}});d3.svg.symbolTypes=d3_svg_symbols.keys();var d3_svg_symbolSqrt3=Math.sqrt(3),d3_svg_symbolTan30=Math.tan(30*d3_radians);function d3_transition(groups,id){d3_subclass(groups,d3_transitionPrototype);groups.id=id;return groups}var d3_transitionPrototype=[],d3_transitionId=0,d3_transitionInheritId,d3_transitionInherit;d3_transitionPrototype.call=d3_selectionPrototype.call;d3_transitionPrototype.empty=d3_selectionPrototype.empty;d3_transitionPrototype.node=d3_selectionPrototype.node;d3_transitionPrototype.size=d3_selectionPrototype.size;d3.transition=function(selection){return arguments.length?d3_transitionInheritId?selection.transition():selection:d3_selectionRoot.transition()};d3.transition.prototype=d3_transitionPrototype;d3_transitionPrototype.select=function(selector){var id=this.id,subgroups=[],subgroup,subnode,node;selector=d3_selection_selector(selector);for(var j=-1,m=this.length;++jid)return stop();lock.active=id;transition.event&&transition.event.start.call(node,d,i);transition.tween.forEach(function(key,value){if(value=value.call(node,d,i)){tweened.push(value)}});if(tick(elapsed))return 1;d3_timer_replace(tick,0,time)}function tick(elapsed){if(lock.active!==id)return stop();var t=(elapsed-delay)/duration,e=ease(t),n=tweened.length;while(n>0){tweened[--n].call(node,e)}if(t>=1){stop();transition.event&&transition.event.end.call(node,d,i);return 1}}function stop(){if(--lock.count)delete lock[id];else delete node.__transition__;return 1}},0,time)}}d3.svg.axis=function(){var scale=d3.scale.linear(),orient=d3_svg_axisDefaultOrient,tickMajorSize=6,tickMinorSize=6,tickEndSize=6,tickPadding=3,tickArguments_=[10],tickValues=null,tickFormat_,tickSubdivide=0;function axis(g){g.each(function(){var g=d3.select(this);var ticks=tickValues==null?scale.ticks?scale.ticks.apply(scale,tickArguments_):scale.domain():tickValues,tickFormat=tickFormat_==null?scale.tickFormat?scale.tickFormat.apply(scale,tickArguments_):String:tickFormat_;var subticks=d3_svg_axisSubdivide(scale,ticks,tickSubdivide),subtick=g.selectAll(".tick.minor").data(subticks,String),subtickEnter=subtick.enter().insert("line",".tick").attr("class","tick minor").style("opacity",1e-6),subtickExit=d3.transition(subtick.exit()).style("opacity",1e-6).remove(),subtickUpdate=d3.transition(subtick).style("opacity",1);var tick=g.selectAll(".tick.major").data(ticks,String),tickEnter=tick.enter().insert("g",".domain").attr("class","tick major").style("opacity",1e-6),tickExit=d3.transition(tick.exit()).style("opacity",1e-6).remove(),tickUpdate=d3.transition(tick).style("opacity",1),tickTransform;var range=d3_scaleRange(scale),path=g.selectAll(".domain").data([0]),pathUpdate=(path.enter().append("path").attr("class","domain"),d3.transition(path));var scale1=scale.copy(),scale0=this.__chart__||scale1;this.__chart__=scale1;tickEnter.append("line");tickEnter.append("text");var lineEnter=tickEnter.select("line"),lineUpdate=tickUpdate.select("line"),text=tick.select("text").text(tickFormat),textEnter=tickEnter.select("text"),textUpdate=tickUpdate.select("text");switch(orient){case"bottom":{tickTransform=d3_svg_axisX;subtickEnter.attr("y2",tickMinorSize);subtickUpdate.attr("x2",0).attr("y2",tickMinorSize);lineEnter.attr("y2",tickMajorSize);textEnter.attr("y",Math.max(tickMajorSize,0)+tickPadding);lineUpdate.attr("x2",0).attr("y2",tickMajorSize);textUpdate.attr("x",0).attr("y",Math.max(tickMajorSize,0)+tickPadding);text.attr("dy",".71em").style("text-anchor","middle");pathUpdate.attr("d","M"+range[0]+","+tickEndSize+"V0H"+range[1]+"V"+tickEndSize);break}case"top":{tickTransform=d3_svg_axisX;subtickEnter.attr("y2",-tickMinorSize);subtickUpdate.attr("x2",0).attr("y2",-tickMinorSize);lineEnter.attr("y2",-tickMajorSize);textEnter.attr("y",-(Math.max(tickMajorSize,0)+tickPadding));lineUpdate.attr("x2",0).attr("y2",-tickMajorSize);textUpdate.attr("x",0).attr("y",-(Math.max(tickMajorSize,0)+tickPadding));text.attr("dy","0em").style("text-anchor","middle");pathUpdate.attr("d","M"+range[0]+","+-tickEndSize+"V0H"+range[1]+"V"+-tickEndSize);break}case"left":{tickTransform=d3_svg_axisY;subtickEnter.attr("x2",-tickMinorSize);subtickUpdate.attr("x2",-tickMinorSize).attr("y2",0);lineEnter.attr("x2",-tickMajorSize);textEnter.attr("x",-(Math.max(tickMajorSize,0)+tickPadding));lineUpdate.attr("x2",-tickMajorSize).attr("y2",0);textUpdate.attr("x",-(Math.max(tickMajorSize,0)+tickPadding)).attr("y",0);text.attr("dy",".32em").style("text-anchor","end");pathUpdate.attr("d","M"+-tickEndSize+","+range[0]+"H0V"+range[1]+"H"+-tickEndSize);break}case"right":{tickTransform=d3_svg_axisY;subtickEnter.attr("x2",tickMinorSize);subtickUpdate.attr("x2",tickMinorSize).attr("y2",0);lineEnter.attr("x2",tickMajorSize);textEnter.attr("x",Math.max(tickMajorSize,0)+tickPadding);lineUpdate.attr("x2",tickMajorSize).attr("y2",0);textUpdate.attr("x",Math.max(tickMajorSize,0)+tickPadding).attr("y",0);text.attr("dy",".32em").style("text-anchor","start");pathUpdate.attr("d","M"+tickEndSize+","+range[0]+"H0V"+range[1]+"H"+tickEndSize);break}}if(scale.rangeBand){var dx=scale1.rangeBand()/2,x=function(d){return scale1(d)+dx};tickEnter.call(tickTransform,x);tickUpdate.call(tickTransform,x)}else{tickEnter.call(tickTransform,scale0);tickUpdate.call(tickTransform,scale1);tickExit.call(tickTransform,scale1);subtickEnter.call(tickTransform,scale0);subtickUpdate.call(tickTransform,scale1);subtickExit.call(tickTransform,scale1)}})}axis.scale=function(x){if(!arguments.length)return scale;scale=x;return axis};axis.orient=function(x){if(!arguments.length)return orient;orient=x in d3_svg_axisOrients?x+"":d3_svg_axisDefaultOrient;return axis};axis.ticks=function(){if(!arguments.length)return tickArguments_;tickArguments_=arguments;return axis};axis.tickValues=function(x){if(!arguments.length)return tickValues;tickValues=x;return axis};axis.tickFormat=function(x){if(!arguments.length)return tickFormat_;tickFormat_=x;return axis};axis.tickSize=function(x,y){if(!arguments.length)return tickMajorSize;var n=arguments.length-1;tickMajorSize=+x;tickMinorSize=n>1?+y:tickMajorSize;tickEndSize=n>0?+arguments[n]:tickMajorSize;return axis};axis.tickPadding=function(x){if(!arguments.length)return tickPadding;tickPadding=+x;return axis};axis.tickSubdivide=function(x){if(!arguments.length)return tickSubdivide;tickSubdivide=+x;return axis};return axis};var d3_svg_axisDefaultOrient="bottom",d3_svg_axisOrients={top:1,right:1,bottom:1,left:1};function d3_svg_axisX(selection,x){selection.attr("transform",function(d){return"translate("+x(d)+",0)"})}function d3_svg_axisY(selection,y){selection.attr("transform",function(d){return"translate(0,"+y(d)+")"})}function d3_svg_axisSubdivide(scale,ticks,m){subticks=[];if(m&&ticks.length>1){var extent=d3_scaleExtent(scale.domain()),subticks,i=-1,n=ticks.length,d=(ticks[1]-ticks[0])/++m,j,v;while(++i0;){if((v=+ticks[i]-j*d)>=extent[0]){subticks.push(v)}}}for(--i,j=0;++jrect,.s>rect").attr("width",extent[1][0]-extent[0][0])}function redrawY(g){g.select(".extent").attr("y",extent[0][1]);g.selectAll(".extent,.e>rect,.w>rect").attr("height",extent[1][1]-extent[0][1])}function brushstart(){var target=this,eventTarget=d3.select(d3.event.target),event_=event.of(target,arguments),g=d3.select(target),resizing=eventTarget.datum(),resizingX=!/^(n|s)$/.test(resizing)&&x,resizingY=!/^(e|w)$/.test(resizing)&&y,dragging=eventTarget.classed("extent"),dragRestore=d3_event_dragSuppress(),center,origin=mouse(),offset;var w=d3.select(d3_window).on("keydown.brush",keydown).on("keyup.brush",keyup);if(d3.event.changedTouches){w.on("touchmove.brush",brushmove).on("touchend.brush",brushend)}else{w.on("mousemove.brush",brushmove).on("mouseup.brush",brushend)}if(dragging){origin[0]=extent[0][0]-origin[0];origin[1]=extent[0][1]-origin[1]}else if(resizing){var ex=+/w$/.test(resizing),ey=+/^n/.test(resizing);offset=[extent[1-ex][0]-origin[0],extent[1-ey][1]-origin[1]];origin[0]=extent[ex][0];origin[1]=extent[ey][1]}else if(d3.event.altKey)center=origin.slice();g.style("pointer-events","none").selectAll(".resize").style("display",null);d3.select("body").style("cursor",eventTarget.style("cursor"));event_({type:"brushstart"});brushmove();function mouse(){var touches=d3.event.changedTouches;return touches?d3.touches(target,touches)[0]:d3.mouse(target)}function keydown(){if(d3.event.keyCode==32){if(!dragging){center=null;origin[0]-=extent[1][0];origin[1]-=extent[1][1];dragging=2}d3_eventPreventDefault()}}function keyup(){if(d3.event.keyCode==32&&dragging==2){origin[0]+=extent[1][0];origin[1]+=extent[1][1];dragging=0;d3_eventPreventDefault()}}function brushmove(){var point=mouse(),moved=false;if(offset){point[0]+=offset[0];point[1]+=offset[1]}if(!dragging){if(d3.event.altKey){if(!center)center=[(extent[0][0]+extent[1][0])/2,(extent[0][1]+extent[1][1])/2];origin[0]=extent[+(point[0]1?Date.UTC.apply(this,arguments):arguments[0])}d3_time_utc.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){d3_time_prototype.setUTCDate.apply(this._,arguments)},setDay:function(){d3_time_prototype.setUTCDay.apply(this._,arguments)},setFullYear:function(){d3_time_prototype.setUTCFullYear.apply(this._,arguments)},setHours:function(){d3_time_prototype.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){d3_time_prototype.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){d3_time_prototype.setUTCMinutes.apply(this._,arguments)},setMonth:function(){d3_time_prototype.setUTCMonth.apply(this._,arguments)},setSeconds:function(){d3_time_prototype.setUTCSeconds.apply(this._,arguments)},setTime:function(){d3_time_prototype.setTime.apply(this._,arguments)}};var d3_time_prototype=Date.prototype;var d3_time_formatDateTime="%a %b %e %X %Y",d3_time_formatDate="%m/%d/%Y",d3_time_formatTime="%H:%M:%S";var d3_time_days=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],d3_time_dayAbbreviations=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],d3_time_months=["January","February","March","April","May","June","July","August","September","October","November","December"],d3_time_monthAbbreviations=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function d3_time_interval(local,step,number){function round(date){var d0=local(date),d1=offset(d0,1);return date-d01){while(time=m)return-1;c=template.charCodeAt(i++);if(c===37){p=d3_time_parsers[template.charAt(i++)];if(!p||(j=p(date,string,j))<0)return-1}else if(c!=string.charCodeAt(j++)){return-1}}return j}function d3_time_formatRe(names){return new RegExp("^(?:"+names.map(d3.requote).join("|")+")","i")}function d3_time_formatLookup(names){var map=new d3_Map,i=-1,n=names.length;while(++i=12?"PM":"AM"},S:function(d,p){return d3_time_formatPad(d.getSeconds(),p,2)},U:function(d,p){return d3_time_formatPad(d3.time.sundayOfYear(d),p,2)},w:function(d){return d.getDay()},W:function(d,p){return d3_time_formatPad(d3.time.mondayOfYear(d),p,2)},x:d3.time.format(d3_time_formatDate),X:d3.time.format(d3_time_formatTime),y:function(d,p){return d3_time_formatPad(d.getFullYear()%100,p,2)},Y:function(d,p){return d3_time_formatPad(d.getFullYear()%1e4,p,4)},Z:d3_time_zone,"%":function(){return"%"}};var d3_time_parsers={a:d3_time_parseWeekdayAbbrev,A:d3_time_parseWeekday,b:d3_time_parseMonthAbbrev,B:d3_time_parseMonth,c:d3_time_parseLocaleFull,d:d3_time_parseDay,e:d3_time_parseDay,H:d3_time_parseHour24,I:d3_time_parseHour24,j:d3_time_parseDayOfYear,L:d3_time_parseMilliseconds,m:d3_time_parseMonthNumber,M:d3_time_parseMinutes,p:d3_time_parseAmPm,S:d3_time_parseSeconds,U:d3_time_parseWeekNumberSunday,w:d3_time_parseWeekdayNumber,W:d3_time_parseWeekNumberMonday,x:d3_time_parseLocaleDate,X:d3_time_parseLocaleTime,y:d3_time_parseYear,Y:d3_time_parseFullYear,"%":d3_time_parseLiteralPercent};function d3_time_parseWeekdayAbbrev(date,string,i){d3_time_dayAbbrevRe.lastIndex=0;var n=d3_time_dayAbbrevRe.exec(string.substring(i));return n?(date.w=d3_time_dayAbbrevLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseWeekday(date,string,i){d3_time_dayRe.lastIndex=0;var n=d3_time_dayRe.exec(string.substring(i));return n?(date.w=d3_time_dayLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseWeekdayNumber(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+1));return n?(date.w=+n[0],i+n[0].length):-1}function d3_time_parseWeekNumberSunday(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i));return n?(date.U=+n[0],i+n[0].length):-1}function d3_time_parseWeekNumberMonday(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i));return n?(date.W=+n[0],i+n[0].length):-1}function d3_time_parseMonthAbbrev(date,string,i){d3_time_monthAbbrevRe.lastIndex=0;var n=d3_time_monthAbbrevRe.exec(string.substring(i));return n?(date.m=d3_time_monthAbbrevLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseMonth(date,string,i){d3_time_monthRe.lastIndex=0;var n=d3_time_monthRe.exec(string.substring(i));return n?(date.m=d3_time_monthLookup.get(n[0].toLowerCase()),i+n[0].length):-1}function d3_time_parseLocaleFull(date,string,i){return d3_time_parse(date,d3_time_formats.c.toString(),string,i)}function d3_time_parseLocaleDate(date,string,i){return d3_time_parse(date,d3_time_formats.x.toString(),string,i)}function d3_time_parseLocaleTime(date,string,i){return d3_time_parse(date,d3_time_formats.X.toString(),string,i)}function d3_time_parseFullYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+4));return n?(date.y=+n[0],i+n[0].length):-1}function d3_time_parseYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.y=d3_time_expandYear(+n[0]),i+n[0].length):-1}function d3_time_expandYear(d){return d+(d>68?1900:2e3)}function d3_time_parseMonthNumber(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.m=n[0]-1,i+n[0].length):-1}function d3_time_parseDay(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.d=+n[0],i+n[0].length):-1}function d3_time_parseDayOfYear(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+3));return n?(date.j=+n[0],i+n[0].length):-1}function d3_time_parseHour24(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.H=+n[0],i+n[0].length):-1}function d3_time_parseMinutes(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.M=+n[0],i+n[0].length):-1}function d3_time_parseSeconds(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+2));return n?(date.S=+n[0],i+n[0].length):-1}function d3_time_parseMilliseconds(date,string,i){d3_time_numberRe.lastIndex=0;var n=d3_time_numberRe.exec(string.substring(i,i+3));return n?(date.L=+n[0],i+n[0].length):-1}var d3_time_numberRe=/^\s*\d+/;function d3_time_parseAmPm(date,string,i){var n=d3_time_amPmLookup.get(string.substring(i,i+=2).toLowerCase());return n==null?-1:(date.p=n,i)}var d3_time_amPmLookup=d3.map({am:0,pm:1});function d3_time_zone(d){var z=d.getTimezoneOffset(),zs=z>0?"-":"+",zh=~~(Math.abs(z)/60),zm=Math.abs(z)%60;return zs+d3_time_formatPad(zh,"0",2)+d3_time_formatPad(zm,"0",2)}function d3_time_parseLiteralPercent(date,string,i){d3_time_percentRe.lastIndex=0;var n=d3_time_percentRe.exec(string.substring(i,i+1));return n?i+n[0].length:-1}d3.time.format.utc=function(template){var local=d3.time.format(template);function format(date){try{d3_time=d3_time_utc;var utc=new d3_time;utc._=date;return local(utc)}finally{d3_time=Date}}format.parse=function(string){try{d3_time=d3_time_utc;var date=local.parse(string);return date&&date._}finally{d3_time=Date}};format.toString=local.toString;return format};var d3_time_formatIso=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?d3_time_formatIsoNative:d3_time_formatIso;function d3_time_formatIsoNative(date){return date.toISOString()}d3_time_formatIsoNative.parse=function(string){var date=new Date(string);return isNaN(date)?null:date};d3_time_formatIsoNative.toString=d3_time_formatIso.toString;d3.time.second=d3_time_interval(function(date){return new d3_time(Math.floor(date/1e3)*1e3)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*1e3)},function(date){return date.getSeconds()});d3.time.seconds=d3.time.second.range;d3.time.seconds.utc=d3.time.second.utc.range;d3.time.minute=d3_time_interval(function(date){return new d3_time(Math.floor(date/6e4)*6e4)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*6e4)},function(date){return date.getMinutes()});d3.time.minutes=d3.time.minute.range;d3.time.minutes.utc=d3.time.minute.utc.range;d3.time.hour=d3_time_interval(function(date){var timezone=date.getTimezoneOffset()/60;return new d3_time((Math.floor(date/36e5-timezone)+timezone)*36e5)},function(date,offset){date.setTime(date.getTime()+Math.floor(offset)*36e5)},function(date){return date.getHours()});d3.time.hours=d3.time.hour.range;d3.time.hours.utc=d3.time.hour.utc.range;d3.time.month=d3_time_interval(function(date){date=d3.time.day(date);date.setDate(1);return date},function(date,offset){date.setMonth(date.getMonth()+offset)},function(date){return date.getMonth()});d3.time.months=d3.time.month.range;d3.time.months.utc=d3.time.month.utc.range;function d3_time_scale(linear,methods,format){function scale(x){return linear(x)}scale.invert=function(x){return d3_time_scaleDate(linear.invert(x))};scale.domain=function(x){if(!arguments.length)return linear.domain().map(d3_time_scaleDate);linear.domain(x);return scale};scale.nice=function(m){return scale.domain(d3_scale_nice(scale.domain(),m))};scale.ticks=function(m,k){var extent=d3_scaleExtent(scale.domain());if(typeof m!=="function"){var span=extent[1]-extent[0],target=span/m,i=d3.bisect(d3_time_scaleSteps,target);if(i==d3_time_scaleSteps.length)return methods.year(extent,m);if(!i)return linear.ticks(m).map(d3_time_scaleDate);if(target/d3_time_scaleSteps[i-1]":">",'"':""","'":"'"};function escapeHTML(string){return String(string).replace(/&(?!\w+;)|[<>"']/g,function(s){return escapeMap[s]||s})}var regexCache={};var Renderer=function(){};Renderer.prototype={otag:"{{",ctag:"}}",pragmas:{},buffer:[],pragmas_implemented:{"IMPLICIT-ITERATOR":true},context:{},render:function(template,context,partials,in_recursion){if(!in_recursion){this.context=context;this.buffer=[]}if(!this.includes("",template)){if(in_recursion){return template}else{this.send(template);return}}template=this.render_pragmas(template);var html=this.render_section(template,context,partials);if(html===false){html=this.render_tags(template,context,partials,in_recursion)}if(in_recursion){return html}else{this.sendLines(html)}},send:function(line){if(line!==""){this.buffer.push(line)}},sendLines:function(text){if(text){var lines=text.split("\n");for(var i=0;i|&|\\{|%)?([^#\\^]+?)\\1?"+ctag+"+","g")})};var regex=new_regex();var tag_replace_callback=function(match,operator,name){switch(operator){case"!":return"";case"=":that.set_delimiters(name);regex=new_regex();return"";case">":return that.render_partial(name,context,partials);case"{":case"&":return that.find(name,context);default:return escapeHTML(that.find(name,context))}};var lines=template.split("\n");for(var i=0;i0){value_context=value;value=value[path.shift()]}if(typeof value=="function"){return value.apply(value_context)}return value},includes:function(needle,haystack){return haystack.indexOf(this.otag+needle)!=-1},create_context:function(_context){if(this.is_object(_context)){return _context}else{var iterator=".";if(this.pragmas["IMPLICIT-ITERATOR"]){iterator=this.pragmas["IMPLICIT-ITERATOR"].iterator}var ctx={};ctx[iterator]=_context;return ctx}},is_object:function(a){return a&&typeof a=="object"},map:function(array,fn){if(typeof array.map=="function"){return array.map(fn)}else{var r=[];var l=array.length;for(var i=0;i3&&typeof args[argsLength-2]=="function"){var callback=baseCreateCallback(args[--argsLength-1],args[argsLength--],2)}else if(argsLength>2&&typeof args[argsLength-1]=="function"){callback=args[--argsLength]}while(++argsIndex2?createBound(func,17,nativeSlice.call(arguments,2),null,thisArg):createBound(func,1,null,null,thisArg)}module.exports=bind},{"lodash._createbound":19,"lodash._renative":24}],19:[function(require,module,exports){var createObject=require("lodash._createobject"),isFunction=require("lodash.isfunction"),isObject=require("lodash.isobject"),reNative=require("lodash._renative"),setBindData=require("lodash._setbinddata"),support=require("lodash.support");var arrayRef=[];var objectProto=Object.prototype;var push=arrayRef.push,toString=objectProto.toString,unshift=arrayRef.unshift;var nativeBind=reNative.test(nativeBind=toString.bind)&&nativeBind,nativeSlice=arrayRef.slice;function createBound(func,bitmask,partialArgs,partialRightArgs,thisArg,arity){var isBind=bitmask&1,isBindKey=bitmask&2,isCurry=bitmask&4,isCurryBound=bitmask&8,isPartial=bitmask&16,isPartialRight=bitmask&32,key=func;if(!isBindKey&&!isFunction(func)){throw new TypeError}if(isPartial&&!partialArgs.length){bitmask&=~16;isPartial=partialArgs=false}if(isPartialRight&&!partialRightArgs.length){bitmask&=~32;isPartialRight=partialRightArgs=false}var bindData=func&&func.__bindData__;if(bindData){if(isBind&&!(bindData[1]&1)){bindData[4]=thisArg}if(!isBind&&bindData[1]&1){bitmask|=8}if(isCurry&&!(bindData[1]&4)){bindData[5]=arity}if(isPartial){push.apply(bindData[2]||(bindData[2]=[]),partialArgs)}if(isPartialRight){push.apply(bindData[3]||(bindData[3]=[]),partialRightArgs)}bindData[1]|=bitmask;return createBound.apply(null,bindData)}if(isBind&&!(isBindKey||isCurry||isPartialRight)&&(support.fastBind||nativeBind&&isPartial)){if(isPartial){var args=[thisArg];push.apply(args,partialArgs)}var bound=isPartial?nativeBind.apply(func,args):nativeBind.call(func,thisArg)}else{bound=function(){var args=arguments,thisBinding=isBind?thisArg:this;if(isCurry||isPartial||isPartialRight){args=nativeSlice.call(args);if(isPartial){unshift.apply(args,partialArgs)}if(isPartialRight){push.apply(args,partialRightArgs)}if(isCurry&&args.length0?port.toString():null,encodeIfExists2(path,URI_DISALLOWED_IN_PATH_),null,encodeIfExists(fragment));if(query){if("string"===typeof query){uri.setRawQuery(query.replace(/[^?&=0-9A-Za-z_\-~.%]/g,encodeOne))}else{uri.setAllParameters(query)}}return uri}function encodeIfExists(unescapedPart){if("string"==typeof unescapedPart){return encodeURIComponent(unescapedPart) -}return null}function encodeIfExists2(unescapedPart,extra){if("string"==typeof unescapedPart){return encodeURI(unescapedPart).replace(extra,encodeOne)}return null}function encodeOne(ch){var n=ch.charCodeAt(0);return"%"+"0123456789ABCDEF".charAt(n>>4&15)+"0123456789ABCDEF".charAt(n&15)}function normPath(path){return path.replace(/(^|\/)\.(?:\/|$)/g,"$1").replace(/\/{2,}/g,"/")}var PARENT_DIRECTORY_HANDLER=new RegExp(""+"(/|^)"+"(?:[^./][^/]*|\\.{2,}(?:[^./][^/]*)|\\.{3,}[^/]*)"+"/\\.\\.(?:/|$)");var PARENT_DIRECTORY_HANDLER_RE=new RegExp(PARENT_DIRECTORY_HANDLER);var EXTRA_PARENT_PATHS_RE=/^(?:\.\.\/)*(?:\.\.$)?/;function collapse_dots(path){if(path===null){return null}var p=normPath(path);var r=PARENT_DIRECTORY_HANDLER_RE;for(var q;(q=p.replace(r,"$1"))!=p;p=q){}return p}function resolve(baseUri,relativeUri){var absoluteUri=baseUri.clone();var overridden=relativeUri.hasScheme();if(overridden){absoluteUri.setRawScheme(relativeUri.getRawScheme())}else{overridden=relativeUri.hasCredentials()}if(overridden){absoluteUri.setRawCredentials(relativeUri.getRawCredentials())}else{overridden=relativeUri.hasDomain()}if(overridden){absoluteUri.setRawDomain(relativeUri.getRawDomain())}else{overridden=relativeUri.hasPort()}var rawPath=relativeUri.getRawPath();var simplifiedPath=collapse_dots(rawPath);if(overridden){absoluteUri.setPort(relativeUri.getPort());simplifiedPath=simplifiedPath&&simplifiedPath.replace(EXTRA_PARENT_PATHS_RE,"")}else{overridden=!!rawPath;if(overridden){if(simplifiedPath.charCodeAt(0)!==47){var absRawPath=collapse_dots(absoluteUri.getRawPath()||"").replace(EXTRA_PARENT_PATHS_RE,"");var slash=absRawPath.lastIndexOf("/")+1;simplifiedPath=collapse_dots((slash?absRawPath.substring(0,slash):"")+collapse_dots(rawPath)).replace(EXTRA_PARENT_PATHS_RE,"")}}else{simplifiedPath=simplifiedPath&&simplifiedPath.replace(EXTRA_PARENT_PATHS_RE,"");if(simplifiedPath!==rawPath){absoluteUri.setRawPath(simplifiedPath)}}}if(overridden){absoluteUri.setRawPath(simplifiedPath)}else{overridden=relativeUri.hasQuery()}if(overridden){absoluteUri.setRawQuery(relativeUri.getRawQuery())}else{overridden=relativeUri.hasFragment()}if(overridden){absoluteUri.setRawFragment(relativeUri.getRawFragment())}return absoluteUri}function URI(rawScheme,rawCredentials,rawDomain,port,rawPath,rawQuery,rawFragment){this.scheme_=rawScheme;this.credentials_=rawCredentials;this.domain_=rawDomain;this.port_=port;this.path_=rawPath;this.query_=rawQuery;this.fragment_=rawFragment;this.paramCache_=null}URI.prototype.toString=function(){var out=[];if(null!==this.scheme_){out.push(this.scheme_,":")}if(null!==this.domain_){out.push("//");if(null!==this.credentials_){out.push(this.credentials_,"@")}out.push(this.domain_);if(null!==this.port_){out.push(":",this.port_.toString())}}if(null!==this.path_){out.push(this.path_)}if(null!==this.query_){out.push("?",this.query_)}if(null!==this.fragment_){out.push("#",this.fragment_)}return out.join("")};URI.prototype.clone=function(){return new URI(this.scheme_,this.credentials_,this.domain_,this.port_,this.path_,this.query_,this.fragment_)};URI.prototype.getScheme=function(){return this.scheme_&&decodeURIComponent(this.scheme_).toLowerCase()};URI.prototype.getRawScheme=function(){return this.scheme_};URI.prototype.setScheme=function(newScheme){this.scheme_=encodeIfExists2(newScheme,URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);return this};URI.prototype.setRawScheme=function(newScheme){this.scheme_=newScheme?newScheme:null;return this};URI.prototype.hasScheme=function(){return null!==this.scheme_};URI.prototype.getCredentials=function(){return this.credentials_&&decodeURIComponent(this.credentials_)};URI.prototype.getRawCredentials=function(){return this.credentials_};URI.prototype.setCredentials=function(newCredentials){this.credentials_=encodeIfExists2(newCredentials,URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);return this};URI.prototype.setRawCredentials=function(newCredentials){this.credentials_=newCredentials?newCredentials:null;return this};URI.prototype.hasCredentials=function(){return null!==this.credentials_};URI.prototype.getDomain=function(){return this.domain_&&decodeURIComponent(this.domain_)};URI.prototype.getRawDomain=function(){return this.domain_};URI.prototype.setDomain=function(newDomain){return this.setRawDomain(newDomain&&encodeURIComponent(newDomain))};URI.prototype.setRawDomain=function(newDomain){this.domain_=newDomain?newDomain:null;return this.setRawPath(this.path_)};URI.prototype.hasDomain=function(){return null!==this.domain_};URI.prototype.getPort=function(){return this.port_&&decodeURIComponent(this.port_)};URI.prototype.setPort=function(newPort){if(newPort){newPort=Number(newPort);if(newPort!==(newPort&65535)){throw new Error("Bad port number "+newPort)}this.port_=""+newPort}else{this.port_=null}return this};URI.prototype.hasPort=function(){return null!==this.port_};URI.prototype.getPath=function(){return this.path_&&decodeURIComponent(this.path_)};URI.prototype.getRawPath=function(){return this.path_};URI.prototype.setPath=function(newPath){return this.setRawPath(encodeIfExists2(newPath,URI_DISALLOWED_IN_PATH_))};URI.prototype.setRawPath=function(newPath){if(newPath){newPath=String(newPath);this.path_=!this.domain_||/^\//.test(newPath)?newPath:"/"+newPath}else{this.path_=null}return this};URI.prototype.hasPath=function(){return null!==this.path_};URI.prototype.getQuery=function(){return this.query_&&decodeURIComponent(this.query_).replace(/\+/g," ")};URI.prototype.getRawQuery=function(){return this.query_};URI.prototype.setQuery=function(newQuery){this.paramCache_=null;this.query_=encodeIfExists(newQuery);return this};URI.prototype.setRawQuery=function(newQuery){this.paramCache_=null;this.query_=newQuery?newQuery:null;return this};URI.prototype.hasQuery=function(){return null!==this.query_};URI.prototype.setAllParameters=function(params){if(typeof params==="object"){if(!(params instanceof Array)&&(params instanceof Object||Object.prototype.toString.call(params)!=="[object Array]")){var newParams=[];var i=-1;for(var k in params){var v=params[k];if("string"===typeof v){newParams[++i]=k;newParams[++i]=v}}params=newParams}}this.paramCache_=null;var queryBuf=[];var separator="";for(var j=0;j0?matchPart:null}var URI_RE_=new RegExp("^"+"(?:"+"([^:/?#]+)"+":)?"+"(?://"+"(?:([^/?#]*)@)?"+"([^/?#:@]*)"+"(?::([0-9]+))?"+")?"+"([^?#]+)?"+"(?:\\?([^#]*))?"+"(?:#(.*))?"+"$");var URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_=/[#\/\?@]/g;var URI_DISALLOWED_IN_PATH_=/[\#\?]/g;URI.parse=parse;URI.create=create;URI.resolve=resolve;URI.collapse_dots=collapse_dots;URI.utils={mimeTypeOf:function(uri){var uriObj=parse(uri);if(/\.html$/.test(uriObj.getPath())){return"text/html"}else{return"application/javascript"}},resolve:function(base,uri){if(base){return resolve(parse(base),parse(uri)).toString()}else{return""+uri}}};return URI}();var html4={};html4.atype={NONE:0,URI:1,URI_FRAGMENT:11,SCRIPT:2,STYLE:3,HTML:12,ID:4,IDREF:5,IDREFS:6,GLOBAL_NAME:7,LOCAL_NAME:8,CLASSES:9,FRAME_TARGET:10,MEDIA_QUERY:13};html4["atype"]=html4.atype;html4.ATTRIBS={"*::class":9,"*::dir":0,"*::draggable":0,"*::hidden":0,"*::id":4,"*::inert":0,"*::itemprop":0,"*::itemref":6,"*::itemscope":0,"*::lang":0,"*::onblur":2,"*::onchange":2,"*::onclick":2,"*::ondblclick":2,"*::onfocus":2,"*::onkeydown":2,"*::onkeypress":2,"*::onkeyup":2,"*::onload":2,"*::onmousedown":2,"*::onmousemove":2,"*::onmouseout":2,"*::onmouseover":2,"*::onmouseup":2,"*::onreset":2,"*::onscroll":2,"*::onselect":2,"*::onsubmit":2,"*::onunload":2,"*::spellcheck":0,"*::style":3,"*::title":0,"*::translate":0,"a::accesskey":0,"a::coords":0,"a::href":1,"a::hreflang":0,"a::name":7,"a::onblur":2,"a::onfocus":2,"a::shape":0,"a::tabindex":0,"a::target":10,"a::type":0,"area::accesskey":0,"area::alt":0,"area::coords":0,"area::href":1,"area::nohref":0,"area::onblur":2,"area::onfocus":2,"area::shape":0,"area::tabindex":0,"area::target":10,"audio::controls":0,"audio::loop":0,"audio::mediagroup":5,"audio::muted":0,"audio::preload":0,"bdo::dir":0,"blockquote::cite":1,"br::clear":0,"button::accesskey":0,"button::disabled":0,"button::name":8,"button::onblur":2,"button::onfocus":2,"button::tabindex":0,"button::type":0,"button::value":0,"canvas::height":0,"canvas::width":0,"caption::align":0,"col::align":0,"col::char":0,"col::charoff":0,"col::span":0,"col::valign":0,"col::width":0,"colgroup::align":0,"colgroup::char":0,"colgroup::charoff":0,"colgroup::span":0,"colgroup::valign":0,"colgroup::width":0,"command::checked":0,"command::command":5,"command::disabled":0,"command::icon":1,"command::label":0,"command::radiogroup":0,"command::type":0,"data::value":0,"del::cite":1,"del::datetime":0,"details::open":0,"dir::compact":0,"div::align":0,"dl::compact":0,"fieldset::disabled":0,"font::color":0,"font::face":0,"font::size":0,"form::accept":0,"form::action":1,"form::autocomplete":0,"form::enctype":0,"form::method":0,"form::name":7,"form::novalidate":0,"form::onreset":2,"form::onsubmit":2,"form::target":10,"h1::align":0,"h2::align":0,"h3::align":0,"h4::align":0,"h5::align":0,"h6::align":0,"hr::align":0,"hr::noshade":0,"hr::size":0,"hr::width":0,"iframe::align":0,"iframe::frameborder":0,"iframe::height":0,"iframe::marginheight":0,"iframe::marginwidth":0,"iframe::width":0,"img::align":0,"img::alt":0,"img::border":0,"img::height":0,"img::hspace":0,"img::ismap":0,"img::name":7,"img::src":1,"img::usemap":11,"img::vspace":0,"img::width":0,"input::accept":0,"input::accesskey":0,"input::align":0,"input::alt":0,"input::autocomplete":0,"input::checked":0,"input::disabled":0,"input::inputmode":0,"input::ismap":0,"input::list":5,"input::max":0,"input::maxlength":0,"input::min":0,"input::multiple":0,"input::name":8,"input::onblur":2,"input::onchange":2,"input::onfocus":2,"input::onselect":2,"input::placeholder":0,"input::readonly":0,"input::required":0,"input::size":0,"input::src":1,"input::step":0,"input::tabindex":0,"input::type":0,"input::usemap":11,"input::value":0,"ins::cite":1,"ins::datetime":0,"label::accesskey":0,"label::for":5,"label::onblur":2,"label::onfocus":2,"legend::accesskey":0,"legend::align":0,"li::type":0,"li::value":0,"map::name":7,"menu::compact":0,"menu::label":0,"menu::type":0,"meter::high":0,"meter::low":0,"meter::max":0,"meter::min":0,"meter::value":0,"ol::compact":0,"ol::reversed":0,"ol::start":0,"ol::type":0,"optgroup::disabled":0,"optgroup::label":0,"option::disabled":0,"option::label":0,"option::selected":0,"option::value":0,"output::for":6,"output::name":8,"p::align":0,"pre::width":0,"progress::max":0,"progress::min":0,"progress::value":0,"q::cite":1,"select::autocomplete":0,"select::disabled":0,"select::multiple":0,"select::name":8,"select::onblur":2,"select::onchange":2,"select::onfocus":2,"select::required":0,"select::size":0,"select::tabindex":0,"source::type":0,"table::align":0,"table::bgcolor":0,"table::border":0,"table::cellpadding":0,"table::cellspacing":0,"table::frame":0,"table::rules":0,"table::summary":0,"table::width":0,"tbody::align":0,"tbody::char":0,"tbody::charoff":0,"tbody::valign":0,"td::abbr":0,"td::align":0,"td::axis":0,"td::bgcolor":0,"td::char":0,"td::charoff":0,"td::colspan":0,"td::headers":6,"td::height":0,"td::nowrap":0,"td::rowspan":0,"td::scope":0,"td::valign":0,"td::width":0,"textarea::accesskey":0,"textarea::autocomplete":0,"textarea::cols":0,"textarea::disabled":0,"textarea::inputmode":0,"textarea::name":8,"textarea::onblur":2,"textarea::onchange":2,"textarea::onfocus":2,"textarea::onselect":2,"textarea::placeholder":0,"textarea::readonly":0,"textarea::required":0,"textarea::rows":0,"textarea::tabindex":0,"textarea::wrap":0,"tfoot::align":0,"tfoot::char":0,"tfoot::charoff":0,"tfoot::valign":0,"th::abbr":0,"th::align":0,"th::axis":0,"th::bgcolor":0,"th::char":0,"th::charoff":0,"th::colspan":0,"th::headers":6,"th::height":0,"th::nowrap":0,"th::rowspan":0,"th::scope":0,"th::valign":0,"th::width":0,"thead::align":0,"thead::char":0,"thead::charoff":0,"thead::valign":0,"tr::align":0,"tr::bgcolor":0,"tr::char":0,"tr::charoff":0,"tr::valign":0,"track::default":0,"track::kind":0,"track::label":0,"track::srclang":0,"ul::compact":0,"ul::type":0,"video::controls":0,"video::height":0,"video::loop":0,"video::mediagroup":5,"video::muted":0,"video::poster":1,"video::preload":0,"video::width":0};html4["ATTRIBS"]=html4.ATTRIBS;html4.eflags={OPTIONAL_ENDTAG:1,EMPTY:2,CDATA:4,RCDATA:8,UNSAFE:16,FOLDABLE:32,SCRIPT:64,STYLE:128,VIRTUALIZED:256};html4["eflags"]=html4.eflags;html4.ELEMENTS={a:0,abbr:0,acronym:0,address:0,applet:272,area:2,article:0,aside:0,audio:0,b:0,base:274,basefont:274,bdi:0,bdo:0,big:0,blockquote:0,body:305,br:2,button:0,canvas:0,caption:0,center:0,cite:0,code:0,col:2,colgroup:1,command:2,data:0,datalist:0,dd:1,del:0,details:0,dfn:0,dialog:272,dir:0,div:0,dl:0,dt:1,em:0,fieldset:0,figcaption:0,figure:0,font:0,footer:0,form:0,frame:274,frameset:272,h1:0,h2:0,h3:0,h4:0,h5:0,h6:0,head:305,header:0,hgroup:0,hr:2,html:305,i:0,iframe:4,img:2,input:2,ins:0,isindex:274,kbd:0,keygen:274,label:0,legend:0,li:1,link:274,map:0,mark:0,menu:0,meta:274,meter:0,nav:0,nobr:0,noembed:276,noframes:276,noscript:276,object:272,ol:0,optgroup:0,option:1,output:0,p:1,param:274,pre:0,progress:0,q:0,s:0,samp:0,script:84,section:0,select:0,small:0,source:2,span:0,strike:0,strong:0,style:148,sub:0,summary:0,sup:0,table:0,tbody:1,td:1,textarea:8,tfoot:1,th:1,thead:1,time:0,title:280,tr:1,track:2,tt:0,u:0,ul:0,"var":0,video:0,wbr:2};html4["ELEMENTS"]=html4.ELEMENTS;html4.ELEMENT_DOM_INTERFACES={a:"HTMLAnchorElement",abbr:"HTMLElement",acronym:"HTMLElement",address:"HTMLElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",article:"HTMLElement",aside:"HTMLElement",audio:"HTMLAudioElement",b:"HTMLElement",base:"HTMLBaseElement",basefont:"HTMLBaseFontElement",bdi:"HTMLElement",bdo:"HTMLElement",big:"HTMLElement",blockquote:"HTMLQuoteElement",body:"HTMLBodyElement",br:"HTMLBRElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",caption:"HTMLTableCaptionElement",center:"HTMLElement",cite:"HTMLElement",code:"HTMLElement",col:"HTMLTableColElement",colgroup:"HTMLTableColElement",command:"HTMLCommandElement",data:"HTMLElement",datalist:"HTMLDataListElement",dd:"HTMLElement",del:"HTMLModElement",details:"HTMLDetailsElement",dfn:"HTMLElement",dialog:"HTMLDialogElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",dl:"HTMLDListElement",dt:"HTMLElement",em:"HTMLElement",fieldset:"HTMLFieldSetElement",figcaption:"HTMLElement",figure:"HTMLElement",font:"HTMLFontElement",footer:"HTMLElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",h1:"HTMLHeadingElement",h2:"HTMLHeadingElement",h3:"HTMLHeadingElement",h4:"HTMLHeadingElement",h5:"HTMLHeadingElement",h6:"HTMLHeadingElement",head:"HTMLHeadElement",header:"HTMLElement",hgroup:"HTMLElement",hr:"HTMLHRElement",html:"HTMLHtmlElement",i:"HTMLElement",iframe:"HTMLIFrameElement",img:"HTMLImageElement",input:"HTMLInputElement",ins:"HTMLModElement",isindex:"HTMLUnknownElement",kbd:"HTMLElement",keygen:"HTMLKeygenElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",li:"HTMLLIElement",link:"HTMLLinkElement",map:"HTMLMapElement",mark:"HTMLElement",menu:"HTMLMenuElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",nav:"HTMLElement",nobr:"HTMLElement",noembed:"HTMLElement",noframes:"HTMLElement",noscript:"HTMLElement",object:"HTMLObjectElement",ol:"HTMLOListElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",s:"HTMLElement",samp:"HTMLElement",script:"HTMLScriptElement",section:"HTMLElement",select:"HTMLSelectElement",small:"HTMLElement",source:"HTMLSourceElement",span:"HTMLSpanElement",strike:"HTMLElement",strong:"HTMLElement",style:"HTMLStyleElement",sub:"HTMLElement",summary:"HTMLElement",sup:"HTMLElement",table:"HTMLTableElement",tbody:"HTMLTableSectionElement",td:"HTMLTableDataCellElement",textarea:"HTMLTextAreaElement",tfoot:"HTMLTableSectionElement",th:"HTMLTableHeaderCellElement",thead:"HTMLTableSectionElement",time:"HTMLTimeElement",title:"HTMLTitleElement",tr:"HTMLTableRowElement",track:"HTMLTrackElement",tt:"HTMLElement",u:"HTMLElement",ul:"HTMLUListElement","var":"HTMLElement",video:"HTMLVideoElement",wbr:"HTMLElement"};html4["ELEMENT_DOM_INTERFACES"]=html4.ELEMENT_DOM_INTERFACES;html4.ueffects={NOT_LOADED:0,SAME_DOCUMENT:1,NEW_DOCUMENT:2};html4["ueffects"]=html4.ueffects;html4.URIEFFECTS={"a::href":2,"area::href":2,"blockquote::cite":0,"command::icon":1,"del::cite":0,"form::action":2,"img::src":1,"input::src":1,"ins::cite":0,"q::cite":0,"video::poster":1};html4["URIEFFECTS"]=html4.URIEFFECTS;html4.ltypes={UNSANDBOXED:2,SANDBOXED:1,DATA:0};html4["ltypes"]=html4.ltypes;html4.LOADERTYPES={"a::href":2,"area::href":2,"blockquote::cite":2,"command::icon":1,"del::cite":2,"form::action":2,"img::src":1,"input::src":1,"ins::cite":2,"q::cite":2,"video::poster":1};html4["LOADERTYPES"]=html4.LOADERTYPES;if("I".toLowerCase()!=="i"){throw"I/i problem"}var html=function(html4){var parseCssDeclarations,sanitizeCssProperty,cssSchema;if("undefined"!==typeof window){parseCssDeclarations=window["parseCssDeclarations"];sanitizeCssProperty=window["sanitizeCssProperty"];cssSchema=window["cssSchema"]}var ENTITIES={lt:"<",LT:"<",gt:">",GT:">",amp:"&",AMP:"&",quot:'"',apos:"'",nbsp:" "};var decimalEscapeRe=/^#(\d+)$/;var hexEscapeRe=/^#x([0-9A-Fa-f]+)$/;var safeEntityNameRe=/^[A-Za-z][A-za-z0-9]+$/;var entityLookupElement="undefined"!==typeof window&&window["document"]?window["document"].createElement("textarea"):null;function lookupEntity(name){if(ENTITIES.hasOwnProperty(name)){return ENTITIES[name]}var m=name.match(decimalEscapeRe);if(m){return String.fromCharCode(parseInt(m[1],10))}else if(!!(m=name.match(hexEscapeRe))){return String.fromCharCode(parseInt(m[1],16))}else if(entityLookupElement&&safeEntityNameRe.test(name)){entityLookupElement.innerHTML="&"+name+";";var text=entityLookupElement.textContent;ENTITIES[name]=text;return text}else{return"&"+name+";"}}function decodeOneEntity(_,name){return lookupEntity(name)}var nulRe=/\0/g;function stripNULs(s){return s.replace(nulRe,"")}var ENTITY_RE_1=/&(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/g;var ENTITY_RE_2=/^(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/;function unescapeEntities(s){return s.replace(ENTITY_RE_1,decodeOneEntity)}var ampRe=/&/g;var looseAmpRe=/&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;var ltRe=/[<]/g;var gtRe=/>/g;var quotRe=/\"/g;function escapeAttrib(s){return(""+s).replace(ampRe,"&").replace(ltRe,"<").replace(gtRe,">").replace(quotRe,""")}function normalizeRCData(rcdata){return rcdata.replace(looseAmpRe,"&$1").replace(ltRe,"<").replace(gtRe,">")}var ATTR_RE=new RegExp("^\\s*"+"([-.:\\w]+)"+"(?:"+("\\s*(=)\\s*"+"("+('(")[^"]*("|$)'+"|"+"(')[^']*('|$)"+"|"+"(?=[a-z][-\\w]*\\s*=)"+"|"+"[^\"'\\s]*")+")")+")?","i");var splitWillCapture="a,b".split(/(,)/).length===3;var EFLAGS_TEXT=html4.eflags["CDATA"]|html4.eflags["RCDATA"];function makeSaxParser(handler){var hcopy={cdata:handler.cdata||handler["cdata"],comment:handler.comment||handler["comment"],endDoc:handler.endDoc||handler["endDoc"],endTag:handler.endTag||handler["endTag"],pcdata:handler.pcdata||handler["pcdata"],rcdata:handler.rcdata||handler["rcdata"],startDoc:handler.startDoc||handler["startDoc"],startTag:handler.startTag||handler["startTag"]};return function(htmlText,param){return parse(htmlText,hcopy,param)}}var continuationMarker={};function parse(htmlText,handler,param){var m,p,tagName;var parts=htmlSplit(htmlText);var state={noMoreGT:false,noMoreEndComments:false};parseCPS(handler,parts,0,state,param)}function continuationMaker(h,parts,initial,state,param){return function(){parseCPS(h,parts,initial,state,param)}}function parseCPS(h,parts,initial,state,param){try{if(h.startDoc&&initial==0){h.startDoc(param)}var m,p,tagName;for(var pos=initial,end=parts.length;pos"){pos+=2;tagName=m[1].toLowerCase();if(h.endTag){h.endTag(tagName,param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}else{pos=parseEndTag(parts,pos,h,param,continuationMarker,state)}}else{if(h.pcdata){h.pcdata("</",param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}break;case"<":if(m=/^([-\w:]+)\s*\/?/.exec(next)){if(m[0].length===next.length&&parts[pos+1]===">"){pos+=2;tagName=m[1].toLowerCase();if(h.startTag){h.startTag(tagName,[],param,continuationMarker,continuationMaker(h,parts,pos,state,param))}var eflags=html4.ELEMENTS[tagName];if(eflags&EFLAGS_TEXT){var tag={name:tagName,next:pos,eflags:eflags};pos=parseText(parts,tag,h,param,continuationMarker,state)}}else{pos=parseStartTag(parts,pos,h,param,continuationMarker,state)}}else{if(h.pcdata){h.pcdata("<",param,continuationMarker,continuationMaker(h,parts,pos,state,param))}}break;case"', and - // repeated failure to find '-->' is quadratic. We avoid that by - // remembering when search for '-->' fails. - if (!state.noMoreEndComments) { - // A comment <\!--x--> is split into three tokens: - // '<\!--', 'x--', '>' - // We want to find the next '>' token that has a preceding '--'. - // pos is at the 'x--'. - for (p = pos + 1; p < end; p++) { - if (parts[p] === '>' && /--$/.test(parts[p - 1])) { break; } - } - if (p < end) { - if (h.comment) { - var comment = parts.slice(pos, p).join(''); - h.comment( - comment.substr(0, comment.length - 2), param, - continuationMarker, - continuationMaker(h, parts, p + 1, state, param)); - } - pos = p + 1; - } else { - state.noMoreEndComments = true; - } - } - if (state.noMoreEndComments) { - if (h.pcdata) { - h.pcdata('<!--', param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - } - break; - case '<\!': - if (!/^\w/.test(next)) { - if (h.pcdata) { - h.pcdata('<!', param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - } else { - // similar to noMoreEndComment logic - if (!state.noMoreGT) { - for (p = pos + 1; p < end; p++) { - if (parts[p] === '>') { break; } - } - if (p < end) { - pos = p + 1; - } else { - state.noMoreGT = true; - } - } - if (state.noMoreGT) { - if (h.pcdata) { - h.pcdata('<!', param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - } - } - break; - case '') { break; } - } - if (p < end) { - pos = p + 1; - } else { - state.noMoreGT = true; - } - } - if (state.noMoreGT) { - if (h.pcdata) { - h.pcdata('<?', param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - } - break; - case '>': - if (h.pcdata) { - h.pcdata(">", param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - break; - case '': - break; - default: - if (h.pcdata) { - h.pcdata(current, param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - break; - } - } - if (h.endDoc) { h.endDoc(param); } - } catch (e) { - if (e !== continuationMarker) { throw e; } - } - } - - // Split str into parts for the html parser. - function htmlSplit(str) { - // can't hoist this out of the function because of the re.exec loop. - var re = /(<\/|<\!--|<[!?]|[&<>])/g; - str += ''; - if (splitWillCapture) { - return str.split(re); - } else { - var parts = []; - var lastPos = 0; - var m; - while ((m = re.exec(str)) !== null) { - parts.push(str.substring(lastPos, m.index)); - parts.push(m[0]); - lastPos = m.index + m[0].length; - } - parts.push(str.substring(lastPos)); - return parts; - } - } - - function parseEndTag(parts, pos, h, param, continuationMarker, state) { - var tag = parseTagAndAttrs(parts, pos); - // drop unclosed tags - if (!tag) { return parts.length; } - if (h.endTag) { - h.endTag(tag.name, param, continuationMarker, - continuationMaker(h, parts, pos, state, param)); - } - return tag.next; - } - - function parseStartTag(parts, pos, h, param, continuationMarker, state) { - var tag = parseTagAndAttrs(parts, pos); - // drop unclosed tags - if (!tag) { return parts.length; } - if (h.startTag) { - h.startTag(tag.name, tag.attrs, param, continuationMarker, - continuationMaker(h, parts, tag.next, state, param)); - } - // tags like + +#### Your ` + +To create another table, simply repeat the steps except for `initiateTableFilter()` + +
+ + + + Learn more about the things you can do with [mustache.js](http://mustache.github.io/). + +### Sheetsee.makeTable(data, targetDiv) + +You'll call this to make a table out of a **data** and tell it what **targetDiv** in the html to render it in (this should also be the same id as your script template id) and how many **rows** you want it to show per "page" of the table. If you don't include the pagination number, it will default to showing all rows on one page. + + Sheetsee.makeTable(gData, "#siteTable", 10) + +## Table Filter/Search + +If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html: + + + Clear + no matches + +### Sheetsee.initiateTableFilter(data, filterDiv, tableDiv) + +You will then call this function to make that input live: + + Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable") diff --git a/docs/sheetsee.md b/docs/sheetsee.md new file mode 100644 index 00000000..6d4393dc --- /dev/null +++ b/docs/sheetsee.md @@ -0,0 +1,110 @@ +# sheetsee + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/sheetsee-03.png) + +This module contains the basic functions for sorting and munipulating data for use in your [sheetsee.js](http://jlord.github.io/sheetsee.js) endeavors. Below is the portion of the [sheetsee.js](http://jlord.github.io/sheetsee.js) readme that covers the use of these functions. For the complete documentation including genera what is sheetsee, go [here](http://jlord.github.io/sheetsee.js)! + +--- + +## Working With Your Data + +Tabletop.js will return all of your data and it will be passed into your site as an _array of objects_ called **gData**. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like. + +### Sheetsee.getGroupCount(data, groupTerm) + +This takes in your data, an _array of objects_, and searches for a _string_, **groupTerm**, in each piece of your **data** (formerly the cells of your spreadsheet). It returns the number of times it found the **groupTerm**. + + getGroupCount(gData, "cat") + // returns 2 + +### Sheetsee.getColumnTotal(data, column) + +Given your **data**, an _array of objects_ and a _string_ **column** header, this functions sums each cell in that column, so they best be numbers. + + getColumnTotal(gData, "cuddlability") + // returns 11 + +### Sheetsee.getAveragefromColumn(data, column) + +A really simple function that builds on `getColumnTotal()` by returning the average number in a **column** of numbers. + + getColumnAverage(gData, "cuddlability") + // returns 1.8333333333333333 + +### Sheetsee.getMin(data, column) + +This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the lowest number value in the **column** you specify from your **data**. + + getMin(gData, "cuddlability") + // returns {breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...} + +### Sheetsee.getMax(data, column) + +This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the highest number value in the **column** you specify from your **data**. + + getMin(gData, "cuddlability") + // returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...} + +### Don't Forget JavaScript Math + +Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that [here on MDN](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math). + + var profit09 = Sheetsee.getColumnTotal(gData, "2009") + var profit10 = Sheetsee.getColumnTotal(gData, "2010") + var difference = profit09 - profit10 + +#### What These Little Bits are Good For + +You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about [icanhas.js](http://icanhazjs.com/). View source on this page to see how I created "Most Cuddlable". + +### Sheetsee.getMatches(data, filter, category) + +Takes **data** as an _array of objects_, a _string_ you'd like to **filter** and a _string_ of the **category** you want it to look in (a column header from your spreadsheet). + + getMatches(gData, "dog", "kind") + +Returns an _array of objects_ matching the category's filter. + + [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ] + + +### Sheetsee.getOccurance(data, category) + +Takes **data** as an _array of objects_ and a _string_ for **category** (a column header from your spreadsheet) you want tally how often an element occured. + + getOccurance(gData, "kind") + +Returns an object with keys and values for each variation of the category and its occurance. + + {"dog": 3, "cat": 3} + +### Sheetsee.makeColorArrayOfObject(data, colors) + +If you use `getOccurance()` and want to then chart that data with d3.js, you'll need to make it into an _array_ (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset). + +This function takes in your data, as an _object_, and an _array_ of hexidecimal color strings which you define. + + var kinds = getOccurance(gData, "kind") + var kindColors = ["#ff00ff", "#DCF13C"] + + var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors) + +It will return an array of objects formatted to go directly into a d3 chart with the appropriate _units_ and _label keys_, like so: + + [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}] + +If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements. + +### Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits) + +If you're using gData, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number). + + var gData = [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}] + +For istance, if from our original data above we want to chart the age of each cat, we'll use: + + Sheetsee.addUnitsLabels(gData, "name", "cuddlability") + +Which will return an array, ready for the d3 charts: + + [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}] \ No newline at end of file diff --git a/docs/tips.md b/docs/tips.md new file mode 100644 index 00000000..e69de29b diff --git a/index.html b/index.html index 166cf190..4c8c80f3 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,13 @@ Yo, yo, yo! - - - + + + + - + @@ -16,17 +17,16 @@ diff --git a/js/jquery.js b/js/jquery.js new file mode 100644 index 00000000..56278964 --- /dev/null +++ b/js/jquery.js @@ -0,0 +1,4 @@ +/*! jQuery v1.7.2 jquery.com | jquery.org/license */ +(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="
"+""+"
",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
t
",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( +a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f +.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); diff --git a/js/sheetsee.js b/js/sheetsee.js new file mode 100644 index 00000000..b0293944 --- /dev/null +++ b/js/sheetsee.js @@ -0,0 +1,25185 @@ +!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.Sheetsee=e():"undefined"!=typeof global?global.Sheetsee=e():"undefined"!=typeof self&&(self.Sheetsee=e())}(function(){var define,module,exports; +return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o b ? 1 : a >= b ? 0 : NaN; + }; + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + function d3_number(x) { + return x != null && !isNaN(x); + } + d3.mean = function(array, f) { + var n = array.length, a, m = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; + } + return j ? m : undefined; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; + }; + d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + }; + var d3_bisector = d3.bisector(function(d) { + return d; + }); + d3.bisectLeft = d3_bisector.left; + d3.bisect = d3.bisectRight = d3_bisector.right; + d3.shuffle = function(array) { + var m = array.length, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m], array[m] = array[i], array[i] = t; + } + return array; + }; + d3.permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + function d3_zipLength(d) { + return d.length; + } + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); + }; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_class(ctor, properties) { + try { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } catch (e) { + ctor.prototype = properties; + } + } + d3.map = function(object) { + var map = new d3_Map(); + if (object instanceof d3_Map) object.forEach(function(key, value) { + map.set(key, value); + }); else for (var key in object) map.set(key, object[key]); + return map; + }; + function d3_Map() {} + d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { + keys.push(key); + }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { + values.push(value); + }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { + entries.push({ + key: key, + value: value + }); + }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); + } + } + } + }); + var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + d3.nest = function() { + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; + } + valuesByKey.forEach(setter); + return object; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var array = [], sortKey = sortKeys[depth++]; + map.forEach(function(key, keyMap) { + array.push({ + key: key, + values: entries(keyMap, depth) + }); + }); + return sortKey ? array.sort(function(a, b) { + return sortKey(a.key, b.key); + }) : array; + } + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); + return set; + }; + function d3_Set() {} + d3_class(d3_Set, { + has: function(value) { + return d3_map_prefix + value in this; + }, + add: function(value) { + this[d3_map_prefix + value] = true; + return value; + }, + remove: function(value) { + value = d3_map_prefix + value; + return value in this && delete this[value]; + }, + values: function() { + var values = []; + this.forEach(function(value) { + values.push(value); + }); + return values; + }, + forEach: function(f) { + for (var value in this) { + if (value.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, value.substring(1)); + } + } + } + }); + d3.behavior = {}; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; + } + function d3_vendorSymbol(object, name) { + if (name in object) return name; + name = name.charAt(0).toUpperCase() + name.substring(1); + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { + var prefixName = d3_vendorPrefixes[i] + name; + if (prefixName in object) return prefixName; + } + } + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; + var d3_array = d3_arraySlice; + function d3_arrayCopy(pseudoarray) { + var i = pseudoarray.length, array = new Array(i); + while (i--) array[i] = pseudoarray[i]; + return array; + } + function d3_arraySlice(pseudoarray) { + return Array.prototype.slice.call(pseudoarray); + } + try { + d3_array(d3_documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = d3_arrayCopy; + } + function d3_noop() {} + d3.dispatch = function() { + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + function d3_dispatch() {} + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i >= 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); + } + return this; + } + }; + function d3_dispatch_event(dispatch) { + var listeners = [], listenerByName = new d3_Map(); + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + d3.event = null; + function d3_eventPreventDefault() { + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + var d3_subclass = {}.__proto__ ? function(object, prototype) { + object.__proto__ = prototype; + } : function(object, prototype) { + for (var property in prototype) object[property] = prototype[property]; + }; + function d3_selection(groups) { + d3_subclass(groups, d3_selectionPrototype); + return groups; + } + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = function(s, n) { + return Sizzle.uniqueSort(Sizzle(s, n)); + }; + d3_selectMatches = Sizzle.matchesSelector; + } + d3.selection = function() { + return d3_selectionRoot; + }; + var d3_selectionPrototype = d3.selection.prototype = []; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selector(selector) { + return typeof selector === "function" ? selector : function() { + return d3_select(selector, this); + }; + } + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selectorAll(selector) { + return typeof selector === "function" ? selector : function() { + return d3_selectAll(selector, this); + }; + } + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classed(name, value) { + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; + if (value) { + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); + } else { + node.setAttribute("class", d3_collapse(c.replace(re, " "))); + } + }; + } + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + d3_selectionPrototype.text = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }) : this.node().textContent; + }; + d3_selectionPrototype.html = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }) : this.node().innerHTML; + }; + d3_selectionPrototype.append = function(name) { + name = d3_selection_creator(name); + return this.select(function() { + return this.appendChild(name.apply(this, arguments)); + }); + }; + function d3_selection_creator(name) { + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { + return d3_document.createElementNS(name.space, name.local); + } : function() { + return d3_document.createElementNS(this.namespaceURI, name); + }; + } + d3_selectionPrototype.insert = function(name, before) { + name = d3_selection_creator(name); + before = d3_selection_selector(before); + return this.select(function() { + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); + }); + }; + d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + }); + }; + d3_selectionPrototype.data = function(value, key) { + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; + for (i = -1; ++i < n; ) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues.push(keyValue); + } + for (i = -1; ++i < m; ) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (node = nodeByKeyValue.get(keyValue)) { + updateNodes[i] = node; + node.__data__ = nodeData; + } else if (!dataByKeyValue.has(keyValue)) { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + dataByKeyValue.set(keyValue, nodeData); + nodeByKeyValue.remove(keyValue); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValues[i])) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + } + for (;i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (;i < n; ++i) { + exitNodes[i] = group[i]; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + d3_selectionPrototype.datum = function(value) { + return arguments.length ? this.property("__data__", value) : this.property("__data__"); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; + }; + } + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.size = function() { + var n = 0; + this.each(function() { + ++n; + }); + return n; + }; + function d3_selection_enter(selection) { + d3_subclass(selection, d3_selection_enterPrototype); + return selection; + } + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.call = d3_selectionPrototype.call; + d3_selection_enterPrototype.size = d3_selectionPrototype.size; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selection_enterPrototype.insert = function(name, before) { + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); + return d3_selectionPrototype.insert.call(this, name, before); + }; + function d3_selection_enterInsertBefore(enter) { + var i0, j0; + return function(d, i, j) { + var group = enter[j].update, n = group.length, node; + if (j != j0) j0 = j, i0 = 0; + if (i >= i0) i0 = i + 1; + while (!(node = group[i0]) && ++i0 < n) ; + return node; + }; + } + d3_selectionPrototype.transition = function() { + var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { + time: Date.now(), + ease: d3_ease_cubicInOut, + delay: 0, + duration: 250 + }; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) d3_transitionNode(node, i, id, transition); + subgroup.push(node); + } + } + return d3_transition(subgroups, id); + }; + d3.select = function(node) { + var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + d3.selectAll = function(nodes) { + var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + var d3_selectionRoot = d3.select(d3_documentElement); + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + function d3_selection_on(type, listener, capture) { + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; + if (i > 0) type = type.substring(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); + delete this[name]; + } + } + } + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; + } + var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }); + d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); + }); + function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; + } + }; + } + function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { + l.call(target, e); + } + }; + } + var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; + function d3_event_dragSuppress() { + var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; + style[d3_event_dragSelect] = "none"; + return function(suppressClick) { + w.on(name, null); + style[d3_event_dragSelect] = select; + if (suppressClick) { + function off() { + w.on(click, null); + } + w.on(click, function() { + d3_eventPreventDefault(); + off(); + }, true); + setTimeout(off, 0); + } + }; + } + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; + function d3_mousePoint(container, e) { + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select("body").append("svg").style({ + position: "absolute", + top: 0, + left: 0, + margin: 0, + padding: 0, + border: "none" + }, "important"); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) { + point.x = e.pageX; + point.y = e.pageY; + } else { + point.x = e.clientX; + point.y = e.clientY; + } + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + d3.behavior.drag = function() { + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); + } + function touchid() { + return d3.event.changedTouches[0].identifier; + } + function touchposition(parent, id) { + return d3.touches(parent).filter(function(p) { + return p.identifier === id; + })[0]; + } + function dragstart(id, position, move, end) { + return function() { + var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); + if (origin) { + offset = origin.apply(target, arguments); + offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + } else { + offset = [ 0, 0 ]; + } + event_({ + type: "dragstart" + }); + function moved() { + if (!parent) return ended(); + var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; + dragged |= dx | dy; + origin_ = p; + event_({ + type: "drag", + x: p[0] + offset[0], + y: p[1] + offset[1], + dx: dx, + dy: dy + }); + } + function ended() { + w.on(move + "." + drag, null).on(end + "." + drag, null); + dragRestore(dragged && d3.event.target === eventTarget); + event_({ + type: "dragend" + }); + } + }; + } + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + d3.behavior.zoom = function() { + var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1; + function zoom() { + this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); + } + zoom.translate = function(x) { + if (!arguments.length) return translate; + translate = x.map(Number); + rescale(); + return zoom; + }; + zoom.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + rescale(); + return zoom; + }; + zoom.scaleExtent = function(x) { + if (!arguments.length) return scaleExtent; + scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + function location(p) { + return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; + } + function point(l) { + return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; + } + function scaleTo(s) { + scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + translate[0] += p[0] - l[0]; + translate[1] += p[1] - l[1]; + } + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - translate[0]) / scale; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - translate[1]) / scale; + }).map(y0.invert)); + } + function dispatch(event) { + rescale(); + event({ + type: "zoom", + scale: scale, + translate: translate + }); + } + function mousedowned() { + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); + function moved() { + dragged = 1; + translateTo(d3.mouse(target), l); + dispatch(event_); + } + function ended() { + w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); + dragRestore(dragged && d3.event.target === eventTarget); + } + } + function touchstarted() { + var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); + started(); + function relocate() { + var touches = d3.touches(target); + scale0 = scale; + locations0 = {}; + touches.forEach(function(t) { + locations0[t.identifier] = location(t); + }); + return touches; + } + function started() { + var now = Date.now(), touches = relocate(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0], l = locations0[p.identifier]; + scaleTo(scale * 2); + translateTo(p, l); + d3_eventPreventDefault(); + dispatch(event_); + } + touchtime = now; + } else if (touches.length > 1) { + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; + distance0 = dx * dx + dy * dy; + } + } + function moved() { + var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier]; + if (p1 = touches[1]) { + var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale; + if (scale1 == null) { + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; + scale1 = distance0 && Math.sqrt(distance1 / distance0); + } + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(scale1 * scale0); + } + touchtime = null; + translateTo(p0, l0); + dispatch(event_); + } + function ended() { + if (d3.event.touches.length) { + relocate(); + } else { + w.on(touchmove, null).on(touchend, null); + t.on(mousedown, mousedowned).on(touchstart, touchstarted); + dragRestore(); + } + } + } + function mousewheeled() { + d3_eventPreventDefault(); + if (!translate0) translate0 = location(d3.mouse(this)); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); + translateTo(d3.mouse(this), translate0); + dispatch(event.of(this, arguments)); + } + function mousewheelreset() { + translate0 = null; + } + function dblclicked() { + var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; + scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomInfinity = [ 0, Infinity ]; + var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return d3.event.wheelDelta; + }, "mousewheel") : (d3_behavior_zoomDelta = function() { + return -d3.event.detail; + }, "MozMousePixelScroll"); + function d3_Color() {} + d3_Color.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.hsl = function(h, s, l) { + return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); + }; + function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); + } + function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; + } + var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); + d3_hslPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); + }; + d3_hslPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); + }; + d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + function d3_hsl_rgb(h, s, l) { + var m1, m2; + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; + function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + function d3_acos(x) { + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); + } + function d3_asin(x) { + return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); + } + function d3_sinh(x) { + return (Math.exp(x) - Math.exp(-x)) / 2; + } + function d3_cosh(x) { + return (Math.exp(x) + Math.exp(-x)) / 2; + } + function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; + } + d3.hcl = function(h, c, l) { + return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); + }; + function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); + } + function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; + } + var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); + d3_hclPrototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + function d3_hcl_lab(h, c, l) { + if (isNaN(h)) h = 0; + if (isNaN(c)) c = 0; + return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); + } + d3.lab = function(l, a, b) { + return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); + }; + function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); + } + function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; + } + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + var d3_labPrototype = d3_Lab.prototype = new d3_Color(); + d3_labPrototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + d3.rgb = function(r, g, b) { + return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); + }; + function d3_rgbNumber(value) { + return d3_rgb(value >> 16, value >> 8 & 255, value & 255); + } + function d3_rgbString(value) { + return d3_rgbNumber(value) + ""; + } + function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); + } + function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + } + var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); + d3_rgbPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); + }; + d3_rgbPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); + }; + d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, name; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); + r += r; + g = format.charAt(2); + g += g; + b = format.charAt(3); + b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + h = NaN; + s = l > 0 && l < 1 ? 0 : h; + } + return d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + var d3_rgb_names = d3.map({ + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgbNumber(value)); + }); + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + d3.functor = d3_functor; + function d3_identity(d) { + return d; + } + d3.xhr = d3_xhrType(d3_identity); + function d3_xhrType(response) { + return function(url, mimeType, callback) { + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, + mimeType = null; + return d3_xhr(url, mimeType, response, callback); + }; + } + function d3_xhr(url, mimeType, response, callback) { + var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; + if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { + request.readyState > 3 && respond(); + }; + function respond() { + var status = request.status, result; + if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { + try { + result = response.call(xhr, request); + } catch (e) { + dispatch.error.call(xhr, e); + return; + } + dispatch.load.call(xhr, result); + } else { + dispatch.error.call(xhr, request); + } + } + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { + dispatch.progress.call(xhr, request); + } finally { + d3.event = o; + } + }; + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; else headers[name] = value + ""; + return xhr; + }; + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; + }; + xhr.responseType = function(value) { + if (!arguments.length) return responseType; + responseType = value; + return xhr; + }; + xhr.response = function(value) { + response = value; + return xhr; + }; + [ "get", "post" ].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); + }; + }); + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (responseType != null) request.responseType = responseType; + if (callback != null) xhr.on("error", callback).on("load", function(request) { + callback(null, request); + }); + request.send(data == null ? null : data); + return xhr; + }; + xhr.abort = function() { + request.abort(); + return xhr; + }; + d3.rebind(xhr, dispatch, "on"); + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); + } + function d3_xhr_fixCallback(callback) { + return callback.length === 1 ? function(error, request) { + callback(error == null ? request : null); + } : callback; + } + d3.dsv = function(delimiter, mimeType) { + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + function dsv(url, row, callback) { + if (arguments.length < 3) callback = row, row = null; + var xhr = d3.xhr(url, mimeType, callback); + xhr.row = function(_) { + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; + }; + return xhr.row(row); + } + function response(request) { + return dsv.parse(request.responseText); + } + function typedResponse(f) { + return function(request) { + return dsv.parse(request.responseText, f); + }; + } + dsv.parse = function(text, f) { + var o; + return dsv.parseRows(text, function(row, i) { + if (o) return o(row, i - 1); + var a = new Function("d", "return {" + row.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "]"; + }).join(",") + "}"); + o = f ? function(row, i) { + return f(a(row), i); + } : a; + }); + }; + dsv.parseRows = function(text, f) { + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; + function token() { + if (I >= N) return EOF; + if (eol) return eol = false, EOL; + var j = I; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < N) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + ++i; + } + } + I = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) ++I; + } else if (c === 10) { + eol = true; + } + return text.substring(j + 1, i).replace(/""/g, '"'); + } + while (I < N) { + var c = text.charCodeAt(I++), k = 1; + if (c === 10) eol = true; else if (c === 13) { + eol = true; + if (text.charCodeAt(I) === 10) ++I, ++k; + } else if (c !== delimiterCode) continue; + return text.substring(j, I - k); + } + return text.substring(j); + } + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && !(a = f(a, n++))) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + if (Array.isArray(rows[0])) return dsv.formatRows(rows); + var fieldSet = new d3_Set(), fields = []; + rows.forEach(function(row) { + for (var field in row) { + if (!fieldSet.has(field)) { + fields.push(fieldSet.add(field)); + } + } + }); + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { + return fields.map(function(field) { + return formatValue(row[field]); + }).join(delimiter); + })).join("\n"); + }; + dsv.formatRows = function(rows) { + return rows.map(formatRow).join("\n"); + }; + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + return dsv; + }; + d3.csv = d3.dsv(",", "text/csv"); + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { + setTimeout(callback, 17); + }; + d3.timer = function(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + var time = then + delay, timer = { + callback: callback, + time: time, + next: null + }; + if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; + d3_timer_queueTail = timer; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + function d3_timer_step() { + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + d3.timer.flush = function() { + d3_timer_mark(); + d3_timer_sweep(); + }; + function d3_timer_replace(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + d3_timer_active.callback = callback; + d3_timer_active.time = then + delay; + } + function d3_timer_mark() { + var now = Date.now(); + d3_timer_active = d3_timer_queueHead; + while (d3_timer_active) { + if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); + d3_timer_active = d3_timer_active.next; + } + return now; + } + function d3_timer_sweep() { + var t0, t1 = d3_timer_queueHead, time = Infinity; + while (t1) { + if (t1.flush) { + t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; + } else { + if (t1.time < time) time = t1.time; + t1 = (t0 = t1).next; + } + } + d3_timer_queueTail = t0; + return time; + } + var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + function d3_formatPrefix(d, i) { + var k = Math.pow(10, Math.abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + d3.format = function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; + if (precision) precision = +precision.substring(1); + if (zfill || fill === "0" && align === "=") { + zfill = fill = "0"; + align = "="; + if (comma) width -= Math.floor((width - 1) / 4); + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + + case "b": + case "o": + case "x": + case "X": + if (symbol === "#") symbol = "0" + type.toLowerCase(); + + case "c": + case "d": + integer = true; + precision = 0; + break; + + case "s": + scale = -1; + type = "r"; + break; + } + if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; + if (type == "r" && !precision) type = "g"; + if (precision != null) { + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); + } + type = d3_format_types.get(type) || d3_format_typeDefault; + var zcomma = zfill && comma; + return function(value) { + if (integer && value % 1) return ""; + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; + if (scale < 0) { + var prefix = d3.formatPrefix(value, precision); + value = prefix.scale(value); + suffix = prefix.symbol; + } else { + value *= scale; + } + value = type(value, precision); + var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); + if (!zfill && comma) before = d3_format_group(before); + var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; + if (zcomma) before = d3_format_group(padding + before); + negative += symbol; + value = before + after; + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; + }; + }; + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; + var d3_format_types = d3.map({ + b: function(x) { + return x.toString(2); + }, + c: function(x) { + return String.fromCharCode(x); + }, + o: function(x) { + return x.toString(8); + }, + x: function(x) { + return x.toString(16); + }, + X: function(x) { + return x.toString(16).toUpperCase(); + }, + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); + } + }); + function d3_format_precision(x, p) { + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); + } + function d3_format_typeDefault(x) { + return x + ""; + } + var d3_format_group = d3_identity; + if (d3_format_grouping) { + var d3_format_groupingLength = d3_format_grouping.length; + d3_format_group = function(value) { + var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; + while (i > 0 && g > 0) { + t.push(value.substring(i -= g, i + g)); + g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; + } + return t.reverse().join(d3_format_thousandsSeparator); + }; + } + d3.geo = {}; + function d3_adder() {} + d3_adder.prototype = { + s: 0, + t: 0, + add: function(y) { + d3_adderSum(y, this.t, d3_adderTemp); + d3_adderSum(d3_adderTemp.s, this.s, this); + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; + }, + reset: function() { + this.s = this.t = 0; + }, + valueOf: function() { + return this.s; + } + }; + var d3_adderTemp = new d3_adder(); + function d3_adderSum(a, b, o) { + var x = o.s = a + b, bv = x - a, av = x - bv; + o.t = a - av + (b - bv); + } + d3.geo.stream = function(object, listener) { + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); + } + }; + function d3_geo_streamGeometry(geometry, listener) { + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); + } + } + var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); + } + }; + var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + var coordinate = object.coordinates; + listener.point(coordinate[0], coordinate[1]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); + } + }; + function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + listener.lineEnd(); + } + function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); + } + d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; + }; + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); + var d3_geo_area = { + sphere: function() { + d3_geo_areaSum += 4 * π; + }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_areaRingSum.reset(); + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * d3_geo_areaRingSum; + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } + }; + function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), + sinφ0 = Math.sin(φ); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; + var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); + d3_geo_areaRingSum.add(Math.atan2(v, u)); + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; + } + function d3_geo_cartesian(spherical) { + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; + } + function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + function d3_geo_cartesianCross(a, b) { + return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; + } + function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + } + function d3_geo_cartesianScale(vector, k) { + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; + } + function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; + } + function d3_geo_spherical(cartesian) { + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; + } + function d3_geo_sphericalEqual(a, b) { + return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; + } + d3.geo.bounds = function() { + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; + var bound = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + bound.point = ringPoint; + bound.lineStart = ringStart; + bound.lineEnd = ringEnd; + dλSum = 0; + d3_geo_area.polygonStart(); + }, + polygonEnd: function() { + d3_geo_area.polygonEnd(); + bound.point = point; + bound.lineStart = lineStart; + bound.lineEnd = lineEnd; + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; + range[0] = λ0, range[1] = λ1; + } + }; + function point(λ, φ) { + ranges.push(range = [ λ0 = λ, λ1 = λ ]); + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + function linePoint(λ, φ) { + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); + if (p0) { + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); + d3_geo_cartesianNormalize(inflection); + inflection = d3_geo_spherical(inflection); + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = inflection[1] * d3_degrees; + if (φi > φ1) φ1 = φi; + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = -inflection[1] * d3_degrees; + if (φi < φ0) φ0 = φi; + } else { + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + if (antimeridian) { + if (λ < λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } else { + if (λ1 >= λ0) { + if (λ < λ0) λ0 = λ; + if (λ > λ1) λ1 = λ; + } else { + if (λ > λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } + } + } else { + point(λ, φ); + } + p0 = p, λ_ = λ; + } + function lineStart() { + bound.point = linePoint; + } + function lineEnd() { + range[0] = λ0, range[1] = λ1; + bound.point = point; + p0 = null; + } + function ringPoint(λ, φ) { + if (p0) { + var dλ = λ - λ_; + dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; + } else λ__ = λ, φ__ = φ; + d3_geo_area.point(λ, φ); + linePoint(λ, φ); + } + function ringStart() { + d3_geo_area.lineStart(); + } + function ringEnd() { + ringPoint(λ__, φ__); + d3_geo_area.lineEnd(); + if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); + range[0] = λ0, range[1] = λ1; + p0 = null; + } + function angle(λ0, λ1) { + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; + } + function compareRanges(a, b) { + return a[0] - b[0]; + } + function withinRange(x, range) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; + } + return function(feature) { + φ1 = λ1 = -(λ0 = φ0 = Infinity); + ranges = []; + d3.geo.stream(feature, bound); + var n = ranges.length; + if (n) { + ranges.sort(compareRanges); + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { + b = ranges[i]; + if (withinRange(b[0], a) || withinRange(b[1], a)) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + var best = -Infinity, dλ; + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { + b = merged[i]; + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; + } + } + ranges = range = null; + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; + }; + }(); + d3.geo.centroid = function(object) { + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, d3_geo_centroid); + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; + if (m < ε2) { + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; + m = x * x + y * y + z * z; + if (m < ε2) return [ NaN, NaN ]; + } + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; + }; + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; + var d3_geo_centroid = { + sphere: d3_noop, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } + }; + function d3_geo_centroidPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); + } + function d3_geo_centroidPointXYZ(x, y, z) { + ++d3_geo_centroidW0; + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; + } + function d3_geo_centroidLineStart() { + var x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; + } + function d3_geo_centroidRingStart() { + var λ00, φ00, x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ00 = λ, φ00 = φ; + d3_geo_centroid.point = nextPoint; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + d3_geo_centroid.lineEnd = function() { + nextPoint(λ00, φ00); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + d3_geo_centroid.point = d3_geo_centroidPoint; + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); + d3_geo_centroidX2 += v * cx; + d3_geo_centroidY2 += v * cy; + d3_geo_centroidZ2 += v * cz; + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_true() { + return true; + } + function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { + var subject = [], clip = []; + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; + } + var a = { + point: p0, + points: segment, + other: null, + visited: false, + entry: true, + subject: true + }, b = { + point: p0, + points: [ p0 ], + other: a, + visited: false, + entry: false, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + a = { + point: p1, + points: [ p1 ], + other: null, + visited: false, + entry: false, + subject: true + }; + b = { + point: p1, + points: [ p1 ], + other: a, + visited: false, + entry: true, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { + clip[i].entry = e = !e; + } + var start = subject[0], current, points, point; + while (1) { + current = start; + while (current.visited) if ((current = current.next) === start) return; + points = current.points; + listener.lineStart(); + do { + current.visited = current.other.visited = true; + if (current.entry) { + if (current.subject) { + for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.next.point, 1, listener); + } + current = current.next; + } else { + if (current.subject) { + points = current.prev.points; + for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.prev.point, -1, listener); + } + current = current.prev; + } + current = current.other; + points = current.points; + } while (!current.visited); + listener.lineEnd(); + } + } + function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, i = 0, a = array[0], b; + while (++i < n) { + a.next = b = array[i]; + b.prev = a; + a = b; + } + a.next = b = array[0]; + b.prev = a; + } + function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { + return function(listener) { + var line = clipLine(listener); + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + listener.polygonStart(); + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = d3.merge(segments); + if (segments.length) { + d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); + } else if (polygonContains(polygon)) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + listener.polygonEnd(); + segments = polygon = null; + }, + sphere: function() { + listener.polygonStart(); + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + listener.polygonEnd(); + } + }; + function point(λ, φ) { + if (pointVisible(λ, φ)) listener.point(λ, φ); + } + function pointLine(λ, φ) { + line.point(λ, φ); + } + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + var segments; + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; + function pointRing(λ, φ) { + ringListener.point(λ, φ); + ring.push([ λ, φ ]); + } + function ringStart() { + ringListener.lineStart(); + ring = []; + } + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; + ring.pop(); + polygon.push(ring); + ring = null; + if (!n) return; + if (clean & 1) { + segment = ringSegments[0]; + var n = segment.length - 1, i = -1, point; + listener.lineStart(); + while (++i < n) listener.point((point = segment[i])[0], point[1]); + listener.lineEnd(); + return; + } + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); + } + return clip; + }; + } + function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; + } + function d3_geo_clipBufferListener() { + var lines = [], line; + return { + lineStart: function() { + lines.push(line = []); + }, + point: function(λ, φ) { + line.push([ λ, φ ]); + }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; + } + function d3_geo_clipSort(a, b) { + return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); + } + function d3_geo_pointInPolygon(point, polygon) { + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; + d3_geo_areaRingSum.reset(); + for (var i = 0, n = polygon.length; i < n; ++i) { + var ring = polygon[i], m = ring.length; + if (!m) continue; + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; + while (true) { + if (j === m) j = 0; + point = ring[j]; + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; + d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); + if (Math.abs(φ) < ε) southPole = true; + polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); + d3_geo_cartesianNormalize(arc); + var intersection = d3_geo_cartesianCross(meridianNormal, arc); + d3_geo_cartesianNormalize(intersection); + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); + if (parallel > φarc) { + winding += antimeridian ^ dλ >= 0 ? 1 : -1; + } + } + if (!j++) break; + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; + } + if (Math.abs(polarAngle) > ε) polar = true; + } + return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; + } + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); + function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; + return { + lineStart: function() { + listener.lineStart(); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); + if (Math.abs(dλ - π) < ε) { + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point(λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { + if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { + listener.lineEnd(); + λ0 = φ0 = NaN; + }, + clean: function() { + return 2 - clean; + } + }; + } + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); + return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; + } + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * π / 2; + listener.point(-π, φ); + listener.point(0, φ); + listener.point(π, φ); + listener.point(π, 0); + listener.point(π, -φ); + listener.point(0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (Math.abs(from[0] - to[0]) > ε) { + var s = (from[0] < to[0] ? 1 : -1) * π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point(0, φ); + listener.point(s, φ); + } else { + listener.point(to[0], to[1]); + } + } + var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; + function d3_geo_clipAntimeridianPolygonContains(polygon) { + return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); + } + function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + return d3_geo_clip(visible, clipLine, interpolate, polygonContains); + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + function clipLine(listener) { + var point0, c0, v0, v00, clean; + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); + } + } + if (v !== v0) { + clean = 0; + if (v) { + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + clean: function() { + return clean | (v00 && v0) << 1; + } + }; + } + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; + if (!determinant) return !two && a; + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + if (t2 < 0) return; + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [ q, d3_geo_spherical(q1) ]; + } + } + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, code = 0; + if (λ < -r) code |= 1; else if (λ > r) code |= 2; + if (φ < -r) code |= 4; else if (φ > r) code |= 8; + return code; + } + function polygonContains(polygon) { + return d3_geo_pointInPolygon(point, polygon); + } + } + var d3_geo_clipViewMAX = 1e9; + function d3_geo_clipView(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + }, + polygonEnd: function() { + listener = listener_; + if ((segments = d3.merge(segments)).length) { + listener.polygonStart(); + d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); + listener.polygonEnd(); + } else if (insidePolygon([ x0, y0 ])) { + listener.polygonStart(), listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(), listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + function inside(point) { + var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); + return i; + } + function insidePolygon(p) { + var wn = 0, n = polygon.length, y = p[1]; + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && isLeft(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && isLeft(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + function isLeft(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + } + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + function visible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + function point(x, y) { + if (visible(x, y)) listener.point(x, y); + } + var x__, y__, v__, x_, y_, v_, first; + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + function linePoint(x, y) { + x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); + y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); + var v = visible(x, y); + if (polygon) ring.push([ x, y ]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); else { + var a = [ x_, y_ ], b = [ x, y ]; + if (clipLine(a, b)) { + if (!v_) { + listener.lineStart(); + listener.point(a[0], a[1]); + } + listener.point(b[0], b[1]); + if (!v) listener.lineEnd(); + } else if (v) { + listener.lineStart(); + listener.point(x, y); + } + } + } + x_ = x, y_ = y, v_ = v; + } + return clip; + }; + function corner(p, direction) { + return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + } + function compare(a, b) { + return comparePoints(a.point, b.point); + } + function comparePoints(a, b) { + var ca = corner(a, 1), cb = corner(b, 1); + return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; + } + function clipLine(a, b) { + var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; + if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; + if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { + if (t[1] < 1) { + b[0] = a[0] + t[1] * dx; + b[1] = a[1] + t[1] * dy; + } + if (t[0] > 0) { + a[0] += t[0] * dx; + a[1] += t[0] * dy; + } + return true; + } + return false; + } + } + function d3_geo_clipViewT(num, denominator, t) { + if (Math.abs(denominator) < ε) return num <= 0; + var u = num / denominator; + if (denominator > 0) { + if (u > t[1]) return false; + if (u > t[0]) t[0] = u; + } else { + if (u < t[0]) return false; + if (u < t[1]) t[1] = u; + } + return true; + } + function d3_geo_compose(a, b) { + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + return compose; + } + function d3_geo_conic(projectAt) { + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); + p.parallels = function(_) { + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + return p; + } + function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; + }; + return forward; + } + (d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); + }).raw = d3_geo_conicEqualArea; + d3.geo.albers = function() { + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); + }; + d3.geo.albersUsa = function() { + var lower48 = d3.geo.albers(); + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); + var point, pointStream = { + point: function(x, y) { + point = [ x, y ]; + } + }, lower48Point, alaskaPoint, hawaiiPoint; + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + point = null; + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); + return point; + } + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); + }; + albersUsa.stream = function(stream) { + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); + return { + point: function(x, y) { + lower48Stream.point(x, y); + alaskaStream.point(x, y); + hawaiiStream.point(x, y); + }, + sphere: function() { + lower48Stream.sphere(); + alaskaStream.sphere(); + hawaiiStream.sphere(); + }, + lineStart: function() { + lower48Stream.lineStart(); + alaskaStream.lineStart(); + hawaiiStream.lineStart(); + }, + lineEnd: function() { + lower48Stream.lineEnd(); + alaskaStream.lineEnd(); + hawaiiStream.lineEnd(); + }, + polygonStart: function() { + lower48Stream.polygonStart(); + alaskaStream.polygonStart(); + hawaiiStream.polygonStart(); + }, + polygonEnd: function() { + lower48Stream.polygonEnd(); + alaskaStream.polygonEnd(); + hawaiiStream.polygonEnd(); + } + }; + }; + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_); + alaska.precision(_); + hawaii.precision(_); + return albersUsa; + }; + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_); + alaska.scale(_ * .35); + hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + return albersUsa; + }; + return albersUsa.scale(1070); + }; + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); + } + }; + function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; + } + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; + var d3_geo_pathBounds = { + point: d3_geo_pathBoundsPoint, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_pathBoundsPoint(x, y) { + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; + } + function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointCircle = d3_geo_pathBufferCircle(_); + return stream; + }, + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + buffer.push("Z"); + } + return stream; + } + function d3_geo_pathBufferCircle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; + } + var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } + }; + function d3_geo_pathCentroidPoint(x, y) { + d3_geo_centroidX0 += x; + d3_geo_centroidY0 += y; + ++d3_geo_centroidZ0; + } + function d3_geo_pathCentroidLineStart() { + var x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + } + function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + } + function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + z = y0 * x - x0 * y; + d3_geo_centroidX2 += z * (x0 + x); + d3_geo_centroidY2 += z * (y0 + y); + d3_geo_centroidZ2 += z * 3; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; + } + function d3_geo_pathContext(context) { + var pointRadius = 4.5; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointRadius = _; + return stream; + }, + result: d3_noop + }; + function point(x, y) { + context.moveTo(x, y); + context.arc(x, y, pointRadius, 0, 2 * π); + } + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + function pointLine(x, y) { + context.lineTo(x, y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + context.closePath(); + } + return stream; + } + function d3_geo_resample(project) { + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; + function resample(stream) { + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; + var resample = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + stream.polygonStart(); + resample.lineStart = ringStart; + }, + polygonEnd: function() { + stream.polygonEnd(); + resample.lineStart = lineStart; + } + }; + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + function linePoint(λ, φ) { + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + function ringStart() { + lineStart(); + resample.point = ringPoint; + resample.lineEnd = ringEnd; + } + function ringPoint(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + } + function ringEnd() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + } + return resample; + } + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); + } + } + } + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + return resample; + } + d3.geo.path = function() { + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); + d3.geo.stream(object, cacheStream); + } + return contextStream.result(); + } + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; + }; + path.centroid = function(object) { + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; + }; + path.bounds = function(object) { + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; + }; + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return reset(); + }; + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return reset(); + }; + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + function reset() { + cacheStream = null; + return path; + } + return path.projection(d3.geo.albersUsa()).context(null); + }; + function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(λ, φ) { + return project([ λ * d3_degrees, φ * d3_degrees ]); + }); + return function(stream) { + stream = resample(stream); + return { + point: function(λ, φ) { + stream.point(λ * d3_radians, φ * d3_radians); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + }; + } + d3.geo.projection = d3_geo_projection; + d3.geo.projectionMutator = d3_geo_projectionMutator; + function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { + return project; + })(); + } + function d3_geo_projectionMutator(projectAt) { + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { + x = project(x, y); + return [ x[0] * k + δx, δy - x[1] * k ]; + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [ point[0] * k + δx, δy - point[1] * k ]; + } + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; + } + projection.stream = function(output) { + if (stream) stream.valid = false; + stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); + stream.valid = true; + return stream; + }; + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return invalidate(); + }; + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); + return invalidate(); + }; + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + projection.translate = function(_) { + if (!arguments.length) return [ x, y ]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + projection.center = function(_) { + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + projection.rotate = function(_) { + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + d3.rebind(projection, projectResample, "precision"); + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return invalidate(); + } + function invalidate() { + if (stream) { + stream.valid = false; + stream = null; + } + return projection; + } + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; + } + function d3_geo_projectionRadiansRotate(rotate, stream) { + return { + point: function(x, y) { + y = rotate(x * d3_radians, y * d3_radians), x = y[0]; + stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + } + function d3_geo_equirectangular(λ, φ) { + return [ λ, φ ]; + } + (d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + } + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + return forward; + }; + function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; + } + function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; + }; + } + function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; + } + function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); + function rotation(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; + } + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; + }; + return rotation; + } + d3.geo.circle = function() { + var origin = [ 0, 0 ], angle, precision = 6, interpolate; + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; + } + }); + return { + type: "Polygon", + coordinates: [ ring ] + }; + } + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + return circle.angle(90); + }; + function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), sr = Math.sin(radius); + return function(from, to, direction, listener) { + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to : from > to) from += direction * 2 * π; + } else { + from = radius + direction * 2 * π; + to = radius; + } + var point; + for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); + } + }; + } + function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); + } + d3.geo.distance = function(a, b) { + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); + }; + d3.geo.graticule = function() { + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; + function graticule() { + return { + type: "MultiLineString", + coordinates: lines() + }; + } + function lines() { + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { + return Math.abs(x % DX) > ε; + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { + return Math.abs(y % DY) > ε; + }).map(y)); + } + graticule.lines = function() { + return lines().map(function(coordinates) { + return { + type: "LineString", + coordinates: coordinates + }; + }); + }; + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] + }; + }; + graticule.extent = function(_) { + if (!arguments.length) return graticule.minorExtent(); + return graticule.majorExtent(_).minorExtent(_); + }; + graticule.majorExtent = function(_) { + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + graticule.minorExtent = function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + graticule.step = function(_) { + if (!arguments.length) return graticule.minorStep(); + return graticule.majorStep(_).minorStep(_); + }; + graticule.majorStep = function(_) { + if (!arguments.length) return [ DX, DY ]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + graticule.minorStep = function(_) { + if (!arguments.length) return [ dx, dy ]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = d3_geo_graticuleX(y0, y1, 90); + y = d3_geo_graticuleY(x0, x1, precision); + X = d3_geo_graticuleX(Y0, Y1, 90); + Y = d3_geo_graticuleY(X0, X1, precision); + return graticule; + }; + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + }; + function d3_geo_graticuleX(y0, y1, dy) { + var y = d3.range(y0, y1 - ε, dy).concat(y1); + return function(x) { + return y.map(function(y) { + return [ x, y ]; + }); + }; + } + function d3_geo_graticuleY(x0, x1, dx) { + var x = d3.range(x0, x1 - ε, dx).concat(x1); + return function(y) { + return x.map(function(x) { + return [ x, y ]; + }); + }; + } + function d3_source(d) { + return d.source; + } + function d3_target(d) { + return d.target; + } + d3.geo.greatArc = function() { + var source = d3_source, source_, target = d3_target, target_; + function greatArc() { + return { + type: "LineString", + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] + }; + } + greatArc.distance = function() { + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _, source_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _, target_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.precision = function() { + return arguments.length ? greatArc : 0; + }; + return greatArc; + }; + d3.geo.interpolate = function(source, target) { + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); + }; + function d3_geo_interpolate(x0, y0, x1, y1) { + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); + var interpolate = d ? function(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; + } : function() { + return [ x0 * d3_degrees, y0 * d3_degrees ]; + }; + interpolate.distance = d; + return interpolate; + } + d3.geo.length = function(object) { + d3_geo_lengthSum = 0; + d3.geo.stream(object, d3_geo_length); + return d3_geo_lengthSum; + }; + var d3_geo_lengthSum; + var d3_geo_length = { + sphere: d3_noop, + point: d3_noop, + lineStart: d3_geo_lengthLineStart, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_lengthLineStart() { + var λ0, sinφ0, cosφ0; + d3_geo_length.point = function(λ, φ) { + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); + d3_geo_length.point = nextPoint; + }; + d3_geo_length.lineEnd = function() { + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; + }; + function nextPoint(λ, φ) { + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; + } + } + function d3_geo_azimuthal(scale, angle) { + function azimuthal(λ, φ) { + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; + } + azimuthal.invert = function(x, y) { + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; + }; + return azimuthal; + } + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { + return Math.sqrt(2 / (1 + cosλcosφ)); + }, function(ρ) { + return 2 * Math.asin(ρ / 2); + }); + (d3.geo.azimuthalEqualArea = function() { + return d3_geo_projection(d3_geo_azimuthalEqualArea); + }).raw = d3_geo_azimuthalEqualArea; + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { + var c = Math.acos(cosλcosφ); + return c && c / Math.sin(c); + }, d3_identity); + (d3.geo.azimuthalEquidistant = function() { + return d3_geo_projection(d3_geo_azimuthalEquidistant); + }).raw = d3_geo_azimuthalEquidistant; + function d3_geo_conicConformal(φ0, φ1) { + var cosφ0 = Math.cos(φ0), t = function(φ) { + return Math.tan(π / 4 + φ / 2); + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; + if (!n) return d3_geo_mercator; + function forward(λ, φ) { + var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; + }; + return forward; + } + (d3.geo.conicConformal = function() { + return d3_geo_conic(d3_geo_conicConformal); + }).raw = d3_geo_conicConformal; + function d3_geo_conicEquidistant(φ0, φ1) { + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; + if (Math.abs(n) < ε) return d3_geo_equirectangular; + function forward(λ, φ) { + var ρ = G - φ; + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = G - y; + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; + }; + return forward; + } + (d3.geo.conicEquidistant = function() { + return d3_geo_conic(d3_geo_conicEquidistant); + }).raw = d3_geo_conicEquidistant; + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / cosλcosφ; + }, Math.atan); + (d3.geo.gnomonic = function() { + return d3_geo_projection(d3_geo_gnomonic); + }).raw = d3_geo_gnomonic; + function d3_geo_mercator(λ, φ) { + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; + } + d3_geo_mercator.invert = function(x, y) { + return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; + }; + function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + return m.clipExtent(null); + } + (d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); + }).raw = d3_geo_mercator; + var d3_geo_orthographic = d3_geo_azimuthal(function() { + return 1; + }, Math.asin); + (d3.geo.orthographic = function() { + return d3_geo_projection(d3_geo_orthographic); + }).raw = d3_geo_orthographic; + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / (1 + cosλcosφ); + }, function(ρ) { + return 2 * Math.atan(ρ); + }); + (d3.geo.stereographic = function() { + return d3_geo_projection(d3_geo_stereographic); + }).raw = d3_geo_stereographic; + function d3_geo_transverseMercator(λ, φ) { + var B = Math.cos(φ) * Math.sin(λ); + return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; + } + d3_geo_transverseMercator.invert = function(x, y) { + return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; + }; + (d3.geo.transverseMercator = function() { + return d3_geo_mercatorProjection(d3_geo_transverseMercator); + }).raw = d3_geo_transverseMercator; + d3.geom = {}; + d3.svg = {}; + function d3_svg_line(projection) { + var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + function line(data) { + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + function d3_svg_lineX(d) { + return d[0]; + } + function d3_svg_lineY(d) { + return d[1]; + } + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + step: d3_svg_lineStep, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStep(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); + if (n > 1) path.push("H", p[0]); + return path.join(""); + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + points.push(points[n - 1]); + while (++i <= n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + points.pop(); + path.push("L", pi); + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < 1e-6) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + d3.geom.hull = function(vertices) { + var x = d3_svg_lineX, y = d3_svg_lineY; + if (arguments.length) return hull(vertices); + function hull(data) { + if (data.length < 3) return []; + var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; + if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, + vertices = []; i < n; ++i) { + vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); + } + for (i = 1; i < n; ++i) { + if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; + } + for (i = 0; i < n; ++i) { + if (i === h) continue; + y1 = vertices[i][1] - vertices[h][1]; + x1 = vertices[i][0] - vertices[h][0]; + points.push({ + angle: Math.atan2(y1, x1), + index: i + }); + } + points.sort(function(a, b) { + return a.angle - b.angle; + }); + a = points[0].angle; + v = points[0].index; + u = 0; + for (i = 1; i < plen; ++i) { + j = points[i].index; + if (a == points[i].angle) { + x1 = vertices[v][0] - vertices[h][0]; + y1 = vertices[v][1] - vertices[h][1]; + x2 = vertices[j][0] - vertices[h][0]; + y2 = vertices[j][1] - vertices[h][1]; + if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { + points[i].index = -1; + continue; + } else { + points[u].index = -1; + } + } + a = points[i].angle; + u = i; + v = j; + } + stack.push(h); + for (i = 0, j = 0; i < 2; ++j) { + if (points[j].index > -1) { + stack.push(points[j].index); + i++; + } + } + sp = stack.length; + for (;j < plen; ++j) { + if (points[j].index < 0) continue; + while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { + --sp; + } + stack[sp++] = points[j].index; + } + var poly = []; + for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); + return poly; + } + hull.x = function(_) { + return arguments.length ? (x = _, hull) : x; + }; + hull.y = function(_) { + return arguments.length ? (y = _, hull) : y; + }; + return hull; + }; + function d3_geom_hullCCW(i1, i2, i3, v) { + var t, a, b, c, d, e, f; + t = v[i1]; + a = t[0]; + b = t[1]; + t = v[i2]; + c = t[0]; + d = t[1]; + t = v[i3]; + e = t[0]; + f = t[1]; + return (f - b) * (c - a) - (d - b) * (e - a) > 0; + } + d3.geom.polygon = function(coordinates) { + d3_subclass(coordinates, d3_geom_polygonPrototype); + return coordinates; + }; + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; + d3_geom_polygonPrototype.area = function() { + var i = -1, n = this.length, a, b = this[n - 1], area = 0; + while (++i < n) { + a = b; + b = this[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + return area * .5; + }; + d3_geom_polygonPrototype.centroid = function(k) { + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; + if (!arguments.length) k = -1 / (6 * this.area()); + while (++i < n) { + a = b; + b = this[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + d3_geom_polygonPrototype.clip = function(subject) { + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = this[i]; + c = input[(m = input.length - closed) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + if (closed) subject.push(subject[0]); + a = b; + } + return subject; + }; + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_geom_polygonClosed(coordinates) { + var a = coordinates[0], b = coordinates[coordinates.length - 1]; + return !(a[0] - b[0] || a[1] - b[1]); + } + d3.geom.delaunay = function(vertices) { + var edges = vertices.map(function() { + return []; + }), triangles = []; + d3_geom_voronoiTessellate(vertices, function(e) { + edges[e.region.l.index].push(vertices[e.region.r.index]); + }); + edges.forEach(function(edge, i) { + var v = vertices[i], cx = v[0], cy = v[1]; + edge.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + edge.sort(function(a, b) { + return a.angle - b.angle; + }); + for (var j = 0, m = edge.length - 1; j < m; j++) { + triangles.push([ v, edge[j], edge[j + 1] ]); + } + }); + return triangles; + }; + d3.geom.voronoi = function(points) { + var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; + if (arguments.length) return voronoi(points); + function voronoi(data) { + var points, polygons = data.map(function() { + return []; + }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var s1, s2, x1, x2, y1, y2; + if (e.a === 1 && e.b >= 0) { + s1 = e.ep.r; + s2 = e.ep.l; + } else { + s1 = e.ep.l; + s2 = e.ep.r; + } + if (e.a === 1) { + y1 = s1 ? s1.y : -Z; + x1 = e.c - e.b * y1; + y2 = s2 ? s2.y : Z; + x2 = e.c - e.b * y2; + } else { + x1 = s1 ? s1.x : -Z; + y1 = e.c - e.a * x1; + x2 = s2 ? s2.x : Z; + y2 = e.c - e.a * x2; + } + var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; + polygons[e.region.l.index].push(v1, v2); + polygons[e.region.r.index].push(v1, v2); + }); + polygons = polygons.map(function(polygon, i) { + var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { + return Math.atan2(v[0] - cx, v[1] - cy); + }), order = d3.range(polygon.length).sort(function(a, b) { + return angle[a] - angle[b]; + }); + return order.filter(function(d, i) { + return !i || angle[d] - angle[order[i - 1]] > ε; + }).map(function(d) { + return polygon[d]; + }); + }); + polygons.forEach(function(polygon, i) { + var n = polygon.length; + if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); + if (n > 2) return; + var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; + if (Math.abs(dy) < ε) { + var y = y0 < y1 ? -Z : Z; + polygon.push([ -Z, y ], [ Z, y ]); + } else if (dx < ε) { + var x = x0 < x1 ? -Z : Z; + polygon.push([ x, -Z ], [ x, Z ]); + } else { + var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; + if (Math.abs(z) < ε) { + polygon.push([ dy < 0 ? y : -y, y ]); + } else { + if (z > 0) y *= -1; + polygon.push([ -Z, y ], [ Z, y ]); + } + } + }); + if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); + for (i = 0; i < n; ++i) polygons[i].point = data[i]; + return polygons; + } + voronoi.x = function(_) { + return arguments.length ? (x = _, voronoi) : x; + }; + voronoi.y = function(_) { + return arguments.length ? (y = _, voronoi) : y; + }; + voronoi.clipExtent = function(_) { + if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; + if (_ == null) clipPolygon = null; else { + var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; + clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); + } + return voronoi; + }; + voronoi.size = function(_) { + if (!arguments.length) return clipPolygon && clipPolygon[2]; + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); + }; + voronoi.links = function(data) { + var points, graph = data.map(function() { + return []; + }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var l = e.region.l.index, r = e.region.r.index; + if (graph[l][r]) return; + graph[l][r] = graph[r][l] = true; + links.push({ + source: data[l], + target: data[r] + }); + }); + return links; + }; + voronoi.triangles = function(data) { + if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); + var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; + while (++i < n) { + (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; + } + return d3.geom.delaunay(points).map(function(triangle) { + return triangle.map(function(point) { + return point.data; + }); + }); + }; + return voronoi; + }; + var d3_geom_voronoiOpposite = { + l: "r", + r: "l" + }; + function d3_geom_voronoiTessellate(points, callback) { + var Sites = { + list: points.map(function(v, i) { + return { + index: i, + x: v[0], + y: v[1] + }; + }).sort(function(a, b) { + return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; + }), + bottomSite: null + }; + var EdgeList = { + list: [], + leftEnd: null, + rightEnd: null, + init: function() { + EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.leftEnd.r = EdgeList.rightEnd; + EdgeList.rightEnd.l = EdgeList.leftEnd; + EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); + }, + createHalfEdge: function(edge, side) { + return { + edge: edge, + side: side, + vertex: null, + l: null, + r: null + }; + }, + insert: function(lb, he) { + he.l = lb; + he.r = lb.r; + lb.r.l = he; + lb.r = he; + }, + leftBound: function(p) { + var he = EdgeList.leftEnd; + do { + he = he.r; + } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); + he = he.l; + return he; + }, + del: function(he) { + he.l.r = he.r; + he.r.l = he.l; + he.edge = null; + }, + right: function(he) { + return he.r; + }, + left: function(he) { + return he.l; + }, + leftRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; + }, + rightRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; + } + }; + var Geom = { + bisect: function(s1, s2) { + var newEdge = { + region: { + l: s1, + r: s2 + }, + ep: { + l: null, + r: null + } + }; + var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; + newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; + if (adx > ady) { + newEdge.a = 1; + newEdge.b = dy / dx; + newEdge.c /= dx; + } else { + newEdge.b = 1; + newEdge.a = dx / dy; + newEdge.c /= dy; + } + return newEdge; + }, + intersect: function(el1, el2) { + var e1 = el1.edge, e2 = el2.edge; + if (!e1 || !e2 || e1.region.r == e2.region.r) { + return null; + } + var d = e1.a * e2.b - e1.b * e2.a; + if (Math.abs(d) < 1e-10) { + return null; + } + var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; + if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + var rightOfSite = xint >= e.region.r.x; + if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { + return null; + } + return { + x: xint, + y: yint + }; + }, + rightOf: function(he, p) { + var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; + if (rightOfSite && he.side === "l") { + return 1; + } + if (!rightOfSite && he.side === "r") { + return 0; + } + if (e.a === 1) { + var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; + if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { + above = fast = dyp >= e.b * dxp; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0) { + above = !above; + } + if (!above) { + fast = 1; + } + } + if (!fast) { + var dxs = topsite.x - e.region.l.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); + if (e.b < 0) { + above = !above; + } + } + } else { + var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return he.side === "l" ? above : !above; + }, + endPoint: function(edge, side, site) { + edge.ep[side] = site; + if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; + callback(edge); + }, + distance: function(s, t) { + var dx = s.x - t.x, dy = s.y - t.y; + return Math.sqrt(dx * dx + dy * dy); + } + }; + var EventQueue = { + list: [], + insert: function(he, site, offset) { + he.vertex = site; + he.ystar = site.y + offset; + for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { + var next = list[i]; + if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { + continue; + } else { + break; + } + } + list.splice(i, 0, he); + }, + del: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} + ls.splice(i, 1); + }, + empty: function() { + return EventQueue.list.length === 0; + }, + nextEvent: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { + if (ls[i] == he) return ls[i + 1]; + } + return null; + }, + min: function() { + var elem = EventQueue.list[0]; + return { + x: elem.vertex.x, + y: elem.ystar + }; + }, + extractMin: function() { + return EventQueue.list.shift(); + } + }; + EdgeList.init(); + Sites.bottomSite = Sites.list.shift(); + var newSite = Sites.list.shift(), newIntStar; + var lbnd, rbnd, llbnd, rrbnd, bisector; + var bot, top, temp, p, v; + var e, pm; + while (true) { + if (!EventQueue.empty()) { + newIntStar = EventQueue.min(); + } + if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { + lbnd = EdgeList.leftBound(newSite); + rbnd = EdgeList.right(lbnd); + bot = EdgeList.rightRegion(lbnd); + e = Geom.bisect(bot, newSite); + bisector = EdgeList.createHalfEdge(e, "l"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(lbnd, bisector); + if (p) { + EventQueue.del(lbnd); + EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); + } + lbnd = bisector; + bisector = EdgeList.createHalfEdge(e, "r"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(bisector, rbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, newSite)); + } + newSite = Sites.list.shift(); + } else if (!EventQueue.empty()) { + lbnd = EventQueue.extractMin(); + llbnd = EdgeList.left(lbnd); + rbnd = EdgeList.right(lbnd); + rrbnd = EdgeList.right(rbnd); + bot = EdgeList.leftRegion(lbnd); + top = EdgeList.rightRegion(rbnd); + v = lbnd.vertex; + Geom.endPoint(lbnd.edge, lbnd.side, v); + Geom.endPoint(rbnd.edge, rbnd.side, v); + EdgeList.del(lbnd); + EventQueue.del(rbnd); + EdgeList.del(rbnd); + pm = "l"; + if (bot.y > top.y) { + temp = bot; + bot = top; + top = temp; + pm = "r"; + } + e = Geom.bisect(bot, top); + bisector = EdgeList.createHalfEdge(e, pm); + EdgeList.insert(llbnd, bisector); + Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); + p = Geom.intersect(llbnd, bisector); + if (p) { + EventQueue.del(llbnd); + EventQueue.insert(llbnd, p, Geom.distance(p, bot)); + } + p = Geom.intersect(bisector, rrbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, bot)); + } + } else { + break; + } + } + for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { + callback(lbnd.edge); + } + } + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + var x = d3_svg_lineX, y = d3_svg_lineY, compat; + if (compat = arguments.length) { + x = d3_geom_quadtreeCompatX; + y = d3_geom_quadtreeCompatY; + if (compat === 3) { + y2 = y1; + x2 = x1; + y1 = x1 = 0; + } + return quadtree(points); + } + function quadtree(data) { + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; + if (x1 != null) { + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; + } else { + x2_ = y2_ = -(x1_ = y1_ = Infinity); + xs = [], ys = []; + n = data.length; + if (compat) for (i = 0; i < n; ++i) { + d = data[i]; + if (d.x < x1_) x1_ = d.x; + if (d.y < y1_) y1_ = d.y; + if (d.x > x2_) x2_ = d.x; + if (d.y > y2_) y2_ = d.y; + xs.push(d.x); + ys.push(d.y); + } else for (i = 0; i < n; ++i) { + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); + if (x_ < x1_) x1_ = x_; + if (y_ < y1_) y1_ = y_; + if (x_ > x2_) x2_ = x_; + if (y_ > y2_) y2_ = y_; + xs.push(x_); + ys.push(y_); + } + } + var dx = x2_ - x1_, dy = y2_ - y1_; + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; + function insert(n, d, x, y, x1, y1, x2, y2) { + if (isNaN(x) || isNaN(y)) return; + if (n.leaf) { + var nx = n.x, ny = n.y; + if (nx != null) { + if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { + insertChild(n, d, x, y, x1, y1, x2, y2); + } else { + var nPoint = n.point; + n.x = n.y = n.point = null; + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } else { + n.x = x, n.y = y, n.point = d; + } + } else { + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } + function insertChild(n, d, x, y, x1, y1, x2, y2) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = sx; else x2 = sx; + if (bottom) y1 = sy; else y2 = sy; + insert(n, d, x, y, x1, y1, x2, y2); + } + var root = d3_geom_quadtreeNode(); + root.add = function(d) { + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); + }; + i = -1; + if (x1 == null) { + while (++i < n) { + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); + } + --i; + } else data.forEach(root.add); + xs = ys = data = d = null; + return root; + } + quadtree.x = function(_) { + return arguments.length ? (x = _, quadtree) : x; + }; + quadtree.y = function(_) { + return arguments.length ? (y = _, quadtree) : y; + }; + quadtree.extent = function(_) { + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], + y2 = +_[1][1]; + return quadtree; + }; + quadtree.size = function(_) { + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; + return quadtree; + }; + return quadtree; + }; + function d3_geom_quadtreeCompatX(d) { + return d.x; + } + function d3_geom_quadtreeCompatY(d) { + return d.y; + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null, + x: null, + y: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + d3.interpolateRgb = d3_interpolateRgb; + function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + } + d3.interpolateObject = d3_interpolateObject; + function d3_interpolateObject(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + } + d3.interpolateNumber = d3_interpolateNumber; + function d3_interpolateNumber(a, b) { + b -= a = +a; + return function(t) { + return a + b * t; + }; + } + d3.interpolateString = d3_interpolateString; + function d3_interpolateString(a, b) { + var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; + a = a + "", b = b + ""; + d3_interpolate_number.lastIndex = 0; + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({ + i: s.length, + x: m[0] + }); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { + if (o.i) { + if (s[o.i + 1] == null) { + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + if (s.length === 1) { + return s[0] == null ? (o = q[0].x, function(t) { + return o(t) + ""; + }) : function() { + return b; + }; + } + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + d3.interpolate = d3_interpolate; + function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + } + d3.interpolators = [ function(a, b) { + var t = typeof b; + return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); + } ]; + d3.interpolateArray = d3_interpolateArray; + function d3_interpolateArray(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (;i < na; ++i) c[i] = a[i]; + for (;i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + } + var d3_ease_default = function() { + return d3_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); + }; + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_quad(t) { + return t * t; + } + function d3_ease_cubic(t) { + return t * t * t; + } + function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * π / 2); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + d3.interpolateHcl = d3_interpolateHcl; + function d3_interpolateHcl(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + } + d3.interpolateHsl = d3_interpolateHsl; + function d3_interpolateHsl(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; + }; + } + d3.interpolateLab = d3_interpolateLab; + function d3_interpolateLab(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + } + d3.interpolateRound = d3_interpolateRound; + function d3_interpolateRound(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + } + d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + if (string != null) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + } + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; + } + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + var d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolateTransform = d3_interpolateTransform; + function d3_interpolateTransform(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3_interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3_interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3_interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3_interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3_interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3_interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + function d3_uninterpolateNumber(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return (x - a) * b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return Math.max(0, Math.min(1, (x - a) * b)); + }; + } + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + d3.layout.chord = function() { + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (2 * π - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; + function repulse(node) { + return function(quad, x1, _, x2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); + if ((x2 - x1) * dn < theta) { + var k = quad.charge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + return true; + } + if (quad.point && isFinite(dn)) { + var k = quad.pointCharge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = typeof x === "function" ? x : +x; + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = typeof x === "function" ? x : +x; + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = +x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = +x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return theta; + theta = +x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + x = +x; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + distances = []; + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; + strengths = []; + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; + charges = []; + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; + function position(dimension, size) { + var neighbors = neighbor(i), j = -1, m = neighbors.length, x; + while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; + return Math.random() * size; + } + function neighbor() { + if (!neighbors) { + neighbors = []; + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + return neighbors[i]; + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); + if (!arguments.length) return drag; + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + function dragmove(d) { + d.px = d3.event.x, d.py = d3.event.y; + force.resume(); + } + return d3.rebind(force, event, "on"); + }; + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= ~6; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + d.px = d.x, d.py = d.y; + } + function d3_layout_forceMouseout(d) { + d.fixed &= ~4; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; + d3.layout.hierarchy = function() { + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + function recurse(node, depth, nodes) { + var childs = children.call(hierarchy, node, depth); + node.depth = depth; + nodes.push(node); + if (childs && (n = childs.length)) { + var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; + while (++i < n) { + d = recurse(childs[i], j, nodes); + d.parent = node; + c.push(d); + v += d.value; + } + if (sort) c.sort(sort); + if (value) node.value = v; + } else if (value) { + node.value = +value.call(hierarchy, node, depth) || 0; + } + return node; + } + function revalue(node, depth) { + var children = node.children, v = 0; + if (children && (n = children.length)) { + var i = -1, n, j = depth + 1; + while (++i < n) v += revalue(children[i], j); + } else if (value) { + v = +value.call(hierarchy, node, depth) || 0; + } + if (value) node.value = v; + return v; + } + function hierarchy(d) { + var nodes = []; + recurse(d, 0, nodes); + return nodes; + } + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + revalue(root, 0); + return root; + }; + return hierarchy; + }; + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.nodes = object; + object.links = d3_layout_hierarchyLinks; + return object; + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + d3.layout.partition = function() { + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; + function pie(data) { + var values = data.map(function(d, i) { + return +value.call(pie, d, i); + }); + var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); + var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); + var index = d3.range(data.length); + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + var arcs = []; + index.forEach(function(i) { + var d; + arcs[i] = { + data: data[i], + value: d = values[i], + startAngle: a, + endAngle: a += d * k + }; + }); + return arcs; + } + pie.value = function(x) { + if (!arguments.length) return value; + value = x; + return pie; + }; + pie.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return pie; + }; + pie.startAngle = function(x) { + if (!arguments.length) return startAngle; + startAngle = x; + return pie; + }; + pie.endAngle = function(x) { + if (!arguments.length) return endAngle; + endAngle = x; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + function stack(data, index) { + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var n = series.length, m = series[0].length, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (;i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + d3.layout.histogram = function() { + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + d3.layout.tree = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function tree(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + function firstWalk(node, previousSibling) { + var children = node.children, layout = node._tree; + if (children && (n = children.length)) { + var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; + while (++i < n) { + child = children[i]; + firstWalk(child, previousChild); + ancestor = apportion(child, previousChild, ancestor); + previousChild = child; + } + d3_layout_treeShift(node); + var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + layout.mod = layout.prelim - midpoint; + } else { + layout.prelim = midpoint; + } + } else { + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + } + } + } + function secondWalk(node, x) { + node.x = node._tree.prelim + x; + var children = node.children; + if (children && (n = children.length)) { + var i = -1, n; + x += node._tree.mod; + while (++i < n) { + secondWalk(children[i], x); + } + } + } + function apportion(node, previousSibling, ancestor) { + if (previousSibling) { + var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop._tree.ancestor = node; + shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); + sip += shift; + sop += shift; + } + sim += vim._tree.mod; + sip += vip._tree.mod; + som += vom._tree.mod; + sop += vop._tree.mod; + } + if (vim && !d3_layout_treeRight(vop)) { + vop._tree.thread = vim; + vop._tree.mod += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom._tree.thread = vip; + vom._tree.mod += sip - som; + ancestor = node; + } + } + return ancestor; + } + d3_layout_treeVisitAfter(root, function(node, previousSibling) { + node._tree = { + ancestor: node, + prelim: 0, + mod: 0, + change: 0, + shift: 0, + number: previousSibling ? previousSibling._tree.number + 1 : 0 + }; + }); + firstWalk(root); + secondWalk(root, -root._tree.prelim); + var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x *= size[0]; + node.y = node.depth * size[1]; + delete node._tree; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = node.depth / y1 * size[1]; + delete node._tree; + }); + return nodes; + } + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return tree; + }; + tree.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(node) { + var children = node.children; + return children && children.length ? children[0] : node._tree.thread; + } + function d3_layout_treeRight(node) { + var children = node.children, n; + return children && (n = children.length) ? children[n - 1] : node._tree.thread; + } + function d3_layout_treeSearch(node, compare) { + var children = node.children; + if (children && (n = children.length)) { + var child, n, i = -1; + while (++i < n) { + if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { + node = child; + } + } + } + return node; + } + function d3_layout_treeRightmost(a, b) { + return a.x - b.x; + } + function d3_layout_treeLeftmost(a, b) { + return b.x - a.x; + } + function d3_layout_treeDeepest(a, b) { + return a.depth - b.depth; + } + function d3_layout_treeVisitAfter(node, callback) { + function visit(node, previousSibling) { + var children = node.children; + if (children && (n = children.length)) { + var child, previousChild = null, i = -1, n; + while (++i < n) { + child = children[i]; + visit(child, previousChild); + previousChild = child; + } + } + callback(node, previousSibling); + } + visit(node, null); + } + function d3_layout_treeShift(node) { + var shift = 0, change = 0, children = node.children, i = children.length, child; + while (--i >= 0) { + child = children[i]._tree; + child.prelim += shift; + child.mod += shift; + shift += child.shift + (change += child.change); + } + } + function d3_layout_treeMove(ancestor, node, shift) { + ancestor = ancestor._tree; + node = node._tree; + var change = shift / (node.number - ancestor.number); + ancestor.change += change; + node.change -= change; + node.shift += shift; + node.prelim += shift; + node.mod += shift; + } + function d3_layout_treeAncestor(vim, node, ancestor) { + return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; + } + d3.layout.pack = function() { + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { + return radius; + }; + root.x = root.y = 0; + d3_layout_treeVisitAfter(root, function(d) { + d.r = +r(d.value); + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + if (padding) { + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; + d3_layout_treeVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + d3_layout_treeVisitAfter(root, function(d) { + d.r -= dr; + }); + } + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); + return nodes; + } + pack.size = function(_) { + if (!arguments.length) return size; + size = _; + return pack; + }; + pack.radius = function(_) { + if (!arguments.length) return radius; + radius = _ == null || typeof _ === "function" ? _ : +_; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return .999 * dr * dr > dx * dx + dy * dy; + } + function d3_layout_packSiblings(node) { + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + d3.layout.cluster = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; + d3_layout_treeVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x = (node.x - root.x) * size[0]; + node.y = (root.y - node.y) * size[1]; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return cluster; + }; + cluster.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + d3.layout.treemap = function() { + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if (mode !== "squarify" || (score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + if (!arguments.length) return padding; + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], + padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + treemap.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function() { + var random = d3.random.normal.apply(d3, arguments); + return function() { + return Math.exp(random()); + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s / m; + }; + } + }; + d3.scale = {}; + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + return domain; + } + function d3_scale_niceStep(step) { + return step ? { + floor: function(x) { + return Math.floor(x / step) * step; + }, + ceil: function(x) { + return Math.ceil(x / step) * step; + } + } : d3_scale_niceIdentity; + } + var d3_scale_niceIdentity = { + floor: d3_identity, + ceil: d3_identity + }; + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); + }; + function d3_scale_linear(domain, range, interpolate, clamp) { + var output, input; + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3_interpolate); + return scale; + } + function scale(x) { + return output(x); + } + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3_interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + d3_scale_linearNice(domain, m); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(domain, m) { + return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); + } + function d3_scale_linearNiceStep(domain) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; + return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); + } + function d3_scale_linearTickRange(domain, m) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m, format) { + var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); + return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { + return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); + }) : ",." + precision + "f"); + } + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); + }; + function d3_scale_log(linear, base, positive, domain) { + function log(x) { + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); + } + function pow(x) { + return positive ? Math.pow(base, x) : -Math.pow(base, -x); + } + function scale(x) { + return linear(log(x)); + } + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + positive = x[0] >= 0; + linear.domain((domain = x.map(Number)).map(log)); + return scale; + }; + scale.base = function(_) { + if (!arguments.length) return base; + base = +_; + linear.domain(domain.map(log)); + return scale; + }; + scale.nice = function() { + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); + linear.domain(niced); + domain = niced.map(pow); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; + if (isFinite(j - i)) { + if (positive) { + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } else { + ticks.push(pow(i)); + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (!arguments.length) return d3_scale_logFormat; + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); + var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, + Math.floor), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), base, positive, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { + floor: function(x) { + return -Math.ceil(-x); + }, + ceil: function(x) { + return -Math.floor(-x); + } + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); + }; + function d3_scale_pow(linear, exponent, domain) { + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + function scale(x) { + return linear(powp(x)); + } + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + linear.domain((domain = x.map(Number)).map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + return scale.domain(d3_scale_linearNice(domain, m)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + linear.domain(domain.map(powp)); + return scale; + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + function d3_scale_ordinal(domain, ranger) { + var index, range, rangeBand; + function scale(x) { + return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map(); + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); + range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; + range = steps(start + Math.round(error / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + function d3_scale_quantile(domain, range) { + var thresholds; + function rescale() { + var k = 0, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.filter(function(d) { + return !isNaN(d); + }).sort(d3.ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + function d3_scale_quantize(x0, x1, range) { + var kx, i; + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + y = y < 0 ? NaN : y / kx + x0; + return [ y, y + 1 / kx ]; + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + function d3_scale_threshold(domain, range) { + function scale(x) { + if (x <= x) return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return [ domain[y - 1], domain[y] ]; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + d3.svg.arc = function() { + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function arc() { + var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, + a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); + return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; + } + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] + d3_svg_arcOffset; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + function area(data) { + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + function d3_svg_chordRadius(d) { + return d.radius; + } + d3.svg.diagonal = function() { + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + d3.svg.symbol = function() { + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / π); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); + function d3_transition(groups, id) { + d3_subclass(groups, d3_transitionPrototype); + groups.id = id; + return groups; + } + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3_transitionPrototype.empty = d3_selectionPrototype.empty; + d3_transitionPrototype.node = d3_selectionPrototype.node; + d3_transitionPrototype.size = d3_selectionPrototype.size; + d3.transition = function(selection) { + return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var id = this.id, subgroups = [], subgroup, subnode, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, id, node.__transition__[id]); + subgroup.push(subnode); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + transition = node.__transition__[id]; + subnodes = selector.call(node, node.__data__, i, j); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); + subgroup.push(subnode); + } + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.id); + }; + d3_transitionPrototype.tween = function(name, tween) { + var id = this.id; + if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); + return d3_selection_each(this, tween == null ? function(node) { + node.__transition__[id].tween.remove(name); + } : function(node) { + node.__transition__[id].tween.set(name, tween); + }); + }; + function d3_transition_tween(groups, name, value, tween) { + var id = groups.id; + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); + } : (value = tween(value), function(node) { + node.__transition__[id].tween.set(name, value); + })); + } + d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrTween(b) { + return b == null ? attrNull : (b += "", function() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttribute(name, i(t)); + }); + }); + } + function attrTweenNS(b) { + return b == null ? attrNullNS : (b += "", function() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttributeNS(name.space, name.local, i(t)); + }); + }); + } + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + priority = ""; + } + function styleNull() { + this.style.removeProperty(name); + } + function styleString(b) { + return b == null ? styleNull : (b += "", function() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = d3_interpolate(a, b), function(t) { + this.style.setProperty(name, i(t), priority); + }); + }); + } + return d3_transition_tween(this, "style." + name, value, styleString); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + function styleTween(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + } + return this.tween("style." + name, styleTween); + }; + d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); + }; + function d3_transition_text(b) { + if (b == null) b = ""; + return function() { + this.textContent = b; + }; + } + d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.ease = function(value) { + var id = this.id; + if (arguments.length < 1) return this.node().__transition__[id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { + node.__transition__[id].ease = value; + }); + }; + d3_transitionPrototype.delay = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; + } : (value |= 0, function(node) { + node.__transition__[id].delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); + } : (value = Math.max(1, value | 0), function(node) { + node.__transition__[id].duration = value; + })); + }; + d3_transitionPrototype.each = function(type, listener) { + var id = this.id; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node.__transition__[id]; + type.call(node, node.__data__, i, j); + }); + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } else { + d3_selection_each(this, function(node) { + var transition = node.__transition__[id]; + (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); + }); + } + return this; + }; + d3_transitionPrototype.transition = function() { + var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = Object.create(node.__transition__[id0]); + transition.delay += transition.duration; + d3_transitionNode(node, i, id1, transition); + } + subgroup.push(node); + } + } + return d3_transition(subgroups, id1); + }; + function d3_transitionNode(node, i, id, inherit) { + var lock = node.__transition__ || (node.__transition__ = { + active: 0, + count: 0 + }), transition = lock[id]; + if (!transition) { + var time = inherit.time; + transition = lock[id] = { + tween: new d3_Map(), + time: time, + ease: inherit.ease, + delay: inherit.delay, + duration: inherit.duration + }; + ++lock.count; + d3.timer(function(elapsed) { + var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; + if (delay <= elapsed) return start(elapsed); + d3_timer_replace(start, delay, time); + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + transition.event && transition.event.start.call(node, d, i); + transition.tween.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); + } + }); + if (tick(elapsed)) return 1; + d3_timer_replace(tick, 0, time); + } + function tick(elapsed) { + if (lock.active !== id) return stop(); + var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + stop(); + transition.event && transition.event.end.call(node, d, i); + return 1; + } + } + function stop() { + if (--lock.count) delete lock[id]; else delete node.__transition__; + return 1; + } + }, 0, time); + } + } + d3.svg.axis = function() { + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; + function axis(g) { + g.each(function() { + var g = d3.select(this); + var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; + var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); + var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; + var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + d3.transition(path)); + var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; + this.__chart__ = scale1; + tickEnter.append("line"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); + switch (orient) { + case "bottom": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); + lineEnter.attr("y2", tickMajorSize); + textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); + textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); + text.attr("dy", ".71em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); + break; + } + + case "top": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", -tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); + lineEnter.attr("y2", -tickMajorSize); + textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); + textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + text.attr("dy", "0em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); + break; + } + + case "left": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", -tickMinorSize); + subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", -tickMajorSize); + textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); + textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "end"); + pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); + break; + } + + case "right": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", tickMinorSize); + subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", tickMajorSize); + textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); + textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "start"); + pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); + break; + } + } + if (scale.rangeBand) { + var dx = scale1.rangeBand() / 2, x = function(d) { + return scale1(d) + dx; + }; + tickEnter.call(tickTransform, x); + tickUpdate.call(tickTransform, x); + } else { + tickEnter.call(tickTransform, scale0); + tickUpdate.call(tickTransform, scale1); + tickExit.call(tickTransform, scale1); + subtickEnter.call(tickTransform, scale0); + subtickUpdate.call(tickTransform, scale1); + subtickExit.call(tickTransform, scale1); + } + }); + } + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x, y) { + if (!arguments.length) return tickMajorSize; + var n = arguments.length - 1; + tickMajorSize = +x; + tickMinorSize = n > 1 ? +y : tickMajorSize; + tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function(x) { + if (!arguments.length) return tickSubdivide; + tickSubdivide = +x; + return axis; + }; + return axis; + }; + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { + top: 1, + right: 1, + bottom: 1, + left: 1 + }; + function d3_svg_axisX(selection, x) { + selection.attr("transform", function(d) { + return "translate(" + x(d) + ",0)"; + }); + } + function d3_svg_axisY(selection, y) { + selection.attr("transform", function(d) { + return "translate(0," + y(d) + ")"; + }); + } + function d3_svg_axisSubdivide(scale, ticks, m) { + subticks = []; + if (m && ticks.length > 1) { + var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; + while (++i < n) { + for (j = m; --j > 0; ) { + if ((v = +ticks[i] - j * d) >= extent[0]) { + subticks.push(v); + } + } + } + for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { + subticks.push(v); + } + } + return subticks; + } + d3.svg.brush = function() { + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; + function brush(g) { + g.each(function() { + var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; + g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); + tz.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + tz.style("display", brush.empty() ? "none" : null); + tz.exit().remove(); + if (x) { + e = d3_scaleRange(x); + bg.attr("x", e[0]).attr("width", e[1] - e[0]); + redrawX(g); + } + if (y) { + e = d3_scaleRange(y); + bg.attr("y", e[0]).attr("height", e[1] - e[0]); + redrawY(g); + } + redraw(g); + }); + } + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", extent[0][0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); + } + function redrawY(g) { + g.select(".extent").attr("y", extent[0][1]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); + } + function brushstart() { + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = mouse(), offset; + var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (d3.event.changedTouches) { + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); + } else { + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); + } + if (dragging) { + origin[0] = extent[0][0] - origin[0]; + origin[1] = extent[0][1] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; + origin[0] = extent[ex][0]; + origin[1] = extent[ey][1]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + function mouse() { + var touches = d3.event.changedTouches; + return touches ? d3.touches(target, touches)[0] : d3.mouse(target); + } + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= extent[1][0]; + origin[1] -= extent[1][1]; + dragging = 2; + } + d3_eventPreventDefault(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += extent[1][0]; + origin[1] += extent[1][1]; + dragging = 0; + d3_eventPreventDefault(); + } + } + function brushmove() { + var point = mouse(), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; + origin[0] = extent[+(point[0] < center[0])][0]; + origin[1] = extent[+(point[1] < center[1])][1]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0][i] !== min || extent[1][i] !== max) { + extentDomain = null; + extent[0][i] = min; + extent[1][i] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + dragRestore(); + event_({ + type: "brushend" + }); + } + } + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.clamp = function(z) { + if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; + if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + z = extentDomain || extent; + if (x) { + x0 = z[0][0], x1 = z[1][0]; + if (!extentDomain) { + x0 = extent[0][0], x1 = extent[1][0]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + y0 = z[0][1], y1 = z[1][1]; + if (!extentDomain) { + y0 = extent[0][1], y1 = extent[1][1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + extentDomain[0][0] = x0, extentDomain[1][0] = x1; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + extentDomain[0][1] = y0, extentDomain[1][1] = y1; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; + } + return brush; + }; + brush.clear = function() { + extentDomain = null; + extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; + return brush; + }; + brush.empty = function() { + return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + d3.time = {}; + var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + function d3_time_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + d3_time_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; + var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_time(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_time(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_time = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = date; + return method(utc, k)._; + } finally { + d3_time = Date; + } + }; + } + d3.time.year = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3.time.years = d3.time.year.range; + d3.time.years.utc = d3.time.year.utc.range; + d3.time.day = d3_time_interval(function(date) { + var day = new d3_time(2e3, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3.time.days = d3.time.day.range; + d3.time.days.utc = d3.time.day.utc.range; + d3.time.dayOfYear = function(date) { + var year = d3.time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + d3_time_daySymbols.forEach(function(day, i) { + day = day.toLowerCase(); + i = 7 - i; + var interval = d3.time[day] = d3_time_interval(function(date) { + (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3.time[day + "s"] = interval.range; + d3.time[day + "s"].utc = interval.utc.range; + d3.time[day + "OfYear"] = function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3.time.week = d3.time.sunday; + d3.time.weeks = d3.time.sunday.range; + d3.time.weeks.utc = d3.time.sunday.utc.range; + d3.time.weekOfYear = d3.time.sundayOfYear; + d3.time.format = function(template) { + var n = template.length; + function format(date) { + var string = [], i = -1, j = 0, c, p, f; + while (++i < n) { + if (template.charCodeAt(i) === 37) { + string.push(template.substring(j, i)); + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); + string.push(c); + j = i + 1; + } + } + string.push(template.substring(j, i)); + return string.join(""); + } + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0 + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var date = new d3_time(); + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + date.setFullYear(d.y, 0, 1); + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); + } else date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H, d.M, d.S, d.L); + return date; + }; + format.toString = function() { + return template; + }; + return format; + }; + function d3_time_parse(date, template, string, j) { + var c, p, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c === 37) { + p = d3_time_parsers[template.charAt(i++)]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map(), i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_formatPad(value, fill, width) { + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); + } + var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; + var d3_time_formatPads = { + "-": "", + _: " ", + "0": "0" + }; + var d3_time_formats = { + a: function(d) { + return d3_time_dayAbbreviations[d.getDay()]; + }, + A: function(d) { + return d3_time_days[d.getDay()]; + }, + b: function(d) { + return d3_time_monthAbbreviations[d.getMonth()]; + }, + B: function(d) { + return d3_time_months[d.getMonth()]; + }, + c: d3.time.format(d3_time_formatDateTime), + d: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + e: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + H: function(d, p) { + return d3_time_formatPad(d.getHours(), p, 2); + }, + I: function(d, p) { + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); + }, + j: function(d, p) { + return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); + }, + L: function(d, p) { + return d3_time_formatPad(d.getMilliseconds(), p, 3); + }, + m: function(d, p) { + return d3_time_formatPad(d.getMonth() + 1, p, 2); + }, + M: function(d, p) { + return d3_time_formatPad(d.getMinutes(), p, 2); + }, + p: function(d) { + return d.getHours() >= 12 ? "PM" : "AM"; + }, + S: function(d, p) { + return d3_time_formatPad(d.getSeconds(), p, 2); + }, + U: function(d, p) { + return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d, p) { + return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); + }, + x: d3.time.format(d3_time_formatDate), + X: d3.time.format(d3_time_formatTime), + y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 100, p, 2); + }, + Y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); + }, + Z: d3_time_zone, + "%": function() { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + j: d3_time_parseDayOfYear, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + U: d3_time_parseWeekNumberSunday, + w: d3_time_parseWeekdayNumber, + W: d3_time_parseWeekNumberMonday, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear, + "%": d3_time_parseLiteralPercent + }; + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekdayNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 1)); + return n ? (date.w = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberSunday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.U = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberMonday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.W = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 4)); + return n ? (date.y = +n[0], i + n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.d = +n[0], i + n[0].length) : -1; + } + function d3_time_parseDayOfYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.j = +n[0], i + n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.H = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.M = +n[0], i + n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.S = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.L = +n[0], i + n[0].length) : -1; + } + var d3_time_numberRe = /^\s*\d+/; + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + var d3_time_amPmLookup = d3.map({ + am: 0, + pm: 1 + }); + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); + } + function d3_time_parseLiteralPercent(date, string, i) { + d3_time_percentRe.lastIndex = 0; + var n = d3_time_percentRe.exec(string.substring(i, i + 1)); + return n ? i + n[0].length : -1; + } + d3.time.format.utc = function(template) { + var local = d3.time.format(template); + function format(date) { + try { + d3_time = d3_time_utc; + var utc = new d3_time(); + utc._ = date; + return local(utc); + } finally { + d3_time = Date; + } + } + format.parse = function(string) { + try { + d3_time = d3_time_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_time = Date; + } + }; + format.toString = local.toString; + return format; + }; + var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3.time.second = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3.time.seconds = d3.time.second.range; + d3.time.seconds.utc = d3.time.second.utc.range; + d3.time.minute = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3.time.minutes = d3.time.minute.range; + d3.time.minutes.utc = d3.time.minute.utc.range; + d3.time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3.time.hours = d3.time.hour.range; + d3.time.hours.utc = d3.time.hour.utc.range; + d3.time.month = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3.time.months = d3.time.month.range; + d3.time.months.utc = d3.time.month.utc.range; + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + scale.nice = function(m) { + return scale.domain(d3_scale_nice(scale.domain(), m)); + }; + scale.ticks = function(m, k) { + var extent = d3_scaleExtent(scale.domain()); + if (typeof m !== "function") { + var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); + if (i == d3_time_scaleSteps.length) return methods.year(extent, m); + if (!i) return linear.ticks(m).map(d3_time_scaleDate); + if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; + m = methods[i]; + k = m[1]; + m = m[0].range; + } + return m(extent[0], new Date(+extent[1] + 1), k); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_time_scaleDate(t) { + return new Date(t); + } + function d3_time_scaleFormat(formats) { + return function(date) { + var i = formats.length - 1, f = formats[i]; + while (!f[1](date)) f = formats[--i]; + return f[0](date); + }; + } + function d3_time_scaleSetYear(y) { + var d = new Date(y, 0, 1); + d.setFullYear(y); + return d; + } + function d3_time_scaleGetYear(d) { + var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; + var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { + return d.getMonth(); + } ], [ d3.time.format("%b %d"), function(d) { + return d.getDate() != 1; + } ], [ d3.time.format("%a %d"), function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ d3.time.format("%I %p"), function(d) { + return d.getHours(); + } ], [ d3.time.format("%I:%M"), function(d) { + return d.getMinutes(); + } ], [ d3.time.format(":%S"), function(d) { + return d.getSeconds(); + } ], [ d3.time.format(".%L"), function(d) { + return d.getMilliseconds(); + } ] ]; + var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); + d3_time_scaleLocalMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); + }; + d3.time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { + return d.getUTCMonth(); + } ], [ d3.time.format.utc("%b %d"), function(d) { + return d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%a %d"), function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%I %p"), function(d) { + return d.getUTCHours(); + } ], [ d3.time.format.utc("%I:%M"), function(d) { + return d.getUTCMinutes(); + } ], [ d3.time.format.utc(":%S"), function(d) { + return d.getUTCSeconds(); + } ], [ d3.time.format.utc(".%L"), function(d) { + return d.getUTCMilliseconds(); + } ] ]; + var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); + function d3_time_scaleUTCSetYear(y) { + var d = new Date(Date.UTC(y, 0, 1)); + d.setUTCFullYear(y); + return d; + } + function d3_time_scaleUTCGetYear(d) { + var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + d3_time_scaleUTCMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); + }; + d3.time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + }; + d3.text = d3_xhrType(function(request) { + return request.responseText; + }); + d3.json = function(url, callback) { + return d3_xhr(url, "application/json", d3_json, callback); + }; + function d3_json(request) { + return JSON.parse(request.responseText); + } + d3.html = function(url, callback) { + return d3_xhr(url, "text/html", d3_html, callback); + }; + function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); + } + d3.xml = d3_xhrType(function(request) { + return request.responseXML; + }); + return d3; +}(); +},{}],3:[function(require,module,exports){ +require("./d3"); +module.exports = d3; +(function () { delete this.d3; })(); // unset global + +},{"./d3":2}],4:[function(require,module,exports){ +var ich = require('icanhaz') + +module.exports.ich = ich + +module.exports.getKeywordCount = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group.length + if (group = []) return "0" +} + +module.exports.getKeyword = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group + if (group = []) return "no matches" +} + +module.exports.getColumnTotal = function(data, column) { + var total = [] + data.forEach(function (d) { + if (d[column] === "") return + total.push(+d[column]) + }) + return total.reduce(function(a,b) { + return a + b + }) +} + +module.exports.getColumnAverage = function(data, column) { + var total = getColumnTotal(data, column) + var average = total / data.length + return average +} + +module.exports.getMax = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() > result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +module.exports.getMin = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() < result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +// out of the data, filter something from a category +module.exports.getMatches = function (data, filter, category) { + var matches = [] + data.forEach(function (element) { + var projectType = element[category].toString().toLowerCase() + if (projectType === filter.toLowerCase()) matches.push(element) + }) + return matches +} + +module.exports.mostFrequent = function(data, category) { + var count = {} + for (var i = 0; i < data.length; i++) { + if (!count[data[i][category]]) { + count[data[i][category]] = 0 + } + count[data[i][category]]++ + } + var sortable = [] + for (var category in count) { + sortable.push([category, count[category]]) + } + sortable.sort(function(a, b) {return b[1] - a[1]}) + return sortable + // returns array of arrays, in order +} + +// thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ +module.exports.deepCopy = function(obj) { + if (Object.prototype.toString.call(obj) === '[object Array]') { + var out = [], i = 0, len = obj.length; + for ( ; i < len; i++ ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + if (typeof obj === 'object') { + var out = {}, i; + for ( i in obj ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + return obj; +} + +module.exports.getOccurance = function(data, category) { + var occuranceCount = {} + for (var i = 0; i < data.length; i++) { + if (!occuranceCount[data[i][category]]) { + occuranceCount[data[i][category]] = 0 + } + occuranceCount[data[i][category]]++ + } + return occuranceCount + // returns object, keys alphabetical +} + +module.exports.makeColorArrayOfObject = function(data, colors, category) { + var category = category + var keys = Object.keys(data) + var counter = 1 + var colorIndex + return keys.map(function(key){ + if (keys.length > colors.length || keys.length <= colors.length ) { + colorIndex = counter % colors.length + } + var h = {units: data[key], hexcolor: colors[colorIndex]} + h[category] = key + counter++ + colorIndex = counter + return h + }) +} + +module.exports.makeArrayOfObject = function(data) { + var keys = Object.keys(data) + return keys.map(function(key){ + // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} + var h = {label: key, units: data[key]} + return h + }) +} + +module.exports.setup = function() { + $(document).on("click", ".tHeader", Sheetsee.sendToSort) +} + +},{"icanhaz":5}],5:[function(require,module,exports){ +/*! +ICanHaz.js version 0.10.2 -- by @HenrikJoreteg +More info at: http://icanhazjs.com +*/ +(function () { +/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.4.0", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +/*! + ICanHaz.js -- by @HenrikJoreteg +*/ +/*global */ +(function () { + function trim(stuff) { + if (''.trim) return stuff.trim(); + else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + var ich = { + VERSION: "0.10.2", + templates: {}, + + // grab jquery or zepto if it's there + $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, + + // public function for adding templates + // can take a name and template string arguments + // or can take an object with name/template pairs + // We're enforcing uniqueness to avoid accidental template overwrites. + // If you want a different template, it should have a different name. + addTemplate: function (name, templateString) { + if (typeof name === 'object') { + for (var template in name) { + this.addTemplate(template, name[template]); + } + return; + } + if (ich[name]) { + console.error("Invalid name: " + name + "."); + } else if (ich.templates[name]) { + console.error("Template \"" + name + " \" exists"); + } else { + ich.templates[name] = templateString; + ich[name] = function (data, raw) { + data = data || {}; + var result = Mustache.to_html(ich.templates[name], data, ich.templates); + return (ich.$ && !raw) ? ich.$(trim(result)) : result; + }; + } + }, + + // clears all retrieval functions and empties cache + clearAll: function () { + for (var key in ich.templates) { + delete ich[key]; + } + ich.templates = {}; + }, + + // clears/grabs + refresh: function () { + ich.clearAll(); + ich.grabTemplates(); + }, + + // grabs templates from the DOM and caches them. + // Loop through and add templates. + // Whitespace at beginning and end of all templates inside + + + + + + + + + + + + + + + diff --git a/demos/demo-map.html b/demos/demo-map.html new file mode 100644 index 00000000..0a9fc126 --- /dev/null +++ b/demos/demo-map.html @@ -0,0 +1,33 @@ + + + Sheetsee Maps Demo + + + + + + + + + + + + + + + + + diff --git a/demos/demo-table.html b/demos/demo-table.html new file mode 100644 index 00000000..5bd12654 --- /dev/null +++ b/demos/demo-table.html @@ -0,0 +1,33 @@ + + + Sheetsee Table Demo + + + + + + + + + + + + + + + + + From 9a4101d0a229fc1ed9a17acc3e7c59be6e1c27e0 Mon Sep 17 00:00:00 2001 From: jlord Date: Tue, 10 Dec 2013 22:38:33 -0800 Subject: [PATCH 015/157] updating docs and repo --- changelog.md | 22 --- docs.md | 447 ------------------------------------------------- docs/about.md | 18 +- docs/basics.md | 85 ++++++++++ index.html | 33 ---- template.html | 30 ++++ 6 files changed, 130 insertions(+), 505 deletions(-) delete mode 100644 changelog.md delete mode 100644 docs.md create mode 100644 docs/basics.md delete mode 100644 index.html create mode 100644 template.html diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 6aba04ae..00000000 --- a/changelog.md +++ /dev/null @@ -1,22 +0,0 @@ -## August 13, 2013 -### Charting Intake - -D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart. - -Previously Sheetsee required you pass your data through a function, `addUnitsAndLabels()` which took in your data and the things you wanted to chart, reformatted your data for you so that you could pass it into one of the d3 charts. This is one more step than actually needs to happen. - -Now Sheetsee just asks for what you want your _labels_ and _units_ to be in the options you give it when calling the chart function. It then sorts the data correctly on the inside of the chart function. Yay, easier! - -``` - var options = { - labels: "name", - units: "cuddleability", - m: [60, 60, 30, 150], - w: 600, h: 400, - div: "#barChart", - xaxis: "no. of pennies", - hiColor: "#FF317D" - } -``` - -Thanks @maxogden for the help with this. diff --git a/docs.md b/docs.md deleted file mode 100644 index 076e886c..00000000 --- a/docs.md +++ /dev/null @@ -1,447 +0,0 @@ -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/sheetsee-03.png) -# Sheetsee.js -Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page. - -Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with. - -To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see [JavaScript for Cats](http://www.jsforcats.com), [Eloquent JavaScript](http://eloquentjavascript.net/) or [Mozilla's Developer Network](https://developer.mozilla.org/en-US/docs/JavaScript). - -### Dependencies - -Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, [Tabletop.js](http://builtbybalance.com/Tabletop/) gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with [IChanHas.js](http://icanhazjs.com/)(built on [mustache.js](http://mustache.github.io/)), maps with [Mapbox.js](http://mapbox.com/mapbox.js/example/v1.0.0/), and charts with [d3.js](http://d3js.org/). And [jQuery](http://jquery.com/) of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below. - -### Building - -```bash -[sudo] npm install -g browserify uglify-js -npm install -make -``` - -### CSS - -Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design. - -### Client-side or Server-side - -Sheetsee.js comes in two flavors, [client-side]() and [server-side](). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal. - -The server-side version is built with [Node.js](http://www.nodejs.org) and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah! - -## The Short & Sweet - -1. Link to Sheetsee.js and dependencies in your HTML header. -2. Create a place holder `
` in your HTML for any chart, map or table you want to have. -3. Create templates for tables in ` - - - - - - -
- - - - -## Awesome Possibilities - -1. Small newsrooms with data for stories but small dev teams. -2. Friends or groups collaborating on data for a website/project. -3. Using [iftt.com](http://www.ifttt.com) to auto populate spreadsheets which are hooked to a website with Sheetsee.js. - -## Examples -1. Hack Spots -2. Pennies -3. [James Sconfitto](https://twitter.com/jugglingnutcase) make a [map of his relationship](https://github.com/jugglingnutcase/katiejamie) with his wife <3 - -## Getting Started - -This bit is the same for both client-side and server-side versions. - -### Your Data - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) - -Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/nonos.png) - -There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting. - - [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] - -#### Hexcolor - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) - -You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! - -#### Geocoding - -If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) - that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. - -> image of lat and long column headers - -#### Publishing Your Spreadsheet - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) - -You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click _File_ > _Publish to the Web_. Then in the next window click _Start Publishing_; it will then turn into a _Stop Publishing_ button. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) - -You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. - -### Your Website - -Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet. - -For now, create empty `div` placeholders for the map, chart and tables you plan on including. - -## Hooking Up Your Data - -Here the paths diverge: - -### Client-side Hookup - -Your Key - -### Server-side Hookup - -Yada. - -#### Running Locally - -Yada. - -## Working With Your Data - -Tabletop.js will return all of your data and it will be passed into your site as an _array of objects_ called **gData**. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like. - -### Sheetsee.getGroupCount(data, groupTerm) - -This takes in your data, an _array of objects_, and searches for a _string_, **groupTerm**, in each piece of your **data** (formerly the cells of your spreadsheet). It returns the number of times it found the **groupTerm**. - - getGroupCount(gData, "cat") - // returns 2 - -### Sheetsee.getColumnTotal(data, column) - -Given your **data**, an _array of objects_ and a _string_ **column** header, this functions sums each cell in that column, so they best be numbers. - - getColumnTotal(gData, "cuddlability") - // returns 11 - -### Sheetsee.getAveragefromColumn(data, column) - -A really simple function that builds on `getColumnTotal()` by returning the average number in a **column** of numbers. - - getColumnAverage(gData, "cuddlability") - // returns 1.8333333333333333 - -### Sheetsee.getMin(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the lowest number value in the **column** you specify from your **data**. - - getMin(gData, "cuddlability") - // returns {breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...} - -### Sheetsee.getMax(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the highest number value in the **column** you specify from your **data**. - - getMin(gData, "cuddlability") - // returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...} - -### Don't Forget JavaScript Math - -Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that [here on MDN](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math). - - var profit09 = Sheetsee.getColumnTotal(gData, "2009") - var profit10 = Sheetsee.getColumnTotal(gData, "2010") - var difference = profit09 - profit10 - -#### What These Little Bits are Good For - -You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about [icanhas.js](http://icanhazjs.com/). View source on this page to see how I created "Most Cuddlable". - -### Sheetsee.getMatches(data, filter, category) - -Takes **data** as an _array of objects_, a _string_ you'd like to **filter** and a _string_ of the **category** you want it to look in (a column header from your spreadsheet). - - getMatches(gData, "dog", "kind") - -Returns an _array of objects_ matching the category's filter. - - [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ] - - -### Sheetsee.getOccurance(data, category) - -Takes **data** as an _array of objects_ and a _string_ for **category** (a column header from your spreadsheet) you want tally how often an element occured. - - getOccurance(gData, "kind") - -Returns an object with keys and values for each variation of the category and its occurance. - - {"dog": 3, "cat": 3} - -### Sheetsee.makeColorArrayOfObject(data, colors) - -If you use `getOccurance()` and want to then chart that data with d3.js, you'll need to make it into an _array_ (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset). - -This function takes in your data, as an _object_, and an _array_ of hexidecimal color strings which you define. - - var kinds = getOccurance(gData, "kind") - var kindColors = ["#ff00ff", "#DCF13C"] - - var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors) - -It will return an array of objects formatted to go directly into a d3 chart with the appropriate _units_ and _label keys_, like so: - - [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}] - -If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements. - -### Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits) - -If you're using gData, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number). - - var gData = [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}] - -For istance, if from our original data above we want to chart the age of each cat, we'll use: - - Sheetsee.addUnitsLabels(gData, "name", "cuddlability") - -Which will return an array, ready for the d3 charts: - - [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}] - - -## Make a Map - -Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [Leaflet.js](http://leafletjs.com/) plugin, to make maps. - -Create an empty `
` in your HTML, with an id. - -
- -Next you'll need to create geoJSON out of your data so that it can be mapped. - -### Sheetsee.createGeoJSON(data, optionsJSON) - -This takes in your **data** and the parts of your data, **optionsJSON**, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data. - - var optionsJSON = ["name", "breed", "cuddlability"] - var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON) - -It will return an _array_ in the special geoJSON format that map making things love. - - [{ - "geometry": {"type": "Point", "coordinates": [long, lat]}, - "properties": { - "marker-size": "small", - "marker-color": lineItem.hexcolor - }, - "opts": {the options you pass in}, - }} - - -### Sheetsee.loadMap(mapDiv) - -To create a simple map, with no data, you simply call `.loadMap() and pass in a _string_ of the **mapDiv** (with no #) from your HTML. - - var map = Sheetsee.loadMap("map") - -### Sheetsee.addTileLayer(map, tileLayer) - -To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your **map** and the source of the **tileLayer**. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See [Mapbox's Documentation](http://mapbox.com/mapbox.js/api/v1.0.2/#L.mapbox.tileLayer) for more information. - - Sheetsee.addTileLayer(map, 'examples.map-20v6611k') - -You can add tiles from awesome mapmakers like [Stamen](examples.map-20v6611k) or create your own in Mapbox's [Tilemill](http://www.mapbox.com/tilemill) or [online](https://tiles.mapbox.com/newmap#3.00/0.00/0.00). - -### Sheetsee.addMarkerLayer(geoJSON, map) - -To add makers to your map, use this function and pass in your **geoJSON** so that it can get the coordinates and your **map** so that it places the markers there. - - var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map) - -### Sheetsee.addPopups(map, markerLayer) - -To customize the marker popup content in your map use this function and pass in your **map** and **markerLayer**. - - Sheetsee.addPopups(map, markerLayer) - -**customize popup content** - -## Make a Table - -Sheetsee.js supports making multiple tables or templates with IcanHas.js. It currently supports sorting and filtering on just one table. For each of these you'll need a `
` in your html, a ` - -#### Your ` - -To create another table, simply repeat the steps except for `initiateTableFilter()` - -
- - - - Learn more about the things you can do with [mustache.js](http://mustache.github.io/). - - -### Sheetsee.makeTable(data, targetDiv) - -You'll call this to make a table out of a **data** and tell it what **targetDiv** in the html to render it in (this should also be the same id as your script template id). - - Sheetsee.makeTable(gData, "#siteTable") - -## Table Filter/Search - -If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html: - - - Clear - no matches - -### Sheetsee.initiateTableFilter(data, filterDiv, tableDiv) - -You will then call this function to make that input live: - - Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable") - -## Make a Chart - -Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an _array of objects_, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting. - -You'll have to experiement with the charts to find the correct size your `
` will need to be to hold the chart with your data in it nicely. - -You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee. - -### Bar Chart - -To create a bar chart you'll need to add a placeholder `
` in your HTML with an id. - -
- -In your CSS, give it dimensions. - - #barChart {height: 400px; max-width: 600px; background: #F8CDCD;} - -In a ` + + + + + + +
+ + + + +## Getting Started + +This bit is the same for both client-side and server-side versions. + +### Your Data + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) + +Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data. + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/nonos.png) + +There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting. + + [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] + +#### Hexcolor + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) + +You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! + +#### Geocoding + +If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) + that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. + +> image of lat and long column headers + +#### Publishing Your Spreadsheet + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) + +You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click _File_ > _Publish to the Web_. Then in the next window click _Start Publishing_; it will then turn into a _Stop Publishing_ button. + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) + +You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. + +### Your Website + +Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet. + +For now, create empty `div` placeholders for the map, chart and tables you plan on including. diff --git a/index.html b/index.html deleted file mode 100644 index 4c8c80f3..00000000 --- a/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - Yo, yo, yo! - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/template.html b/template.html new file mode 100644 index 00000000..65cd0abf --- /dev/null +++ b/template.html @@ -0,0 +1,30 @@ + + + Yo, yo, yo! + + + + + + + + + + + + + + + + \ No newline at end of file From c4a4e42449dca22d68cfa1d4e300c132e7c6d7bd Mon Sep 17 00:00:00 2001 From: jlord Date: Wed, 18 Dec 2013 17:42:00 -0800 Subject: [PATCH 016/157] working on templates --- ...6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json | 1 + demos/demo-table.html | 38 +- demos/demo.html | 505 ++++++++++++++++++ demos/template.html | 30 ++ docs/basics.md | 5 +- js/sheetsee.js | 322 ++++++++--- 6 files changed, 797 insertions(+), 104 deletions(-) create mode 100644 demos/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json create mode 100644 demos/demo.html create mode 100644 demos/template.html diff --git a/demos/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json b/demos/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json new file mode 100644 index 00000000..fc390fce --- /dev/null +++ b/demos/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json @@ -0,0 +1 @@ +[{"id":"0","placename":"Oakland Zoo","venue":"Oakland Zoo","image":"elephant","noun":"animal","lat":"37.7502645413531","long":"-122.14675065","hexcolor":"#FFE7E7","city":"Oakland","state":"California","year":"2013","photo-url":"","rowNumber":1},{"id":"1","placename":"Winchester Mystery House","venue":"Winchester Mystery House","image":"mansion","noun":"place","lat":"37.3183373","long":"-121.9510439","hexcolor":"#F7CE86","city":"San Jose","state":"California","year":"2012","photo-url":"","rowNumber":2},{"id":"2","placename":"Winchester Mystery House","venue":"Winchester Mystery House","image":"Sarah Winchester","noun":"person","lat":"37.3183373","long":"-121.9510439","hexcolor":"#F78585","city":"San Jose","state":"California","year":"2012","photo-url":"","rowNumber":3},{"id":"3","placename":"Amerian Museum of Natural History","venue":"Amerian Museum of Natural History","image":"mammoth","noun":"animal","lat":"40.7809389","long":"-73.9730135","hexcolor":"#FFE7E7","city":"Washington DC","state":"Washington DC","year":"2011","photo-url":"","rowNumber":4},{"id":"4","placename":"Six Flags Over Georgia","venue":"Six Flags Over Georgia","image":"Viper","noun":"animal, ride","lat":"33.767303","long":"-84.551204","hexcolor":"#F7CE86","city":"Atlanta","state":"Georgia","year":"2000","photo-url":"","rowNumber":5},{"id":"5","placename":"World Trade Center","venue":"","image":"skyline","noun":"place","lat":"40.7143528","long":"-74.0059731","hexcolor":"#F7CE86","city":"New York City","state":"New York","year":"2008","photo-url":"","rowNumber":6},{"id":"6","placename":"The St. Pete Pier","venue":"The St. Pete Pier","image":"pier building","noun":"place","lat":"27.773566","long":"-82.622326","hexcolor":"#F7CE86","city":"St. Petersburg","state":"Florida","year":"1998","photo-url":"","rowNumber":7},{"id":"7","placename":"Miss Katie's Restaurant","venue":"","image":"logo","noun":"graphic","lat":"33.8081608","long":"-84.170196","hexcolor":"#F78585","city":"Stone Mountain","state":"Georgia","year":"1993","photo-url":"","rowNumber":8},{"id":"8","placename":"Rhode Island","venue":"","image":"ship","noun":"thing","lat":"41.8239891","long":"-71.4128343","hexcolor":"#FFE7E7","city":"Providence","state":"Rhode Island","year":"2008","photo-url":"","rowNumber":9},{"id":"9","placename":"River Street, Savannah","venue":"","image":"skyline","noun":"place","lat":"32.0814473472438","long":"-81.0903453826904","hexcolor":"#F78585","city":"Savannah ","state":"Georgia","year":"2004","photo-url":"","rowNumber":10},{"id":"10","placename":"Natchez New Orleans","venue":"","image":"ship","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2007","photo-url":"","rowNumber":11},{"id":"11","placename":"Margarittaville","venue":"","image":"drink","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2007","photo-url":"","rowNumber":12},{"id":"12","placename":"Woodman's","venue":"Woodman's","image":"clam","noun":"animal","lat":"42.630151","long":"-70.774552","hexcolor":"#F78585","city":"Essex","state":"Massachusetts","year":"2008","photo-url":"","rowNumber":13},{"id":"13","placename":"Summit Pikes Peak","venue":"Summit Pikes Peak","image":"logo","noun":"graphic","lat":"38.840556","long":"-105.044167","hexcolor":"#F78585","city":"Pikes Peak","state":"Colorado","year":"2002","photo-url":"","rowNumber":14},{"id":"14","placename":"Polar Caves Park","venue":"Polar Caves Park","image":"polar bear","noun":"animal","lat":"43.7940757","long":"-71.8508395","hexcolor":"#F78585","city":"Rumney","state":"New Hampshire","year":"2010","photo-url":"","rowNumber":15},{"id":"15","placename":"Rainforest Cafe","venue":"OpryMills","image":"butterfly","noun":"animal","lat":"36.2051067","long":"-86.6938833","hexcolor":"#F7CE86","city":"Nashville","state":"Tennessee","year":"1999","photo-url":"","rowNumber":16},{"id":"16","placename":"National Museum of American History","venue":"National Museum of American History","image":"house","noun":"place","lat":"38.8911993","long":"-77.0300391","hexcolor":"#F78585","city":"Washington DC","state":"Washington DC","year":"2011","photo-url":"","rowNumber":17},{"id":"17","placename":"Boston Celtics","venue":"TD Garden","image":"mascot","noun":"person","lat":"42.3660275025778","long":"-71.0615873336792","hexcolor":"#FFE7E7","city":"Boston","state":"Massachusetts","year":"2010","photo-url":"","rowNumber":18},{"id":"18","placename":"Cafe du Monde","venue":"Cafe Du Monde","image":"coffee and bengiet","noun":"food","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2012","photo-url":"","rowNumber":19},{"id":"19","placename":"Six Flags Over Georgia","venue":"Six Flags Over Georgia","image":"Wylie Cyotte","noun":"animal","lat":"33.767303","long":"-84.551204","hexcolor":"#FFE7E7","city":"Atlanta","state":"Georgia","year":"2003","photo-url":"","rowNumber":20},{"id":"20","placename":"Mardis Gras","venue":"","image":"masks","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2004","photo-url":"","rowNumber":21},{"id":"21","placename":"Buzz Lightyear","venue":"Six Flags Over Georgia","image":"Buzz Lightyear","noun":"person","lat":"28.3702563165193","long":"-81.5497970581055","hexcolor":"#F78585","city":"Walt Disney World","state":"Florida","year":"2001","photo-url":"","rowNumber":22},{"id":"22","placename":"Independence Hall","venue":"Independence Hall","image":"Indepence Hall","noun":"place","lat":"39.952335","long":"-75.163789","hexcolor":"#FFE7E7","city":"Philadelphia","state":"Pennsylvania","year":"2008","photo-url":"","rowNumber":23},{"id":"23","placename":"Golden Gate Bridge","venue":"","image":"Golden Gate Bridge","noun":"thing","lat":"37.809783953011","long":"-122.47740983963","hexcolor":"#FFE7E7","city":"San Francisco","state":"California","year":"2011","photo-url":"","rowNumber":24},{"id":"24","placename":"Pirates of the Caribean","venue":"Magic Kingdom, Walt Disney World","image":"Goofey","noun":"person","lat":"28.3702563165193","long":"-81.5497970581055","hexcolor":"#FFE7E7","city":"Walt Disney World","state":"Florida","year":"2001","photo-url":"","rowNumber":25},{"id":"25","placename":"Boston Skyline","venue":"TD Garden","image":"skyline","noun":"place","lat":"42.3660275025778","long":"-71.0615873336792","hexcolor":"#FFE7E7","city":"Boston","state":"Massachusetts","year":"2009","photo-url":"","rowNumber":26},{"id":"26","placename":"Johnny Bravo","venue":"Six Flags Over Georgia","image":"Johnny Bravo","noun":"person","lat":"33.767303","long":"-84.551204","hexcolor":"#FFE7E7","city":"Atlanta","state":"Georgia","year":"2003","photo-url":"","rowNumber":27},{"id":"27","placename":"Busch Gardens","venue":"Busch Gardens","image":"clydesdale","noun":"animal","lat":"28.033158","long":"-82.420593","hexcolor":"#F78585","city":"Tampa","state":"Florida","year":"2002","photo-url":"","rowNumber":28},{"id":"28","placename":"California Academy of Sciences","venue":"California Academy of Sciences","image":"aligator","noun":"animal","lat":"37.769979","long":"-122.466288","hexcolor":"#FFE7E7","city":"San Francisco","state":"California","year":"2012","photo-url":"","rowNumber":29},{"id":"29","placename":"Santa Monica Pier","venue":"Pacific Park","image":"rollercoaster","noun":"thing","lat":"34.009471","long":"-118.497322","hexcolor":"#F78585","city":"Santa Monica","state":"California","year":"2013","photo-url":"","rowNumber":30},{"id":"30","placename":"Monterey Aquarium","venue":"Monterey Aquarium","image":"animal","noun":"animal","lat":"36.618032","long":"-121.902054","hexcolor":"#FFE7E7","city":"Monterey","state":"California","year":"2013","photo-url":"","rowNumber":31},{"id":"31","placename":"Hearst Castle","venue":"Hearst Castle","image":"architecture","noun":"architecture","lat":"35.685312","long":"-121.16894","hexcolor":"#F78585","city":"San Simeon","state":"California","year":"2013","photo-url":"","rowNumber":32}] \ No newline at end of file diff --git a/demos/demo-table.html b/demos/demo-table.html index 5bd12654..fa2841d0 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -1,31 +1,39 @@ Sheetsee Table Demo - - - - + + + - + - + +
- diff --git a/demos/demo.html b/demos/demo.html new file mode 100644 index 00000000..fdaed1f3 --- /dev/null +++ b/demos/demo.html @@ -0,0 +1,505 @@ + + + Yo, yo, yo! + + + + + + + + + + + + + + + +
+

sheetsee

+

Sheetsee.js

+

Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page.

+

Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with.

+

To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see JavaScript for Cats, Eloquent JavaScript or Mozilla's Developer Network.

+ +

Dependencies

+

Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, Tabletop.js gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with IChanHas.js (built on mustache.js), maps with Mapbox.js, and charts with d3.js. And jQuery of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below.

+ +

CSS

+

Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design.

+ +

Client-side or Server-side

+

Sheetsee.js comes in two flavors, client-side (this repo) and server-side (sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal.

+

The server-side version is built with Node.js and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah!

+ +
+

The Short & Sweet

+
    +
  1. Link to Sheetsee.js and dependencies in your HTML header.
  2. +
  3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
  4. +
  5. Create templates for tables in <script> tags.
  6. +
  7. Create a script tag that waits for the document to load and then executes any of the map, chart or tables you've specified in it.
  8. +
  9. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information everytime they load the page.
  10. +
+
+ +

Bare Minimum Setup

+

Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

+
<html>
+    <head>
+        <script type="text/javascript" src="http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.js"></script>
+        <script type="text/javascript" src="js/ICanHaz.js"></script>
+        <script type="text/javascript" src="js/jquery.js"></script>
+        <script type="text/javascript" src="js/tabletop.js"></script>
+        <script type="text/javascript" src="js/d3.js"></script>
+        <script type="text/javascript" src="js/sheetsee.js"></script>
+        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.css' rel='stylesheet' />
+    </head>
+    <style> #map {height: 600px; width: 600px;} </style>
+    <body>
+    <div id="map"></div>
+    <script type="text/javascript">
+      document.addEventListener('DOMContentLoaded', function() {
+        var gData
+        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
+        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
+      })
+      function showInfo(data) {
+        gData = data
+        optionsJSON = ["something", "something"]
+        var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
+        var map = Sheetsee.loadMap("map")
+        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
+        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
+        // customize the popup content
+        addPopups(map, markerLayer)
+        function addPopups(map, markerLayer) {
+          markerLayer.on('click', function(e) {
+            var feature = e.layer.feature
+            var popupContent = '<h3>' + feature.opts.something + '</h3>'
+            e.layer.bindPopup(popupContent,{closeButton: false})
+          })
+        }
+      }
+    </script>
+    </body>
+</html>
+ +

Awesome Possibilities

+
    +
  1. Small newsrooms with data for stories but small dev teams.
  2. +
  3. Friends or groups collaborating on data for a website/project.
  4. +
  5. Using iftt.com to auto populate spreadsheets which are hooked to a website with Sheetsee.js.
  6. +
+ +

Examples

+
    +
  1. Hack Spots
  2. +
  3. James Sconfitto make a map of his relationship with his wife <3
  4. +
+ +

Getting Started

+

This bit is the same for both client-side and server-side versions.

+

Your Data

+

sheetsee

+

Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

+

sheetsee

+

There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

+
[{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
+ +

Hexcolor

+

sheetsee

+

You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

+ +

Geocoding

+

If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin + that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

+ sheetsee +

Publishing Your Spreadsheet

+

sheetsee

+

You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

+

sheetsee

+

You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet.

+

Your Website

+

Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet.

+

For now, create empty div placeholders for the map, chart and tables you plan on including.

+

Hooking Up Your Data

+

Here the paths diverge:

+

Client-side Hookup

+

For client-siders, all you need to do is include the depences and sheetsee in your HTML <head> and then in a script tag at the bottom of your page, right before the </body> tag, you'll include this:

+
<script type="text/javascript">
+    document.addEventListener('DOMContentLoaded', function() {
+        var gData
+        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
+        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
+    })
+    function showInfo(data) {
+        gData = data
+        //
+        //everything you do with sheetsee goes here
+        //
+    }
+</script>
+

The URL variable is the key from your spreadsheet's longer URL, explained above. Tabletop.init() takes that URL and execute's Tabletop, when it's done generating the table it executes the callback showInfo function. It's inside of this function that you'll then use your spreadsheet data, gData, to do all the Sheetsee.js goodness with.

+

Server-side Hookup

+

The server-side version is in the repo sheetsee-cache. It uses Node.js to go to Google, get the spreadsheet data (with a Node.js version of Tabletop.js, thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data.

+

When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled.

+
<script type="text/javascript">
+    document.addEventListener('DOMContentLoaded', function() {
+        // table/templating things the rest can be in their own script tags if you'd like
+    })
+</script>
+

Running Locally

+

You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay!

+

Once you clone the repo, navigate there in Terminal, install the node modules and launch the server.

+
cd sheetsee-cache
+npm install
+node server.js
+

This will launch a local server you can visit and develop locally with in your browser.

+

Working With Your Data

+

Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

+

Play Along!

+

This page is using sheetsee. If you (are in Chrome and) right click on the page and select Inspect Element it will bring up the Web Inspector. Select the Console tab. Now you can interact with the data and functions from Sheetsee. Give the functions below a try - gData is the variable with the data (from this spreadsheet). + sheetsee +

Sheetsee.getKeyword(data, keyword)

+

This takes in your data, an array of objects, and searches for a string, keyword, in each piece of your data (formerly the cells of your spreadsheet). It returns an array of each row that contained a keyword match. Similarly, using `getKeywordCount(data, keyword)` will return just the number of times the keyword occured.

+
getKeyword(gData, "cat")
+// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}]
+

Sheetsee.getColumnTotal(data, column)

+

Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

+
getColumnTotal(gData, "cuddlability")
+// returns 11
+

Sheetsee.getAveragefromColumn(data, column)

+

A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

+
getColumnAverage(gData, "cuddlability")
+// returns 1.8333333333333333
+

Sheetsee.getMin(data, column)

+

This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

+
getMin(gData, "cuddlability")
+// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}]
+ +

Sheetsee.getMax(data, column)

+

This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

+
getMax(gData, "cuddlability")
+// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
+ +
+ + +

Don't Forget JavaScript Math

+

Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

+
var profit09 = Sheetsee.getColumnTotal(gData, "2009")
+var profit10 = Sheetsee.getColumnTotal(gData, "2010")
+var difference = profit09 - profit10
+

What These Little Bits are Good For

+

You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

+ +

Sheetsee.getMatches(data, filter, category)

+

Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

+
getMatches(gData, "dog", "kind")
+

Returns an array of objects matching the category's filter.

+
[{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
+ +

Sheetsee.getOccurance(data, category)

+

Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

+
getOccurance(gData, "kind")
+

Returns an object with keys and values for each variation of the category and its occurance.

+
{"dog": 3, "cat": 3}
+ +

Sheetsee.makeColorArrayOfObject(data, colors)

+

If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

+

This function takes in your data, as an object, an array of hexidecimal color strings which you define and the category you used in getOccurance().

+
var kinds = getOccurance(gData, "kind")
+var kindColors = ["#ff00ff", "#DCF13C"]
+var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors, "kind")
+

It will return an array of objects with units as the title of the occurance amount like so:

+
[{"kind": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"kind": "cat", "units": 3, "hexcolor": "#DCF13C"}]
+

If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

+ +

Make a Map

+
+

Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps.

+

Create an empty <div> in your HTML, with an id.

+
<div id="map"></div>
+

Next you'll need to create geoJSON out of your data so that it can be mapped.

+ +

Sheetsee.createGeoJSON(data, optionsJSON)

+

This takes in your data and the parts of your data, optionsJSON, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data.

+
var optionsJSON = ["name", "breed", "cuddlability"]
+var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
+

It will return an array in the special geoJSON format that map making things love.

+
[{
+  "geometry": {"type": "Point", "coordinates": [long, lat]},
+  "properties": {
+    "marker-size": "small",
+    "marker-color": lineItem.hexcolor
+  },
+  "opts": {the options you pass in},
+}}
+ +

Sheetsee.loadMap(mapDiv)

+

To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

+
var map = Sheetsee.loadMap("map")
+ +

Sheetsee.addTileLayer(map, tileLayer)

+

To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

+
Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
+

You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

+ +

Sheetsee.addMarkerLayer(geoJSON, map)

+

To add makers to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there.

+
var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
+ +

Sheetsee.addPopups(map, markerLayer)

+

To customize the marker popup content in your map use this function and pass in your map and markerLayer.

+
 Sheetsee.addPopups(map, markerLayer)
+

To customize the marker popup content in your map you'll need to use this entire function on your website.

+
function addPopups(map, markerLayer) {
+  markerLayer.on('click', function(e) {
+    var feature = e.layer.feature
+    var popupContent = '<h2>' + feature.opts.name + '</h2>' +
+                        '<h3>' + feature.opts.breed + '</h3>'
+    e.layer.bindPopup(popupContent,{closeButton: false,})
+  })
+}
+

You will edit the popupContent variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use feature.opts and then one of the column headers you passed into createGeoJSON().

+ +

Make a Table

+ +
+

Example - Local Pet Friends

+ + Clear + no matches +
+
+ + +

Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for searches and table headers can be used to sort the data in that column. For each of these you'll need a <div> in your html, a <script> template and a <script> that calls table functions.

+

Your HTML Placeholder <div>

+

This is as simple as an empty <div> with an id. This id should match the script tempate id in the next section.

+
 <div id="siteTable"></div>
+

Your <script> Template

+

Your template is the mockup of what you'd like your table to look like and what content it should show. Most of this is up to you but if you want users to be able to click on headers and sort that column you must make a table row with table headers with the class tHeader.

+

The variables inside the {{}} must match the column headers in your spreadsheet. Lowercase (?) and remember spaces are ommited, so "Place Name" will become "placename".

+
<script id="siteTable" type="text/html">
+    <table>
+    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
+      {{#rows}}
+        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
+      {{/rows}}
+  </table>
+</script>
+

Your <script> Execution

+
<script type="text/javascript">
+    document.addEventListener('DOMContentLoaded', function() {
+        Sheetsee.makeTable(gData, "#siteTable")
+        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
+    })
+</script>
+

To create another table, simply repeat the steps with the corresponding data and divs.

+
<div id="secondTable"></div>
+<script id="secondTable"> // your table template here </script>
+<script>
+  Sheetsee.makeTable(otherData, "#secondTable")
+  Sheetsee.initiateTableFilter(otherData, "#secondFilter", "#secondTable")
+</script>
+
+

Learn more about the things you can do with mustache.js.

+ +

Sheetsee.makeTable(data, targetDiv)

+

You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id).

+
Sheetsee.makeTable(gData, "#siteTable")
+ +

Table Filter/Search

+

If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html:

+
<input id="tableFilter" type="text" placeholder="filter by.."></input>
+<span class="clear button">Clear</span>
+<span class="noMatches">no matches</span>
+ +

Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

+

You will then call this function to make that input live:

+
Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
+ +

Make a Chart

+

Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting.

+

You'll have to experiement with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

+

You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee.

+ +

Bar Chart

+ +
+
+
+ +

To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

+
<div id="barChart"></div>
+

In your CSS, give it dimensions.

+
#barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
+

In a <script> tag set up your options.

+
var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
+
    +
  • labels is a string, usually a column header, it's what you call what you're charting
  • +
  • units is a string, usually a column header, it's the value you're charting
  • +
  • m is margins: top, right, bottom, left
  • +
  • w and h are width and height, this should match your CSS specs
  • +
  • div is the id for the <div> in your HTML
  • +
  • xaxis is optional text label for your x axis
  • +
  • hiColor is the highlight color of your choosing!
  • +
+

Then call the d3BarChart() function with your data and options.

+
Sheetsee.d3BarChart(data, barOptions)
+ +

Line Chart

+ +
+
+
+ +

To create a line chart you'll need to add a placeholder <div> in your html with an id.

+
<div id="lineChart"></div>
+

In your CSS, give it dimensions.

+
#lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
+

In a <script> tag set up your options.

+
var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
+
    +
  • labels is a string, usually a column header, it's what you call what you're charting
  • +
  • units is a string, usually a column header, it's the value you're charting
  • +
  • m is your margins: top, right, bottom, left
  • +
  • w and h are width and height, this should match your CSS specs
  • +
  • div is the id for the <div> in your HTML
  • +
  • yaxis is optional text label for your y axis
  • +
  • hiColor is the highlight color of your choosing!
  • +
+

Then call the d3LineChart() function with your data and options.

+
Sheetsee.d3LineChart(data, lineOptions)
+ +

Pie Chart

+ +
+
+
+ +

To create a bar chart you'll need to add a placeholder <div> in your html with an id.

+
<div id="pieChart"></div>
+

In your CSS, give it dimensions.

+
#pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
+

In a <script> tag set up your options. You must include labels and units, this tells it what you're charting. Because for the pie chart we're using data we got from getOccurance() and makeColorArrayofObject(), our units are already called units. If we were using original data, we might have units as "cuddleability" or something else.

+
var pieOptions = {labels: "kind", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
+
    +
  • labels is a string, usually a column header, it's what you call what you're charting
  • +
  • units is a string, usually a column header, it's the value you're charting
  • +
  • m is your margins: top, right, bottom, left
  • +
  • w and h are width and height, this should match your CSS specs
  • +
  • div is the id for the <div> in your HTML
  • +
  • hiColor is the highlight color of your choosing!
  • +
+

Then call the d3PieChart() function with your data and options.

+
Sheetsee.d3PieChart(data, pieOptions)
+ +

Don't forget, right click this page, select View Source and scroll to the bottom and see exactly how these charts were set up!

+ + +

Big Time Thanks

+

Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georga.

+

Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

+

Thanks to Max Ogden for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making Tabletop.js for Node.js.

+

Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

+

Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

+ +

Licensed under BSD. East Bay represent!

+ + + + + + + + + diff --git a/demos/template.html b/demos/template.html new file mode 100644 index 00000000..65cd0abf --- /dev/null +++ b/demos/template.html @@ -0,0 +1,30 @@ + + + Yo, yo, yo! + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/basics.md b/docs/basics.md index 4df6c2eb..05bbfb0e 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -1,3 +1,6 @@ +## Why Use Spreadsheets? +## Why Not Use Spreadsheets? + ### CSS Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design. @@ -38,7 +41,7 @@ Ignoring some HTML things to conserve space, you get the point. This gives you a - + ## Getting Started This bit is the same for both client-side and server-side versions. diff --git a/js/sheetsee.js b/js/sheetsee.js index b0293944..7d107797 100644 --- a/js/sheetsee.js +++ b/js/sheetsee.js @@ -1,5 +1,4 @@ -!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.Sheetsee=e():"undefined"!=typeof global?global.Sheetsee=e():"undefined"!=typeof self&&(self.Sheetsee=e())}(function(){var define,module,exports; -return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; } @@ -8081,7 +8080,7 @@ d3 = function() { var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; - var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), d3.transition(path)); var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; this.__chart__ = scale1; @@ -9303,11 +9302,6 @@ module.exports.makeArrayOfObject = function(data) { return h }) } - -module.exports.setup = function() { - $(document).on("click", ".tHeader", Sheetsee.sendToSort) -} - },{"icanhaz":5}],5:[function(require,module,exports){ /*! ICanHaz.js version 0.10.2 -- by @HenrikJoreteg @@ -9873,33 +9867,93 @@ module.exports.buildOptionObject = function(optionsJSON, lineItem) { return newObj } +module.exports.makeupOptionObject = function(lineItem) { + var options = [] + for (var i in lineItem) { + options.push(i); + } + return options +} + // for geocoding: http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding // create geoJSON from your spreadsheet's coordinates module.exports.createGeoJSON = function(data, optionsJSON) { var geoJSON = [] data.forEach(function(lineItem){ - // skip if there are no coords - if (!lineItem.long || !lineItem.lat) return - if (optionsJSON) var optionObj = Sheetsee.buildOptionObject(optionsJSON, lineItem) - var feature = { - type: 'Feature', - "geometry": {"type": "Point", "coordinates": [lineItem.long, lineItem.lat]}, - "properties": { - "marker-size": "small", - "marker-color": lineItem.hexcolor - }, - "opts": optionObj, + var hasGeo = false + if (lineItem.lat && lineItem.long || lineItem.polygon) hasGeo = true + if (lineItem.linestring || lineItem.multipolygon) hasGeo = true + if (!hasGeo) return + + if (!optionsJSON) { + optionsJSON = makeupOptionObject(lineItem) + var optionObj = buildOptionObject(optionsJSON, lineItem) + } else { + optionObj = buildOptionObject(optionsJSON, lineItem) } - geoJSON.push(feature) + + var type = determineType(lineItem) + + if (lineItem.polygon || lineItem.multipolygon || lineItem.linestring) { + var shapeFeature = shapeJSON(lineItem, type, optionObj) + geoJSON.push(shapeFeature) + } else { + var poitnFeature = pointJSON(lineItem, type, optionObj) + geoJSON.push(poitnFeature) + } }) return geoJSON } -// load basic map with tiles +module.exports.pointJSON = function(lineItem, type, optionObj) { + var lowercaseType = type.toLowerCase() + var pointFeature = { + type: "Feature", + "geometry": { + "type": type, + "coordinates": [+lineItem.long, +lineItem.lat] + }, + "properties": { + "marker-size": "small", + "marker-color": lineItem.hexcolor + }, + "opts": optionObj + } + return pointFeature +} + +module.exports.shapeJSON = function(lineItem, type, optionObj) { + var lowercaseType = type.toLowerCase() + var coords + if (type !== "LineString") { + coords = JSON.parse( "[[" + lineItem[lowercaseType] + "]]" ) + } else { coords = JSON.parse("[" + lineItem[lowercaseType] + "]") } + var shapeFeature = { + type: "Feature", + "geometry": { + "type": type, + "coordinates": coords + }, + "properties": { + "fillColor": lineItem.hexcolor, + "color": lineItem.hexcolor + }, + "opts": optionObj + } + return shapeFeature +} + +module.exports.determineType = function(lineItem) { + var type = "" + if (lineItem.lat && lineItem.long) type = "Point" + if (lineItem.polygon) type = "Polygon" + if (lineItem.multipolygon) type = "MultiPolygon" + if (lineItem.linestring) type = "LineString" + return type +} + module.exports.loadMap = function(mapDiv) { var map = L.mapbox.map(mapDiv) - // map.setView(, 4) - // map.addLayer(L.tileLayer('http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png')) map.touchZoom.disable() map.doubleClickZoom.disable() map.scrollWheelZoom.disable() @@ -9907,18 +9961,66 @@ module.exports.loadMap = function(mapDiv) { } module.exports.addTileLayer = function(map, tileLayer) { - var layer = L.mapbox.tileLayer(tileLayer) - layer.addTo(map) + var layer = L.mapbox.tileLayer(tileLayer) + layer.addTo(map) +} + +module.exports.makePopupTemplate = function(geoJSON) { + var allOptions = geoJSON[0].opts + var keys = [] + for (var i in allOptions) keys.push(i) + + var mustacheKeys = mustachify(keys) + + var template = {} + template.name ="popup" + template.template = templateString(mustacheKeys) + return template +} + +module.exports.templateString = function(mustacheKeys) { + var template = "
    " + var counter = mustacheKeys.length + mustacheKeys.forEach(function(key) { + counter-- + if (counter === 0) template = template.concat(key, "
") + else template = template.concat(key) + }) + return template } -module.exports.addMarkerLayer = function(geoJSON, map, zoomLevel) { - var viewCoords = [geoJSON[0].geometry.coordinates[1], geoJSON[0].geometry.coordinates[0]] - var markerLayer = L.mapbox.markerLayer(geoJSON) - markerLayer.setGeoJSON(geoJSON) - map.setView(viewCoords, zoomLevel) - // map.fitBounds(geoJSON) - markerLayer.addTo(map) - return markerLayer +module.exports.mustachify = function(array) { + var newArray = [] + array.forEach(function(item) { + item = "
  • " + item + ": {{" + item + "}}
  • " + newArray.push(item) + }) + return newArray +} + +module.exports.addMarkerLayer = function(geoJSON, map, template) { + if (!template) { + template = makePopupTemplate(geoJSON) + ich.addTemplate(template.name, template.template) + } + var features = { + "type": "FeatureCollection", + "features": geoJSON + } + + var layer = L.geoJson(features, { + pointToLayer: L.mapbox.marker.style, + style: function(feature) { return feature.properties } + }) + var bounds = layer.getBounds() + layer.addTo(map) + map.fitBounds(bounds) + + layer.eachLayer(function(marker) { + var popupContent = ich["popup"](marker.feature.opts) + marker.bindPopup(popupContent, {closeButton: false,}) + }) + return layer } },{"mapbox.js":8}],7:[function(require,module,exports){ // Copyright (C) 2010 Google Inc. @@ -10332,7 +10434,7 @@ URI.prototype.setPath = function (newPath) { URI.prototype.setRawPath = function (newPath) { if (newPath) { newPath = String(newPath); - this.path_ = + this.path_ = // Paths must start with '/' unless this is a path-relative URL. (!this.domain_ || /^\//.test(newPath)) ? newPath : '/' + newPath; } else { @@ -24245,46 +24347,47 @@ module.exports = { },{}],33:[function(require,module,exports){ var ich = require('icanhaz') -// Make Table, Sort and Filter Interactions -module.exports.initiateTableFilter = function(data, filterDiv, tableDiv) { +module.exports.initiateTableFilter = function(opts) { $('.clear').on("click", function() { $(this.id + ".noMatches").css("visibility", "hidden") - $(this.id + filterDiv).val("") - Sheetsee.makeTable(data, tableDiv) + $(this.id + opts.filterDiv).val("") + makeTable(opts) }) - $(filterDiv).keyup(function(e) { + $(opts.filterDiv).keyup(function(e) { var text = $(e.target).val() - Sheetsee.searchTable(data, text, tableDiv) + console.log(opts.data.length, text) + searchTable(opts, text) }) } -module.exports.searchTable = function(data, searchTerm, tableDiv) { +module.exports.searchTable = function(opts, searchTerm) { var filteredList = [] - data.forEach(function(object) { + opts.data.forEach(function(object) { var stringObject = JSON.stringify(object).toLowerCase() if (stringObject.match(searchTerm.toLowerCase())) filteredList.push(object) }) if (filteredList.length === 0) { - console.log("no matchie") $(".noMatches").css("visibility", "inherit") - Sheetsee.makeTable("no matches", tableDiv) + makeTable(opts, filteredList) + } + else { + $(".noMatches").css("visibility", "hidden") + makeTable(opts, filteredList) } - else $(".noMatches").css("visibility", "hidden") - Sheetsee.makeTable(filteredList, tableDiv) - return filteredList } -module.exports.sortThings = function(data, sorter, sorted, tableDiv) { - data.sort(function(a,b){ +module.exports.sortThings = function(opts, sorter, sorted) { + console.log("here is data", opts.data) + opts.data.sort(function(a,b){ if (a[sorter]b[sorter]) return 1 return 0 }) - if (sorted === "descending") data.reverse() - Sheetsee.makeTable(data, tableDiv) + if (sorted === "descending") opts.data.reverse() + makeTable(opts) var header - $(tableDiv + " .tHeader").each(function(i, el){ - var contents = Sheetsee.resolveDataTitle($(el).text()) + $(opts.tableDiv + " .tHeader").each(function(i, el){ + var contents = resolveDataTitle($(el).text()) if (contents === sorter) header = el }) $(header).attr("data-sorted", sorted) @@ -24295,20 +24398,74 @@ module.exports.resolveDataTitle = function(string) { return adjusted } -module.exports.sendToSort = function(event) { - var tableDiv = "#" + $(event.target).closest("div").attr("id") - console.log("came from this table",tableDiv) - var sorted = $(event.target).attr("data-sorted") - if (sorted) { - if (sorted === "descending") sorted = "ascending" - else sorted = "descending" - } - else { sorted = "ascending" } - var sorter = Sheetsee.resolveDataTitle(event.target.innerHTML) - Sheetsee.sortThings(gData, sorter, sorted, tableDiv) +module.exports.initiateTableSorter = function(options) { + var sortInfo = $(document).on("click", ".tHeader", sendToSort) + + function sendToSort(event) { + var tableDiv = "#" + $(event.target).closest("div").attr("id") + console.log("came from this table",tableDiv) + var sorted = $(event.target).attr("data-sorted") + if (sorted) { + if (sorted === "descending") sorted = "ascending" + else sorted = "descending" + } + else { sorted = "ascending" } + var sorter = resolveDataTitle(event.target.innerHTML) + var sortInfo = {"sorter": sorter, "sorted": sorted, "tableDiv": tableDiv} + console.log(sortInfo) + sortThings(options, sorter, sorted, tableDiv) + } +} + +module.exports.makeTable = function(opts, filteredList) { + if (filteredList) var data = filteredList + else var data = opts.data + console.log(opts) + + if (!opts.pagination) table(data, opts.targetDiv) + var allRows = data.length + var totalPages = Math.floor(allRows / opts.pagination) + var currentPage = 1 + var currentStart = (currentPage * opts.pagination) - opts.pagination + var currentEnd = currentPage * opts.pagination + var currentRows = data.slice(currentStart, currentEnd) + table(currentRows, opts.tableDiv) + if (opts.data.length > opts.pagination) setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + + $(document).on("click", (".pagination-next"), function() { + currentPage = currentPage + 1 + var nextPage = currentPage + 1 + currentStart = (currentPage * opts.pagination) - opts.pagination + currentEnd = currentPage * opts.pagination + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, opts.tableDiv) + setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + }) + + $(document).on("click", (".pagination-pre"), function() { + currentPage = currentPage - 1 + var nextPage = currentPage + 1 + currentStart = (currentPage * opts.pagination) - opts.pagination + currentEnd = currentPage * opts.pagination + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, opts.tableDiv) + setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + }) +} + +module.exports.setPreNext = function(targetDiv, currentPage, currentPage, totalPages) { + $(targetDiv).append("" ) +} + +module.exports.clearPreNExt = function() { + $(".table-pagination").attr("display", "none") } -module.exports.makeTable = function(data, targetDiv) { +module.exports.table = table +function table(data, targetDiv) { + console.log(targetDiv) var templateID = targetDiv.replace("#", "") var tableContents = ich[templateID]({ rows: data @@ -24318,16 +24475,7 @@ module.exports.makeTable = function(data, targetDiv) { },{"icanhaz":34}],34:[function(require,module,exports){ module.exports=require(5) },{}],35:[function(require,module,exports){ -var Sheetsee = {} -var extend = require('lodash.assign') - -// consider this a "build file!" you can add/remove dependencies here, and the file will be created at dist/sheetsee.full.js. -// creating these components are easy, just export an object, and things inside it will be extended to the main Sheetsee here. -// in the future, these could be separate node modules. (for example: sheetsee-d3, sheetsee-mapbox, etc) -extend(Sheetsee, require('sheetsee-core'), require('sheetsee-tables'), require('sheetsee-maps'), require('sheetsee-charts')) - -module.exports = Sheetsee - +if (typeof window.Sheetsee === 'undefined') window.Sheetsee = {}; window.Sheetsee = require('sheetsee-core'); var extend = require('lodash.assign'); extend(window.Sheetsee, require('sheetsee-maps'), require('sheetsee-charts'), require('sheetsee-tables')); module.exports = Sheetsee; },{"lodash.assign":36,"sheetsee-charts":1,"sheetsee-core":4,"sheetsee-maps":6,"sheetsee-tables":33}],36:[function(require,module,exports){ /** * Lo-Dash 2.1.0 (Custom Build) @@ -25180,6 +25328,4 @@ module.exports = shimKeys; },{"lodash._objecttypes":56}],60:[function(require,module,exports){ module.exports=require(51) },{"lodash._objecttypes":56}]},{},[35]) -(35) -}); -; \ No newline at end of file +; From 57982f2654c9c776c2098398c71bd97c1f097579 Mon Sep 17 00:00:00 2001 From: jlord Date: Sun, 29 Dec 2013 13:43:25 -0800 Subject: [PATCH 017/157] updates --- ...6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json | 1 - demo.html | 505 - demos/demo-table.html | 24 +- dist/sheetsee.js | 25185 ---------------- dist/sheetsee.min.js | 16 - js/jquery.js | 4 - js/sheetsee.js | 14614 ++++----- js/sheetsee.min.js | 16 - readme.md | 2 + template.html | 30 - 10 files changed, 7333 insertions(+), 33064 deletions(-) delete mode 100644 0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json delete mode 100644 demo.html delete mode 100644 dist/sheetsee.js delete mode 100644 dist/sheetsee.min.js delete mode 100644 js/jquery.js delete mode 100644 js/sheetsee.min.js delete mode 100644 template.html diff --git a/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json b/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json deleted file mode 100644 index fc390fce..00000000 --- a/0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc.json +++ /dev/null @@ -1 +0,0 @@ -[{"id":"0","placename":"Oakland Zoo","venue":"Oakland Zoo","image":"elephant","noun":"animal","lat":"37.7502645413531","long":"-122.14675065","hexcolor":"#FFE7E7","city":"Oakland","state":"California","year":"2013","photo-url":"","rowNumber":1},{"id":"1","placename":"Winchester Mystery House","venue":"Winchester Mystery House","image":"mansion","noun":"place","lat":"37.3183373","long":"-121.9510439","hexcolor":"#F7CE86","city":"San Jose","state":"California","year":"2012","photo-url":"","rowNumber":2},{"id":"2","placename":"Winchester Mystery House","venue":"Winchester Mystery House","image":"Sarah Winchester","noun":"person","lat":"37.3183373","long":"-121.9510439","hexcolor":"#F78585","city":"San Jose","state":"California","year":"2012","photo-url":"","rowNumber":3},{"id":"3","placename":"Amerian Museum of Natural History","venue":"Amerian Museum of Natural History","image":"mammoth","noun":"animal","lat":"40.7809389","long":"-73.9730135","hexcolor":"#FFE7E7","city":"Washington DC","state":"Washington DC","year":"2011","photo-url":"","rowNumber":4},{"id":"4","placename":"Six Flags Over Georgia","venue":"Six Flags Over Georgia","image":"Viper","noun":"animal, ride","lat":"33.767303","long":"-84.551204","hexcolor":"#F7CE86","city":"Atlanta","state":"Georgia","year":"2000","photo-url":"","rowNumber":5},{"id":"5","placename":"World Trade Center","venue":"","image":"skyline","noun":"place","lat":"40.7143528","long":"-74.0059731","hexcolor":"#F7CE86","city":"New York City","state":"New York","year":"2008","photo-url":"","rowNumber":6},{"id":"6","placename":"The St. Pete Pier","venue":"The St. Pete Pier","image":"pier building","noun":"place","lat":"27.773566","long":"-82.622326","hexcolor":"#F7CE86","city":"St. Petersburg","state":"Florida","year":"1998","photo-url":"","rowNumber":7},{"id":"7","placename":"Miss Katie's Restaurant","venue":"","image":"logo","noun":"graphic","lat":"33.8081608","long":"-84.170196","hexcolor":"#F78585","city":"Stone Mountain","state":"Georgia","year":"1993","photo-url":"","rowNumber":8},{"id":"8","placename":"Rhode Island","venue":"","image":"ship","noun":"thing","lat":"41.8239891","long":"-71.4128343","hexcolor":"#FFE7E7","city":"Providence","state":"Rhode Island","year":"2008","photo-url":"","rowNumber":9},{"id":"9","placename":"River Street, Savannah","venue":"","image":"skyline","noun":"place","lat":"32.0814473472438","long":"-81.0903453826904","hexcolor":"#F78585","city":"Savannah ","state":"Georgia","year":"2004","photo-url":"","rowNumber":10},{"id":"10","placename":"Natchez New Orleans","venue":"","image":"ship","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2007","photo-url":"","rowNumber":11},{"id":"11","placename":"Margarittaville","venue":"","image":"drink","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2007","photo-url":"","rowNumber":12},{"id":"12","placename":"Woodman's","venue":"Woodman's","image":"clam","noun":"animal","lat":"42.630151","long":"-70.774552","hexcolor":"#F78585","city":"Essex","state":"Massachusetts","year":"2008","photo-url":"","rowNumber":13},{"id":"13","placename":"Summit Pikes Peak","venue":"Summit Pikes Peak","image":"logo","noun":"graphic","lat":"38.840556","long":"-105.044167","hexcolor":"#F78585","city":"Pikes Peak","state":"Colorado","year":"2002","photo-url":"","rowNumber":14},{"id":"14","placename":"Polar Caves Park","venue":"Polar Caves Park","image":"polar bear","noun":"animal","lat":"43.7940757","long":"-71.8508395","hexcolor":"#F78585","city":"Rumney","state":"New Hampshire","year":"2010","photo-url":"","rowNumber":15},{"id":"15","placename":"Rainforest Cafe","venue":"OpryMills","image":"butterfly","noun":"animal","lat":"36.2051067","long":"-86.6938833","hexcolor":"#F7CE86","city":"Nashville","state":"Tennessee","year":"1999","photo-url":"","rowNumber":16},{"id":"16","placename":"National Museum of American History","venue":"National Museum of American History","image":"house","noun":"place","lat":"38.8911993","long":"-77.0300391","hexcolor":"#F78585","city":"Washington DC","state":"Washington DC","year":"2011","photo-url":"","rowNumber":17},{"id":"17","placename":"Boston Celtics","venue":"TD Garden","image":"mascot","noun":"person","lat":"42.3660275025778","long":"-71.0615873336792","hexcolor":"#FFE7E7","city":"Boston","state":"Massachusetts","year":"2010","photo-url":"","rowNumber":18},{"id":"18","placename":"Cafe du Monde","venue":"Cafe Du Monde","image":"coffee and bengiet","noun":"food","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2012","photo-url":"","rowNumber":19},{"id":"19","placename":"Six Flags Over Georgia","venue":"Six Flags Over Georgia","image":"Wylie Cyotte","noun":"animal","lat":"33.767303","long":"-84.551204","hexcolor":"#FFE7E7","city":"Atlanta","state":"Georgia","year":"2003","photo-url":"","rowNumber":20},{"id":"20","placename":"Mardis Gras","venue":"","image":"masks","noun":"thing","lat":"29.9510658","long":"-90.0715323","hexcolor":"#FFE7E7","city":"New Orleans","state":"Lousianna","year":"2004","photo-url":"","rowNumber":21},{"id":"21","placename":"Buzz Lightyear","venue":"Six Flags Over Georgia","image":"Buzz Lightyear","noun":"person","lat":"28.3702563165193","long":"-81.5497970581055","hexcolor":"#F78585","city":"Walt Disney World","state":"Florida","year":"2001","photo-url":"","rowNumber":22},{"id":"22","placename":"Independence Hall","venue":"Independence Hall","image":"Indepence Hall","noun":"place","lat":"39.952335","long":"-75.163789","hexcolor":"#FFE7E7","city":"Philadelphia","state":"Pennsylvania","year":"2008","photo-url":"","rowNumber":23},{"id":"23","placename":"Golden Gate Bridge","venue":"","image":"Golden Gate Bridge","noun":"thing","lat":"37.809783953011","long":"-122.47740983963","hexcolor":"#FFE7E7","city":"San Francisco","state":"California","year":"2011","photo-url":"","rowNumber":24},{"id":"24","placename":"Pirates of the Caribean","venue":"Magic Kingdom, Walt Disney World","image":"Goofey","noun":"person","lat":"28.3702563165193","long":"-81.5497970581055","hexcolor":"#FFE7E7","city":"Walt Disney World","state":"Florida","year":"2001","photo-url":"","rowNumber":25},{"id":"25","placename":"Boston Skyline","venue":"TD Garden","image":"skyline","noun":"place","lat":"42.3660275025778","long":"-71.0615873336792","hexcolor":"#FFE7E7","city":"Boston","state":"Massachusetts","year":"2009","photo-url":"","rowNumber":26},{"id":"26","placename":"Johnny Bravo","venue":"Six Flags Over Georgia","image":"Johnny Bravo","noun":"person","lat":"33.767303","long":"-84.551204","hexcolor":"#FFE7E7","city":"Atlanta","state":"Georgia","year":"2003","photo-url":"","rowNumber":27},{"id":"27","placename":"Busch Gardens","venue":"Busch Gardens","image":"clydesdale","noun":"animal","lat":"28.033158","long":"-82.420593","hexcolor":"#F78585","city":"Tampa","state":"Florida","year":"2002","photo-url":"","rowNumber":28},{"id":"28","placename":"California Academy of Sciences","venue":"California Academy of Sciences","image":"aligator","noun":"animal","lat":"37.769979","long":"-122.466288","hexcolor":"#FFE7E7","city":"San Francisco","state":"California","year":"2012","photo-url":"","rowNumber":29},{"id":"29","placename":"Santa Monica Pier","venue":"Pacific Park","image":"rollercoaster","noun":"thing","lat":"34.009471","long":"-118.497322","hexcolor":"#F78585","city":"Santa Monica","state":"California","year":"2013","photo-url":"","rowNumber":30},{"id":"30","placename":"Monterey Aquarium","venue":"Monterey Aquarium","image":"animal","noun":"animal","lat":"36.618032","long":"-121.902054","hexcolor":"#FFE7E7","city":"Monterey","state":"California","year":"2013","photo-url":"","rowNumber":31},{"id":"31","placename":"Hearst Castle","venue":"Hearst Castle","image":"architecture","noun":"architecture","lat":"35.685312","long":"-121.16894","hexcolor":"#F78585","city":"San Simeon","state":"California","year":"2013","photo-url":"","rowNumber":32}] \ No newline at end of file diff --git a/demo.html b/demo.html deleted file mode 100644 index fdaed1f3..00000000 --- a/demo.html +++ /dev/null @@ -1,505 +0,0 @@ - - - Yo, yo, yo! - - - - - - - - - - - - - - - -
    -

    sheetsee

    -

    Sheetsee.js

    -

    Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page.

    -

    Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with.

    -

    To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see JavaScript for Cats, Eloquent JavaScript or Mozilla's Developer Network.

    - -

    Dependencies

    -

    Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, Tabletop.js gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with IChanHas.js (built on mustache.js), maps with Mapbox.js, and charts with d3.js. And jQuery of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below.

    - -

    CSS

    -

    Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design.

    - -

    Client-side or Server-side

    -

    Sheetsee.js comes in two flavors, client-side (this repo) and server-side (sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal.

    -

    The server-side version is built with Node.js and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah!

    - -
    -

    The Short & Sweet

    -
      -
    1. Link to Sheetsee.js and dependencies in your HTML header.
    2. -
    3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
    4. -
    5. Create templates for tables in <script> tags.
    6. -
    7. Create a script tag that waits for the document to load and then executes any of the map, chart or tables you've specified in it.
    8. -
    9. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information everytime they load the page.
    10. -
    -
    - -

    Bare Minimum Setup

    -

    Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

    -
    <html>
    -    <head>
    -        <script type="text/javascript" src="http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.js"></script>
    -        <script type="text/javascript" src="js/ICanHaz.js"></script>
    -        <script type="text/javascript" src="js/jquery.js"></script>
    -        <script type="text/javascript" src="js/tabletop.js"></script>
    -        <script type="text/javascript" src="js/d3.js"></script>
    -        <script type="text/javascript" src="js/sheetsee.js"></script>
    -        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.css' rel='stylesheet' />
    -    </head>
    -    <style> #map {height: 600px; width: 600px;} </style>
    -    <body>
    -    <div id="map"></div>
    -    <script type="text/javascript">
    -      document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -      })
    -      function showInfo(data) {
    -        gData = data
    -        optionsJSON = ["something", "something"]
    -        var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -        var map = Sheetsee.loadMap("map")
    -        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
    -        // customize the popup content
    -        addPopups(map, markerLayer)
    -        function addPopups(map, markerLayer) {
    -          markerLayer.on('click', function(e) {
    -            var feature = e.layer.feature
    -            var popupContent = '<h3>' + feature.opts.something + '</h3>'
    -            e.layer.bindPopup(popupContent,{closeButton: false})
    -          })
    -        }
    -      }
    -    </script>
    -    </body>
    -</html>
    - -

    Awesome Possibilities

    -
      -
    1. Small newsrooms with data for stories but small dev teams.
    2. -
    3. Friends or groups collaborating on data for a website/project.
    4. -
    5. Using iftt.com to auto populate spreadsheets which are hooked to a website with Sheetsee.js.
    6. -
    - -

    Examples

    -
      -
    1. Hack Spots
    2. -
    3. James Sconfitto make a map of his relationship with his wife <3
    4. -
    - -

    Getting Started

    -

    This bit is the same for both client-side and server-side versions.

    -

    Your Data

    -

    sheetsee

    -

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

    -

    sheetsee

    -

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    -
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    - -

    Hexcolor

    -

    sheetsee

    -

    You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    - -

    Geocoding

    -

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin - that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    - sheetsee -

    Publishing Your Spreadsheet

    -

    sheetsee

    -

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    -

    sheetsee

    -

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet.

    -

    Your Website

    -

    Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet.

    -

    For now, create empty div placeholders for the map, chart and tables you plan on including.

    -

    Hooking Up Your Data

    -

    Here the paths diverge:

    -

    Client-side Hookup

    -

    For client-siders, all you need to do is include the depences and sheetsee in your HTML <head> and then in a script tag at the bottom of your page, right before the </body> tag, you'll include this:

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -    })
    -    function showInfo(data) {
    -        gData = data
    -        //
    -        //everything you do with sheetsee goes here
    -        //
    -    }
    -</script>
    -

    The URL variable is the key from your spreadsheet's longer URL, explained above. Tabletop.init() takes that URL and execute's Tabletop, when it's done generating the table it executes the callback showInfo function. It's inside of this function that you'll then use your spreadsheet data, gData, to do all the Sheetsee.js goodness with.

    -

    Server-side Hookup

    -

    The server-side version is in the repo sheetsee-cache. It uses Node.js to go to Google, get the spreadsheet data (with a Node.js version of Tabletop.js, thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data.

    -

    When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled.

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        // table/templating things the rest can be in their own script tags if you'd like
    -    })
    -</script>
    -

    Running Locally

    -

    You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay!

    -

    Once you clone the repo, navigate there in Terminal, install the node modules and launch the server.

    -
    cd sheetsee-cache
    -npm install
    -node server.js
    -

    This will launch a local server you can visit and develop locally with in your browser.

    -

    Working With Your Data

    -

    Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

    -

    Play Along!

    -

    This page is using sheetsee. If you (are in Chrome and) right click on the page and select Inspect Element it will bring up the Web Inspector. Select the Console tab. Now you can interact with the data and functions from Sheetsee. Give the functions below a try - gData is the variable with the data (from this spreadsheet). - sheetsee -

    Sheetsee.getKeyword(data, keyword)

    -

    This takes in your data, an array of objects, and searches for a string, keyword, in each piece of your data (formerly the cells of your spreadsheet). It returns an array of each row that contained a keyword match. Similarly, using `getKeywordCount(data, keyword)` will return just the number of times the keyword occured.

    -
    getKeyword(gData, "cat")
    -// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}]
    -

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

    -
    getColumnTotal(gData, "cuddlability")
    -// returns 11
    -

    Sheetsee.getAveragefromColumn(data, column)

    -

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(gData, "cuddlability")
    -// returns 1.8333333333333333
    -

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}]
    - -

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMax(gData, "cuddlability")
    -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
    - -
    - - -

    Don't Forget JavaScript Math

    -

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(gData, "2009")
    -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
    -var difference = profit09 - profit10
    -

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

    - -

    Sheetsee.getMatches(data, filter, category)

    -

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(gData, "dog", "kind")
    -

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    - -

    Sheetsee.getOccurance(data, category)

    -

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(gData, "kind")
    -

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    - -

    Sheetsee.makeColorArrayOfObject(data, colors)

    -

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    -

    This function takes in your data, as an object, an array of hexidecimal color strings which you define and the category you used in getOccurance().

    -
    var kinds = getOccurance(gData, "kind")
    -var kindColors = ["#ff00ff", "#DCF13C"]
    -var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors, "kind")
    -

    It will return an array of objects with units as the title of the occurance amount like so:

    -
    [{"kind": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"kind": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    -

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    - -

    Make a Map

    -
    -

    Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps.

    -

    Create an empty <div> in your HTML, with an id.

    -
    <div id="map"></div>
    -

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    - -

    Sheetsee.createGeoJSON(data, optionsJSON)

    -

    This takes in your data and the parts of your data, optionsJSON, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data.

    -
    var optionsJSON = ["name", "breed", "cuddlability"]
    -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -

    It will return an array in the special geoJSON format that map making things love.

    -
    [{
    -  "geometry": {"type": "Point", "coordinates": [long, lat]},
    -  "properties": {
    -    "marker-size": "small",
    -    "marker-color": lineItem.hexcolor
    -  },
    -  "opts": {the options you pass in},
    -}}
    - -

    Sheetsee.loadMap(mapDiv)

    -

    To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

    -
    var map = Sheetsee.loadMap("map")
    - -

    Sheetsee.addTileLayer(map, tileLayer)

    -

    To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

    -
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    - -

    Sheetsee.addMarkerLayer(geoJSON, map)

    -

    To add makers to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there.

    -
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
    - -

    Sheetsee.addPopups(map, markerLayer)

    -

    To customize the marker popup content in your map use this function and pass in your map and markerLayer.

    -
     Sheetsee.addPopups(map, markerLayer)
    -

    To customize the marker popup content in your map you'll need to use this entire function on your website.

    -
    function addPopups(map, markerLayer) {
    -  markerLayer.on('click', function(e) {
    -    var feature = e.layer.feature
    -    var popupContent = '<h2>' + feature.opts.name + '</h2>' +
    -                        '<h3>' + feature.opts.breed + '</h3>'
    -    e.layer.bindPopup(popupContent,{closeButton: false,})
    -  })
    -}
    -

    You will edit the popupContent variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use feature.opts and then one of the column headers you passed into createGeoJSON().

    - -

    Make a Table

    - -
    -

    Example - Local Pet Friends

    - - Clear - no matches -
    -
    - - -

    Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for searches and table headers can be used to sort the data in that column. For each of these you'll need a <div> in your html, a <script> template and a <script> that calls table functions.

    -

    Your HTML Placeholder <div>

    -

    This is as simple as an empty <div> with an id. This id should match the script tempate id in the next section.

    -
     <div id="siteTable"></div>
    -

    Your <script> Template

    -

    Your template is the mockup of what you'd like your table to look like and what content it should show. Most of this is up to you but if you want users to be able to click on headers and sort that column you must make a table row with table headers with the class tHeader.

    -

    The variables inside the {{}} must match the column headers in your spreadsheet. Lowercase (?) and remember spaces are ommited, so "Place Name" will become "placename".

    -
    <script id="siteTable" type="text/html">
    -    <table>
    -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    -      {{#rows}}
    -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    -      {{/rows}}
    -  </table>
    -</script>
    -

    Your <script> Execution

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        Sheetsee.makeTable(gData, "#siteTable")
    -        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
    -    })
    -</script>
    -

    To create another table, simply repeat the steps with the corresponding data and divs.

    -
    <div id="secondTable"></div>
    -<script id="secondTable"> // your table template here </script>
    -<script>
    -  Sheetsee.makeTable(otherData, "#secondTable")
    -  Sheetsee.initiateTableFilter(otherData, "#secondFilter", "#secondTable")
    -</script>
    -
    -

    Learn more about the things you can do with mustache.js.

    - -

    Sheetsee.makeTable(data, targetDiv)

    -

    You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id).

    -
    Sheetsee.makeTable(gData, "#siteTable")
    - -

    Table Filter/Search

    -

    If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html:

    -
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    -<span class="clear button">Clear</span>
    -<span class="noMatches">no matches</span>
    - -

    Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

    -

    You will then call this function to make that input live:

    -
    Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
    - -

    Make a Chart

    -

    Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting.

    -

    You'll have to experiement with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    -

    You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee.

    - -

    Bar Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    -
    <div id="barChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • xaxis is optional text label for your x axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3BarChart() function with your data and options.

    -
    Sheetsee.d3BarChart(data, barOptions)
    - -

    Line Chart

    - -
    -
    -
    - -

    To create a line chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="lineChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • yaxis is optional text label for your y axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3LineChart() function with your data and options.

    -
    Sheetsee.d3LineChart(data, lineOptions)
    - -

    Pie Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="pieChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options. You must include labels and units, this tells it what you're charting. Because for the pie chart we're using data we got from getOccurance() and makeColorArrayofObject(), our units are already called units. If we were using original data, we might have units as "cuddleability" or something else.

    -
    var pieOptions = {labels: "kind", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3PieChart() function with your data and options.

    -
    Sheetsee.d3PieChart(data, pieOptions)
    - -

    Don't forget, right click this page, select View Source and scroll to the bottom and see exactly how these charts were set up!

    - - -

    Big Time Thanks

    -

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georga.

    -

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    -

    Thanks to Max Ogden for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making Tabletop.js for Node.js.

    -

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    -

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    - -

    Licensed under BSD. East Bay represent!

    - - - - - - - - - diff --git a/demos/demo-table.html b/demos/demo-table.html index fa2841d0..f52dff0f 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -12,6 +12,9 @@
    + +
    + + + - - - - - \ No newline at end of file From a7e45ac420e9080003d9049f60ef1a0f4c72015b Mon Sep 17 00:00:00 2001 From: jlord Date: Mon, 30 Dec 2013 18:03:44 -0800 Subject: [PATCH 018/157] gahhh pagination --- demos/demo-table.html | 9 ++++++- js/sheetsee.js | 63 +++++++++++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/demos/demo-table.html b/demos/demo-table.html index f52dff0f..f2e24316 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -8,6 +8,13 @@ +
    @@ -47,7 +54,7 @@ Sheetsee.initiateTableFilter(tableOptions) var california = Sheetsee.getKeyword(gData, "california") - console.log(california) + // console.log(california) var calOptions = {"data": california, "pagination": 5, "tableDiv": "#calTable", "filterDiv": "#calFilter"} Sheetsee.makeTable(calOptions) Sheetsee.initiateTableFilter(calOptions) diff --git a/js/sheetsee.js b/js/sheetsee.js index 1af8b407..df49ee0f 100644 --- a/js/sheetsee.js +++ b/js/sheetsee.js @@ -24422,44 +24422,68 @@ module.exports.makeTable = makeTable function makeTable(opts, filteredList) { if (filteredList) var data = filteredList else var data = opts.data - console.log(opts) - + var tableId = opts.tableDiv.slice(1) if (!opts.pagination) table(data, opts.targetDiv) var allRows = data.length - var totalPages = Math.floor(allRows / opts.pagination) + var totalPages = Math.ceil(allRows / opts.pagination) var currentPage = 1 var currentStart = (currentPage * opts.pagination) - opts.pagination var currentEnd = currentPage * opts.pagination var currentRows = data.slice(currentStart, currentEnd) table(currentRows, opts.tableDiv) - if (opts.data.length > opts.pagination) setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + if (opts.data.length > opts.pagination) setPreNext(opts.tableDiv, currentPage, currentPage, totalPages, data, opts.pagination) + +} - $(document).on("click", (".pagination-next"), function() { +module.exports.setPagClicks = setPagClicks +function setPagClicks(data, tableId, currentPage, pagination, totalPages) { + // if (currentPage = 1) { + // $(".pagination-pre-" + tableId).css("display", "none") + // } + + $(document).on("click", (".pagination-next-" + tableId), function() { currentPage = currentPage + 1 var nextPage = currentPage + 1 - currentStart = (currentPage * opts.pagination) - opts.pagination - currentEnd = currentPage * opts.pagination - currentRows = data.slice(currentStart, currentEnd) - table(currentRows, opts.tableDiv) - setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + currentStart = (currentPage * pagination) - pagination + currentEnd = currentPage * pagination + console.log(currentPage, totalPages) + if (currentPage = totalPages) { + $(".pagination-next-" + tableId).addClass("no-pag") + return + } + else { + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, "#" + tableId) + setPreNext("#" + tableId, currentPage, currentPage, totalPages) + } }) - $(document).on("click", (".pagination-pre"), function() { + $(document).on("click", (".pagination-pre-" + tableId), function() { currentPage = currentPage - 1 + console.log("current", currentPage) var nextPage = currentPage + 1 - currentStart = (currentPage * opts.pagination) - opts.pagination - currentEnd = currentPage * opts.pagination - currentRows = data.slice(currentStart, currentEnd) - table(currentRows, opts.tableDiv) - setPreNext(opts.tableDiv, currentPage, currentPage, totalPages) + currentStart = (currentPage * pagination) - pagination + currentEnd = currentPage * pagination + if (currentPage = 0) { + $(".pagination-pre-" + tableId).addClass("no-pag") + return + } + else { + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, "#" + tableId) + setPreNext("#" + tableId, currentPage, currentPage, totalPages) + } + }) } module.exports.setPreNext = setPreNext -function setPreNext(targetDiv, currentPage, currentPage, totalPages) { +function setPreNext(targetDiv, currentPage, currentPage, totalPages, data, pagination) { + var tableId = targetDiv.slice(1) $(targetDiv).append("" ) + + currentPage + " of " + totalPages + " Previous" + + " Next

    " ) + setPagClicks(data, tableId, currentPage, pagination, totalPages) } module.exports.clearPreNext = clearPreNext @@ -24469,7 +24493,6 @@ function clearPreNext() { module.exports.table = table function table(data, targetDiv) { - console.log(targetDiv) var templateID = targetDiv.replace("#", "") var tableContents = ich[templateID]({ rows: data From 797e941777a1632c3a67d988852f918ddd0b87cb Mon Sep 17 00:00:00 2001 From: jlord Date: Mon, 30 Dec 2013 18:54:12 -0800 Subject: [PATCH 019/157] two working tables --- js/sheetsee.js | 60 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/js/sheetsee.js b/js/sheetsee.js index df49ee0f..a3f98d69 100644 --- a/js/sheetsee.js +++ b/js/sheetsee.js @@ -24431,7 +24431,7 @@ function makeTable(opts, filteredList) { var currentEnd = currentPage * opts.pagination var currentRows = data.slice(currentStart, currentEnd) table(currentRows, opts.tableDiv) - if (opts.data.length > opts.pagination) setPreNext(opts.tableDiv, currentPage, currentPage, totalPages, data, opts.pagination) + if (opts.data.length > opts.pagination) writePreNext(opts.tableDiv, currentPage, currentPage, totalPages, data, opts.pagination) } @@ -24447,38 +24447,56 @@ function setPagClicks(data, tableId, currentPage, pagination, totalPages) { currentStart = (currentPage * pagination) - pagination currentEnd = currentPage * pagination console.log(currentPage, totalPages) - if (currentPage = totalPages) { - $(".pagination-next-" + tableId).addClass("no-pag") - return - } - else { - currentRows = data.slice(currentStart, currentEnd) - table(currentRows, "#" + tableId) - setPreNext("#" + tableId, currentPage, currentPage, totalPages) - } + + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, "#" + tableId) + setPreNext("#" + tableId, currentPage, currentPage, totalPages) + + // if (currentPage = totalPages) { + // $(".pagination-next-" + tableId).addClass("no-pag") + // return + // } + // else { + // currentRows = data.slice(currentStart, currentEnd) + // table(currentRows, "#" + tableId) + // setPreNext("#" + tableId, currentPage, currentPage, totalPages) + // } }) $(document).on("click", (".pagination-pre-" + tableId), function() { currentPage = currentPage - 1 - console.log("current", currentPage) + // console.log("current", currentPage) var nextPage = currentPage + 1 currentStart = (currentPage * pagination) - pagination currentEnd = currentPage * pagination - if (currentPage = 0) { - $(".pagination-pre-" + tableId).addClass("no-pag") - return - } - else { - currentRows = data.slice(currentStart, currentEnd) - table(currentRows, "#" + tableId) - setPreNext("#" + tableId, currentPage, currentPage, totalPages) - } + + currentRows = data.slice(currentStart, currentEnd) + table(currentRows, "#" + tableId) + setPreNext("#" + tableId, currentPage, currentPage, totalPages) + + // if (currentPage = 0) { + // $(".pagination-pre-" + tableId).addClass("no-pag") + // return + // } + // else { + // currentRows = data.slice(currentStart, currentEnd) + // table(currentRows, "#" + tableId) + // setPreNext("#" + tableId, currentPage, currentPage, totalPages) + // } }) } module.exports.setPreNext = setPreNext -function setPreNext(targetDiv, currentPage, currentPage, totalPages, data, pagination) { +function setPreNext(targetDiv, currentPage, currentPage, totalPages, data, pagination) { + var tableId = targetDiv.slice(1) + $(targetDiv).append("" ) +} + +module.exports.writePreNext = writePreNext +function writePreNext(targetDiv, currentPage, currentPage, totalPages, data, pagination) { var tableId = targetDiv.slice(1) $(targetDiv).append(" diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 4da18d79..9037939c 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -97,6 +97,7 @@

    Ideas

    Demos

    Contact

    diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 30cfbf7b..25677f0d 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -14,11 +14,14 @@

    Sheetsee-maps

    Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based). See a map demo.

    -

    You'll create a placeholder <div> in your HTML and fire up a map from within <script> tags.

    +

    You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags.

    Your HTML Placeholder <div>

    -

    Create an empty <div> in your HTML, with an id (name).

    +

    Create an empty <div> in your HTML, with an id (name). Add CSS to give it dimensions

    <div id="map"></div>
     
    +

    CSS

    +
    #map {width: 500px; height: 500px;}
    +

    Your <script> Functions

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    Sheetsee.createGeoJSON(data, optionsJSON)

    @@ -36,8 +39,15 @@

    Sheetsee.createGeoJSON(data, o "opts": {the options you pass in}, }} +

    Sheetsee.addMarkerLayer(geoJSON, map)

    +

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is HTML and can reference the column headers you included in your optionsJSON.

    +
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
    +
    +

    Example template:

    +
    var popupTemplate = "<h4>Hello {{name}}</h4>"
    +

    Sheetsee.loadMap(mapDiv)

    -

    To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

    +

    To create a simple map, with no data, you simply call .loadMap() and pass in a string of the mapDiv (with no '#') from your HTML.

    var map = Sheetsee.loadMap("map")
     

    Sheetsee.addTileLayer(map, tileLayer)

    @@ -45,13 +55,6 @@

    Sheetsee.addTileLayer(map, tileLay
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
     

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    -

    Sheetsee.addMarkerLayer(geoJSON, map)

    -

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is HTML and can reference the column headers you included in your optionsJSON.

    -
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
    -
    -

    Example template:

    -
    var template = "<h4>Hello {{world}}</h4>"
    -
    diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 186b3900..89211bea 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -22,7 +22,7 @@

    Your HTML Placeholder <div>Your <script> Template

    Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you!

    Sorting

    -

    If you want users to be able to click on headers and sort that column, your template must include table headers with the class theader.

    +

    If you want users to be able to click on headers and sort that column, your template must include table headers with the class tHeader.

    Example

    The variables inside the {{}} must match the column headers in your spreadsheet. They should be lowercase and remember spaces are omitted, so "Place Name" will become "placename".

    <script id="siteTable" type="text/html">
    @@ -92,6 +92,7 @@ 

    Ideas

    Demos

    Contact

    diff --git a/site/docs/tips.html b/site/docs/tips.html index 7ca2024f..ec60406f 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -42,6 +42,7 @@

    Ideas

    Demos

    Contact

    diff --git a/site/index.html b/site/index.html index 7b6bd504..1e82ef37 100644 --- a/site/index.html +++ b/site/index.html @@ -8,7 +8,7 @@ such site, very sheetsee.js - +
    @@ -17,7 +17,7 @@

    Sheetsee.js

    Sheetsee.js is a library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts.

    Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

    Modules

    -

    Each of sheetsee.js's features are divided into modules. Use just the parts you need (see docs on building). If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    +

    Each of sheetsee.js's features are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    @@ -55,6 +55,7 @@

    Making Things

  • Hack-Spots
  • Combine with IFTTT
  • +

    List your sheetsee project here: file an issue or pull request.

    Demos & Templates

    Demos pages for the documentation.

      @@ -74,6 +75,7 @@

      Ideas

      Use

      @@ -95,6 +96,7 @@

      Ideas

      Demos

      Contact

      diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js new file mode 100644 index 00000000..7ee2af93 --- /dev/null +++ b/site/js/sheetsee.js @@ -0,0 +1,25351 @@ +;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreateCallback = require('lodash._basecreatecallback'), + keys = require('lodash.keys'), + objectTypes = require('lodash._objecttypes'); + +/** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources will overwrite property assignments of previous + * sources. If a callback is provided it will be executed to produce the + * assigned values. The callback is bound to `thisArg` and invoked with two + * arguments; (objectValue, sourceValue). + * + * @static + * @memberOf _ + * @type Function + * @alias extend + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param {Function} [callback] The function to customize assigning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the destination object. + * @example + * + * _.assign({ 'name': 'moe' }, { 'age': 40 }); + * // => { 'name': 'moe', 'age': 40 } + * + * var defaults = _.partialRight(_.assign, function(a, b) { + * return typeof a == 'undefined' ? b : a; + * }); + * + * var food = { 'name': 'apple' }; + * defaults(food, { 'name': 'banana', 'type': 'fruit' }); + * // => { 'name': 'apple', 'type': 'fruit' } + */ +var assign = function(object, source, guard) { + var index, iterable = object, result = iterable; + if (!iterable) return result; + var args = arguments, + argsIndex = 0, + argsLength = typeof guard == 'number' ? 2 : args.length; + if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { + var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); + } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { + callback = args[--argsLength]; + } + while (++argsIndex < argsLength) { + iterable = args[argsIndex]; + if (iterable && objectTypes[typeof iterable]) { + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; + } + } + } + return result +}; + +module.exports = assign; + +},{"lodash._basecreatecallback":3,"lodash._objecttypes":22,"lodash.keys":23}],3:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var bind = require('lodash.bind'), + identity = require('lodash.identity'), + setBindData = require('lodash._setbinddata'), + support = require('lodash.support'); + +/** Used to detected named functions */ +var reFuncName = /^function[ \n\r\t]+\w/; + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** Native method shortcuts */ +var fnToString = Function.prototype.toString; + +/** + * The base implementation of `_.createCallback` without support for creating + * "_.pluck" or "_.where" style callbacks. + * + * @private + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + */ +function baseCreateCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + // exit early if there is no `thisArg` + if (typeof thisArg == 'undefined') { + return func; + } + var bindData = func.__bindData__ || (support.funcNames && !func.name); + if (typeof bindData == 'undefined') { + var source = reThis && fnToString.call(func); + if (!support.funcNames && source && !reFuncName.test(source)) { + bindData = true; + } + if (support.funcNames || !bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = !support.funcDecomp || reThis.test(source); + setBindData(func, bindData); + } + } + // exit early if there are no `this` references or `func` is bound + if (bindData !== true && (bindData && bindData[1] & 1)) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 2: return function(a, b) { + return func.call(thisArg, a, b); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return bind(func, thisArg); +} + +module.exports = baseCreateCallback; + +},{"lodash._setbinddata":4,"lodash.bind":12,"lodash.identity":19,"lodash.support":20}],4:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var getObject = require('lodash._getobject'), + noop = require('lodash._noop'), + reNative = require('lodash._renative'), + releaseObject = require('lodash._releaseobject'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +var defineProperty = (function() { + try { + var o = {}, + func = reNative.test(func = Object.defineProperty) && func, + result = func(o, o, o) && func; + } catch(e) { } + return result; +}()); + +/** + * Sets `this` binding data on a given function. + * + * @private + * @param {Function} func The function to set data on. + * @param {*} value The value to set. + */ +var setBindData = !defineProperty ? noop : function(func, value) { + var descriptor = getObject(); + descriptor.value = value; + defineProperty(func, '__bindData__', descriptor); + releaseObject(descriptor); +}; + +module.exports = setBindData; + +},{"lodash._getobject":5,"lodash._noop":7,"lodash._releaseobject":8,"lodash._renative":11}],5:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectPool = require('lodash._objectpool'); + +/** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ +function getObject() { + return objectPool.pop() || { + 'array': null, + 'cache': null, + 'configurable': false, + 'criteria': null, + 'enumerable': false, + 'false': false, + 'index': 0, + 'leading': false, + 'maxWait': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'string': null, + 'trailing': false, + 'true': false, + 'undefined': false, + 'value': null, + 'writable': false + }; +} + +module.exports = getObject; + +},{"lodash._objectpool":6}],6:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to pool arrays and objects used internally */ +var objectPool = []; + +module.exports = objectPool; + +},{}],7:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A no-operation function. + * + * @private + */ +function noop() { + // no operation performed +} + +module.exports = noop; + +},{}],8:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var maxPoolSize = require('lodash._maxpoolsize'), + objectPool = require('lodash._objectpool'); + +/** + * Releases the given object back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ +function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + if (objectPool.length < maxPoolSize) { + objectPool.push(object); + } +} + +module.exports = releaseObject; + +},{"lodash._maxpoolsize":9,"lodash._objectpool":10}],9:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used as the max size of the `arrayPool` and `objectPool` */ +var maxPoolSize = 40; + +module.exports = maxPoolSize; + +},{}],10:[function(require,module,exports){ +module.exports=require(6) +},{}],11:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Used to detect if a method is native */ +var reNative = RegExp('^' + + String(objectProto.valueOf) + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + .replace(/valueOf|for [^\]]+/g, '.+?') + '$' +); + +module.exports = reNative; + +},{}],12:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var createBound = require('lodash._createbound'), + reNative = require('lodash._renative'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeSlice = arrayRef.slice; + +/** + * Creates a function that, when called, invokes `func` with the `this` + * binding of `thisArg` and prepends any additional `bind` arguments to those + * provided to the bound function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var func = function(greeting) { + * return greeting + ' ' + this.name; + * }; + * + * func = _.bind(func, { 'name': 'moe' }, 'hi'); + * func(); + * // => 'hi moe' + */ +function bind(func, thisArg) { + return arguments.length > 2 + ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg) + : createBound(func, 1, null, null, thisArg); +} + +module.exports = bind; + +},{"lodash._createbound":13,"lodash._renative":18}],13:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var createObject = require('lodash._createobject'), + isFunction = require('lodash.isfunction'), + isObject = require('lodash.isobject'), + reNative = require('lodash._renative'), + setBindData = require('lodash._setbinddata'), + support = require('lodash.support'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var push = arrayRef.push, + toString = objectProto.toString, + unshift = arrayRef.unshift; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeSlice = arrayRef.slice; + +/** + * Creates a function that, when called, either curries or invokes `func` + * with an optional `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of method flags to compose. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` + * 8 - `_.curry` (bound) + * 16 - `_.partial` + * 32 - `_.partialRight` + * @param {Array} [partialArgs] An array of arguments to prepend to those + * provided to the new function. + * @param {Array} [partialRightArgs] An array of arguments to append to those + * provided to the new function. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new bound function. + */ +function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + isPartial = bitmask & 16, + isPartialRight = bitmask & 32, + key = func; + + if (!isBindKey && !isFunction(func)) { + throw new TypeError; + } + if (isPartial && !partialArgs.length) { + bitmask &= ~16; + isPartial = partialArgs = false; + } + if (isPartialRight && !partialRightArgs.length) { + bitmask &= ~32; + isPartialRight = partialRightArgs = false; + } + var bindData = func && func.__bindData__; + if (bindData) { + if (isBind && !(bindData[1] & 1)) { + bindData[4] = thisArg; + } + if (!isBind && bindData[1] & 1) { + bitmask |= 8; + } + if (isCurry && !(bindData[1] & 4)) { + bindData[5] = arity; + } + if (isPartial) { + push.apply(bindData[2] || (bindData[2] = []), partialArgs); + } + if (isPartialRight) { + push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + } + bindData[1] |= bitmask; + return createBound.apply(null, bindData); + } + // use `Function#bind` if it exists and is fast + // (in V8 `Function#bind` is slower except when partially applied) + if (isBind && !(isBindKey || isCurry || isPartialRight) && + (support.fastBind || (nativeBind && isPartial))) { + if (isPartial) { + var args = [thisArg]; + push.apply(args, partialArgs); + } + var bound = isPartial + ? nativeBind.apply(func, args) + : nativeBind.call(func, thisArg); + } + else { + bound = function() { + // `Function#bind` spec + // http://es5.github.io/#x15.3.4.5 + var args = arguments, + thisBinding = isBind ? thisArg : this; + + if (isCurry || isPartial || isPartialRight) { + args = nativeSlice.call(args); + if (isPartial) { + unshift.apply(args, partialArgs); + } + if (isPartialRight) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity); + } + } + if (isBindKey) { + func = thisBinding[key]; + } + if (this instanceof bound) { + // ensure `new bound` is an instance of `func` + thisBinding = createObject(func.prototype); + + // mimic the constructor's `return` behavior + // http://es5.github.io/#x13.2.2 + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisBinding, args); + }; + } + setBindData(bound, nativeSlice.call(arguments)); + return bound; +} + +module.exports = createBound; + +},{"lodash._createobject":14,"lodash._renative":18,"lodash._setbinddata":4,"lodash.isfunction":16,"lodash.isobject":17,"lodash.support":20}],14:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('lodash.isobject'), + noop = require('lodash._noop'), + reNative = require('lodash._renative'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate; + +/** + * Creates a new object with the specified `prototype`. + * + * @private + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. + */ +function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; +} + +module.exports = createObject; + +},{"lodash._noop":15,"lodash._renative":18,"lodash.isobject":17}],15:[function(require,module,exports){ +module.exports=require(7) +},{}],16:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * Checks if `value` is a function. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + */ +function isFunction(value) { + return typeof value == 'function'; +} + +module.exports = isFunction; + +},{}],17:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('lodash._objecttypes'); + +/** + * Checks if `value` is the language type of Object. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // check if the value is the ECMAScript language type of Object + // http://es5.github.io/#x8 + // and avoid a V8 bug + // http://code.google.com/p/v8/issues/detail?id=2291 + return !!(value && objectTypes[typeof value]); +} + +module.exports = isObject; + +},{"lodash._objecttypes":22}],18:[function(require,module,exports){ +module.exports=require(11) +},{}],19:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var moe = { 'name': 'moe' }; + * moe === _.identity(moe); + * // => true + */ +function identity(value) { + return value; +} + +module.exports = identity; + +},{}],20:[function(require,module,exports){ +var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var reNative = require('lodash._renative'); + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var toString = objectProto.toString; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind; + +/** Detect various environments */ +var isIeOpera = reNative.test(global.attachEvent), + isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); + +/** + * An object used to flag environments features. + * + * @static + * @memberOf _ + * @type Object + */ +var support = {}; + +/** + * Detect if `Function#bind` exists and is inferred to be fast (all but V8). + * + * @memberOf _.support + * @type boolean + */ +support.fastBind = nativeBind && !isV8; + +/** + * Detect if functions can be decompiled by `Function#toString` + * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). + * + * @memberOf _.support + * @type boolean + */ +support.funcDecomp = !reNative.test(global.WinRTError) && reThis.test(function() { return this; }); + +/** + * Detect if `Function#name` is supported (all but IE). + * + * @memberOf _.support + * @type boolean + */ +support.funcNames = typeof Function.name == 'string'; + +module.exports = support; + +},{"lodash._renative":21}],21:[function(require,module,exports){ +module.exports=require(11) +},{}],22:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to determine if values are of the language type Object */ +var objectTypes = { + 'boolean': false, + 'function': true, + 'object': true, + 'number': false, + 'string': false, + 'undefined': false +}; + +module.exports = objectTypes; + +},{}],23:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('lodash.isobject'), + reNative = require('lodash._renative'), + shimKeys = require('lodash._shimkeys'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys; + +/** + * Creates an array composed of the own enumerable property names of an object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + * @example + * + * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); + * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) + */ +var keys = !nativeKeys ? shimKeys : function(object) { + if (!isObject(object)) { + return []; + } + return nativeKeys(object); +}; + +module.exports = keys; + +},{"lodash._renative":24,"lodash._shimkeys":25,"lodash.isobject":26}],24:[function(require,module,exports){ +module.exports=require(11) +},{}],25:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('lodash._objecttypes'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A fallback implementation of `Object.keys` which produces an array of the + * given object's own enumerable property names. + * + * @private + * @type Function + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + */ +var shimKeys = function(object) { + var index, iterable = object, result = []; + if (!iterable) return result; + if (!(objectTypes[typeof object])) return result; + for (index in iterable) { + if (hasOwnProperty.call(iterable, index)) { + result.push(index); + } + } + return result +}; + +module.exports = shimKeys; + +},{"lodash._objecttypes":22}],26:[function(require,module,exports){ +module.exports=require(17) +},{"lodash._objecttypes":22}],27:[function(require,module,exports){ +var d3 = require('d3') + +module.exports.d3 = d3 + +// Bar Chart +// Adapted mostly from http://bl.ocks.org/mbostock/3885705 +// options = {units: "string", labels: "string", m: [60, 150, 30, 150], w: 800, h: 300, div: "#dogBar", xaxis: "cuddlability", hiColor: "#EE0097"} + +module.exports.d3BarChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + // m = [t0, r1, b2, l3] + var m = options.m, + w = options.w - m[1] - m[3], + h = options.h - (m[0] + m[2]) + var format = d3.format(",.0f") + + var x = d3.scale.linear().range([0, w]), + y = d3.scale.ordinal().rangeRoundBands([0, h], .1) + + var xAxis = d3.svg.axis().scale(x).orient("top").tickSize(-h).tickFormat(d3.format("1s")), + yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0) + + var svg = d3.select(options.div).append("svg") + .attr("width", w + m[1] + m[3]) + .attr("height", h + m[0] + m[2]) + .append("g") + .attr("transform", "translate(" + m[3] + "," + m[0] + ")") + + x.domain([0, d3.max(data, function(d) { return d.units })]) // 0 to max of units + y.domain(data.map(function(d) { return d.labels })) // makes array of labels + + var mouseOver = function() { + var rect = d3.select(this) + var indexValue = rect.attr("index_value") + + var barSelector = "." + "rect-" + indexValue + var selectedBar = d3.selectAll(barSelector) + selectedBar.style("fill", options.hiColor) + + var valueSelector = "." + "value-" + indexValue + var selectedValue = d3.selectAll(valueSelector) + selectedValue.style("fill", options.hiColor) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.style("fill", options.hiColor) + } + + var mouseOut = function() { + var rect = d3.select(this) + var indexValue = rect.attr("index_value") + + var barSelector = "." + "rect-" + indexValue + var selectedBar = d3.selectAll(barSelector) + selectedBar.style("fill", function(d) { return d.hexcolor}) + + var valueSelector = "." + "value-" + indexValue + var selectedValue = d3.selectAll(valueSelector) + selectedValue.style("fill", "#333333") + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.style("fill", "#333") + } + + var bar = svg.selectAll("g.bar") + .data(data) + .enter().append("g") + .attr("class", "bar") + .attr("transform", function(d) { return "translate(0," + y(d.labels) + ")" }) + + bar.append("text") + .attr("x", function(d) { return x(d.units) }) + .attr("y", y.rangeBand() / 2) + .attr("dx", 12) + .attr("dy", ".35em") + .attr("text-anchor", "end") + .attr("index_value", function(d, i) { return "index-" + i }) + .text(function(d) { return format(d.units) }) + .attr("class", function(d, i) { return "value-" + "index-" + i }) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + + bar.append("text") + .attr("x", -5) + .attr("y", y.rangeBand() / 2) + .attr("dx", 0) + .attr("dy", ".35em") + .attr("text-anchor", "end") + .attr("index_value", function(d, i) { return "index-" + i }) + .text(function(d) { return d.labels }) + .attr("class", function(d, i) { return "value-" + "index-" + i }) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + + bar.append("rect") + .attr("width", function(d) { return x(d.units)}) + .attr("height", y.rangeBand()) + .attr("index_value", function(d, i) { return "index-" + i }) + .style("fill", function(d) { return d.hexcolor}) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + .attr("class", function(d, i) { return "rect-" + "index-" + i }) + + svg.append("g") + .attr("class", "x axis") + .call(xAxis) + .append("text") + // .attr("transform", "rotate(-90)") + .attr("y", -20) + .attr("x", m[1]) + .attr("class", "xLabel") + .style("text-anchor", "end") + .text(function() { + if (options.xaxis) return options.xaxis + return + }) +} + +// Pie Chart +// pieOptions = {units: "string", labels: "string", m: [80, 80, 80, 80], w: 800, h: 400, div: "#dogPie", hiColor: "#E4EB29"} +module.exports.d3PieChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + + var width = options.w, + height = options.h, + radius = Math.min(width, height) / 2.3 + + var arc = d3.svg.arc() + .outerRadius(radius - 10) + .innerRadius(0) + + var arcOver = d3.svg.arc() + .outerRadius(radius + .1) + + var pie = d3.layout.pie() + .sort(null) + .value(function(d) { return d.units }) + + var svg = d3.select(options.div).append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", "translate(" + width / 3 + "," + height / 2 + ")") + + var data = data + + data.forEach(function(d) { + d.units = +d.units + }) + function mouseOver(d) { + d3.select(this).select("path").transition() + .duration(500) + .attr("d", arcOver) + var slice = d3.select(this) + var indexValue = slice.attr("index_value") + + var pathSelector = "." + "path-" + indexValue + var selectedPath = d3.selectAll(pathSelector) + selectedPath.style("fill", options.hiColor) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.transition() + .duration(150) + .style("font-size", "12px").style("font-weight", "bold").style("fill", options.hiColor) + selectedText.attr("class", function(d, i) { return "labels-" + indexValue + " bigg" }) + } + function mouseOut(d) { + d3.select(this).select("path").transition() + .duration(150) + .attr("d", arc) + var slice = d3.select(this) + var indexValue = slice.attr("index_value") + + var pathSelector = "." + "path-" + indexValue + var selectedPath = d3.selectAll(pathSelector) + selectedPath.style("fill", function(d) { return d.data.hexcolor }) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.transition() + .duration(200) + .style("font-size", "10px").style("font-weight", "normal").style("fill", function(d) { return d.hexcolor }) + } + + var g = svg.selectAll(".arc") + .data(pie(data)) + .enter().append("g") + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "slice-" + "index-" + i + " slice arc" }) + .on("mouseover", mouseOver) + .on("mouseout", mouseOut) + + var path = g.append("path") + .attr("d", arc) + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "path-" + "index-" + i }) + .style("fill", function(d) { return d.data.hexcolor}) + .attr("fill", function(d) { return d.data.hexcolor}) + + svg.selectAll("g.labels") + .data(data) + .enter().append("g") // Append legend elements + .append("text") + .attr("text-anchor", "start") + .attr("x", width / 2.5) + .attr("y", function(d, i) { return (height / 2) - i*(data.length * 20)}) + .attr("dx", 0) + .attr("dy", "-140px") // Controls padding to place text above bars + .text(function(d) { return d.labels + ", " + d.units}) + .style("fill", function(d) { return d.hexcolor }) + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "labels-" + "index-" + i + " aLabel "}) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) +} + +// Line Chart +// Adapted from http://bl.ocks.org/1166403 and +// http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html +/// options = {units: "string", labels: "string", m: [80, 100, 120, 100], w: 800, h: 400, div: "#dogLine", yaxis: "cuddlability", hiColor: "#E4EB29"} +module.exports.d3LineChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + var m = options.m + var w = options.w - m[1] - m[3] + var h = options.h - m[0] - m[2] + var data = data + + var x = d3.scale.ordinal().rangeRoundBands([0, w], 1) + x.domain(data.map(function(d) { return d.labels })) + var y = d3.scale.linear().range([0, h]) + y.domain([d3.max(data, function(d) { return d.units }) + 2, 0]) + + var line = d3.svg.line() + .x(function(d, i) { return x(i) }) + .y(function(d) { return y(d) }) + + var graph = d3.select(options.div).append("svg:svg") + .attr("width", w + m[1] + m[3]) + .attr("height", h + m[0] + m[2]) + .append("svg:g") + .attr("transform", "translate(" + m[3] + "," + m[0] + ")") + + var div = d3.select(options.div).append("div") + .attr("class", "tooltip") + .style("opacity", 0) + + // create yAxis + var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(true) + // Add the x-axis. + graph.append("svg:g") + .attr("class", "x axis") + .attr("transform", "translate(0," + h + ")") + .call(xAxis) + .selectAll("text") + .style("text-anchor", "end") + .attr("dy", "-.5em") + .attr('dx', "-1em") + .attr("transform", "rotate(-80)") + .call(xAxis) + + // create left yAxis + var yAxisLeft = d3.svg.axis().scale(y).ticks(4).tickSize(-w).tickSubdivide(true).orient("left") + // Add the y-axis to the left + graph.append("svg:g") + .attr("class", "y axis") + .attr("dx", "25") + .attr("transform", "translate(0,0)") + .call(yAxisLeft) + .append("text") + .attr("transform", "rotate(-90)") + .attr("y", -40) + .attr("dy", 0) + .style("text-anchor", "end") + .text(function() { + if (options.yaxis) return options.yaxis + return + }) + +var lineData = data.map(function(d) { return d.units }) + graph.append("svg:path") + .attr("d", line(lineData)) + .attr("class", "chartLine") + .attr("index_value", function(d, i) { return i }) + // .attr("stroke", options.hiColor).attr("fill", "none") + + graph.selectAll("dot") + .data(data) + .enter().append("circle") + .attr("r", 3.5) + .attr("fill", options.hiColor) + .attr("cx", function(d) { return x(d.labels); }) + .attr("cy", function(d) { return y(d.units); }) + .on("mouseover", function(d) { + div.transition().duration(200).style("opacity", .9) + div .html(d.labels + ", " + d.units) + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px") + }) + .on("mouseout", function(d) { + div.transition().duration(500).style("opacity", 0) + }) +} + + +},{"d3":29}],28:[function(require,module,exports){ +d3 = function() { + var d3 = { + version: "3.2.8" + }; + if (!Date.now) Date.now = function() { + return +new Date(); + }; + var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; + try { + d3_document.createElement("div").style.setProperty("opacity", 0, ""); + } catch (error) { + var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; + d3_element_prototype.setAttribute = function(name, value) { + d3_element_setAttribute.call(this, name, value + ""); + }; + d3_element_prototype.setAttributeNS = function(space, local, value) { + d3_element_setAttributeNS.call(this, space, local, value + ""); + }; + d3_style_prototype.setProperty = function(name, value, priority) { + d3_style_setProperty.call(this, name, value + "", priority); + }; + } + d3.ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + }; + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + function d3_number(x) { + return x != null && !isNaN(x); + } + d3.mean = function(array, f) { + var n = array.length, a, m = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; + } + return j ? m : undefined; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; + }; + d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + }; + var d3_bisector = d3.bisector(function(d) { + return d; + }); + d3.bisectLeft = d3_bisector.left; + d3.bisect = d3.bisectRight = d3_bisector.right; + d3.shuffle = function(array) { + var m = array.length, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m], array[m] = array[i], array[i] = t; + } + return array; + }; + d3.permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + function d3_zipLength(d) { + return d.length; + } + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); + }; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_class(ctor, properties) { + try { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } catch (e) { + ctor.prototype = properties; + } + } + d3.map = function(object) { + var map = new d3_Map(); + if (object instanceof d3_Map) object.forEach(function(key, value) { + map.set(key, value); + }); else for (var key in object) map.set(key, object[key]); + return map; + }; + function d3_Map() {} + d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { + keys.push(key); + }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { + values.push(value); + }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { + entries.push({ + key: key, + value: value + }); + }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); + } + } + } + }); + var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + d3.nest = function() { + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; + } + valuesByKey.forEach(setter); + return object; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var array = [], sortKey = sortKeys[depth++]; + map.forEach(function(key, keyMap) { + array.push({ + key: key, + values: entries(keyMap, depth) + }); + }); + return sortKey ? array.sort(function(a, b) { + return sortKey(a.key, b.key); + }) : array; + } + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); + return set; + }; + function d3_Set() {} + d3_class(d3_Set, { + has: function(value) { + return d3_map_prefix + value in this; + }, + add: function(value) { + this[d3_map_prefix + value] = true; + return value; + }, + remove: function(value) { + value = d3_map_prefix + value; + return value in this && delete this[value]; + }, + values: function() { + var values = []; + this.forEach(function(value) { + values.push(value); + }); + return values; + }, + forEach: function(f) { + for (var value in this) { + if (value.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, value.substring(1)); + } + } + } + }); + d3.behavior = {}; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; + } + function d3_vendorSymbol(object, name) { + if (name in object) return name; + name = name.charAt(0).toUpperCase() + name.substring(1); + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { + var prefixName = d3_vendorPrefixes[i] + name; + if (prefixName in object) return prefixName; + } + } + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; + var d3_array = d3_arraySlice; + function d3_arrayCopy(pseudoarray) { + var i = pseudoarray.length, array = new Array(i); + while (i--) array[i] = pseudoarray[i]; + return array; + } + function d3_arraySlice(pseudoarray) { + return Array.prototype.slice.call(pseudoarray); + } + try { + d3_array(d3_documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = d3_arrayCopy; + } + function d3_noop() {} + d3.dispatch = function() { + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + function d3_dispatch() {} + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i >= 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); + } + return this; + } + }; + function d3_dispatch_event(dispatch) { + var listeners = [], listenerByName = new d3_Map(); + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + d3.event = null; + function d3_eventPreventDefault() { + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + var d3_subclass = {}.__proto__ ? function(object, prototype) { + object.__proto__ = prototype; + } : function(object, prototype) { + for (var property in prototype) object[property] = prototype[property]; + }; + function d3_selection(groups) { + d3_subclass(groups, d3_selectionPrototype); + return groups; + } + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = function(s, n) { + return Sizzle.uniqueSort(Sizzle(s, n)); + }; + d3_selectMatches = Sizzle.matchesSelector; + } + d3.selection = function() { + return d3_selectionRoot; + }; + var d3_selectionPrototype = d3.selection.prototype = []; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selector(selector) { + return typeof selector === "function" ? selector : function() { + return d3_select(selector, this); + }; + } + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selectorAll(selector) { + return typeof selector === "function" ? selector : function() { + return d3_selectAll(selector, this); + }; + } + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classed(name, value) { + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; + if (value) { + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); + } else { + node.setAttribute("class", d3_collapse(c.replace(re, " "))); + } + }; + } + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + d3_selectionPrototype.text = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }) : this.node().textContent; + }; + d3_selectionPrototype.html = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }) : this.node().innerHTML; + }; + d3_selectionPrototype.append = function(name) { + name = d3_selection_creator(name); + return this.select(function() { + return this.appendChild(name.apply(this, arguments)); + }); + }; + function d3_selection_creator(name) { + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { + return d3_document.createElementNS(name.space, name.local); + } : function() { + return d3_document.createElementNS(this.namespaceURI, name); + }; + } + d3_selectionPrototype.insert = function(name, before) { + name = d3_selection_creator(name); + before = d3_selection_selector(before); + return this.select(function() { + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); + }); + }; + d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + }); + }; + d3_selectionPrototype.data = function(value, key) { + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; + for (i = -1; ++i < n; ) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues.push(keyValue); + } + for (i = -1; ++i < m; ) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (node = nodeByKeyValue.get(keyValue)) { + updateNodes[i] = node; + node.__data__ = nodeData; + } else if (!dataByKeyValue.has(keyValue)) { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + dataByKeyValue.set(keyValue, nodeData); + nodeByKeyValue.remove(keyValue); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValues[i])) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + } + for (;i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (;i < n; ++i) { + exitNodes[i] = group[i]; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + d3_selectionPrototype.datum = function(value) { + return arguments.length ? this.property("__data__", value) : this.property("__data__"); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; + }; + } + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.size = function() { + var n = 0; + this.each(function() { + ++n; + }); + return n; + }; + function d3_selection_enter(selection) { + d3_subclass(selection, d3_selection_enterPrototype); + return selection; + } + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.call = d3_selectionPrototype.call; + d3_selection_enterPrototype.size = d3_selectionPrototype.size; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selection_enterPrototype.insert = function(name, before) { + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); + return d3_selectionPrototype.insert.call(this, name, before); + }; + function d3_selection_enterInsertBefore(enter) { + var i0, j0; + return function(d, i, j) { + var group = enter[j].update, n = group.length, node; + if (j != j0) j0 = j, i0 = 0; + if (i >= i0) i0 = i + 1; + while (!(node = group[i0]) && ++i0 < n) ; + return node; + }; + } + d3_selectionPrototype.transition = function() { + var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { + time: Date.now(), + ease: d3_ease_cubicInOut, + delay: 0, + duration: 250 + }; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) d3_transitionNode(node, i, id, transition); + subgroup.push(node); + } + } + return d3_transition(subgroups, id); + }; + d3.select = function(node) { + var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + d3.selectAll = function(nodes) { + var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + var d3_selectionRoot = d3.select(d3_documentElement); + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + function d3_selection_on(type, listener, capture) { + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; + if (i > 0) type = type.substring(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); + delete this[name]; + } + } + } + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; + } + var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }); + d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); + }); + function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; + } + }; + } + function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { + l.call(target, e); + } + }; + } + var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; + function d3_event_dragSuppress() { + var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; + style[d3_event_dragSelect] = "none"; + return function(suppressClick) { + w.on(name, null); + style[d3_event_dragSelect] = select; + if (suppressClick) { + function off() { + w.on(click, null); + } + w.on(click, function() { + d3_eventPreventDefault(); + off(); + }, true); + setTimeout(off, 0); + } + }; + } + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; + function d3_mousePoint(container, e) { + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select("body").append("svg").style({ + position: "absolute", + top: 0, + left: 0, + margin: 0, + padding: 0, + border: "none" + }, "important"); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) { + point.x = e.pageX; + point.y = e.pageY; + } else { + point.x = e.clientX; + point.y = e.clientY; + } + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + d3.behavior.drag = function() { + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); + } + function touchid() { + return d3.event.changedTouches[0].identifier; + } + function touchposition(parent, id) { + return d3.touches(parent).filter(function(p) { + return p.identifier === id; + })[0]; + } + function dragstart(id, position, move, end) { + return function() { + var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); + if (origin) { + offset = origin.apply(target, arguments); + offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + } else { + offset = [ 0, 0 ]; + } + event_({ + type: "dragstart" + }); + function moved() { + if (!parent) return ended(); + var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; + dragged |= dx | dy; + origin_ = p; + event_({ + type: "drag", + x: p[0] + offset[0], + y: p[1] + offset[1], + dx: dx, + dy: dy + }); + } + function ended() { + w.on(move + "." + drag, null).on(end + "." + drag, null); + dragRestore(dragged && d3.event.target === eventTarget); + event_({ + type: "dragend" + }); + } + }; + } + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + d3.behavior.zoom = function() { + var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1; + function zoom() { + this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); + } + zoom.translate = function(x) { + if (!arguments.length) return translate; + translate = x.map(Number); + rescale(); + return zoom; + }; + zoom.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + rescale(); + return zoom; + }; + zoom.scaleExtent = function(x) { + if (!arguments.length) return scaleExtent; + scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + function location(p) { + return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; + } + function point(l) { + return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; + } + function scaleTo(s) { + scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + translate[0] += p[0] - l[0]; + translate[1] += p[1] - l[1]; + } + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - translate[0]) / scale; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - translate[1]) / scale; + }).map(y0.invert)); + } + function dispatch(event) { + rescale(); + event({ + type: "zoom", + scale: scale, + translate: translate + }); + } + function mousedowned() { + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); + function moved() { + dragged = 1; + translateTo(d3.mouse(target), l); + dispatch(event_); + } + function ended() { + w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); + dragRestore(dragged && d3.event.target === eventTarget); + } + } + function touchstarted() { + var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); + started(); + function relocate() { + var touches = d3.touches(target); + scale0 = scale; + locations0 = {}; + touches.forEach(function(t) { + locations0[t.identifier] = location(t); + }); + return touches; + } + function started() { + var now = Date.now(), touches = relocate(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0], l = locations0[p.identifier]; + scaleTo(scale * 2); + translateTo(p, l); + d3_eventPreventDefault(); + dispatch(event_); + } + touchtime = now; + } else if (touches.length > 1) { + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; + distance0 = dx * dx + dy * dy; + } + } + function moved() { + var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier]; + if (p1 = touches[1]) { + var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale; + if (scale1 == null) { + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; + scale1 = distance0 && Math.sqrt(distance1 / distance0); + } + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(scale1 * scale0); + } + touchtime = null; + translateTo(p0, l0); + dispatch(event_); + } + function ended() { + if (d3.event.touches.length) { + relocate(); + } else { + w.on(touchmove, null).on(touchend, null); + t.on(mousedown, mousedowned).on(touchstart, touchstarted); + dragRestore(); + } + } + } + function mousewheeled() { + d3_eventPreventDefault(); + if (!translate0) translate0 = location(d3.mouse(this)); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); + translateTo(d3.mouse(this), translate0); + dispatch(event.of(this, arguments)); + } + function mousewheelreset() { + translate0 = null; + } + function dblclicked() { + var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; + scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomInfinity = [ 0, Infinity ]; + var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return d3.event.wheelDelta; + }, "mousewheel") : (d3_behavior_zoomDelta = function() { + return -d3.event.detail; + }, "MozMousePixelScroll"); + function d3_Color() {} + d3_Color.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.hsl = function(h, s, l) { + return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); + }; + function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); + } + function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; + } + var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); + d3_hslPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); + }; + d3_hslPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); + }; + d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + function d3_hsl_rgb(h, s, l) { + var m1, m2; + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; + function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + function d3_acos(x) { + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); + } + function d3_asin(x) { + return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); + } + function d3_sinh(x) { + return (Math.exp(x) - Math.exp(-x)) / 2; + } + function d3_cosh(x) { + return (Math.exp(x) + Math.exp(-x)) / 2; + } + function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; + } + d3.hcl = function(h, c, l) { + return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); + }; + function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); + } + function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; + } + var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); + d3_hclPrototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + function d3_hcl_lab(h, c, l) { + if (isNaN(h)) h = 0; + if (isNaN(c)) c = 0; + return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); + } + d3.lab = function(l, a, b) { + return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); + }; + function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); + } + function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; + } + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + var d3_labPrototype = d3_Lab.prototype = new d3_Color(); + d3_labPrototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + d3.rgb = function(r, g, b) { + return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); + }; + function d3_rgbNumber(value) { + return d3_rgb(value >> 16, value >> 8 & 255, value & 255); + } + function d3_rgbString(value) { + return d3_rgbNumber(value) + ""; + } + function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); + } + function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + } + var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); + d3_rgbPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); + }; + d3_rgbPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); + }; + d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, name; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); + r += r; + g = format.charAt(2); + g += g; + b = format.charAt(3); + b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + h = NaN; + s = l > 0 && l < 1 ? 0 : h; + } + return d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + var d3_rgb_names = d3.map({ + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgbNumber(value)); + }); + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + d3.functor = d3_functor; + function d3_identity(d) { + return d; + } + d3.xhr = d3_xhrType(d3_identity); + function d3_xhrType(response) { + return function(url, mimeType, callback) { + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, + mimeType = null; + return d3_xhr(url, mimeType, response, callback); + }; + } + function d3_xhr(url, mimeType, response, callback) { + var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; + if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { + request.readyState > 3 && respond(); + }; + function respond() { + var status = request.status, result; + if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { + try { + result = response.call(xhr, request); + } catch (e) { + dispatch.error.call(xhr, e); + return; + } + dispatch.load.call(xhr, result); + } else { + dispatch.error.call(xhr, request); + } + } + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { + dispatch.progress.call(xhr, request); + } finally { + d3.event = o; + } + }; + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; else headers[name] = value + ""; + return xhr; + }; + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; + }; + xhr.responseType = function(value) { + if (!arguments.length) return responseType; + responseType = value; + return xhr; + }; + xhr.response = function(value) { + response = value; + return xhr; + }; + [ "get", "post" ].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); + }; + }); + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (responseType != null) request.responseType = responseType; + if (callback != null) xhr.on("error", callback).on("load", function(request) { + callback(null, request); + }); + request.send(data == null ? null : data); + return xhr; + }; + xhr.abort = function() { + request.abort(); + return xhr; + }; + d3.rebind(xhr, dispatch, "on"); + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); + } + function d3_xhr_fixCallback(callback) { + return callback.length === 1 ? function(error, request) { + callback(error == null ? request : null); + } : callback; + } + d3.dsv = function(delimiter, mimeType) { + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + function dsv(url, row, callback) { + if (arguments.length < 3) callback = row, row = null; + var xhr = d3.xhr(url, mimeType, callback); + xhr.row = function(_) { + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; + }; + return xhr.row(row); + } + function response(request) { + return dsv.parse(request.responseText); + } + function typedResponse(f) { + return function(request) { + return dsv.parse(request.responseText, f); + }; + } + dsv.parse = function(text, f) { + var o; + return dsv.parseRows(text, function(row, i) { + if (o) return o(row, i - 1); + var a = new Function("d", "return {" + row.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "]"; + }).join(",") + "}"); + o = f ? function(row, i) { + return f(a(row), i); + } : a; + }); + }; + dsv.parseRows = function(text, f) { + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; + function token() { + if (I >= N) return EOF; + if (eol) return eol = false, EOL; + var j = I; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < N) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + ++i; + } + } + I = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) ++I; + } else if (c === 10) { + eol = true; + } + return text.substring(j + 1, i).replace(/""/g, '"'); + } + while (I < N) { + var c = text.charCodeAt(I++), k = 1; + if (c === 10) eol = true; else if (c === 13) { + eol = true; + if (text.charCodeAt(I) === 10) ++I, ++k; + } else if (c !== delimiterCode) continue; + return text.substring(j, I - k); + } + return text.substring(j); + } + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && !(a = f(a, n++))) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + if (Array.isArray(rows[0])) return dsv.formatRows(rows); + var fieldSet = new d3_Set(), fields = []; + rows.forEach(function(row) { + for (var field in row) { + if (!fieldSet.has(field)) { + fields.push(fieldSet.add(field)); + } + } + }); + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { + return fields.map(function(field) { + return formatValue(row[field]); + }).join(delimiter); + })).join("\n"); + }; + dsv.formatRows = function(rows) { + return rows.map(formatRow).join("\n"); + }; + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + return dsv; + }; + d3.csv = d3.dsv(",", "text/csv"); + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { + setTimeout(callback, 17); + }; + d3.timer = function(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + var time = then + delay, timer = { + callback: callback, + time: time, + next: null + }; + if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; + d3_timer_queueTail = timer; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + function d3_timer_step() { + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + d3.timer.flush = function() { + d3_timer_mark(); + d3_timer_sweep(); + }; + function d3_timer_replace(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + d3_timer_active.callback = callback; + d3_timer_active.time = then + delay; + } + function d3_timer_mark() { + var now = Date.now(); + d3_timer_active = d3_timer_queueHead; + while (d3_timer_active) { + if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); + d3_timer_active = d3_timer_active.next; + } + return now; + } + function d3_timer_sweep() { + var t0, t1 = d3_timer_queueHead, time = Infinity; + while (t1) { + if (t1.flush) { + t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; + } else { + if (t1.time < time) time = t1.time; + t1 = (t0 = t1).next; + } + } + d3_timer_queueTail = t0; + return time; + } + var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + function d3_formatPrefix(d, i) { + var k = Math.pow(10, Math.abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + d3.format = function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; + if (precision) precision = +precision.substring(1); + if (zfill || fill === "0" && align === "=") { + zfill = fill = "0"; + align = "="; + if (comma) width -= Math.floor((width - 1) / 4); + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + + case "b": + case "o": + case "x": + case "X": + if (symbol === "#") symbol = "0" + type.toLowerCase(); + + case "c": + case "d": + integer = true; + precision = 0; + break; + + case "s": + scale = -1; + type = "r"; + break; + } + if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; + if (type == "r" && !precision) type = "g"; + if (precision != null) { + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); + } + type = d3_format_types.get(type) || d3_format_typeDefault; + var zcomma = zfill && comma; + return function(value) { + if (integer && value % 1) return ""; + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; + if (scale < 0) { + var prefix = d3.formatPrefix(value, precision); + value = prefix.scale(value); + suffix = prefix.symbol; + } else { + value *= scale; + } + value = type(value, precision); + var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); + if (!zfill && comma) before = d3_format_group(before); + var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; + if (zcomma) before = d3_format_group(padding + before); + negative += symbol; + value = before + after; + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; + }; + }; + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; + var d3_format_types = d3.map({ + b: function(x) { + return x.toString(2); + }, + c: function(x) { + return String.fromCharCode(x); + }, + o: function(x) { + return x.toString(8); + }, + x: function(x) { + return x.toString(16); + }, + X: function(x) { + return x.toString(16).toUpperCase(); + }, + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); + } + }); + function d3_format_precision(x, p) { + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); + } + function d3_format_typeDefault(x) { + return x + ""; + } + var d3_format_group = d3_identity; + if (d3_format_grouping) { + var d3_format_groupingLength = d3_format_grouping.length; + d3_format_group = function(value) { + var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; + while (i > 0 && g > 0) { + t.push(value.substring(i -= g, i + g)); + g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; + } + return t.reverse().join(d3_format_thousandsSeparator); + }; + } + d3.geo = {}; + function d3_adder() {} + d3_adder.prototype = { + s: 0, + t: 0, + add: function(y) { + d3_adderSum(y, this.t, d3_adderTemp); + d3_adderSum(d3_adderTemp.s, this.s, this); + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; + }, + reset: function() { + this.s = this.t = 0; + }, + valueOf: function() { + return this.s; + } + }; + var d3_adderTemp = new d3_adder(); + function d3_adderSum(a, b, o) { + var x = o.s = a + b, bv = x - a, av = x - bv; + o.t = a - av + (b - bv); + } + d3.geo.stream = function(object, listener) { + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); + } + }; + function d3_geo_streamGeometry(geometry, listener) { + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); + } + } + var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); + } + }; + var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + var coordinate = object.coordinates; + listener.point(coordinate[0], coordinate[1]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); + } + }; + function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + listener.lineEnd(); + } + function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); + } + d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; + }; + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); + var d3_geo_area = { + sphere: function() { + d3_geo_areaSum += 4 * π; + }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_areaRingSum.reset(); + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * d3_geo_areaRingSum; + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } + }; + function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), + sinφ0 = Math.sin(φ); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; + var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); + d3_geo_areaRingSum.add(Math.atan2(v, u)); + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; + } + function d3_geo_cartesian(spherical) { + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; + } + function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + function d3_geo_cartesianCross(a, b) { + return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; + } + function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + } + function d3_geo_cartesianScale(vector, k) { + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; + } + function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; + } + function d3_geo_spherical(cartesian) { + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; + } + function d3_geo_sphericalEqual(a, b) { + return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; + } + d3.geo.bounds = function() { + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; + var bound = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + bound.point = ringPoint; + bound.lineStart = ringStart; + bound.lineEnd = ringEnd; + dλSum = 0; + d3_geo_area.polygonStart(); + }, + polygonEnd: function() { + d3_geo_area.polygonEnd(); + bound.point = point; + bound.lineStart = lineStart; + bound.lineEnd = lineEnd; + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; + range[0] = λ0, range[1] = λ1; + } + }; + function point(λ, φ) { + ranges.push(range = [ λ0 = λ, λ1 = λ ]); + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + function linePoint(λ, φ) { + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); + if (p0) { + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); + d3_geo_cartesianNormalize(inflection); + inflection = d3_geo_spherical(inflection); + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = inflection[1] * d3_degrees; + if (φi > φ1) φ1 = φi; + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = -inflection[1] * d3_degrees; + if (φi < φ0) φ0 = φi; + } else { + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + if (antimeridian) { + if (λ < λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } else { + if (λ1 >= λ0) { + if (λ < λ0) λ0 = λ; + if (λ > λ1) λ1 = λ; + } else { + if (λ > λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } + } + } else { + point(λ, φ); + } + p0 = p, λ_ = λ; + } + function lineStart() { + bound.point = linePoint; + } + function lineEnd() { + range[0] = λ0, range[1] = λ1; + bound.point = point; + p0 = null; + } + function ringPoint(λ, φ) { + if (p0) { + var dλ = λ - λ_; + dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; + } else λ__ = λ, φ__ = φ; + d3_geo_area.point(λ, φ); + linePoint(λ, φ); + } + function ringStart() { + d3_geo_area.lineStart(); + } + function ringEnd() { + ringPoint(λ__, φ__); + d3_geo_area.lineEnd(); + if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); + range[0] = λ0, range[1] = λ1; + p0 = null; + } + function angle(λ0, λ1) { + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; + } + function compareRanges(a, b) { + return a[0] - b[0]; + } + function withinRange(x, range) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; + } + return function(feature) { + φ1 = λ1 = -(λ0 = φ0 = Infinity); + ranges = []; + d3.geo.stream(feature, bound); + var n = ranges.length; + if (n) { + ranges.sort(compareRanges); + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { + b = ranges[i]; + if (withinRange(b[0], a) || withinRange(b[1], a)) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + var best = -Infinity, dλ; + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { + b = merged[i]; + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; + } + } + ranges = range = null; + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; + }; + }(); + d3.geo.centroid = function(object) { + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, d3_geo_centroid); + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; + if (m < ε2) { + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; + m = x * x + y * y + z * z; + if (m < ε2) return [ NaN, NaN ]; + } + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; + }; + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; + var d3_geo_centroid = { + sphere: d3_noop, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } + }; + function d3_geo_centroidPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); + } + function d3_geo_centroidPointXYZ(x, y, z) { + ++d3_geo_centroidW0; + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; + } + function d3_geo_centroidLineStart() { + var x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; + } + function d3_geo_centroidRingStart() { + var λ00, φ00, x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ00 = λ, φ00 = φ; + d3_geo_centroid.point = nextPoint; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + d3_geo_centroid.lineEnd = function() { + nextPoint(λ00, φ00); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + d3_geo_centroid.point = d3_geo_centroidPoint; + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); + d3_geo_centroidX2 += v * cx; + d3_geo_centroidY2 += v * cy; + d3_geo_centroidZ2 += v * cz; + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_true() { + return true; + } + function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { + var subject = [], clip = []; + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; + } + var a = { + point: p0, + points: segment, + other: null, + visited: false, + entry: true, + subject: true + }, b = { + point: p0, + points: [ p0 ], + other: a, + visited: false, + entry: false, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + a = { + point: p1, + points: [ p1 ], + other: null, + visited: false, + entry: false, + subject: true + }; + b = { + point: p1, + points: [ p1 ], + other: a, + visited: false, + entry: true, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { + clip[i].entry = e = !e; + } + var start = subject[0], current, points, point; + while (1) { + current = start; + while (current.visited) if ((current = current.next) === start) return; + points = current.points; + listener.lineStart(); + do { + current.visited = current.other.visited = true; + if (current.entry) { + if (current.subject) { + for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.next.point, 1, listener); + } + current = current.next; + } else { + if (current.subject) { + points = current.prev.points; + for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.prev.point, -1, listener); + } + current = current.prev; + } + current = current.other; + points = current.points; + } while (!current.visited); + listener.lineEnd(); + } + } + function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, i = 0, a = array[0], b; + while (++i < n) { + a.next = b = array[i]; + b.prev = a; + a = b; + } + a.next = b = array[0]; + b.prev = a; + } + function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { + return function(listener) { + var line = clipLine(listener); + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + listener.polygonStart(); + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = d3.merge(segments); + if (segments.length) { + d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); + } else if (polygonContains(polygon)) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + listener.polygonEnd(); + segments = polygon = null; + }, + sphere: function() { + listener.polygonStart(); + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + listener.polygonEnd(); + } + }; + function point(λ, φ) { + if (pointVisible(λ, φ)) listener.point(λ, φ); + } + function pointLine(λ, φ) { + line.point(λ, φ); + } + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + var segments; + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; + function pointRing(λ, φ) { + ringListener.point(λ, φ); + ring.push([ λ, φ ]); + } + function ringStart() { + ringListener.lineStart(); + ring = []; + } + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; + ring.pop(); + polygon.push(ring); + ring = null; + if (!n) return; + if (clean & 1) { + segment = ringSegments[0]; + var n = segment.length - 1, i = -1, point; + listener.lineStart(); + while (++i < n) listener.point((point = segment[i])[0], point[1]); + listener.lineEnd(); + return; + } + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); + } + return clip; + }; + } + function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; + } + function d3_geo_clipBufferListener() { + var lines = [], line; + return { + lineStart: function() { + lines.push(line = []); + }, + point: function(λ, φ) { + line.push([ λ, φ ]); + }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; + } + function d3_geo_clipSort(a, b) { + return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); + } + function d3_geo_pointInPolygon(point, polygon) { + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; + d3_geo_areaRingSum.reset(); + for (var i = 0, n = polygon.length; i < n; ++i) { + var ring = polygon[i], m = ring.length; + if (!m) continue; + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; + while (true) { + if (j === m) j = 0; + point = ring[j]; + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; + d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); + if (Math.abs(φ) < ε) southPole = true; + polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); + d3_geo_cartesianNormalize(arc); + var intersection = d3_geo_cartesianCross(meridianNormal, arc); + d3_geo_cartesianNormalize(intersection); + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); + if (parallel > φarc) { + winding += antimeridian ^ dλ >= 0 ? 1 : -1; + } + } + if (!j++) break; + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; + } + if (Math.abs(polarAngle) > ε) polar = true; + } + return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; + } + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); + function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; + return { + lineStart: function() { + listener.lineStart(); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); + if (Math.abs(dλ - π) < ε) { + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point(λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { + if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { + listener.lineEnd(); + λ0 = φ0 = NaN; + }, + clean: function() { + return 2 - clean; + } + }; + } + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); + return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; + } + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * π / 2; + listener.point(-π, φ); + listener.point(0, φ); + listener.point(π, φ); + listener.point(π, 0); + listener.point(π, -φ); + listener.point(0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (Math.abs(from[0] - to[0]) > ε) { + var s = (from[0] < to[0] ? 1 : -1) * π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point(0, φ); + listener.point(s, φ); + } else { + listener.point(to[0], to[1]); + } + } + var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; + function d3_geo_clipAntimeridianPolygonContains(polygon) { + return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); + } + function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + return d3_geo_clip(visible, clipLine, interpolate, polygonContains); + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + function clipLine(listener) { + var point0, c0, v0, v00, clean; + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); + } + } + if (v !== v0) { + clean = 0; + if (v) { + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + clean: function() { + return clean | (v00 && v0) << 1; + } + }; + } + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; + if (!determinant) return !two && a; + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + if (t2 < 0) return; + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [ q, d3_geo_spherical(q1) ]; + } + } + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, code = 0; + if (λ < -r) code |= 1; else if (λ > r) code |= 2; + if (φ < -r) code |= 4; else if (φ > r) code |= 8; + return code; + } + function polygonContains(polygon) { + return d3_geo_pointInPolygon(point, polygon); + } + } + var d3_geo_clipViewMAX = 1e9; + function d3_geo_clipView(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + }, + polygonEnd: function() { + listener = listener_; + if ((segments = d3.merge(segments)).length) { + listener.polygonStart(); + d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); + listener.polygonEnd(); + } else if (insidePolygon([ x0, y0 ])) { + listener.polygonStart(), listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(), listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + function inside(point) { + var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); + return i; + } + function insidePolygon(p) { + var wn = 0, n = polygon.length, y = p[1]; + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && isLeft(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && isLeft(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + function isLeft(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + } + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + function visible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + function point(x, y) { + if (visible(x, y)) listener.point(x, y); + } + var x__, y__, v__, x_, y_, v_, first; + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + function linePoint(x, y) { + x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); + y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); + var v = visible(x, y); + if (polygon) ring.push([ x, y ]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); else { + var a = [ x_, y_ ], b = [ x, y ]; + if (clipLine(a, b)) { + if (!v_) { + listener.lineStart(); + listener.point(a[0], a[1]); + } + listener.point(b[0], b[1]); + if (!v) listener.lineEnd(); + } else if (v) { + listener.lineStart(); + listener.point(x, y); + } + } + } + x_ = x, y_ = y, v_ = v; + } + return clip; + }; + function corner(p, direction) { + return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + } + function compare(a, b) { + return comparePoints(a.point, b.point); + } + function comparePoints(a, b) { + var ca = corner(a, 1), cb = corner(b, 1); + return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; + } + function clipLine(a, b) { + var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; + if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; + if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { + if (t[1] < 1) { + b[0] = a[0] + t[1] * dx; + b[1] = a[1] + t[1] * dy; + } + if (t[0] > 0) { + a[0] += t[0] * dx; + a[1] += t[0] * dy; + } + return true; + } + return false; + } + } + function d3_geo_clipViewT(num, denominator, t) { + if (Math.abs(denominator) < ε) return num <= 0; + var u = num / denominator; + if (denominator > 0) { + if (u > t[1]) return false; + if (u > t[0]) t[0] = u; + } else { + if (u < t[0]) return false; + if (u < t[1]) t[1] = u; + } + return true; + } + function d3_geo_compose(a, b) { + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + return compose; + } + function d3_geo_conic(projectAt) { + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); + p.parallels = function(_) { + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + return p; + } + function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; + }; + return forward; + } + (d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); + }).raw = d3_geo_conicEqualArea; + d3.geo.albers = function() { + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); + }; + d3.geo.albersUsa = function() { + var lower48 = d3.geo.albers(); + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); + var point, pointStream = { + point: function(x, y) { + point = [ x, y ]; + } + }, lower48Point, alaskaPoint, hawaiiPoint; + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + point = null; + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); + return point; + } + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); + }; + albersUsa.stream = function(stream) { + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); + return { + point: function(x, y) { + lower48Stream.point(x, y); + alaskaStream.point(x, y); + hawaiiStream.point(x, y); + }, + sphere: function() { + lower48Stream.sphere(); + alaskaStream.sphere(); + hawaiiStream.sphere(); + }, + lineStart: function() { + lower48Stream.lineStart(); + alaskaStream.lineStart(); + hawaiiStream.lineStart(); + }, + lineEnd: function() { + lower48Stream.lineEnd(); + alaskaStream.lineEnd(); + hawaiiStream.lineEnd(); + }, + polygonStart: function() { + lower48Stream.polygonStart(); + alaskaStream.polygonStart(); + hawaiiStream.polygonStart(); + }, + polygonEnd: function() { + lower48Stream.polygonEnd(); + alaskaStream.polygonEnd(); + hawaiiStream.polygonEnd(); + } + }; + }; + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_); + alaska.precision(_); + hawaii.precision(_); + return albersUsa; + }; + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_); + alaska.scale(_ * .35); + hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + return albersUsa; + }; + return albersUsa.scale(1070); + }; + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); + } + }; + function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; + } + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; + var d3_geo_pathBounds = { + point: d3_geo_pathBoundsPoint, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_pathBoundsPoint(x, y) { + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; + } + function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointCircle = d3_geo_pathBufferCircle(_); + return stream; + }, + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + buffer.push("Z"); + } + return stream; + } + function d3_geo_pathBufferCircle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; + } + var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } + }; + function d3_geo_pathCentroidPoint(x, y) { + d3_geo_centroidX0 += x; + d3_geo_centroidY0 += y; + ++d3_geo_centroidZ0; + } + function d3_geo_pathCentroidLineStart() { + var x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + } + function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + } + function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + z = y0 * x - x0 * y; + d3_geo_centroidX2 += z * (x0 + x); + d3_geo_centroidY2 += z * (y0 + y); + d3_geo_centroidZ2 += z * 3; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; + } + function d3_geo_pathContext(context) { + var pointRadius = 4.5; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointRadius = _; + return stream; + }, + result: d3_noop + }; + function point(x, y) { + context.moveTo(x, y); + context.arc(x, y, pointRadius, 0, 2 * π); + } + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + function pointLine(x, y) { + context.lineTo(x, y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + context.closePath(); + } + return stream; + } + function d3_geo_resample(project) { + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; + function resample(stream) { + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; + var resample = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + stream.polygonStart(); + resample.lineStart = ringStart; + }, + polygonEnd: function() { + stream.polygonEnd(); + resample.lineStart = lineStart; + } + }; + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + function linePoint(λ, φ) { + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + function ringStart() { + lineStart(); + resample.point = ringPoint; + resample.lineEnd = ringEnd; + } + function ringPoint(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + } + function ringEnd() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + } + return resample; + } + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); + } + } + } + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + return resample; + } + d3.geo.path = function() { + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); + d3.geo.stream(object, cacheStream); + } + return contextStream.result(); + } + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; + }; + path.centroid = function(object) { + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; + }; + path.bounds = function(object) { + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; + }; + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return reset(); + }; + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return reset(); + }; + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + function reset() { + cacheStream = null; + return path; + } + return path.projection(d3.geo.albersUsa()).context(null); + }; + function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(λ, φ) { + return project([ λ * d3_degrees, φ * d3_degrees ]); + }); + return function(stream) { + stream = resample(stream); + return { + point: function(λ, φ) { + stream.point(λ * d3_radians, φ * d3_radians); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + }; + } + d3.geo.projection = d3_geo_projection; + d3.geo.projectionMutator = d3_geo_projectionMutator; + function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { + return project; + })(); + } + function d3_geo_projectionMutator(projectAt) { + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { + x = project(x, y); + return [ x[0] * k + δx, δy - x[1] * k ]; + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [ point[0] * k + δx, δy - point[1] * k ]; + } + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; + } + projection.stream = function(output) { + if (stream) stream.valid = false; + stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); + stream.valid = true; + return stream; + }; + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return invalidate(); + }; + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); + return invalidate(); + }; + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + projection.translate = function(_) { + if (!arguments.length) return [ x, y ]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + projection.center = function(_) { + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + projection.rotate = function(_) { + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + d3.rebind(projection, projectResample, "precision"); + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return invalidate(); + } + function invalidate() { + if (stream) { + stream.valid = false; + stream = null; + } + return projection; + } + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; + } + function d3_geo_projectionRadiansRotate(rotate, stream) { + return { + point: function(x, y) { + y = rotate(x * d3_radians, y * d3_radians), x = y[0]; + stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + } + function d3_geo_equirectangular(λ, φ) { + return [ λ, φ ]; + } + (d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + } + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + return forward; + }; + function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; + } + function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; + }; + } + function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; + } + function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); + function rotation(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; + } + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; + }; + return rotation; + } + d3.geo.circle = function() { + var origin = [ 0, 0 ], angle, precision = 6, interpolate; + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; + } + }); + return { + type: "Polygon", + coordinates: [ ring ] + }; + } + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + return circle.angle(90); + }; + function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), sr = Math.sin(radius); + return function(from, to, direction, listener) { + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to : from > to) from += direction * 2 * π; + } else { + from = radius + direction * 2 * π; + to = radius; + } + var point; + for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); + } + }; + } + function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); + } + d3.geo.distance = function(a, b) { + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); + }; + d3.geo.graticule = function() { + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; + function graticule() { + return { + type: "MultiLineString", + coordinates: lines() + }; + } + function lines() { + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { + return Math.abs(x % DX) > ε; + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { + return Math.abs(y % DY) > ε; + }).map(y)); + } + graticule.lines = function() { + return lines().map(function(coordinates) { + return { + type: "LineString", + coordinates: coordinates + }; + }); + }; + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] + }; + }; + graticule.extent = function(_) { + if (!arguments.length) return graticule.minorExtent(); + return graticule.majorExtent(_).minorExtent(_); + }; + graticule.majorExtent = function(_) { + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + graticule.minorExtent = function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + graticule.step = function(_) { + if (!arguments.length) return graticule.minorStep(); + return graticule.majorStep(_).minorStep(_); + }; + graticule.majorStep = function(_) { + if (!arguments.length) return [ DX, DY ]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + graticule.minorStep = function(_) { + if (!arguments.length) return [ dx, dy ]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = d3_geo_graticuleX(y0, y1, 90); + y = d3_geo_graticuleY(x0, x1, precision); + X = d3_geo_graticuleX(Y0, Y1, 90); + Y = d3_geo_graticuleY(X0, X1, precision); + return graticule; + }; + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + }; + function d3_geo_graticuleX(y0, y1, dy) { + var y = d3.range(y0, y1 - ε, dy).concat(y1); + return function(x) { + return y.map(function(y) { + return [ x, y ]; + }); + }; + } + function d3_geo_graticuleY(x0, x1, dx) { + var x = d3.range(x0, x1 - ε, dx).concat(x1); + return function(y) { + return x.map(function(x) { + return [ x, y ]; + }); + }; + } + function d3_source(d) { + return d.source; + } + function d3_target(d) { + return d.target; + } + d3.geo.greatArc = function() { + var source = d3_source, source_, target = d3_target, target_; + function greatArc() { + return { + type: "LineString", + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] + }; + } + greatArc.distance = function() { + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _, source_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _, target_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.precision = function() { + return arguments.length ? greatArc : 0; + }; + return greatArc; + }; + d3.geo.interpolate = function(source, target) { + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); + }; + function d3_geo_interpolate(x0, y0, x1, y1) { + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); + var interpolate = d ? function(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; + } : function() { + return [ x0 * d3_degrees, y0 * d3_degrees ]; + }; + interpolate.distance = d; + return interpolate; + } + d3.geo.length = function(object) { + d3_geo_lengthSum = 0; + d3.geo.stream(object, d3_geo_length); + return d3_geo_lengthSum; + }; + var d3_geo_lengthSum; + var d3_geo_length = { + sphere: d3_noop, + point: d3_noop, + lineStart: d3_geo_lengthLineStart, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_lengthLineStart() { + var λ0, sinφ0, cosφ0; + d3_geo_length.point = function(λ, φ) { + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); + d3_geo_length.point = nextPoint; + }; + d3_geo_length.lineEnd = function() { + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; + }; + function nextPoint(λ, φ) { + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; + } + } + function d3_geo_azimuthal(scale, angle) { + function azimuthal(λ, φ) { + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; + } + azimuthal.invert = function(x, y) { + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; + }; + return azimuthal; + } + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { + return Math.sqrt(2 / (1 + cosλcosφ)); + }, function(ρ) { + return 2 * Math.asin(ρ / 2); + }); + (d3.geo.azimuthalEqualArea = function() { + return d3_geo_projection(d3_geo_azimuthalEqualArea); + }).raw = d3_geo_azimuthalEqualArea; + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { + var c = Math.acos(cosλcosφ); + return c && c / Math.sin(c); + }, d3_identity); + (d3.geo.azimuthalEquidistant = function() { + return d3_geo_projection(d3_geo_azimuthalEquidistant); + }).raw = d3_geo_azimuthalEquidistant; + function d3_geo_conicConformal(φ0, φ1) { + var cosφ0 = Math.cos(φ0), t = function(φ) { + return Math.tan(π / 4 + φ / 2); + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; + if (!n) return d3_geo_mercator; + function forward(λ, φ) { + var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; + }; + return forward; + } + (d3.geo.conicConformal = function() { + return d3_geo_conic(d3_geo_conicConformal); + }).raw = d3_geo_conicConformal; + function d3_geo_conicEquidistant(φ0, φ1) { + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; + if (Math.abs(n) < ε) return d3_geo_equirectangular; + function forward(λ, φ) { + var ρ = G - φ; + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = G - y; + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; + }; + return forward; + } + (d3.geo.conicEquidistant = function() { + return d3_geo_conic(d3_geo_conicEquidistant); + }).raw = d3_geo_conicEquidistant; + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / cosλcosφ; + }, Math.atan); + (d3.geo.gnomonic = function() { + return d3_geo_projection(d3_geo_gnomonic); + }).raw = d3_geo_gnomonic; + function d3_geo_mercator(λ, φ) { + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; + } + d3_geo_mercator.invert = function(x, y) { + return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; + }; + function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + return m.clipExtent(null); + } + (d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); + }).raw = d3_geo_mercator; + var d3_geo_orthographic = d3_geo_azimuthal(function() { + return 1; + }, Math.asin); + (d3.geo.orthographic = function() { + return d3_geo_projection(d3_geo_orthographic); + }).raw = d3_geo_orthographic; + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / (1 + cosλcosφ); + }, function(ρ) { + return 2 * Math.atan(ρ); + }); + (d3.geo.stereographic = function() { + return d3_geo_projection(d3_geo_stereographic); + }).raw = d3_geo_stereographic; + function d3_geo_transverseMercator(λ, φ) { + var B = Math.cos(φ) * Math.sin(λ); + return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; + } + d3_geo_transverseMercator.invert = function(x, y) { + return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; + }; + (d3.geo.transverseMercator = function() { + return d3_geo_mercatorProjection(d3_geo_transverseMercator); + }).raw = d3_geo_transverseMercator; + d3.geom = {}; + d3.svg = {}; + function d3_svg_line(projection) { + var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + function line(data) { + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + function d3_svg_lineX(d) { + return d[0]; + } + function d3_svg_lineY(d) { + return d[1]; + } + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + step: d3_svg_lineStep, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStep(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); + if (n > 1) path.push("H", p[0]); + return path.join(""); + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + points.push(points[n - 1]); + while (++i <= n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + points.pop(); + path.push("L", pi); + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < 1e-6) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + d3.geom.hull = function(vertices) { + var x = d3_svg_lineX, y = d3_svg_lineY; + if (arguments.length) return hull(vertices); + function hull(data) { + if (data.length < 3) return []; + var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; + if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, + vertices = []; i < n; ++i) { + vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); + } + for (i = 1; i < n; ++i) { + if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; + } + for (i = 0; i < n; ++i) { + if (i === h) continue; + y1 = vertices[i][1] - vertices[h][1]; + x1 = vertices[i][0] - vertices[h][0]; + points.push({ + angle: Math.atan2(y1, x1), + index: i + }); + } + points.sort(function(a, b) { + return a.angle - b.angle; + }); + a = points[0].angle; + v = points[0].index; + u = 0; + for (i = 1; i < plen; ++i) { + j = points[i].index; + if (a == points[i].angle) { + x1 = vertices[v][0] - vertices[h][0]; + y1 = vertices[v][1] - vertices[h][1]; + x2 = vertices[j][0] - vertices[h][0]; + y2 = vertices[j][1] - vertices[h][1]; + if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { + points[i].index = -1; + continue; + } else { + points[u].index = -1; + } + } + a = points[i].angle; + u = i; + v = j; + } + stack.push(h); + for (i = 0, j = 0; i < 2; ++j) { + if (points[j].index > -1) { + stack.push(points[j].index); + i++; + } + } + sp = stack.length; + for (;j < plen; ++j) { + if (points[j].index < 0) continue; + while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { + --sp; + } + stack[sp++] = points[j].index; + } + var poly = []; + for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); + return poly; + } + hull.x = function(_) { + return arguments.length ? (x = _, hull) : x; + }; + hull.y = function(_) { + return arguments.length ? (y = _, hull) : y; + }; + return hull; + }; + function d3_geom_hullCCW(i1, i2, i3, v) { + var t, a, b, c, d, e, f; + t = v[i1]; + a = t[0]; + b = t[1]; + t = v[i2]; + c = t[0]; + d = t[1]; + t = v[i3]; + e = t[0]; + f = t[1]; + return (f - b) * (c - a) - (d - b) * (e - a) > 0; + } + d3.geom.polygon = function(coordinates) { + d3_subclass(coordinates, d3_geom_polygonPrototype); + return coordinates; + }; + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; + d3_geom_polygonPrototype.area = function() { + var i = -1, n = this.length, a, b = this[n - 1], area = 0; + while (++i < n) { + a = b; + b = this[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + return area * .5; + }; + d3_geom_polygonPrototype.centroid = function(k) { + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; + if (!arguments.length) k = -1 / (6 * this.area()); + while (++i < n) { + a = b; + b = this[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + d3_geom_polygonPrototype.clip = function(subject) { + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = this[i]; + c = input[(m = input.length - closed) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + if (closed) subject.push(subject[0]); + a = b; + } + return subject; + }; + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_geom_polygonClosed(coordinates) { + var a = coordinates[0], b = coordinates[coordinates.length - 1]; + return !(a[0] - b[0] || a[1] - b[1]); + } + d3.geom.delaunay = function(vertices) { + var edges = vertices.map(function() { + return []; + }), triangles = []; + d3_geom_voronoiTessellate(vertices, function(e) { + edges[e.region.l.index].push(vertices[e.region.r.index]); + }); + edges.forEach(function(edge, i) { + var v = vertices[i], cx = v[0], cy = v[1]; + edge.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + edge.sort(function(a, b) { + return a.angle - b.angle; + }); + for (var j = 0, m = edge.length - 1; j < m; j++) { + triangles.push([ v, edge[j], edge[j + 1] ]); + } + }); + return triangles; + }; + d3.geom.voronoi = function(points) { + var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; + if (arguments.length) return voronoi(points); + function voronoi(data) { + var points, polygons = data.map(function() { + return []; + }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var s1, s2, x1, x2, y1, y2; + if (e.a === 1 && e.b >= 0) { + s1 = e.ep.r; + s2 = e.ep.l; + } else { + s1 = e.ep.l; + s2 = e.ep.r; + } + if (e.a === 1) { + y1 = s1 ? s1.y : -Z; + x1 = e.c - e.b * y1; + y2 = s2 ? s2.y : Z; + x2 = e.c - e.b * y2; + } else { + x1 = s1 ? s1.x : -Z; + y1 = e.c - e.a * x1; + x2 = s2 ? s2.x : Z; + y2 = e.c - e.a * x2; + } + var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; + polygons[e.region.l.index].push(v1, v2); + polygons[e.region.r.index].push(v1, v2); + }); + polygons = polygons.map(function(polygon, i) { + var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { + return Math.atan2(v[0] - cx, v[1] - cy); + }), order = d3.range(polygon.length).sort(function(a, b) { + return angle[a] - angle[b]; + }); + return order.filter(function(d, i) { + return !i || angle[d] - angle[order[i - 1]] > ε; + }).map(function(d) { + return polygon[d]; + }); + }); + polygons.forEach(function(polygon, i) { + var n = polygon.length; + if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); + if (n > 2) return; + var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; + if (Math.abs(dy) < ε) { + var y = y0 < y1 ? -Z : Z; + polygon.push([ -Z, y ], [ Z, y ]); + } else if (dx < ε) { + var x = x0 < x1 ? -Z : Z; + polygon.push([ x, -Z ], [ x, Z ]); + } else { + var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; + if (Math.abs(z) < ε) { + polygon.push([ dy < 0 ? y : -y, y ]); + } else { + if (z > 0) y *= -1; + polygon.push([ -Z, y ], [ Z, y ]); + } + } + }); + if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); + for (i = 0; i < n; ++i) polygons[i].point = data[i]; + return polygons; + } + voronoi.x = function(_) { + return arguments.length ? (x = _, voronoi) : x; + }; + voronoi.y = function(_) { + return arguments.length ? (y = _, voronoi) : y; + }; + voronoi.clipExtent = function(_) { + if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; + if (_ == null) clipPolygon = null; else { + var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; + clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); + } + return voronoi; + }; + voronoi.size = function(_) { + if (!arguments.length) return clipPolygon && clipPolygon[2]; + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); + }; + voronoi.links = function(data) { + var points, graph = data.map(function() { + return []; + }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var l = e.region.l.index, r = e.region.r.index; + if (graph[l][r]) return; + graph[l][r] = graph[r][l] = true; + links.push({ + source: data[l], + target: data[r] + }); + }); + return links; + }; + voronoi.triangles = function(data) { + if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); + var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; + while (++i < n) { + (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; + } + return d3.geom.delaunay(points).map(function(triangle) { + return triangle.map(function(point) { + return point.data; + }); + }); + }; + return voronoi; + }; + var d3_geom_voronoiOpposite = { + l: "r", + r: "l" + }; + function d3_geom_voronoiTessellate(points, callback) { + var Sites = { + list: points.map(function(v, i) { + return { + index: i, + x: v[0], + y: v[1] + }; + }).sort(function(a, b) { + return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; + }), + bottomSite: null + }; + var EdgeList = { + list: [], + leftEnd: null, + rightEnd: null, + init: function() { + EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.leftEnd.r = EdgeList.rightEnd; + EdgeList.rightEnd.l = EdgeList.leftEnd; + EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); + }, + createHalfEdge: function(edge, side) { + return { + edge: edge, + side: side, + vertex: null, + l: null, + r: null + }; + }, + insert: function(lb, he) { + he.l = lb; + he.r = lb.r; + lb.r.l = he; + lb.r = he; + }, + leftBound: function(p) { + var he = EdgeList.leftEnd; + do { + he = he.r; + } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); + he = he.l; + return he; + }, + del: function(he) { + he.l.r = he.r; + he.r.l = he.l; + he.edge = null; + }, + right: function(he) { + return he.r; + }, + left: function(he) { + return he.l; + }, + leftRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; + }, + rightRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; + } + }; + var Geom = { + bisect: function(s1, s2) { + var newEdge = { + region: { + l: s1, + r: s2 + }, + ep: { + l: null, + r: null + } + }; + var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; + newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; + if (adx > ady) { + newEdge.a = 1; + newEdge.b = dy / dx; + newEdge.c /= dx; + } else { + newEdge.b = 1; + newEdge.a = dx / dy; + newEdge.c /= dy; + } + return newEdge; + }, + intersect: function(el1, el2) { + var e1 = el1.edge, e2 = el2.edge; + if (!e1 || !e2 || e1.region.r == e2.region.r) { + return null; + } + var d = e1.a * e2.b - e1.b * e2.a; + if (Math.abs(d) < 1e-10) { + return null; + } + var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; + if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + var rightOfSite = xint >= e.region.r.x; + if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { + return null; + } + return { + x: xint, + y: yint + }; + }, + rightOf: function(he, p) { + var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; + if (rightOfSite && he.side === "l") { + return 1; + } + if (!rightOfSite && he.side === "r") { + return 0; + } + if (e.a === 1) { + var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; + if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { + above = fast = dyp >= e.b * dxp; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0) { + above = !above; + } + if (!above) { + fast = 1; + } + } + if (!fast) { + var dxs = topsite.x - e.region.l.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); + if (e.b < 0) { + above = !above; + } + } + } else { + var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return he.side === "l" ? above : !above; + }, + endPoint: function(edge, side, site) { + edge.ep[side] = site; + if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; + callback(edge); + }, + distance: function(s, t) { + var dx = s.x - t.x, dy = s.y - t.y; + return Math.sqrt(dx * dx + dy * dy); + } + }; + var EventQueue = { + list: [], + insert: function(he, site, offset) { + he.vertex = site; + he.ystar = site.y + offset; + for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { + var next = list[i]; + if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { + continue; + } else { + break; + } + } + list.splice(i, 0, he); + }, + del: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} + ls.splice(i, 1); + }, + empty: function() { + return EventQueue.list.length === 0; + }, + nextEvent: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { + if (ls[i] == he) return ls[i + 1]; + } + return null; + }, + min: function() { + var elem = EventQueue.list[0]; + return { + x: elem.vertex.x, + y: elem.ystar + }; + }, + extractMin: function() { + return EventQueue.list.shift(); + } + }; + EdgeList.init(); + Sites.bottomSite = Sites.list.shift(); + var newSite = Sites.list.shift(), newIntStar; + var lbnd, rbnd, llbnd, rrbnd, bisector; + var bot, top, temp, p, v; + var e, pm; + while (true) { + if (!EventQueue.empty()) { + newIntStar = EventQueue.min(); + } + if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { + lbnd = EdgeList.leftBound(newSite); + rbnd = EdgeList.right(lbnd); + bot = EdgeList.rightRegion(lbnd); + e = Geom.bisect(bot, newSite); + bisector = EdgeList.createHalfEdge(e, "l"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(lbnd, bisector); + if (p) { + EventQueue.del(lbnd); + EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); + } + lbnd = bisector; + bisector = EdgeList.createHalfEdge(e, "r"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(bisector, rbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, newSite)); + } + newSite = Sites.list.shift(); + } else if (!EventQueue.empty()) { + lbnd = EventQueue.extractMin(); + llbnd = EdgeList.left(lbnd); + rbnd = EdgeList.right(lbnd); + rrbnd = EdgeList.right(rbnd); + bot = EdgeList.leftRegion(lbnd); + top = EdgeList.rightRegion(rbnd); + v = lbnd.vertex; + Geom.endPoint(lbnd.edge, lbnd.side, v); + Geom.endPoint(rbnd.edge, rbnd.side, v); + EdgeList.del(lbnd); + EventQueue.del(rbnd); + EdgeList.del(rbnd); + pm = "l"; + if (bot.y > top.y) { + temp = bot; + bot = top; + top = temp; + pm = "r"; + } + e = Geom.bisect(bot, top); + bisector = EdgeList.createHalfEdge(e, pm); + EdgeList.insert(llbnd, bisector); + Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); + p = Geom.intersect(llbnd, bisector); + if (p) { + EventQueue.del(llbnd); + EventQueue.insert(llbnd, p, Geom.distance(p, bot)); + } + p = Geom.intersect(bisector, rrbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, bot)); + } + } else { + break; + } + } + for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { + callback(lbnd.edge); + } + } + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + var x = d3_svg_lineX, y = d3_svg_lineY, compat; + if (compat = arguments.length) { + x = d3_geom_quadtreeCompatX; + y = d3_geom_quadtreeCompatY; + if (compat === 3) { + y2 = y1; + x2 = x1; + y1 = x1 = 0; + } + return quadtree(points); + } + function quadtree(data) { + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; + if (x1 != null) { + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; + } else { + x2_ = y2_ = -(x1_ = y1_ = Infinity); + xs = [], ys = []; + n = data.length; + if (compat) for (i = 0; i < n; ++i) { + d = data[i]; + if (d.x < x1_) x1_ = d.x; + if (d.y < y1_) y1_ = d.y; + if (d.x > x2_) x2_ = d.x; + if (d.y > y2_) y2_ = d.y; + xs.push(d.x); + ys.push(d.y); + } else for (i = 0; i < n; ++i) { + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); + if (x_ < x1_) x1_ = x_; + if (y_ < y1_) y1_ = y_; + if (x_ > x2_) x2_ = x_; + if (y_ > y2_) y2_ = y_; + xs.push(x_); + ys.push(y_); + } + } + var dx = x2_ - x1_, dy = y2_ - y1_; + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; + function insert(n, d, x, y, x1, y1, x2, y2) { + if (isNaN(x) || isNaN(y)) return; + if (n.leaf) { + var nx = n.x, ny = n.y; + if (nx != null) { + if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { + insertChild(n, d, x, y, x1, y1, x2, y2); + } else { + var nPoint = n.point; + n.x = n.y = n.point = null; + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } else { + n.x = x, n.y = y, n.point = d; + } + } else { + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } + function insertChild(n, d, x, y, x1, y1, x2, y2) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = sx; else x2 = sx; + if (bottom) y1 = sy; else y2 = sy; + insert(n, d, x, y, x1, y1, x2, y2); + } + var root = d3_geom_quadtreeNode(); + root.add = function(d) { + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); + }; + i = -1; + if (x1 == null) { + while (++i < n) { + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); + } + --i; + } else data.forEach(root.add); + xs = ys = data = d = null; + return root; + } + quadtree.x = function(_) { + return arguments.length ? (x = _, quadtree) : x; + }; + quadtree.y = function(_) { + return arguments.length ? (y = _, quadtree) : y; + }; + quadtree.extent = function(_) { + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], + y2 = +_[1][1]; + return quadtree; + }; + quadtree.size = function(_) { + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; + return quadtree; + }; + return quadtree; + }; + function d3_geom_quadtreeCompatX(d) { + return d.x; + } + function d3_geom_quadtreeCompatY(d) { + return d.y; + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null, + x: null, + y: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + d3.interpolateRgb = d3_interpolateRgb; + function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + } + d3.interpolateObject = d3_interpolateObject; + function d3_interpolateObject(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + } + d3.interpolateNumber = d3_interpolateNumber; + function d3_interpolateNumber(a, b) { + b -= a = +a; + return function(t) { + return a + b * t; + }; + } + d3.interpolateString = d3_interpolateString; + function d3_interpolateString(a, b) { + var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; + a = a + "", b = b + ""; + d3_interpolate_number.lastIndex = 0; + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({ + i: s.length, + x: m[0] + }); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { + if (o.i) { + if (s[o.i + 1] == null) { + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + if (s.length === 1) { + return s[0] == null ? (o = q[0].x, function(t) { + return o(t) + ""; + }) : function() { + return b; + }; + } + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + d3.interpolate = d3_interpolate; + function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + } + d3.interpolators = [ function(a, b) { + var t = typeof b; + return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); + } ]; + d3.interpolateArray = d3_interpolateArray; + function d3_interpolateArray(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (;i < na; ++i) c[i] = a[i]; + for (;i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + } + var d3_ease_default = function() { + return d3_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); + }; + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_quad(t) { + return t * t; + } + function d3_ease_cubic(t) { + return t * t * t; + } + function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * π / 2); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + d3.interpolateHcl = d3_interpolateHcl; + function d3_interpolateHcl(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + } + d3.interpolateHsl = d3_interpolateHsl; + function d3_interpolateHsl(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; + }; + } + d3.interpolateLab = d3_interpolateLab; + function d3_interpolateLab(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + } + d3.interpolateRound = d3_interpolateRound; + function d3_interpolateRound(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + } + d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + if (string != null) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + } + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; + } + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + var d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolateTransform = d3_interpolateTransform; + function d3_interpolateTransform(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3_interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3_interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3_interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3_interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3_interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3_interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + function d3_uninterpolateNumber(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return (x - a) * b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return Math.max(0, Math.min(1, (x - a) * b)); + }; + } + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + d3.layout.chord = function() { + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (2 * π - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; + function repulse(node) { + return function(quad, x1, _, x2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); + if ((x2 - x1) * dn < theta) { + var k = quad.charge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + return true; + } + if (quad.point && isFinite(dn)) { + var k = quad.pointCharge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = typeof x === "function" ? x : +x; + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = typeof x === "function" ? x : +x; + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = +x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = +x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return theta; + theta = +x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + x = +x; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + distances = []; + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; + strengths = []; + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; + charges = []; + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; + function position(dimension, size) { + var neighbors = neighbor(i), j = -1, m = neighbors.length, x; + while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; + return Math.random() * size; + } + function neighbor() { + if (!neighbors) { + neighbors = []; + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + return neighbors[i]; + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); + if (!arguments.length) return drag; + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + function dragmove(d) { + d.px = d3.event.x, d.py = d3.event.y; + force.resume(); + } + return d3.rebind(force, event, "on"); + }; + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= ~6; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + d.px = d.x, d.py = d.y; + } + function d3_layout_forceMouseout(d) { + d.fixed &= ~4; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; + d3.layout.hierarchy = function() { + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + function recurse(node, depth, nodes) { + var childs = children.call(hierarchy, node, depth); + node.depth = depth; + nodes.push(node); + if (childs && (n = childs.length)) { + var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; + while (++i < n) { + d = recurse(childs[i], j, nodes); + d.parent = node; + c.push(d); + v += d.value; + } + if (sort) c.sort(sort); + if (value) node.value = v; + } else if (value) { + node.value = +value.call(hierarchy, node, depth) || 0; + } + return node; + } + function revalue(node, depth) { + var children = node.children, v = 0; + if (children && (n = children.length)) { + var i = -1, n, j = depth + 1; + while (++i < n) v += revalue(children[i], j); + } else if (value) { + v = +value.call(hierarchy, node, depth) || 0; + } + if (value) node.value = v; + return v; + } + function hierarchy(d) { + var nodes = []; + recurse(d, 0, nodes); + return nodes; + } + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + revalue(root, 0); + return root; + }; + return hierarchy; + }; + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.nodes = object; + object.links = d3_layout_hierarchyLinks; + return object; + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + d3.layout.partition = function() { + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; + function pie(data) { + var values = data.map(function(d, i) { + return +value.call(pie, d, i); + }); + var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); + var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); + var index = d3.range(data.length); + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + var arcs = []; + index.forEach(function(i) { + var d; + arcs[i] = { + data: data[i], + value: d = values[i], + startAngle: a, + endAngle: a += d * k + }; + }); + return arcs; + } + pie.value = function(x) { + if (!arguments.length) return value; + value = x; + return pie; + }; + pie.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return pie; + }; + pie.startAngle = function(x) { + if (!arguments.length) return startAngle; + startAngle = x; + return pie; + }; + pie.endAngle = function(x) { + if (!arguments.length) return endAngle; + endAngle = x; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + function stack(data, index) { + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var n = series.length, m = series[0].length, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (;i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + d3.layout.histogram = function() { + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + d3.layout.tree = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function tree(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + function firstWalk(node, previousSibling) { + var children = node.children, layout = node._tree; + if (children && (n = children.length)) { + var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; + while (++i < n) { + child = children[i]; + firstWalk(child, previousChild); + ancestor = apportion(child, previousChild, ancestor); + previousChild = child; + } + d3_layout_treeShift(node); + var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + layout.mod = layout.prelim - midpoint; + } else { + layout.prelim = midpoint; + } + } else { + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + } + } + } + function secondWalk(node, x) { + node.x = node._tree.prelim + x; + var children = node.children; + if (children && (n = children.length)) { + var i = -1, n; + x += node._tree.mod; + while (++i < n) { + secondWalk(children[i], x); + } + } + } + function apportion(node, previousSibling, ancestor) { + if (previousSibling) { + var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop._tree.ancestor = node; + shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); + sip += shift; + sop += shift; + } + sim += vim._tree.mod; + sip += vip._tree.mod; + som += vom._tree.mod; + sop += vop._tree.mod; + } + if (vim && !d3_layout_treeRight(vop)) { + vop._tree.thread = vim; + vop._tree.mod += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom._tree.thread = vip; + vom._tree.mod += sip - som; + ancestor = node; + } + } + return ancestor; + } + d3_layout_treeVisitAfter(root, function(node, previousSibling) { + node._tree = { + ancestor: node, + prelim: 0, + mod: 0, + change: 0, + shift: 0, + number: previousSibling ? previousSibling._tree.number + 1 : 0 + }; + }); + firstWalk(root); + secondWalk(root, -root._tree.prelim); + var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x *= size[0]; + node.y = node.depth * size[1]; + delete node._tree; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = node.depth / y1 * size[1]; + delete node._tree; + }); + return nodes; + } + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return tree; + }; + tree.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(node) { + var children = node.children; + return children && children.length ? children[0] : node._tree.thread; + } + function d3_layout_treeRight(node) { + var children = node.children, n; + return children && (n = children.length) ? children[n - 1] : node._tree.thread; + } + function d3_layout_treeSearch(node, compare) { + var children = node.children; + if (children && (n = children.length)) { + var child, n, i = -1; + while (++i < n) { + if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { + node = child; + } + } + } + return node; + } + function d3_layout_treeRightmost(a, b) { + return a.x - b.x; + } + function d3_layout_treeLeftmost(a, b) { + return b.x - a.x; + } + function d3_layout_treeDeepest(a, b) { + return a.depth - b.depth; + } + function d3_layout_treeVisitAfter(node, callback) { + function visit(node, previousSibling) { + var children = node.children; + if (children && (n = children.length)) { + var child, previousChild = null, i = -1, n; + while (++i < n) { + child = children[i]; + visit(child, previousChild); + previousChild = child; + } + } + callback(node, previousSibling); + } + visit(node, null); + } + function d3_layout_treeShift(node) { + var shift = 0, change = 0, children = node.children, i = children.length, child; + while (--i >= 0) { + child = children[i]._tree; + child.prelim += shift; + child.mod += shift; + shift += child.shift + (change += child.change); + } + } + function d3_layout_treeMove(ancestor, node, shift) { + ancestor = ancestor._tree; + node = node._tree; + var change = shift / (node.number - ancestor.number); + ancestor.change += change; + node.change -= change; + node.shift += shift; + node.prelim += shift; + node.mod += shift; + } + function d3_layout_treeAncestor(vim, node, ancestor) { + return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; + } + d3.layout.pack = function() { + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { + return radius; + }; + root.x = root.y = 0; + d3_layout_treeVisitAfter(root, function(d) { + d.r = +r(d.value); + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + if (padding) { + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; + d3_layout_treeVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + d3_layout_treeVisitAfter(root, function(d) { + d.r -= dr; + }); + } + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); + return nodes; + } + pack.size = function(_) { + if (!arguments.length) return size; + size = _; + return pack; + }; + pack.radius = function(_) { + if (!arguments.length) return radius; + radius = _ == null || typeof _ === "function" ? _ : +_; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return .999 * dr * dr > dx * dx + dy * dy; + } + function d3_layout_packSiblings(node) { + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + d3.layout.cluster = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; + d3_layout_treeVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x = (node.x - root.x) * size[0]; + node.y = (root.y - node.y) * size[1]; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return cluster; + }; + cluster.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + d3.layout.treemap = function() { + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if (mode !== "squarify" || (score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + if (!arguments.length) return padding; + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], + padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + treemap.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function() { + var random = d3.random.normal.apply(d3, arguments); + return function() { + return Math.exp(random()); + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s / m; + }; + } + }; + d3.scale = {}; + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + return domain; + } + function d3_scale_niceStep(step) { + return step ? { + floor: function(x) { + return Math.floor(x / step) * step; + }, + ceil: function(x) { + return Math.ceil(x / step) * step; + } + } : d3_scale_niceIdentity; + } + var d3_scale_niceIdentity = { + floor: d3_identity, + ceil: d3_identity + }; + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); + }; + function d3_scale_linear(domain, range, interpolate, clamp) { + var output, input; + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3_interpolate); + return scale; + } + function scale(x) { + return output(x); + } + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3_interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + d3_scale_linearNice(domain, m); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(domain, m) { + return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); + } + function d3_scale_linearNiceStep(domain) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; + return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); + } + function d3_scale_linearTickRange(domain, m) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m, format) { + var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); + return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { + return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); + }) : ",." + precision + "f"); + } + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); + }; + function d3_scale_log(linear, base, positive, domain) { + function log(x) { + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); + } + function pow(x) { + return positive ? Math.pow(base, x) : -Math.pow(base, -x); + } + function scale(x) { + return linear(log(x)); + } + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + positive = x[0] >= 0; + linear.domain((domain = x.map(Number)).map(log)); + return scale; + }; + scale.base = function(_) { + if (!arguments.length) return base; + base = +_; + linear.domain(domain.map(log)); + return scale; + }; + scale.nice = function() { + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); + linear.domain(niced); + domain = niced.map(pow); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; + if (isFinite(j - i)) { + if (positive) { + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } else { + ticks.push(pow(i)); + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (!arguments.length) return d3_scale_logFormat; + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); + var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, + Math.floor), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), base, positive, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { + floor: function(x) { + return -Math.ceil(-x); + }, + ceil: function(x) { + return -Math.floor(-x); + } + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); + }; + function d3_scale_pow(linear, exponent, domain) { + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + function scale(x) { + return linear(powp(x)); + } + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + linear.domain((domain = x.map(Number)).map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + return scale.domain(d3_scale_linearNice(domain, m)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + linear.domain(domain.map(powp)); + return scale; + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + function d3_scale_ordinal(domain, ranger) { + var index, range, rangeBand; + function scale(x) { + return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map(); + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); + range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; + range = steps(start + Math.round(error / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + function d3_scale_quantile(domain, range) { + var thresholds; + function rescale() { + var k = 0, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.filter(function(d) { + return !isNaN(d); + }).sort(d3.ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + function d3_scale_quantize(x0, x1, range) { + var kx, i; + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + y = y < 0 ? NaN : y / kx + x0; + return [ y, y + 1 / kx ]; + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + function d3_scale_threshold(domain, range) { + function scale(x) { + if (x <= x) return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return [ domain[y - 1], domain[y] ]; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + d3.svg.arc = function() { + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function arc() { + var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, + a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); + return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; + } + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] + d3_svg_arcOffset; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + function area(data) { + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + function d3_svg_chordRadius(d) { + return d.radius; + } + d3.svg.diagonal = function() { + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + d3.svg.symbol = function() { + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / π); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); + function d3_transition(groups, id) { + d3_subclass(groups, d3_transitionPrototype); + groups.id = id; + return groups; + } + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3_transitionPrototype.empty = d3_selectionPrototype.empty; + d3_transitionPrototype.node = d3_selectionPrototype.node; + d3_transitionPrototype.size = d3_selectionPrototype.size; + d3.transition = function(selection) { + return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var id = this.id, subgroups = [], subgroup, subnode, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, id, node.__transition__[id]); + subgroup.push(subnode); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + transition = node.__transition__[id]; + subnodes = selector.call(node, node.__data__, i, j); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); + subgroup.push(subnode); + } + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.id); + }; + d3_transitionPrototype.tween = function(name, tween) { + var id = this.id; + if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); + return d3_selection_each(this, tween == null ? function(node) { + node.__transition__[id].tween.remove(name); + } : function(node) { + node.__transition__[id].tween.set(name, tween); + }); + }; + function d3_transition_tween(groups, name, value, tween) { + var id = groups.id; + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); + } : (value = tween(value), function(node) { + node.__transition__[id].tween.set(name, value); + })); + } + d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrTween(b) { + return b == null ? attrNull : (b += "", function() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttribute(name, i(t)); + }); + }); + } + function attrTweenNS(b) { + return b == null ? attrNullNS : (b += "", function() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttributeNS(name.space, name.local, i(t)); + }); + }); + } + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + priority = ""; + } + function styleNull() { + this.style.removeProperty(name); + } + function styleString(b) { + return b == null ? styleNull : (b += "", function() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = d3_interpolate(a, b), function(t) { + this.style.setProperty(name, i(t), priority); + }); + }); + } + return d3_transition_tween(this, "style." + name, value, styleString); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + function styleTween(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + } + return this.tween("style." + name, styleTween); + }; + d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); + }; + function d3_transition_text(b) { + if (b == null) b = ""; + return function() { + this.textContent = b; + }; + } + d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.ease = function(value) { + var id = this.id; + if (arguments.length < 1) return this.node().__transition__[id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { + node.__transition__[id].ease = value; + }); + }; + d3_transitionPrototype.delay = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; + } : (value |= 0, function(node) { + node.__transition__[id].delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); + } : (value = Math.max(1, value | 0), function(node) { + node.__transition__[id].duration = value; + })); + }; + d3_transitionPrototype.each = function(type, listener) { + var id = this.id; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node.__transition__[id]; + type.call(node, node.__data__, i, j); + }); + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } else { + d3_selection_each(this, function(node) { + var transition = node.__transition__[id]; + (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); + }); + } + return this; + }; + d3_transitionPrototype.transition = function() { + var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = Object.create(node.__transition__[id0]); + transition.delay += transition.duration; + d3_transitionNode(node, i, id1, transition); + } + subgroup.push(node); + } + } + return d3_transition(subgroups, id1); + }; + function d3_transitionNode(node, i, id, inherit) { + var lock = node.__transition__ || (node.__transition__ = { + active: 0, + count: 0 + }), transition = lock[id]; + if (!transition) { + var time = inherit.time; + transition = lock[id] = { + tween: new d3_Map(), + time: time, + ease: inherit.ease, + delay: inherit.delay, + duration: inherit.duration + }; + ++lock.count; + d3.timer(function(elapsed) { + var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; + if (delay <= elapsed) return start(elapsed); + d3_timer_replace(start, delay, time); + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + transition.event && transition.event.start.call(node, d, i); + transition.tween.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); + } + }); + if (tick(elapsed)) return 1; + d3_timer_replace(tick, 0, time); + } + function tick(elapsed) { + if (lock.active !== id) return stop(); + var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + stop(); + transition.event && transition.event.end.call(node, d, i); + return 1; + } + } + function stop() { + if (--lock.count) delete lock[id]; else delete node.__transition__; + return 1; + } + }, 0, time); + } + } + d3.svg.axis = function() { + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; + function axis(g) { + g.each(function() { + var g = d3.select(this); + var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; + var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); + var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; + var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + d3.transition(path)); + var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; + this.__chart__ = scale1; + tickEnter.append("line"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); + switch (orient) { + case "bottom": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); + lineEnter.attr("y2", tickMajorSize); + textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); + textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); + text.attr("dy", ".71em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); + break; + } + + case "top": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", -tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); + lineEnter.attr("y2", -tickMajorSize); + textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); + textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + text.attr("dy", "0em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); + break; + } + + case "left": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", -tickMinorSize); + subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", -tickMajorSize); + textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); + textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "end"); + pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); + break; + } + + case "right": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", tickMinorSize); + subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", tickMajorSize); + textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); + textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "start"); + pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); + break; + } + } + if (scale.rangeBand) { + var dx = scale1.rangeBand() / 2, x = function(d) { + return scale1(d) + dx; + }; + tickEnter.call(tickTransform, x); + tickUpdate.call(tickTransform, x); + } else { + tickEnter.call(tickTransform, scale0); + tickUpdate.call(tickTransform, scale1); + tickExit.call(tickTransform, scale1); + subtickEnter.call(tickTransform, scale0); + subtickUpdate.call(tickTransform, scale1); + subtickExit.call(tickTransform, scale1); + } + }); + } + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x, y) { + if (!arguments.length) return tickMajorSize; + var n = arguments.length - 1; + tickMajorSize = +x; + tickMinorSize = n > 1 ? +y : tickMajorSize; + tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function(x) { + if (!arguments.length) return tickSubdivide; + tickSubdivide = +x; + return axis; + }; + return axis; + }; + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { + top: 1, + right: 1, + bottom: 1, + left: 1 + }; + function d3_svg_axisX(selection, x) { + selection.attr("transform", function(d) { + return "translate(" + x(d) + ",0)"; + }); + } + function d3_svg_axisY(selection, y) { + selection.attr("transform", function(d) { + return "translate(0," + y(d) + ")"; + }); + } + function d3_svg_axisSubdivide(scale, ticks, m) { + subticks = []; + if (m && ticks.length > 1) { + var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; + while (++i < n) { + for (j = m; --j > 0; ) { + if ((v = +ticks[i] - j * d) >= extent[0]) { + subticks.push(v); + } + } + } + for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { + subticks.push(v); + } + } + return subticks; + } + d3.svg.brush = function() { + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; + function brush(g) { + g.each(function() { + var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; + g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); + tz.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + tz.style("display", brush.empty() ? "none" : null); + tz.exit().remove(); + if (x) { + e = d3_scaleRange(x); + bg.attr("x", e[0]).attr("width", e[1] - e[0]); + redrawX(g); + } + if (y) { + e = d3_scaleRange(y); + bg.attr("y", e[0]).attr("height", e[1] - e[0]); + redrawY(g); + } + redraw(g); + }); + } + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", extent[0][0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); + } + function redrawY(g) { + g.select(".extent").attr("y", extent[0][1]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); + } + function brushstart() { + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = mouse(), offset; + var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (d3.event.changedTouches) { + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); + } else { + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); + } + if (dragging) { + origin[0] = extent[0][0] - origin[0]; + origin[1] = extent[0][1] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; + origin[0] = extent[ex][0]; + origin[1] = extent[ey][1]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + function mouse() { + var touches = d3.event.changedTouches; + return touches ? d3.touches(target, touches)[0] : d3.mouse(target); + } + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= extent[1][0]; + origin[1] -= extent[1][1]; + dragging = 2; + } + d3_eventPreventDefault(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += extent[1][0]; + origin[1] += extent[1][1]; + dragging = 0; + d3_eventPreventDefault(); + } + } + function brushmove() { + var point = mouse(), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; + origin[0] = extent[+(point[0] < center[0])][0]; + origin[1] = extent[+(point[1] < center[1])][1]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0][i] !== min || extent[1][i] !== max) { + extentDomain = null; + extent[0][i] = min; + extent[1][i] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + dragRestore(); + event_({ + type: "brushend" + }); + } + } + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.clamp = function(z) { + if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; + if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + z = extentDomain || extent; + if (x) { + x0 = z[0][0], x1 = z[1][0]; + if (!extentDomain) { + x0 = extent[0][0], x1 = extent[1][0]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + y0 = z[0][1], y1 = z[1][1]; + if (!extentDomain) { + y0 = extent[0][1], y1 = extent[1][1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + extentDomain[0][0] = x0, extentDomain[1][0] = x1; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + extentDomain[0][1] = y0, extentDomain[1][1] = y1; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; + } + return brush; + }; + brush.clear = function() { + extentDomain = null; + extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; + return brush; + }; + brush.empty = function() { + return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + d3.time = {}; + var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + function d3_time_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + d3_time_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; + var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_time(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_time(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_time = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = date; + return method(utc, k)._; + } finally { + d3_time = Date; + } + }; + } + d3.time.year = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3.time.years = d3.time.year.range; + d3.time.years.utc = d3.time.year.utc.range; + d3.time.day = d3_time_interval(function(date) { + var day = new d3_time(2e3, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3.time.days = d3.time.day.range; + d3.time.days.utc = d3.time.day.utc.range; + d3.time.dayOfYear = function(date) { + var year = d3.time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + d3_time_daySymbols.forEach(function(day, i) { + day = day.toLowerCase(); + i = 7 - i; + var interval = d3.time[day] = d3_time_interval(function(date) { + (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3.time[day + "s"] = interval.range; + d3.time[day + "s"].utc = interval.utc.range; + d3.time[day + "OfYear"] = function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3.time.week = d3.time.sunday; + d3.time.weeks = d3.time.sunday.range; + d3.time.weeks.utc = d3.time.sunday.utc.range; + d3.time.weekOfYear = d3.time.sundayOfYear; + d3.time.format = function(template) { + var n = template.length; + function format(date) { + var string = [], i = -1, j = 0, c, p, f; + while (++i < n) { + if (template.charCodeAt(i) === 37) { + string.push(template.substring(j, i)); + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); + string.push(c); + j = i + 1; + } + } + string.push(template.substring(j, i)); + return string.join(""); + } + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0 + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var date = new d3_time(); + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + date.setFullYear(d.y, 0, 1); + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); + } else date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H, d.M, d.S, d.L); + return date; + }; + format.toString = function() { + return template; + }; + return format; + }; + function d3_time_parse(date, template, string, j) { + var c, p, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c === 37) { + p = d3_time_parsers[template.charAt(i++)]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map(), i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_formatPad(value, fill, width) { + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); + } + var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; + var d3_time_formatPads = { + "-": "", + _: " ", + "0": "0" + }; + var d3_time_formats = { + a: function(d) { + return d3_time_dayAbbreviations[d.getDay()]; + }, + A: function(d) { + return d3_time_days[d.getDay()]; + }, + b: function(d) { + return d3_time_monthAbbreviations[d.getMonth()]; + }, + B: function(d) { + return d3_time_months[d.getMonth()]; + }, + c: d3.time.format(d3_time_formatDateTime), + d: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + e: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + H: function(d, p) { + return d3_time_formatPad(d.getHours(), p, 2); + }, + I: function(d, p) { + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); + }, + j: function(d, p) { + return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); + }, + L: function(d, p) { + return d3_time_formatPad(d.getMilliseconds(), p, 3); + }, + m: function(d, p) { + return d3_time_formatPad(d.getMonth() + 1, p, 2); + }, + M: function(d, p) { + return d3_time_formatPad(d.getMinutes(), p, 2); + }, + p: function(d) { + return d.getHours() >= 12 ? "PM" : "AM"; + }, + S: function(d, p) { + return d3_time_formatPad(d.getSeconds(), p, 2); + }, + U: function(d, p) { + return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d, p) { + return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); + }, + x: d3.time.format(d3_time_formatDate), + X: d3.time.format(d3_time_formatTime), + y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 100, p, 2); + }, + Y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); + }, + Z: d3_time_zone, + "%": function() { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + j: d3_time_parseDayOfYear, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + U: d3_time_parseWeekNumberSunday, + w: d3_time_parseWeekdayNumber, + W: d3_time_parseWeekNumberMonday, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear, + "%": d3_time_parseLiteralPercent + }; + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekdayNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 1)); + return n ? (date.w = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberSunday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.U = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberMonday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.W = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 4)); + return n ? (date.y = +n[0], i + n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.d = +n[0], i + n[0].length) : -1; + } + function d3_time_parseDayOfYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.j = +n[0], i + n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.H = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.M = +n[0], i + n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.S = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.L = +n[0], i + n[0].length) : -1; + } + var d3_time_numberRe = /^\s*\d+/; + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + var d3_time_amPmLookup = d3.map({ + am: 0, + pm: 1 + }); + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); + } + function d3_time_parseLiteralPercent(date, string, i) { + d3_time_percentRe.lastIndex = 0; + var n = d3_time_percentRe.exec(string.substring(i, i + 1)); + return n ? i + n[0].length : -1; + } + d3.time.format.utc = function(template) { + var local = d3.time.format(template); + function format(date) { + try { + d3_time = d3_time_utc; + var utc = new d3_time(); + utc._ = date; + return local(utc); + } finally { + d3_time = Date; + } + } + format.parse = function(string) { + try { + d3_time = d3_time_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_time = Date; + } + }; + format.toString = local.toString; + return format; + }; + var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3.time.second = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3.time.seconds = d3.time.second.range; + d3.time.seconds.utc = d3.time.second.utc.range; + d3.time.minute = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3.time.minutes = d3.time.minute.range; + d3.time.minutes.utc = d3.time.minute.utc.range; + d3.time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3.time.hours = d3.time.hour.range; + d3.time.hours.utc = d3.time.hour.utc.range; + d3.time.month = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3.time.months = d3.time.month.range; + d3.time.months.utc = d3.time.month.utc.range; + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + scale.nice = function(m) { + return scale.domain(d3_scale_nice(scale.domain(), m)); + }; + scale.ticks = function(m, k) { + var extent = d3_scaleExtent(scale.domain()); + if (typeof m !== "function") { + var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); + if (i == d3_time_scaleSteps.length) return methods.year(extent, m); + if (!i) return linear.ticks(m).map(d3_time_scaleDate); + if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; + m = methods[i]; + k = m[1]; + m = m[0].range; + } + return m(extent[0], new Date(+extent[1] + 1), k); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_time_scaleDate(t) { + return new Date(t); + } + function d3_time_scaleFormat(formats) { + return function(date) { + var i = formats.length - 1, f = formats[i]; + while (!f[1](date)) f = formats[--i]; + return f[0](date); + }; + } + function d3_time_scaleSetYear(y) { + var d = new Date(y, 0, 1); + d.setFullYear(y); + return d; + } + function d3_time_scaleGetYear(d) { + var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; + var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { + return d.getMonth(); + } ], [ d3.time.format("%b %d"), function(d) { + return d.getDate() != 1; + } ], [ d3.time.format("%a %d"), function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ d3.time.format("%I %p"), function(d) { + return d.getHours(); + } ], [ d3.time.format("%I:%M"), function(d) { + return d.getMinutes(); + } ], [ d3.time.format(":%S"), function(d) { + return d.getSeconds(); + } ], [ d3.time.format(".%L"), function(d) { + return d.getMilliseconds(); + } ] ]; + var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); + d3_time_scaleLocalMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); + }; + d3.time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { + return d.getUTCMonth(); + } ], [ d3.time.format.utc("%b %d"), function(d) { + return d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%a %d"), function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%I %p"), function(d) { + return d.getUTCHours(); + } ], [ d3.time.format.utc("%I:%M"), function(d) { + return d.getUTCMinutes(); + } ], [ d3.time.format.utc(":%S"), function(d) { + return d.getUTCSeconds(); + } ], [ d3.time.format.utc(".%L"), function(d) { + return d.getUTCMilliseconds(); + } ] ]; + var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); + function d3_time_scaleUTCSetYear(y) { + var d = new Date(Date.UTC(y, 0, 1)); + d.setUTCFullYear(y); + return d; + } + function d3_time_scaleUTCGetYear(d) { + var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + d3_time_scaleUTCMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); + }; + d3.time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + }; + d3.text = d3_xhrType(function(request) { + return request.responseText; + }); + d3.json = function(url, callback) { + return d3_xhr(url, "application/json", d3_json, callback); + }; + function d3_json(request) { + return JSON.parse(request.responseText); + } + d3.html = function(url, callback) { + return d3_xhr(url, "text/html", d3_html, callback); + }; + function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); + } + d3.xml = d3_xhrType(function(request) { + return request.responseXML; + }); + return d3; +}(); +},{}],29:[function(require,module,exports){ +require("./d3"); +module.exports = d3; +(function () { delete this.d3; })(); // unset global + +},{"./d3":28}],30:[function(require,module,exports){ +var ich = require('icanhaz') + +module.exports.ich = ich + +module.exports.getKeywordCount = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group.length + if (group = []) return "0" +} + +module.exports.getKeyword = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group + if (group = []) return "no matches" +} + +module.exports.getColumnTotal = function(data, column) { + var total = [] + data.forEach(function (d) { + if (d[column] === "") return + total.push(+d[column]) + }) + return total.reduce(function(a,b) { + return a + b + }) +} + +module.exports.getColumnAverage = function(data, column) { + var total = getColumnTotal(data, column) + var average = total / data.length + return average +} + +module.exports.getMax = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() > result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +module.exports.getMin = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() < result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +// out of the data, filter something from a category +module.exports.getMatches = function (data, filter, category) { + var matches = [] + data.forEach(function (element) { + var projectType = element[category].toString().toLowerCase() + if (projectType === filter.toLowerCase()) matches.push(element) + }) + return matches +} + +module.exports.mostFrequent = function(data, category) { + var count = {} + for (var i = 0; i < data.length; i++) { + if (!count[data[i][category]]) { + count[data[i][category]] = 0 + } + count[data[i][category]]++ + } + var sortable = [] + for (var category in count) { + sortable.push([category, count[category]]) + } + sortable.sort(function(a, b) {return b[1] - a[1]}) + return sortable + // returns array of arrays, in order +} + +// thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ +module.exports.deepCopy = function(obj) { + if (Object.prototype.toString.call(obj) === '[object Array]') { + var out = [], i = 0, len = obj.length; + for ( ; i < len; i++ ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + if (typeof obj === 'object') { + var out = {}, i; + for ( i in obj ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + return obj; +} + +module.exports.getOccurance = function(data, category) { + var occuranceCount = {} + for (var i = 0; i < data.length; i++) { + if (!occuranceCount[data[i][category]]) { + occuranceCount[data[i][category]] = 0 + } + occuranceCount[data[i][category]]++ + } + return occuranceCount + // returns object, keys alphabetical +} + +module.exports.makeColorArrayOfObject = function(data, colors, category) { + var category = category + var keys = Object.keys(data) + var counter = 1 + var colorIndex + return keys.map(function(key){ + if (keys.length > colors.length || keys.length <= colors.length ) { + colorIndex = counter % colors.length + } + var h = {units: data[key], hexcolor: colors[colorIndex]} + h[category] = key + counter++ + colorIndex = counter + return h + }) +} + +module.exports.makeArrayOfObject = function(data) { + var keys = Object.keys(data) + return keys.map(function(key){ + // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} + var h = {label: key, units: data[key]} + return h + }) +} + +},{"icanhaz":31}],31:[function(require,module,exports){ +/*! +ICanHaz.js version 0.10.2 -- by @HenrikJoreteg +More info at: http://icanhazjs.com +*/ +(function () { +/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = window.Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.4.0", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +/*! + ICanHaz.js -- by @HenrikJoreteg +*/ +/*global */ +(function () { + function trim(stuff) { + if (''.trim) return stuff.trim(); + else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + var ich = { + VERSION: "0.10.2", + templates: {}, + + // grab jquery or zepto if it's there + $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, + + // public function for adding templates + // can take a name and template string arguments + // or can take an object with name/template pairs + // We're enforcing uniqueness to avoid accidental template overwrites. + // If you want a different template, it should have a different name. + addTemplate: function (name, templateString) { + if (typeof name === 'object') { + for (var template in name) { + this.addTemplate(template, name[template]); + } + return; + } + if (ich[name]) { + console.error("Invalid name: " + name + "."); + } else if (ich.templates[name]) { + console.error("Template \"" + name + " \" exists"); + } else { + ich.templates[name] = templateString; + ich[name] = function (data, raw) { + data = data || {}; + var result = Mustache.to_html(ich.templates[name], data, ich.templates); + return (ich.$ && !raw) ? ich.$(trim(result)) : result; + }; + } + }, + + // clears all retrieval functions and empties cache + clearAll: function () { + for (var key in ich.templates) { + delete ich[key]; + } + ich.templates = {}; + }, + + // clears/grabs + refresh: function () { + ich.clearAll(); + ich.grabTemplates(); + }, + + // grabs templates from the DOM and caches them. + // Loop through and add templates. + // Whitespace at beginning and end of all templates inside - - - - - - - - - - - - - - -
      -

      sheetsee

      -

      Sheetsee.js

      -

      Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page.

      -

      Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with.

      -

      To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see JavaScript for Cats, Eloquent JavaScript or Mozilla's Developer Network.

      - -

      Dependencies

      -

      Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, Tabletop.js gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with IChanHas.js (built on mustache.js), maps with Mapbox.js, and charts with d3.js. And jQuery of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below.

      - -

      CSS

      -

      Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design.

      - -

      Client-side or Server-side

      -

      Sheetsee.js comes in two flavors, client-side (this repo) and server-side (sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal.

      -

      The server-side version is built with Node.js and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah!

      - -
      -

      The Short & Sweet

      -
        -
      1. Link to Sheetsee.js and dependencies in your HTML header.
      2. -
      3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
      4. -
      5. Create templates for tables in <script> tags.
      6. -
      7. Create a script tag that waits for the document to load and then executes any of the map, chart or tables you've specified in it.
      8. -
      9. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information everytime they load the page.
      10. -
      -
      - -

      Bare Minimum Setup

      -

      Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

      -
      <html>
      -    <head>
      -        <script type="text/javascript" src="http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.js"></script>
      -        <script type="text/javascript" src="js/ICanHaz.js"></script>
      -        <script type="text/javascript" src="js/jquery.js"></script>
      -        <script type="text/javascript" src="js/tabletop.js"></script>
      -        <script type="text/javascript" src="js/d3.js"></script>
      -        <script type="text/javascript" src="js/sheetsee.js"></script>
      -        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.css' rel='stylesheet' />
      -    </head>
      -    <style> #map {height: 600px; width: 600px;} </style>
      -    <body>
      -    <div id="map"></div>
      -    <script type="text/javascript">
      -      document.addEventListener('DOMContentLoaded', function() {
      -        var gData
      -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
      -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
      -      })
      -      function showInfo(data) {
      -        gData = data
      -        optionsJSON = ["something", "something"]
      -        var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
      -        var map = Sheetsee.loadMap("map")
      -        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
      -        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
      -        // customize the popup content
      -        addPopups(map, markerLayer)
      -        function addPopups(map, markerLayer) {
      -          markerLayer.on('click', function(e) {
      -            var feature = e.layer.feature
      -            var popupContent = '<h3>' + feature.opts.something + '</h3>'
      -            e.layer.bindPopup(popupContent,{closeButton: false})
      -          })
      -        }
      -      }
      -    </script>
      -    </body>
      -</html>
      - -

      Awesome Possibilities

      -
        -
      1. Small newsrooms with data for stories but small dev teams.
      2. -
      3. Friends or groups collaborating on data for a website/project.
      4. -
      5. Using iftt.com to auto populate spreadsheets which are hooked to a website with Sheetsee.js.
      6. -
      - -

      Examples

      -
        -
      1. Hack Spots
      2. -
      3. James Sconfitto make a map of his relationship with his wife <3
      4. -
      - -

      Getting Started

      -

      This bit is the same for both client-side and server-side versions.

      -

      Your Data

      -

      sheetsee

      -

      Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

      -

      sheetsee

      -

      There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

      -
      [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
      - -

      Hexcolor

      -

      sheetsee

      -

      You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

      - -

      Geocoding

      -

      If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin - that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

      - sheetsee -

      Publishing Your Spreadsheet

      -

      sheetsee

      -

      You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

      -

      sheetsee

      -

      You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet.

      -

      Your Website

      -

      Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet.

      -

      For now, create empty div placeholders for the map, chart and tables you plan on including.

      -

      Hooking Up Your Data

      -

      Here the paths diverge:

      -

      Client-side Hookup

      -

      For client-siders, all you need to do is include the depences and sheetsee in your HTML <head> and then in a script tag at the bottom of your page, right before the </body> tag, you'll include this:

      -
      <script type="text/javascript">
      -    document.addEventListener('DOMContentLoaded', function() {
      -        var gData
      -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
      -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
      -    })
      -    function showInfo(data) {
      -        gData = data
      -        //
      -        //everything you do with sheetsee goes here
      -        //
      -    }
      -</script>
      -

      The URL variable is the key from your spreadsheet's longer URL, explained above. Tabletop.init() takes that URL and execute's Tabletop, when it's done generating the table it executes the callback showInfo function. It's inside of this function that you'll then use your spreadsheet data, gData, to do all the Sheetsee.js goodness with.

      -

      Server-side Hookup

      -

      The server-side version is in the repo sheetsee-cache. It uses Node.js to go to Google, get the spreadsheet data (with a Node.js version of Tabletop.js, thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data.

      -

      When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled.

      -
      <script type="text/javascript">
      -    document.addEventListener('DOMContentLoaded', function() {
      -        // table/templating things the rest can be in their own script tags if you'd like
      -    })
      -</script>
      -

      Running Locally

      -

      You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay!

      -

      Once you clone the repo, navigate there in Terminal, install the node modules and launch the server.

      -
      cd sheetsee-cache
      -npm install
      -node server.js
      -

      This will launch a local server you can visit and develop locally with in your browser.

      -

      Working With Your Data

      -

      Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

      -

      Play Along!

      -

      This page is using sheetsee. If you (are in Chrome and) right click on the page and select Inspect Element it will bring up the Web Inspector. Select the Console tab. Now you can interact with the data and functions from Sheetsee. Give the functions below a try - gData is the variable with the data (from this spreadsheet). - sheetsee -

      Sheetsee.getKeyword(data, keyword)

      -

      This takes in your data, an array of objects, and searches for a string, keyword, in each piece of your data (formerly the cells of your spreadsheet). It returns an array of each row that contained a keyword match. Similarly, using `getKeywordCount(data, keyword)` will return just the number of times the keyword occured.

      -
      getKeyword(gData, "cat")
      -// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}]
      -

      Sheetsee.getColumnTotal(data, column)

      -

      Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

      -
      getColumnTotal(gData, "cuddlability")
      -// returns 11
      -

      Sheetsee.getAveragefromColumn(data, column)

      -

      A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

      -
      getColumnAverage(gData, "cuddlability")
      -// returns 1.8333333333333333
      -

      Sheetsee.getMin(data, column)

      -

      This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

      -
      getMin(gData, "cuddlability")
      -// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}]
      - -

      Sheetsee.getMax(data, column)

      -

      This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

      -
      getMax(gData, "cuddlability")
      -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
      - -
      - - -

      Don't Forget JavaScript Math

      -

      Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

      -
      var profit09 = Sheetsee.getColumnTotal(gData, "2009")
      -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
      -var difference = profit09 - profit10
      -

      What These Little Bits are Good For

      -

      You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

      - -

      Sheetsee.getMatches(data, filter, category)

      -

      Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

      -
      getMatches(gData, "dog", "kind")
      -

      Returns an array of objects matching the category's filter.

      -
      [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
      - -

      Sheetsee.getOccurance(data, category)

      -

      Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

      -
      getOccurance(gData, "kind")
      -

      Returns an object with keys and values for each variation of the category and its occurance.

      -
      {"dog": 3, "cat": 3}
      - -

      Sheetsee.makeColorArrayOfObject(data, colors)

      -

      If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

      -

      This function takes in your data, as an object, an array of hexidecimal color strings which you define and the category you used in getOccurance().

      -
      var kinds = getOccurance(gData, "kind")
      -var kindColors = ["#ff00ff", "#DCF13C"]
      -var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors, "kind")
      -

      It will return an array of objects with units as the title of the occurance amount like so:

      -
      [{"kind": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"kind": "cat", "units": 3, "hexcolor": "#DCF13C"}]
      -

      If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

      - -

      Make a Map

      -
      -

      Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps.

      -

      Create an empty <div> in your HTML, with an id.

      -
      <div id="map"></div>
      -

      Next you'll need to create geoJSON out of your data so that it can be mapped.

      - -

      Sheetsee.createGeoJSON(data, optionsJSON)

      -

      This takes in your data and the parts of your data, optionsJSON, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data.

      -
      var optionsJSON = ["name", "breed", "cuddlability"]
      -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
      -

      It will return an array in the special geoJSON format that map making things love.

      -
      [{
      -  "geometry": {"type": "Point", "coordinates": [long, lat]},
      -  "properties": {
      -    "marker-size": "small",
      -    "marker-color": lineItem.hexcolor
      -  },
      -  "opts": {the options you pass in},
      -}}
      - -

      Sheetsee.loadMap(mapDiv)

      -

      To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

      -
      var map = Sheetsee.loadMap("map")
      - -

      Sheetsee.addTileLayer(map, tileLayer)

      -

      To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

      -
      Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
      -

      You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

      - -

      Sheetsee.addMarkerLayer(geoJSON, map)

      -

      To add makers to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there.

      -
      var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
      - -

      Sheetsee.addPopups(map, markerLayer)

      -

      To customize the marker popup content in your map use this function and pass in your map and markerLayer.

      -
       Sheetsee.addPopups(map, markerLayer)
      -

      To customize the marker popup content in your map you'll need to use this entire function on your website.

      -
      function addPopups(map, markerLayer) {
      -  markerLayer.on('click', function(e) {
      -    var feature = e.layer.feature
      -    var popupContent = '<h2>' + feature.opts.name + '</h2>' +
      -                        '<h3>' + feature.opts.breed + '</h3>'
      -    e.layer.bindPopup(popupContent,{closeButton: false,})
      -  })
      -}
      -

      You will edit the popupContent variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use feature.opts and then one of the column headers you passed into createGeoJSON().

      - -

      Make a Table

      - -
      -

      Example - Local Pet Friends

      - - Clear - no matches -
      -
      - - -

      Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for searches and table headers can be used to sort the data in that column. For each of these you'll need a <div> in your html, a <script> template and a <script> that calls table functions.

      -

      Your HTML Placeholder <div>

      -

      This is as simple as an empty <div> with an id. This id should match the script tempate id in the next section.

      -
       <div id="siteTable"></div>
      -

      Your <script> Template

      -

      Your template is the mockup of what you'd like your table to look like and what content it should show. Most of this is up to you but if you want users to be able to click on headers and sort that column you must make a table row with table headers with the class tHeader.

      -

      The variables inside the {{}} must match the column headers in your spreadsheet. Lowercase (?) and remember spaces are ommited, so "Place Name" will become "placename".

      -
      <script id="siteTable" type="text/html">
      -    <table>
      -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
      -      {{#rows}}
      -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
      -      {{/rows}}
      -  </table>
      -</script>
      -

      Your <script> Execution

      -
      <script type="text/javascript">
      -    document.addEventListener('DOMContentLoaded', function() {
      -        Sheetsee.makeTable(gData, "#siteTable")
      -        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
      -    })
      -</script>
      -

      To create another table, simply repeat the steps with the corresponding data and divs.

      -
      <div id="secondTable"></div>
      -<script id="secondTable"> // your table template here </script>
      -<script>
      -  Sheetsee.makeTable(otherData, "#secondTable")
      -  Sheetsee.initiateTableFilter(otherData, "#secondFilter", "#secondTable")
      -</script>
      -
      -

      Learn more about the things you can do with mustache.js.

      - -

      Sheetsee.makeTable(data, targetDiv)

      -

      You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id).

      -
      Sheetsee.makeTable(gData, "#siteTable")
      - -

      Table Filter/Search

      -

      If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html:

      -
      <input id="tableFilter" type="text" placeholder="filter by.."></input>
      -<span class="clear button">Clear</span>
      -<span class="noMatches">no matches</span>
      - -

      Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

      -

      You will then call this function to make that input live:

      -
      Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
      - -

      Make a Chart

      -

      Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting.

      -

      You'll have to experiement with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

      -

      You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee.

      - -

      Bar Chart

      - -
      -
      -
      - -

      To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

      -
      <div id="barChart"></div>
      -

      In your CSS, give it dimensions.

      -
      #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
      -

      In a <script> tag set up your options.

      -
      var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
      -
        -
      • labels is a string, usually a column header, it's what you call what you're charting
      • -
      • units is a string, usually a column header, it's the value you're charting
      • -
      • m is margins: top, right, bottom, left
      • -
      • w and h are width and height, this should match your CSS specs
      • -
      • div is the id for the <div> in your HTML
      • -
      • xaxis is optional text label for your x axis
      • -
      • hiColor is the highlight color of your choosing!
      • -
      -

      Then call the d3BarChart() function with your data and options.

      -
      Sheetsee.d3BarChart(data, barOptions)
      - -

      Line Chart

      - -
      -
      -
      - -

      To create a line chart you'll need to add a placeholder <div> in your html with an id.

      -
      <div id="lineChart"></div>
      -

      In your CSS, give it dimensions.

      -
      #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
      -

      In a <script> tag set up your options.

      -
      var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
      -
        -
      • labels is a string, usually a column header, it's what you call what you're charting
      • -
      • units is a string, usually a column header, it's the value you're charting
      • -
      • m is your margins: top, right, bottom, left
      • -
      • w and h are width and height, this should match your CSS specs
      • -
      • div is the id for the <div> in your HTML
      • -
      • yaxis is optional text label for your y axis
      • -
      • hiColor is the highlight color of your choosing!
      • -
      -

      Then call the d3LineChart() function with your data and options.

      -
      Sheetsee.d3LineChart(data, lineOptions)
      - -

      Pie Chart

      - -
      -
      -
      - -

      To create a bar chart you'll need to add a placeholder <div> in your html with an id.

      -
      <div id="pieChart"></div>
      -

      In your CSS, give it dimensions.

      -
      #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
      -

      In a <script> tag set up your options. You must include labels and units, this tells it what you're charting. Because for the pie chart we're using data we got from getOccurance() and makeColorArrayofObject(), our units are already called units. If we were using original data, we might have units as "cuddleability" or something else.

      -
      var pieOptions = {labels: "kind", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
      -
        -
      • labels is a string, usually a column header, it's what you call what you're charting
      • -
      • units is a string, usually a column header, it's the value you're charting
      • -
      • m is your margins: top, right, bottom, left
      • -
      • w and h are width and height, this should match your CSS specs
      • -
      • div is the id for the <div> in your HTML
      • -
      • hiColor is the highlight color of your choosing!
      • -
      -

      Then call the d3PieChart() function with your data and options.

      -
      Sheetsee.d3PieChart(data, pieOptions)
      - -

      Don't forget, right click this page, select View Source and scroll to the bottom and see exactly how these charts were set up!

      - - -

      Big Time Thanks

      -

      Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georga.

      -

      Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

      -

      Thanks to Max Ogden for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making Tabletop.js for Node.js.

      -

      Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

      -

      Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

      - -

      Licensed under BSD. East Bay represent!

      - - - - - - - - - diff --git a/demos/template.html b/demos/template.html index 0a6f5266..ab937bf5 100644 --- a/demos/template.html +++ b/demos/template.html @@ -3,6 +3,7 @@ Yo, yo, yo! + diff --git a/docs/custom-charts.md b/docs/custom-charts.md index 22c4cc8f..c6fc93d9 100644 --- a/docs/custom-charts.md +++ b/docs/custom-charts.md @@ -1,6 +1,6 @@ # Custom Charts -It's easy to take a d3 chart of your own and use it with Sheetsee. If you make it into a module, anyone can use your chart, too! +It's easy to take a d3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too! Sheetsee charts currently work by taking in some options, like so: @@ -8,10 +8,14 @@ Sheetsee charts currently work by taking in some options, like so: var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"} ``` -The _labels_ represent the, the actual thing you're charting and _units_ are how many of those things. Margin, width and height are _m, w, h_ and the div to build your chart in is _div_. Finally, you can supply a highlight color if you want. +The _labels_ represent the actual thing you're charting and _units_ are how many of those things. Margin, width and height are _m, w, h_ and the div to build your chart in is _div_. Finally, you can supply a highlight color if you want. -So, your chart could take the same options, but map them into your d3 code with the correct variables. For instance if what sheetsee calls _labels_ you call _itemID_ you just add at the top of your code: +So, your chart could take the same options, but map them into your d3 code with the correct variables. For instance if what sheetsee calls _labels_ you call _itemID_ you just add at the top of your d3 code: ```javascript labels = itemID ``` + +Include your d3.js code with the HTML and call it. + +WIP diff --git a/docs/sheetsee-charts.md b/docs/sheetsee-charts.md index 7db5ee3a..6c0f948b 100644 --- a/docs/sheetsee-charts.md +++ b/docs/sheetsee-charts.md @@ -1,6 +1,8 @@ # Sheetsee-charts -Sheetsee provides three d3 chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. See a [demo](demos/demo-chart.html). You can also plug in your own custom d3 chart to sheetsee, read about that [here](custom-charts.md). +_[View Demo](/demos/demo-chart.html)_ + +Sheetsee.js provides three [d3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. You can also plug in your own custom d3.js chart to sheetsee, read about that [here](custom-charts.md). ## Make a Chart diff --git a/docs/sheetsee-maps.md b/docs/sheetsee-maps.md index fef66c68..3b7ea844 100644 --- a/docs/sheetsee-maps.md +++ b/docs/sheetsee-maps.md @@ -1,6 +1,8 @@ # Sheetsee-maps -Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [Leaflet.js](http://leafletjs.com/) plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based). See a map [demo](/demos/demo-map.html). +_[View Demo](/demos/demo-map.html)_ + +Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [Leaflet.js](http://leafletjs.com/) plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based). You'll create a placeholder `
      ` in your HTML, CSS giving it a size and fire up a map from within ` + diff --git a/site/docs/about.html b/site/docs/about.html index fc8e0d5d..5bd60df5 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -56,7 +56,7 @@

      Ideas

      Demos

        @@ -67,16 +67,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/basics.html b/site/docs/basics.html index e48c6283..341ea9cb 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -84,7 +84,7 @@

      Ideas

      Demos

        @@ -95,16 +95,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/building.html b/site/docs/building.html index 7aeab7ca..f92da27c 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -48,7 +48,7 @@

      Ideas

      Demos

        @@ -59,16 +59,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 57f972a9..b9bc1781 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -42,7 +42,7 @@

      Ideas

      Demos

        @@ -53,16 +53,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 0a084450..2716b75f 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -13,14 +13,16 @@

      Custom Charts

      -

      It's easy to take a d3 chart of your own and use it with Sheetsee. If you make it into a module, anyone can use your chart, too!

      +

      It's easy to take a d3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

      Sheetsee charts currently work by taking in some options, like so:

      var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
       
      -

      The labels represent the, the actual thing you're charting and units are how many of those things. Margin, width and height are m, w, h and the div to build your chart in is div. Finally, you can supply a highlight color if you want.

      -

      So, your chart could take the same options, but map them into your d3 code with the correct variables. For instance if what sheetsee calls labels you call itemID you just add at the top of your code:

      +

      The labels represent the actual thing you're charting and units are how many of those things. Margin, width and height are m, w, h and the div to build your chart in is div. Finally, you can supply a highlight color if you want.

      +

      So, your chart could take the same options, but map them into your d3 code with the correct variables. For instance if what sheetsee calls labels you call itemID you just add at the top of your d3 code:

      labels = itemID
       
      +

      Include your d3.js code with the HTML and call it.

      +

      WIP

      diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index abe63661..4f4aa7fd 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -35,7 +35,7 @@

      Ideas

      Demos

        @@ -46,16 +46,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index c2342a82..aa71c930 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -13,7 +13,8 @@

      Sheetsee-charts

      -

      Sheetsee provides three d3 chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. See a demo. You can also plug in your own custom d3 chart to sheetsee, read about that here.

      +

      View Demo

      +

      Sheetsee.js provides three d3.js chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. You can also plug in your own custom d3.js chart to sheetsee, read about that here.

      Make a Chart

      Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, with objects containing "label" and "units" key/value pairs. See the section above on Your Data to learn about formatting.

      Experiment with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

      @@ -93,7 +94,7 @@

      Ideas

      Demos

        @@ -104,16 +105,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 9037939c..bca50952 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -97,7 +97,7 @@

      Ideas

      Demos

        @@ -108,16 +108,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 25677f0d..5c639c5f 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -13,7 +13,8 @@

      Sheetsee-maps

      -

      Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based). See a map demo.

      +

      View Demo

      +

      Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based).

      You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags.

      Your HTML Placeholder <div>

      Create an empty <div> in your HTML, with an id (name). Add CSS to give it dimensions

      @@ -67,7 +68,7 @@

      Ideas

      Demos

        @@ -78,16 +79,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 89211bea..23cd100f 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -13,7 +13,8 @@

      Sheetsee-tables

      -

      With this module you can create tables of your data that are sortable, searchable and paginate-able. See the demo.

      +

      View Demo

      +

      With this module you can create tables of your data that are sortable, searchable and paginate-able.

      You'll need a placeholder <div> in your html, a <script> mustache template and a <script> that initiates the table.

      Your HTML Placeholder <div>

      This is as simple as an empty <div> with an id. This id should match the script template id in the next section.

      @@ -62,7 +63,7 @@

      Pagination

      CSS:

      <style>
      -  body {font-family: Helvetica Neue; }
      +  body {font-family: Helvetica Neue; Helvetica, Arial, sans-serif; }
         #Pagination {background: #eee;}
         .pagination-next, .pagination-pre {cursor: hand;}
         .no-pag {color: #acacac;}
      @@ -92,7 +93,7 @@ 

      Ideas

      Demos

        @@ -103,16 +104,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/docs/tips.html b/site/docs/tips.html index ec60406f..373dfdea 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -42,7 +42,7 @@

      Ideas

      Demos

        @@ -53,16 +53,17 @@

        Demos

      Use

      Contact

      +

      Home Page

      diff --git a/site/index.html b/site/index.html index 1e82ef37..06c580f8 100644 --- a/site/index.html +++ b/site/index.html @@ -117,6 +117,7 @@

      Contact

    • @jllord
    • File an issue
    +

    Home Page

    diff --git a/template.hbs b/template.hbs index 39de2e9c..44780f06 100644 --- a/template.hbs +++ b/template.hbs @@ -45,6 +45,7 @@
  • @jllord
  • File an issue
  • +

    Home Page

    From 701f3d15fe64d2a0a9b189d86028f4159e976943 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 2 Feb 2014 23:19:36 -0800 Subject: [PATCH 030/157] so close --- css/sss.css | 6 +- demos/demo-chart.html | 1 + demos/demo-map.html | 3 +- demos/demo-table.html | 3 +- docs/about.md | 32 +++++------ docs/basics.md | 68 +++++++++------------- new-readme.md | 3 +- readme.md | 7 ++- site/assets/sss.css | 67 ++++++---------------- site/assets/style.css | 100 +++++++++------------------------ site/demos/demo-chart.html | 1 + site/demos/demo-map.html | 3 +- site/demos/demo-table.html | 5 +- site/docs/about.html | 41 +++++++------- site/docs/basics.html | 71 +++++++++++------------ site/docs/building.html | 9 +-- site/docs/changelog.html | 9 +-- site/docs/custom-charts.html | 9 +-- site/docs/fork-n-go.html | 9 +-- site/docs/sheetsee-charts.html | 9 +-- site/docs/sheetsee-core.html | 9 +-- site/docs/sheetsee-maps.html | 9 +-- site/docs/sheetsee-tables.html | 9 +-- site/docs/tips.html | 9 +-- site/img/fbi_spinner.gif | Bin 0 -> 1899 bytes site/img/hexcolors.png | Bin 0 -> 118186 bytes site/img/key.png | Bin 0 -> 40026 bytes site/img/latlong.png | Bin 0 -> 46644 bytes site/img/nonos.png | Bin 0 -> 49990 bytes site/img/publish.png | Bin 0 -> 50108 bytes site/img/sheetsee-03.png | Bin 0 -> 76716 bytes site/img/spreadsheettodata.png | Bin 0 -> 79410 bytes site/img/webconsole.png | Bin 0 -> 35675 bytes site/index.html | 4 +- template.hbs | 9 +-- 35 files changed, 213 insertions(+), 292 deletions(-) create mode 100644 site/img/fbi_spinner.gif create mode 100644 site/img/hexcolors.png create mode 100644 site/img/key.png create mode 100644 site/img/latlong.png create mode 100644 site/img/nonos.png create mode 100644 site/img/publish.png create mode 100644 site/img/sheetsee-03.png create mode 100644 site/img/spreadsheettodata.png create mode 100644 site/img/webconsole.png diff --git a/css/sss.css b/css/sss.css index 89eeb1f9..db232d59 100644 --- a/css/sss.css +++ b/css/sss.css @@ -1,6 +1,6 @@ - /* SHEETSEE STYLES */ - /* These are styles that you'll need to handle for certain elements, - /* or are available to you through elements sheetsee.js generates */ +/* SHEETSEE STYLES */ +/* These are styles that you'll need to handle for certain elements, +/* or are available to you through elements sheetsee.js generates */ /* Table */ diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 63919ef3..6168eac2 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -36,6 +36,7 @@

    Getting Started

    Ideas

      diff --git a/demos/demo-map.html b/demos/demo-map.html index 96f41549..5e22d0b7 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -25,7 +25,8 @@

      All Pennies Map

      Getting Started

      Ideas

        diff --git a/demos/demo-table.html b/demos/demo-table.html index f112786c..7c6896ce 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -11,7 +11,7 @@ - -
        - - + + + + + + + +
        + + -## Getting Started - -This bit is the same for both client-side and server-side versions. -### Your Data +## Your Data ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) @@ -58,20 +46,20 @@ There shouldn't be any breaks or horizontal organization in the spreadsheet. But [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] -#### Hexcolor +### Hexcolor ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! -#### Geocoding +### Geocoding If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. > image of lat and long column headers -#### Publishing Your Spreadsheet +### Publishing Your Spreadsheet ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) @@ -81,8 +69,6 @@ You need to do this in order to generate a unique key for your spreadsheet, whic You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. -### Your Website - -Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet. +### CSS -For now, create empty `div` placeholders for the map, chart and tables you plan on including. +Sheetsee.js comes with a bare minimum stylesheet, `sss.csss`, which contains elements you'll want to style when using the feature they correspond to. diff --git a/new-readme.md b/new-readme.md index 1e161181..68391f21 100644 --- a/new-readme.md +++ b/new-readme.md @@ -3,7 +3,7 @@ # Sheetsee.js -**Sheetsee.js** is a library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. +**Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](/docs/basics.md). @@ -46,6 +46,7 @@ More resources on using Sheetsee.js: - [About Sheetsee.js](docs/about.md) - [Building Sheetsee](docs/building.md) +- [Basics](docs/basics.md) #### Ideas diff --git a/readme.md b/readme.md index 37d85af7..40151151 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,9 @@ _**Attention!** Hi! Sheetsee will be updated *soon*. Fun! I'm currently working on adding in some features (pagination on tables and polygons in maps) and breaking the tables, maps and charts components of Sheetsee into individual modules allowing for custom builds with just the components you plan on using (or all if you don't care). Changes currently in progress on the [`modules` branch](https://github.com/jlord/sheetsee.js/tree/modules). Sheetsee modules (still being debugged) are in my [repositories](https://github.com/search?q=%40jlord+sheetsee+module&type=Repositories&ref=searchresults)._ ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/sheetsee-03.png) + # Sheetsee.js -Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page. +Sheetsee.js is a client-side JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page. Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with. @@ -273,7 +274,7 @@ If you pass in an array of just one color it will repeat that color for all item ## Make a Map -Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [Leaflet.js](http://leafletjs.com/) plugin, to make maps. +Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [[Leaflet.js](http://leafletjs.com/)](http://leafletjs.com/) plugin, to make maps. Create an empty `
        ` in your HTML, with an id. @@ -496,6 +497,6 @@ Thanks to [Dan Sinker](http://www.twitter.com/dansinker) at [Open News](http://w Thanks to [Max Ogden](http://www.twitter.com/maxogden) for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making [Tabletop.js for Node.js](https://npmjs.org/tabletop). -Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow. +Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, [Leaflet.js](http://leafletjs.com/), jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow. Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here. diff --git a/site/assets/sss.css b/site/assets/sss.css index eef4b2bf..de9fa702 100644 --- a/site/assets/sss.css +++ b/site/assets/sss.css @@ -1,56 +1,25 @@ - /* General */ +/* General */ - body {margin: 0px auto;} - a {color: #333;} - #wrapper {margin: 0px auto; max-width: 600px;} - .button {padding: 5px 4px; background-color: #fff; font-size: 10px;} - .button:hover {cursor: hand;} - input:focus {outline: none;} +body {margin: 0px auto;} +a {color: #333;} +input:focus {outline: none;} - /* Table */ +/* Table */ - table {text-align: left; width: 100%} - th {padding: 10px 0px;} - td, text {padding: 3px 20px 3px 0px; font-size: 14px;} - #tableFilter, #basicFilter, #dogFilter {margin: 12px 0px; border: none; border-bottom: 1px solid #333; background-color: transparent; padding: 0px; font-family: Merriweather; color: #FCB688; font-size: 13px; height: 22px;} - /*.tHeader { table column header style } */ - .noMatches {margin-left: 20px; font-size: 11px; font-style: italic; visibility: hidden;} -/* #Pagination {} - .pagination-next, .pagination-pre {} - .no-pag {}*/ - - /* Containers */ - .container {margin: 14px 0px;} - #map {height: 400px; max-width: 800px; background: #DADADA; overflow: hidden;} - #holder {height: 400px; max-width: 600px; background: #FFE4E4;} - - /* Overflow for large tables and chart */ - .container {overflow-x: auto;} - #yourDiv {min-width: 600px} - - /* Bar Chart */ - - .labels text {text-align: right;} - .bar .labels text {fill: #333;} - .bar rect {fill: #e6e6e6;} - .axis {shape-rendering: crispEdges;} - .x.axis line {stroke: #fff; fill: none;} - .x.axis path {fill: none;} - .x.axis text {fill: #333;} - .xLabel {font-family: sans-serif; font-size: 9px;} +table {text-align: left; width: 100%} +th {padding: 10px 0px;} +td, text {padding: 3px 20px 3px 0px; font-size: 14px;} +.noMatches {margin-left: 20px; font-size: 11px; font-style: italic; visibility: hidden;} /* Line Chart */ - .axis {shape-rendering: crispEdges;} - .x.axis .minor, .y.axis .minor {stroke-opacity: .5;} - .x.axis {stroke-opacity: 1;} - .y.axis line, .y.axis path {fill: none; stroke: #acacac; stroke-width: 1;} - .bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);} - path.chartLine {stroke: #333; stroke-width: 3; fill: none;} - div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;} - circle {fill: #e6e6e6;} - -/* Map */ - +.axis {shape-rendering: crispEdges;} +.x.axis .minor, .y.axis .minor {stroke-opacity: .5;} +.x.axis {stroke-opacity: 1;} +.y.axis line, .y.axis path {fill: none; stroke: #acacac; stroke-width: 1;} +.bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);} +path.chartLine {stroke: #333; stroke-width: 3; fill: none;} +div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;} +circle {fill: #e6e6e6;} - @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) {} +@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) {} diff --git a/site/assets/style.css b/site/assets/style.css index 05591dc1..6fafbc53 100644 --- a/site/assets/style.css +++ b/site/assets/style.css @@ -1,20 +1,18 @@ -body {background: #ff00ff;} .container {max-width: 800px; margin: 0 auto; overflow: auto;} -img {width: 100%;} -/*footer h4:first-child {margin-top: 0px;}*/ h3 {padding-top: 18px;} h1 {font-size: 36px;} - + table {border-spacing: 0;} tbody tr:nth-child(odd) {background-color: #f3f3f3;} td {min-width: 140px; vertical-align: top; padding: 8px;} tr {height: 50px;} -ul {text-indent: 0; margin: 0; padding-left: 18px;} -ul li {padding-bottom: 6px;} +ul, ol {text-indent: 0; margin: 0; padding-left: 20px;} +ul li {padding-bottom: 6px; line-height: 22px;} footer {font-size: 10px; padding-top: 20px; margin-top: 60px; border-top: 1px solid #CCF4FF; -webkit-column-count: 6; -webkit-column-gap: 20px; height: 125px;} footer ul {list-style: none; padding-left: 0px;} +footer li {line-height: inherit;} footer h4 {-webkit-column-break-before: always; } footer h4 {margin-top: 0px;} footer a {border: none;} @@ -22,80 +20,34 @@ footer a {border: none;} .half {max-width: 50%; display: inline-block; vertical-align: top;} .half:nth-child(odd) {padding-left: 20px;} - /* General */ - - /* Page Specific CSS */ - - body {font-family: Libre Baskerville, Baskerville, Georgia, serif; background: #fff; color: #333; font-size: 14px; border: 10px #47CCFC solid; margin: 0px; padding: 20px 20px 100px 20px; } - h1, h2, h3, h4, h5, h6 {font-family: Helvetica, Arial, sans-serif;} - h2 {margin-top: 40px;} - - h3.functionH {margin-left: -14px; margin-top: 52px; border-top: 3px solid #47CCFC; border-left: 3px solid #47CCFC; border-right: 3px solid #47CCFC; padding-left: 14px; padding-top: 9px; } - img {width: 100%;} - - p a, a {color: #333; text-decoration: none; padding-bottom: 0px; border-bottom: 2px #CCF4FF solid;} - p a:visted {color: #ff00ff;} - a:hover {color: #47CCFC;} - a:visited {color: #333;} - small {padding: 10px 0px;} - p, ol {line-height: 24px;} - - pre {word-wrap: break-word; padding: 14px; background: #F0F0F0;} - code {font-family: "Consolas", "Ubuntu Mono", monospace; line-height: 22px; /*font-size: 13px; */color: #636363; font-weight: normal;} - - /* funsies */ - ::selection {background: #44FFB4;} - ::-moz-selection {background: #44FFB4;} - - img.petThumbs {height: 80px; width: 80px; border-radius: 1000px;} - - .button {padding: 5px 4px; background-color: #fff; font-size: 10px;} - - #menu {color: #fff; padding: 20px; float: left; position: fixed; left: 40px; top: 40px; max-width: 300px; font-family: Helvetica, Arial, sans-serif; font-size: 14px;} - #menu ul {list-style: none; margin: 0px; padding: 0px;} - #menu li {line-height: 34px;} - #menu li a {padding: 4px 8px; background-color: #F0F0F0; text-decoration: none; border: none;} - #menu li a.a2 {background-color: #CCF4FF;} - #menu li a:hover {background-color: #e7e7e7; color: #333;} +/* older css */ - #wrapper {margin: 0px auto; max-width: 800px; padding-top: 40px;} +body {font-family: Libre Baskerville, Baskerville, Georgia, serif; background: #fff; color: #333; font-size: 14px; border: 10px #47CCFC solid; margin: 0px; padding: 20px 20px 100px 20px; } +h1, h2, h3, h4, h5, h6 {font-family: Helvetica, Arial, sans-serif;} +h2 {margin-top: 40px;} - /* Examples */ - .ssExample {margin: 20px -28px; background-color: #CCF4FF; padding: 20px 28px; background-color: #CCF4FF; border: 8px solid #47CCFC; margin-top: 44px; padding-top: 0px; overflow: auto;} - .ssExample li {padding: 2px 0px;} - .ssExample h2 {margin-top: inherit;} +img {width: 100%;} - /* Table */ - .ssExample table {min-width: 600px;} - .tHeader::after {content: " \2193 \2191 "; font-size: 10px; padding-left: 3px; cursor: hand;} +p a, a {color: #333; text-decoration: none; padding-bottom: 0px; border-bottom: 2px #CCF4FF solid;} +p a:visted {color: #ff00ff;} +a:hover {color: #47CCFC;} +a:visited {color: #333;} +small {padding: 10px 0px;} +p, ol {line-height: 24px;} - /* Map Popup Style */ - .leaflet-popup-content h2 {margin-bottom: 4px; margin-top: auto;} +pre {word-wrap: break-word; padding: 14px; background: #F0F0F0;} +code {font-family: "Consolas", "Ubuntu Mono", monospace; line-height: 22px; /*font-size: 13px; */color: #636363; font-weight: normal;} - /* Bar Chart */ - #dogBar.labels text {text-align: right;} - #dogBar.bar .labels text {fill: #333;} - #dogBar.bar rect {fill: #e6e6e6;} - #dogBar.axis {shape-rendering: crispEdges;} - #dogBar .x.axis line {stroke: #CCF4FF; /*stroke-opacity: .2;*/ fill: none;} - #dogBar.x.axis path {fill: none;} - #dogBar.x.axis text {fill: #333;} - #dogBar.xLabel {font-family: sans-serif; font-size: 9px;} +/* funsies */ +::selection {background: #44FFB4;} +::-moz-selection {background: #44FFB4;} - /* Line Chart */ - #dogLine.axis {shape-rendering: crispEdges;} - #dogLine.x.axis .minor, #dogLine.y.axis .minor {stroke-opacity: .5;} - #dogLine.x.axis {stroke-opacity: 1;} - #dogLine.y.axis line, #dogLine.y.axis path, #dogLine.x.axis path {fill: none; stroke: #acacac; stroke-width: 1;} - #dogLine .x.axis line {stroke: #acacac; stroke-opacity: .75;} - .bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);} - path.chartLine {stroke: #14ECC8; stroke-width: 3; fill: none;} - div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;} - circle {fill: #fff;} +/* Table */ +.ssExample table {min-width: 600px;} +.tHeader::after {content: " \2193 \2191 "; font-size: 10px; padding-left: 3px; cursor: hand;} - /* Pie Chart */ - .arc path { stroke: #fff;} +/* Map Popup Style */ +.leaflet-popup-content h2 {margin-bottom: 4px; margin-top: auto;} - /* Responsive Town */ - @media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) {} +@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) {} diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index 63919ef3..6168eac2 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -36,6 +36,7 @@

        Getting Started

        Ideas

          diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index 96f41549..5e22d0b7 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -25,7 +25,8 @@

          All Pennies Map

          Getting Started

          Ideas

            diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index a5422c73..7c6896ce 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -11,7 +11,7 @@
            @@ -32,7 +35,7 @@

            Ideas

            Demos

              @@ -43,10 +46,10 @@

              Demos

            Use

            Contact

              @@ -66,8 +69,10 @@

              Home Page

              function showInfo(data) { gData = data - var optionsJSON = ["placename", "image"] - var template = "
              • placename: {{placename}}
              " + var optionsJSON = ["placename", "photo-url"] + var template = "" var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON) var map = Sheetsee.loadMap("map") Sheetsee.addTileLayer(map, 'examples.map-20v6611k') diff --git a/demos/demo-table.html b/demos/demo-table.html index 7c6896ce..c444d6cd 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -16,6 +16,8 @@ .no-pag:hover {color: #acacac;} input {border: none; border-bottom: 1px solid #333;margin: 10px 0px; width: 200px; font-size: 16px; padding-bottom: 6px;} .tHeader {padding: 8px; font-family: Helvetica Neue; Helvetica, Arial, sans-serif; cursor: hand;} + .photo {display: inline-block; float: left; width: 100px;} + #photogrid {overflow: auto;}
              @@ -26,20 +28,22 @@

              All Pennies

              California Pennies

              +

              Pretty Pennies

              +

              View Source

              -

              Home Page

              + + + + - @@ -35,36 +35,34 @@

              Pretty Pennies

            diff --git a/demos/template.html b/demos/template.html deleted file mode 100644 index ab937bf5..00000000 --- a/demos/template.html +++ /dev/null @@ -1,31 +0,0 @@ - - - Yo, yo, yo! - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/about.md b/docs/about.md index 07accbca..583f4e82 100644 --- a/docs/about.md +++ b/docs/about.md @@ -6,7 +6,7 @@ In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open Ne The present version makes the project modular, customizable and with more maping and table features. -## Built ontop of Tabletop.js +## Built on top of Tabletop.js Sheetsee would not exist were it not for [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely JSON of your data. Every instance of Sheetsee begins with running tabletop.js. ### Sheetsee.js + Mapbox.js + d3.js diff --git a/docs/basics.md b/docs/basics.md index 21bde9fe..6de25c83 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -1,6 +1,6 @@ # Spreadsheets as Databases -Hi, hello. +Spreadsheets are a great _lightweight_ database. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database set ups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet! ## The Short & Sweet @@ -15,24 +15,34 @@ Hi, hello. Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points. - - - - - - - - -
            - - - - +```HTML + + + + + + + + +
            + + + + + + +``` ## Your Data diff --git a/js/sheetsee.js b/js/sheetsee.js index 7ee2af93..7c85f06d 100644 --- a/js/sheetsee.js +++ b/js/sheetsee.js @@ -25195,8 +25195,8 @@ function searchTable(opts, searchTerm) { makeTable(opts, filteredList) } } - -module.exports.sortThings = function(opts, sorter, sorted) { +module.exports.sortThings = sortThings +function sortThings(opts, sorter, sorted) { console.log("here is data", opts.data) opts.data.sort(function(a,b){ if (a[sorter]Pennies by State
        - @@ -35,36 +35,34 @@

        Pretty Pennies

        diff --git a/site/demos/template.html b/site/demos/template.html index ab937bf5..28067525 100644 --- a/site/demos/template.html +++ b/site/demos/template.html @@ -1,3 +1,15 @@ + + + Sheetsee Maps Demo + + + + + + +
        +

        Here it is:

        +
        
         
         	
         		Yo, yo, yo!
        @@ -11,7 +23,7 @@
         
           
             
        -  	
        +	
           
        @@ -28,4 +40,55 @@
           
         
           
        -
        \ No newline at end of file
        +
        +
        + + + +
        + + + + + + + + + + + + + diff --git a/site/docs/about.html b/site/docs/about.html index abf10c0e..def52175 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -16,7 +16,7 @@

        About

        Sheetsee.js began as a part of my Code for America 2012 Fellowship project, See Penny Work. The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet.

        In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

        The present version makes the project modular, customizable and with more maping and table features.

        -

        Built ontop of Tabletop.js

        +

        Built on top of Tabletop.js

        Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely JSON of your data. Every instance of Sheetsee begins with running tabletop.js.

        Sheetsee.js + Mapbox.js + d3.js

        Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

        @@ -64,7 +64,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/basics.html b/site/docs/basics.html index 26c540ab..287c1bc9 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -13,7 +13,7 @@

        Spreadsheets as Databases

        -

        Hi, hello.

        +

        Spreadsheets are a great lightweight database. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database set ups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet!

        The Short & Sweet

        1. Link to Sheetsee.js, tabletop.js and jquery in your HTML head.
        2. @@ -25,24 +25,34 @@

          The Short & Sweet

        Bare Minimum Setup

        Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

        -
        <html>
        +
        <html>
           <head>
             <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
             <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
             <script type="text/javascript" src='dist/sheetsee.full.js'></script>
        +    <link rel="stylesheet" type="text/css" href="css/sss.css"> 
           </head>
        -  <style> #map {height: 600px; width: 600px;} </style>
           <body>
        -  <div id="map"></div>
        -  <script>
        -      var geoJSON = Sheetsee.createGeoJSON(gData, featureElements)
        -      var map = Sheetsee.loadMap("map")
        -      Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
        -      var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, 11)
        +  <div id="placeholder"></div>
        +
        +  <script id="placeholder" type="text/html">
        +    // template if you so desire!
        +  </script>
        +
        +  <script type="text/javascript">
        +    //  document.addEventListener('DOMContentLoaded', function() {
        +    //      var gData
        +    //      var URL = "YOURSPREADSHEETSKEYHERE"
        +    //        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } ) 
        +    //    }) 
        +    // function myData(data) {
        +       // All the sheetsee things you want to do!
        +    // }
           </script>
           </body>
         </html>
        -

        Your Data

        +
        +

        Your Data

        sheetsee

        Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

        sheetsee

        @@ -84,7 +94,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/building.html b/site/docs/building.html index 79d52616..d25b52c2 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -56,7 +56,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/changelog.html b/site/docs/changelog.html index ee129e74..4bc7438a 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -50,7 +50,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 68390c75..db873807 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -43,7 +43,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 9d935683..4c6922eb 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -46,7 +46,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 0b0bafbb..d7293e92 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -102,7 +102,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 33bbf50a..fe15eea7 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -105,7 +105,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 8931e46f..e0294f6d 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -76,7 +76,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 856fc429..6a1787c6 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -101,7 +101,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        diff --git a/site/docs/template.html b/site/docs/template.html new file mode 100644 index 00000000..143e75f3 --- /dev/null +++ b/site/docs/template.html @@ -0,0 +1,86 @@ + + + + + + + + such site, very sheetsee.js + + + + + +
        +

        Basic Template

        +
        <html>
        +    <head>
        +        <title>Yo, yo, yo!</title>
        +    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
        +    <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
        +    <script type="text/javascript" src='../js/sheetsee.js'></script>
        +      <meta charset='utf-8'>    
        +    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        +        <link rel="stylesheet" type="text/css" href="css/sss.css"> 
        +    </head>
        +
        +  <body>
        +    <!-- Your HTML Here -->
        +
        +  <script id="" type="text/html">
        +    // template if you so desire!
        +  </script>
        +
        +  <script type="text/javascript">
        +  //  document.addEventListener('DOMContentLoaded', function() {
        +  //      var gData
        +  //      var URL = "YOURSPREADSHEETSKEYHERE"
        +  //        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } ) 
        +  //    }) 
        +  // function myData(data) {
        +     // All the sheetsee things you want to do!
        +  // }
        +  </script>
        +
        +  </body>
        +</html>
        +
        + + + +
        + + \ No newline at end of file diff --git a/site/docs/tips.html b/site/docs/tips.html index 278640a9..8c501797 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -48,7 +48,6 @@

        Demos

      • Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

      Use

        diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js index 7ee2af93..7c85f06d 100644 --- a/site/js/sheetsee.js +++ b/site/js/sheetsee.js @@ -25195,8 +25195,8 @@ function searchTable(opts, searchTerm) { makeTable(opts, filteredList) } } - -module.exports.sortThings = function(opts, sorter, sorted) { +module.exports.sortThings = sortThings +function sortThings(opts, sorter, sorted) { console.log("here is data", opts.data) opts.data.sort(function(a,b){ if (a[sorter]Table Demo
      • Map Demo
      • Chart Demo
      • -
      • Basic Template

      Use

        From fc6e3a4631f5e152b16c58a2eb51419cac47b150 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 3 Feb 2014 21:27:17 -0800 Subject: [PATCH 033/157] .. --- js/sheetsee.js | 25355 ----------------------------------------------- 1 file changed, 25355 deletions(-) delete mode 100644 js/sheetsee.js diff --git a/js/sheetsee.js b/js/sheetsee.js deleted file mode 100644 index 7c85f06d..00000000 --- a/js/sheetsee.js +++ /dev/null @@ -1,25355 +0,0 @@ -;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var baseCreateCallback = require('lodash._basecreatecallback'), - keys = require('lodash.keys'), - objectTypes = require('lodash._objecttypes'); - -/** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources will overwrite property assignments of previous - * sources. If a callback is provided it will be executed to produce the - * assigned values. The callback is bound to `thisArg` and invoked with two - * arguments; (objectValue, sourceValue). - * - * @static - * @memberOf _ - * @type Function - * @alias extend - * @category Objects - * @param {Object} object The destination object. - * @param {...Object} [source] The source objects. - * @param {Function} [callback] The function to customize assigning values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the destination object. - * @example - * - * _.assign({ 'name': 'moe' }, { 'age': 40 }); - * // => { 'name': 'moe', 'age': 40 } - * - * var defaults = _.partialRight(_.assign, function(a, b) { - * return typeof a == 'undefined' ? b : a; - * }); - * - * var food = { 'name': 'apple' }; - * defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } - */ -var assign = function(object, source, guard) { - var index, iterable = object, result = iterable; - if (!iterable) return result; - var args = arguments, - argsIndex = 0, - argsLength = typeof guard == 'number' ? 2 : args.length; - if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { - var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); - } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { - callback = args[--argsLength]; - } - while (++argsIndex < argsLength) { - iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) { - var ownIndex = -1, - ownProps = objectTypes[typeof iterable] && keys(iterable), - length = ownProps ? ownProps.length : 0; - - while (++ownIndex < length) { - index = ownProps[ownIndex]; - result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; - } - } - } - return result -}; - -module.exports = assign; - -},{"lodash._basecreatecallback":3,"lodash._objecttypes":22,"lodash.keys":23}],3:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var bind = require('lodash.bind'), - identity = require('lodash.identity'), - setBindData = require('lodash._setbinddata'), - support = require('lodash.support'); - -/** Used to detected named functions */ -var reFuncName = /^function[ \n\r\t]+\w/; - -/** Used to detect functions containing a `this` reference */ -var reThis = /\bthis\b/; - -/** Native method shortcuts */ -var fnToString = Function.prototype.toString; - -/** - * The base implementation of `_.createCallback` without support for creating - * "_.pluck" or "_.where" style callbacks. - * - * @private - * @param {*} [func=identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of the created callback. - * @param {number} [argCount] The number of arguments the callback accepts. - * @returns {Function} Returns a callback function. - */ -function baseCreateCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { - return func; - } - var bindData = func.__bindData__ || (support.funcNames && !func.name); - if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; - } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); - } - } - // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 2: return function(a, b) { - return func.call(thisArg, a, b); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return bind(func, thisArg); -} - -module.exports = baseCreateCallback; - -},{"lodash._setbinddata":4,"lodash.bind":12,"lodash.identity":19,"lodash.support":20}],4:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var getObject = require('lodash._getobject'), - noop = require('lodash._noop'), - reNative = require('lodash._renative'), - releaseObject = require('lodash._releaseobject'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -var defineProperty = (function() { - try { - var o = {}, - func = reNative.test(func = Object.defineProperty) && func, - result = func(o, o, o) && func; - } catch(e) { } - return result; -}()); - -/** - * Sets `this` binding data on a given function. - * - * @private - * @param {Function} func The function to set data on. - * @param {*} value The value to set. - */ -var setBindData = !defineProperty ? noop : function(func, value) { - var descriptor = getObject(); - descriptor.value = value; - defineProperty(func, '__bindData__', descriptor); - releaseObject(descriptor); -}; - -module.exports = setBindData; - -},{"lodash._getobject":5,"lodash._noop":7,"lodash._releaseobject":8,"lodash._renative":11}],5:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectPool = require('lodash._objectpool'); - -/** - * Gets an object from the object pool or creates a new one if the pool is empty. - * - * @private - * @returns {Object} The object from the pool. - */ -function getObject() { - return objectPool.pop() || { - 'array': null, - 'cache': null, - 'configurable': false, - 'criteria': null, - 'enumerable': false, - 'false': false, - 'index': 0, - 'leading': false, - 'maxWait': 0, - 'null': false, - 'number': null, - 'object': null, - 'push': null, - 'string': null, - 'trailing': false, - 'true': false, - 'undefined': false, - 'value': null, - 'writable': false - }; -} - -module.exports = getObject; - -},{"lodash._objectpool":6}],6:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used to pool arrays and objects used internally */ -var objectPool = []; - -module.exports = objectPool; - -},{}],7:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * A no-operation function. - * - * @private - */ -function noop() { - // no operation performed -} - -module.exports = noop; - -},{}],8:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var maxPoolSize = require('lodash._maxpoolsize'), - objectPool = require('lodash._objectpool'); - -/** - * Releases the given object back to the object pool. - * - * @private - * @param {Object} [object] The object to release. - */ -function releaseObject(object) { - var cache = object.cache; - if (cache) { - releaseObject(cache); - } - object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; - if (objectPool.length < maxPoolSize) { - objectPool.push(object); - } -} - -module.exports = releaseObject; - -},{"lodash._maxpoolsize":9,"lodash._objectpool":10}],9:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used as the max size of the `arrayPool` and `objectPool` */ -var maxPoolSize = 40; - -module.exports = maxPoolSize; - -},{}],10:[function(require,module,exports){ -module.exports=require(6) -},{}],11:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Used to detect if a method is native */ -var reNative = RegExp('^' + - String(objectProto.valueOf) - .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - .replace(/valueOf|for [^\]]+/g, '.+?') + '$' -); - -module.exports = reNative; - -},{}],12:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var createBound = require('lodash._createbound'), - reNative = require('lodash._renative'); - -/** - * Used for `Array` method references. - * - * Normally `Array.prototype` would suffice, however, using an array literal - * avoids issues in Narwhal. - */ -var arrayRef = []; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeSlice = arrayRef.slice; - -/** - * Creates a function that, when called, invokes `func` with the `this` - * binding of `thisArg` and prepends any additional `bind` arguments to those - * provided to the bound function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var func = function(greeting) { - * return greeting + ' ' + this.name; - * }; - * - * func = _.bind(func, { 'name': 'moe' }, 'hi'); - * func(); - * // => 'hi moe' - */ -function bind(func, thisArg) { - return arguments.length > 2 - ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg) - : createBound(func, 1, null, null, thisArg); -} - -module.exports = bind; - -},{"lodash._createbound":13,"lodash._renative":18}],13:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var createObject = require('lodash._createobject'), - isFunction = require('lodash.isfunction'), - isObject = require('lodash.isobject'), - reNative = require('lodash._renative'), - setBindData = require('lodash._setbinddata'), - support = require('lodash.support'); - -/** - * Used for `Array` method references. - * - * Normally `Array.prototype` would suffice, however, using an array literal - * avoids issues in Narwhal. - */ -var arrayRef = []; - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var push = arrayRef.push, - toString = objectProto.toString, - unshift = arrayRef.unshift; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, - nativeSlice = arrayRef.slice; - -/** - * Creates a function that, when called, either curries or invokes `func` - * with an optional `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of method flags to compose. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` - * 8 - `_.curry` (bound) - * 16 - `_.partial` - * 32 - `_.partialRight` - * @param {Array} [partialArgs] An array of arguments to prepend to those - * provided to the new function. - * @param {Array} [partialRightArgs] An array of arguments to append to those - * provided to the new function. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new bound function. - */ -function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { - var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - isPartial = bitmask & 16, - isPartialRight = bitmask & 32, - key = func; - - if (!isBindKey && !isFunction(func)) { - throw new TypeError; - } - if (isPartial && !partialArgs.length) { - bitmask &= ~16; - isPartial = partialArgs = false; - } - if (isPartialRight && !partialRightArgs.length) { - bitmask &= ~32; - isPartialRight = partialRightArgs = false; - } - var bindData = func && func.__bindData__; - if (bindData) { - if (isBind && !(bindData[1] & 1)) { - bindData[4] = thisArg; - } - if (!isBind && bindData[1] & 1) { - bitmask |= 8; - } - if (isCurry && !(bindData[1] & 4)) { - bindData[5] = arity; - } - if (isPartial) { - push.apply(bindData[2] || (bindData[2] = []), partialArgs); - } - if (isPartialRight) { - push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); - } - bindData[1] |= bitmask; - return createBound.apply(null, bindData); - } - // use `Function#bind` if it exists and is fast - // (in V8 `Function#bind` is slower except when partially applied) - if (isBind && !(isBindKey || isCurry || isPartialRight) && - (support.fastBind || (nativeBind && isPartial))) { - if (isPartial) { - var args = [thisArg]; - push.apply(args, partialArgs); - } - var bound = isPartial - ? nativeBind.apply(func, args) - : nativeBind.call(func, thisArg); - } - else { - bound = function() { - // `Function#bind` spec - // http://es5.github.io/#x15.3.4.5 - var args = arguments, - thisBinding = isBind ? thisArg : this; - - if (isCurry || isPartial || isPartialRight) { - args = nativeSlice.call(args); - if (isPartial) { - unshift.apply(args, partialArgs); - } - if (isPartialRight) { - push.apply(args, partialRightArgs); - } - if (isCurry && args.length < arity) { - bitmask |= 16 & ~32; - return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity); - } - } - if (isBindKey) { - func = thisBinding[key]; - } - if (this instanceof bound) { - // ensure `new bound` is an instance of `func` - thisBinding = createObject(func.prototype); - - // mimic the constructor's `return` behavior - // http://es5.github.io/#x13.2.2 - var result = func.apply(thisBinding, args); - return isObject(result) ? result : thisBinding; - } - return func.apply(thisBinding, args); - }; - } - setBindData(bound, nativeSlice.call(arguments)); - return bound; -} - -module.exports = createBound; - -},{"lodash._createobject":14,"lodash._renative":18,"lodash._setbinddata":4,"lodash.isfunction":16,"lodash.isobject":17,"lodash.support":20}],14:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var isObject = require('lodash.isobject'), - noop = require('lodash._noop'), - reNative = require('lodash._renative'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate; - -/** - * Creates a new object with the specified `prototype`. - * - * @private - * @param {Object} prototype The prototype object. - * @returns {Object} Returns the new object. - */ -function createObject(prototype) { - return isObject(prototype) ? nativeCreate(prototype) : {}; -} - -module.exports = createObject; - -},{"lodash._noop":15,"lodash._renative":18,"lodash.isobject":17}],15:[function(require,module,exports){ -module.exports=require(7) -},{}],16:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * Checks if `value` is a function. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - */ -function isFunction(value) { - return typeof value == 'function'; -} - -module.exports = isFunction; - -},{}],17:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectTypes = require('lodash._objecttypes'); - -/** - * Checks if `value` is the language type of Object. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // check if the value is the ECMAScript language type of Object - // http://es5.github.io/#x8 - // and avoid a V8 bug - // http://code.google.com/p/v8/issues/detail?id=2291 - return !!(value && objectTypes[typeof value]); -} - -module.exports = isObject; - -},{"lodash._objecttypes":22}],18:[function(require,module,exports){ -module.exports=require(11) -},{}],19:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * This method returns the first argument provided to it. - * - * @static - * @memberOf _ - * @category Utilities - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var moe = { 'name': 'moe' }; - * moe === _.identity(moe); - * // => true - */ -function identity(value) { - return value; -} - -module.exports = identity; - -},{}],20:[function(require,module,exports){ -var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var reNative = require('lodash._renative'); - -/** Used to detect functions containing a `this` reference */ -var reThis = /\bthis\b/; - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var toString = objectProto.toString; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind; - -/** Detect various environments */ -var isIeOpera = reNative.test(global.attachEvent), - isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); - -/** - * An object used to flag environments features. - * - * @static - * @memberOf _ - * @type Object - */ -var support = {}; - -/** - * Detect if `Function#bind` exists and is inferred to be fast (all but V8). - * - * @memberOf _.support - * @type boolean - */ -support.fastBind = nativeBind && !isV8; - -/** - * Detect if functions can be decompiled by `Function#toString` - * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). - * - * @memberOf _.support - * @type boolean - */ -support.funcDecomp = !reNative.test(global.WinRTError) && reThis.test(function() { return this; }); - -/** - * Detect if `Function#name` is supported (all but IE). - * - * @memberOf _.support - * @type boolean - */ -support.funcNames = typeof Function.name == 'string'; - -module.exports = support; - -},{"lodash._renative":21}],21:[function(require,module,exports){ -module.exports=require(11) -},{}],22:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used to determine if values are of the language type Object */ -var objectTypes = { - 'boolean': false, - 'function': true, - 'object': true, - 'number': false, - 'string': false, - 'undefined': false -}; - -module.exports = objectTypes; - -},{}],23:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var isObject = require('lodash.isobject'), - reNative = require('lodash._renative'), - shimKeys = require('lodash._shimkeys'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys; - -/** - * Creates an array composed of the own enumerable property names of an object. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - * @example - * - * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); - * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) - */ -var keys = !nativeKeys ? shimKeys : function(object) { - if (!isObject(object)) { - return []; - } - return nativeKeys(object); -}; - -module.exports = keys; - -},{"lodash._renative":24,"lodash._shimkeys":25,"lodash.isobject":26}],24:[function(require,module,exports){ -module.exports=require(11) -},{}],25:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectTypes = require('lodash._objecttypes'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * A fallback implementation of `Object.keys` which produces an array of the - * given object's own enumerable property names. - * - * @private - * @type Function - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - */ -var shimKeys = function(object) { - var index, iterable = object, result = []; - if (!iterable) return result; - if (!(objectTypes[typeof object])) return result; - for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - result.push(index); - } - } - return result -}; - -module.exports = shimKeys; - -},{"lodash._objecttypes":22}],26:[function(require,module,exports){ -module.exports=require(17) -},{"lodash._objecttypes":22}],27:[function(require,module,exports){ -var d3 = require('d3') - -module.exports.d3 = d3 - -// Bar Chart -// Adapted mostly from http://bl.ocks.org/mbostock/3885705 -// options = {units: "string", labels: "string", m: [60, 150, 30, 150], w: 800, h: 300, div: "#dogBar", xaxis: "cuddlability", hiColor: "#EE0097"} - -module.exports.d3BarChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - // m = [t0, r1, b2, l3] - var m = options.m, - w = options.w - m[1] - m[3], - h = options.h - (m[0] + m[2]) - var format = d3.format(",.0f") - - var x = d3.scale.linear().range([0, w]), - y = d3.scale.ordinal().rangeRoundBands([0, h], .1) - - var xAxis = d3.svg.axis().scale(x).orient("top").tickSize(-h).tickFormat(d3.format("1s")), - yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0) - - var svg = d3.select(options.div).append("svg") - .attr("width", w + m[1] + m[3]) - .attr("height", h + m[0] + m[2]) - .append("g") - .attr("transform", "translate(" + m[3] + "," + m[0] + ")") - - x.domain([0, d3.max(data, function(d) { return d.units })]) // 0 to max of units - y.domain(data.map(function(d) { return d.labels })) // makes array of labels - - var mouseOver = function() { - var rect = d3.select(this) - var indexValue = rect.attr("index_value") - - var barSelector = "." + "rect-" + indexValue - var selectedBar = d3.selectAll(barSelector) - selectedBar.style("fill", options.hiColor) - - var valueSelector = "." + "value-" + indexValue - var selectedValue = d3.selectAll(valueSelector) - selectedValue.style("fill", options.hiColor) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.style("fill", options.hiColor) - } - - var mouseOut = function() { - var rect = d3.select(this) - var indexValue = rect.attr("index_value") - - var barSelector = "." + "rect-" + indexValue - var selectedBar = d3.selectAll(barSelector) - selectedBar.style("fill", function(d) { return d.hexcolor}) - - var valueSelector = "." + "value-" + indexValue - var selectedValue = d3.selectAll(valueSelector) - selectedValue.style("fill", "#333333") - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.style("fill", "#333") - } - - var bar = svg.selectAll("g.bar") - .data(data) - .enter().append("g") - .attr("class", "bar") - .attr("transform", function(d) { return "translate(0," + y(d.labels) + ")" }) - - bar.append("text") - .attr("x", function(d) { return x(d.units) }) - .attr("y", y.rangeBand() / 2) - .attr("dx", 12) - .attr("dy", ".35em") - .attr("text-anchor", "end") - .attr("index_value", function(d, i) { return "index-" + i }) - .text(function(d) { return format(d.units) }) - .attr("class", function(d, i) { return "value-" + "index-" + i }) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - - bar.append("text") - .attr("x", -5) - .attr("y", y.rangeBand() / 2) - .attr("dx", 0) - .attr("dy", ".35em") - .attr("text-anchor", "end") - .attr("index_value", function(d, i) { return "index-" + i }) - .text(function(d) { return d.labels }) - .attr("class", function(d, i) { return "value-" + "index-" + i }) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - - bar.append("rect") - .attr("width", function(d) { return x(d.units)}) - .attr("height", y.rangeBand()) - .attr("index_value", function(d, i) { return "index-" + i }) - .style("fill", function(d) { return d.hexcolor}) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - .attr("class", function(d, i) { return "rect-" + "index-" + i }) - - svg.append("g") - .attr("class", "x axis") - .call(xAxis) - .append("text") - // .attr("transform", "rotate(-90)") - .attr("y", -20) - .attr("x", m[1]) - .attr("class", "xLabel") - .style("text-anchor", "end") - .text(function() { - if (options.xaxis) return options.xaxis - return - }) -} - -// Pie Chart -// pieOptions = {units: "string", labels: "string", m: [80, 80, 80, 80], w: 800, h: 400, div: "#dogPie", hiColor: "#E4EB29"} -module.exports.d3PieChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - - var width = options.w, - height = options.h, - radius = Math.min(width, height) / 2.3 - - var arc = d3.svg.arc() - .outerRadius(radius - 10) - .innerRadius(0) - - var arcOver = d3.svg.arc() - .outerRadius(radius + .1) - - var pie = d3.layout.pie() - .sort(null) - .value(function(d) { return d.units }) - - var svg = d3.select(options.div).append("svg") - .attr("width", width) - .attr("height", height) - .append("g") - .attr("transform", "translate(" + width / 3 + "," + height / 2 + ")") - - var data = data - - data.forEach(function(d) { - d.units = +d.units - }) - function mouseOver(d) { - d3.select(this).select("path").transition() - .duration(500) - .attr("d", arcOver) - var slice = d3.select(this) - var indexValue = slice.attr("index_value") - - var pathSelector = "." + "path-" + indexValue - var selectedPath = d3.selectAll(pathSelector) - selectedPath.style("fill", options.hiColor) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.transition() - .duration(150) - .style("font-size", "12px").style("font-weight", "bold").style("fill", options.hiColor) - selectedText.attr("class", function(d, i) { return "labels-" + indexValue + " bigg" }) - } - function mouseOut(d) { - d3.select(this).select("path").transition() - .duration(150) - .attr("d", arc) - var slice = d3.select(this) - var indexValue = slice.attr("index_value") - - var pathSelector = "." + "path-" + indexValue - var selectedPath = d3.selectAll(pathSelector) - selectedPath.style("fill", function(d) { return d.data.hexcolor }) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.transition() - .duration(200) - .style("font-size", "10px").style("font-weight", "normal").style("fill", function(d) { return d.hexcolor }) - } - - var g = svg.selectAll(".arc") - .data(pie(data)) - .enter().append("g") - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "slice-" + "index-" + i + " slice arc" }) - .on("mouseover", mouseOver) - .on("mouseout", mouseOut) - - var path = g.append("path") - .attr("d", arc) - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "path-" + "index-" + i }) - .style("fill", function(d) { return d.data.hexcolor}) - .attr("fill", function(d) { return d.data.hexcolor}) - - svg.selectAll("g.labels") - .data(data) - .enter().append("g") // Append legend elements - .append("text") - .attr("text-anchor", "start") - .attr("x", width / 2.5) - .attr("y", function(d, i) { return (height / 2) - i*(data.length * 20)}) - .attr("dx", 0) - .attr("dy", "-140px") // Controls padding to place text above bars - .text(function(d) { return d.labels + ", " + d.units}) - .style("fill", function(d) { return d.hexcolor }) - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "labels-" + "index-" + i + " aLabel "}) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) -} - -// Line Chart -// Adapted from http://bl.ocks.org/1166403 and -// http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html -/// options = {units: "string", labels: "string", m: [80, 100, 120, 100], w: 800, h: 400, div: "#dogLine", yaxis: "cuddlability", hiColor: "#E4EB29"} -module.exports.d3LineChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - var m = options.m - var w = options.w - m[1] - m[3] - var h = options.h - m[0] - m[2] - var data = data - - var x = d3.scale.ordinal().rangeRoundBands([0, w], 1) - x.domain(data.map(function(d) { return d.labels })) - var y = d3.scale.linear().range([0, h]) - y.domain([d3.max(data, function(d) { return d.units }) + 2, 0]) - - var line = d3.svg.line() - .x(function(d, i) { return x(i) }) - .y(function(d) { return y(d) }) - - var graph = d3.select(options.div).append("svg:svg") - .attr("width", w + m[1] + m[3]) - .attr("height", h + m[0] + m[2]) - .append("svg:g") - .attr("transform", "translate(" + m[3] + "," + m[0] + ")") - - var div = d3.select(options.div).append("div") - .attr("class", "tooltip") - .style("opacity", 0) - - // create yAxis - var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(true) - // Add the x-axis. - graph.append("svg:g") - .attr("class", "x axis") - .attr("transform", "translate(0," + h + ")") - .call(xAxis) - .selectAll("text") - .style("text-anchor", "end") - .attr("dy", "-.5em") - .attr('dx', "-1em") - .attr("transform", "rotate(-80)") - .call(xAxis) - - // create left yAxis - var yAxisLeft = d3.svg.axis().scale(y).ticks(4).tickSize(-w).tickSubdivide(true).orient("left") - // Add the y-axis to the left - graph.append("svg:g") - .attr("class", "y axis") - .attr("dx", "25") - .attr("transform", "translate(0,0)") - .call(yAxisLeft) - .append("text") - .attr("transform", "rotate(-90)") - .attr("y", -40) - .attr("dy", 0) - .style("text-anchor", "end") - .text(function() { - if (options.yaxis) return options.yaxis - return - }) - -var lineData = data.map(function(d) { return d.units }) - graph.append("svg:path") - .attr("d", line(lineData)) - .attr("class", "chartLine") - .attr("index_value", function(d, i) { return i }) - // .attr("stroke", options.hiColor).attr("fill", "none") - - graph.selectAll("dot") - .data(data) - .enter().append("circle") - .attr("r", 3.5) - .attr("fill", options.hiColor) - .attr("cx", function(d) { return x(d.labels); }) - .attr("cy", function(d) { return y(d.units); }) - .on("mouseover", function(d) { - div.transition().duration(200).style("opacity", .9) - div .html(d.labels + ", " + d.units) - .style("left", (d3.event.pageX) + "px") - .style("top", (d3.event.pageY - 28) + "px") - }) - .on("mouseout", function(d) { - div.transition().duration(500).style("opacity", 0) - }) -} - - -},{"d3":29}],28:[function(require,module,exports){ -d3 = function() { - var d3 = { - version: "3.2.8" - }; - if (!Date.now) Date.now = function() { - return +new Date(); - }; - var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; - try { - d3_document.createElement("div").style.setProperty("opacity", 0, ""); - } catch (error) { - var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; - d3_element_prototype.setAttribute = function(name, value) { - d3_element_setAttribute.call(this, name, value + ""); - }; - d3_element_prototype.setAttributeNS = function(space, local, value) { - d3_element_setAttributeNS.call(this, space, local, value + ""); - }; - d3_style_prototype.setProperty = function(name, value, priority) { - d3_style_setProperty.call(this, name, value + "", priority); - }; - } - d3.ascending = function(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; - }; - d3.descending = function(a, b) { - return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; - }; - d3.min = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && a > b) a = b; - } else { - while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; - } - return a; - }; - d3.max = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && b > a) a = b; - } else { - while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; - } - return a; - }; - d3.extent = function(array, f) { - var i = -1, n = array.length, a, b, c; - if (arguments.length === 1) { - while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; - while (++i < n) if ((b = array[i]) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } else { - while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - return [ a, c ]; - }; - d3.sum = function(array, f) { - var s = 0, n = array.length, a, i = -1; - if (arguments.length === 1) { - while (++i < n) if (!isNaN(a = +array[i])) s += a; - } else { - while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; - } - return s; - }; - function d3_number(x) { - return x != null && !isNaN(x); - } - d3.mean = function(array, f) { - var n = array.length, a, m = 0, i = -1, j = 0; - if (arguments.length === 1) { - while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; - } else { - while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; - } - return j ? m : undefined; - }; - d3.quantile = function(values, p) { - var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; - return e ? v + e * (values[h] - v) : v; - }; - d3.median = function(array, f) { - if (arguments.length > 1) array = array.map(f); - array = array.filter(d3_number); - return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; - }; - d3.bisector = function(f) { - return { - left: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; - } - return lo; - }, - right: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; - } - return lo; - } - }; - }; - var d3_bisector = d3.bisector(function(d) { - return d; - }); - d3.bisectLeft = d3_bisector.left; - d3.bisect = d3.bisectRight = d3_bisector.right; - d3.shuffle = function(array) { - var m = array.length, t, i; - while (m) { - i = Math.random() * m-- | 0; - t = array[m], array[m] = array[i], array[i] = t; - } - return array; - }; - d3.permute = function(array, indexes) { - var i = indexes.length, permutes = new Array(i); - while (i--) permutes[i] = array[indexes[i]]; - return permutes; - }; - d3.zip = function() { - if (!(n = arguments.length)) return []; - for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { - for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { - zip[j] = arguments[j][i]; - } - } - return zips; - }; - function d3_zipLength(d) { - return d.length; - } - d3.transpose = function(matrix) { - return d3.zip.apply(d3, matrix); - }; - d3.keys = function(map) { - var keys = []; - for (var key in map) keys.push(key); - return keys; - }; - d3.values = function(map) { - var values = []; - for (var key in map) values.push(map[key]); - return values; - }; - d3.entries = function(map) { - var entries = []; - for (var key in map) entries.push({ - key: key, - value: map[key] - }); - return entries; - }; - d3.merge = function(arrays) { - return Array.prototype.concat.apply([], arrays); - }; - d3.range = function(start, stop, step) { - if (arguments.length < 3) { - step = 1; - if (arguments.length < 2) { - stop = start; - start = 0; - } - } - if ((stop - start) / step === Infinity) throw new Error("infinite range"); - var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; - start *= k, stop *= k, step *= k; - if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); - return range; - }; - function d3_range_integerScale(x) { - var k = 1; - while (x * k % 1) k *= 10; - return k; - } - function d3_class(ctor, properties) { - try { - for (var key in properties) { - Object.defineProperty(ctor.prototype, key, { - value: properties[key], - enumerable: false - }); - } - } catch (e) { - ctor.prototype = properties; - } - } - d3.map = function(object) { - var map = new d3_Map(); - if (object instanceof d3_Map) object.forEach(function(key, value) { - map.set(key, value); - }); else for (var key in object) map.set(key, object[key]); - return map; - }; - function d3_Map() {} - d3_class(d3_Map, { - has: function(key) { - return d3_map_prefix + key in this; - }, - get: function(key) { - return this[d3_map_prefix + key]; - }, - set: function(key, value) { - return this[d3_map_prefix + key] = value; - }, - remove: function(key) { - key = d3_map_prefix + key; - return key in this && delete this[key]; - }, - keys: function() { - var keys = []; - this.forEach(function(key) { - keys.push(key); - }); - return keys; - }, - values: function() { - var values = []; - this.forEach(function(key, value) { - values.push(value); - }); - return values; - }, - entries: function() { - var entries = []; - this.forEach(function(key, value) { - entries.push({ - key: key, - value: value - }); - }); - return entries; - }, - forEach: function(f) { - for (var key in this) { - if (key.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, key.substring(1), this[key]); - } - } - } - }); - var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); - d3.nest = function() { - var nest = {}, keys = [], sortKeys = [], sortValues, rollup; - function map(mapType, array, depth) { - if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; - var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; - while (++i < n) { - if (values = valuesByKey.get(keyValue = key(object = array[i]))) { - values.push(object); - } else { - valuesByKey.set(keyValue, [ object ]); - } - } - if (mapType) { - object = mapType(); - setter = function(keyValue, values) { - object.set(keyValue, map(mapType, values, depth)); - }; - } else { - object = {}; - setter = function(keyValue, values) { - object[keyValue] = map(mapType, values, depth); - }; - } - valuesByKey.forEach(setter); - return object; - } - function entries(map, depth) { - if (depth >= keys.length) return map; - var array = [], sortKey = sortKeys[depth++]; - map.forEach(function(key, keyMap) { - array.push({ - key: key, - values: entries(keyMap, depth) - }); - }); - return sortKey ? array.sort(function(a, b) { - return sortKey(a.key, b.key); - }) : array; - } - nest.map = function(array, mapType) { - return map(mapType, array, 0); - }; - nest.entries = function(array) { - return entries(map(d3.map, array, 0), 0); - }; - nest.key = function(d) { - keys.push(d); - return nest; - }; - nest.sortKeys = function(order) { - sortKeys[keys.length - 1] = order; - return nest; - }; - nest.sortValues = function(order) { - sortValues = order; - return nest; - }; - nest.rollup = function(f) { - rollup = f; - return nest; - }; - return nest; - }; - d3.set = function(array) { - var set = new d3_Set(); - if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); - return set; - }; - function d3_Set() {} - d3_class(d3_Set, { - has: function(value) { - return d3_map_prefix + value in this; - }, - add: function(value) { - this[d3_map_prefix + value] = true; - return value; - }, - remove: function(value) { - value = d3_map_prefix + value; - return value in this && delete this[value]; - }, - values: function() { - var values = []; - this.forEach(function(value) { - values.push(value); - }); - return values; - }, - forEach: function(f) { - for (var value in this) { - if (value.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, value.substring(1)); - } - } - } - }); - d3.behavior = {}; - d3.rebind = function(target, source) { - var i = 1, n = arguments.length, method; - while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); - return target; - }; - function d3_rebind(target, source, method) { - return function() { - var value = method.apply(source, arguments); - return value === source ? target : value; - }; - } - function d3_vendorSymbol(object, name) { - if (name in object) return name; - name = name.charAt(0).toUpperCase() + name.substring(1); - for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { - var prefixName = d3_vendorPrefixes[i] + name; - if (prefixName in object) return prefixName; - } - } - var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; - var d3_array = d3_arraySlice; - function d3_arrayCopy(pseudoarray) { - var i = pseudoarray.length, array = new Array(i); - while (i--) array[i] = pseudoarray[i]; - return array; - } - function d3_arraySlice(pseudoarray) { - return Array.prototype.slice.call(pseudoarray); - } - try { - d3_array(d3_documentElement.childNodes)[0].nodeType; - } catch (e) { - d3_array = d3_arrayCopy; - } - function d3_noop() {} - d3.dispatch = function() { - var dispatch = new d3_dispatch(), i = -1, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - return dispatch; - }; - function d3_dispatch() {} - d3_dispatch.prototype.on = function(type, listener) { - var i = type.indexOf("."), name = ""; - if (i >= 0) { - name = type.substring(i + 1); - type = type.substring(0, i); - } - if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); - if (arguments.length === 2) { - if (listener == null) for (type in this) { - if (this.hasOwnProperty(type)) this[type].on(name, null); - } - return this; - } - }; - function d3_dispatch_event(dispatch) { - var listeners = [], listenerByName = new d3_Map(); - function event() { - var z = listeners, i = -1, n = z.length, l; - while (++i < n) if (l = z[i].on) l.apply(this, arguments); - return dispatch; - } - event.on = function(name, listener) { - var l = listenerByName.get(name), i; - if (arguments.length < 2) return l && l.on; - if (l) { - l.on = null; - listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); - listenerByName.remove(name); - } - if (listener) listeners.push(listenerByName.set(name, { - on: listener - })); - return dispatch; - }; - return event; - } - d3.event = null; - function d3_eventPreventDefault() { - d3.event.preventDefault(); - } - function d3_eventSource() { - var e = d3.event, s; - while (s = e.sourceEvent) e = s; - return e; - } - function d3_eventDispatch(target) { - var dispatch = new d3_dispatch(), i = 0, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - dispatch.of = function(thiz, argumentz) { - return function(e1) { - try { - var e0 = e1.sourceEvent = d3.event; - e1.target = target; - d3.event = e1; - dispatch[e1.type].apply(thiz, argumentz); - } finally { - d3.event = e0; - } - }; - }; - return dispatch; - } - d3.requote = function(s) { - return s.replace(d3_requote_re, "\\$&"); - }; - var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; - var d3_subclass = {}.__proto__ ? function(object, prototype) { - object.__proto__ = prototype; - } : function(object, prototype) { - for (var property in prototype) object[property] = prototype[property]; - }; - function d3_selection(groups) { - d3_subclass(groups, d3_selectionPrototype); - return groups; - } - var d3_select = function(s, n) { - return n.querySelector(s); - }, d3_selectAll = function(s, n) { - return n.querySelectorAll(s); - }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { - return d3_selectMatcher.call(n, s); - }; - if (typeof Sizzle === "function") { - d3_select = function(s, n) { - return Sizzle(s, n)[0] || null; - }; - d3_selectAll = function(s, n) { - return Sizzle.uniqueSort(Sizzle(s, n)); - }; - d3_selectMatches = Sizzle.matchesSelector; - } - d3.selection = function() { - return d3_selectionRoot; - }; - var d3_selectionPrototype = d3.selection.prototype = []; - d3_selectionPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, group, node; - selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(subnode = selector.call(node, node.__data__, i, j)); - if (subnode && "__data__" in node) subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_selector(selector) { - return typeof selector === "function" ? selector : function() { - return d3_select(selector, this); - }; - } - d3_selectionPrototype.selectAll = function(selector) { - var subgroups = [], subgroup, node; - selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); - subgroup.parentNode = node; - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_selectorAll(selector) { - return typeof selector === "function" ? selector : function() { - return d3_selectAll(selector, this); - }; - } - var d3_nsPrefix = { - svg: "http://www.w3.org/2000/svg", - xhtml: "http://www.w3.org/1999/xhtml", - xlink: "http://www.w3.org/1999/xlink", - xml: "http://www.w3.org/XML/1998/namespace", - xmlns: "http://www.w3.org/2000/xmlns/" - }; - d3.ns = { - prefix: d3_nsPrefix, - qualify: function(name) { - var i = name.indexOf(":"), prefix = name; - if (i >= 0) { - prefix = name.substring(0, i); - name = name.substring(i + 1); - } - return d3_nsPrefix.hasOwnProperty(prefix) ? { - space: d3_nsPrefix[prefix], - local: name - } : name; - } - }; - d3_selectionPrototype.attr = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(); - name = d3.ns.qualify(name); - return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); - } - for (value in name) this.each(d3_selection_attr(value, name[value])); - return this; - } - return this.each(d3_selection_attr(name, value)); - }; - function d3_selection_attr(name, value) { - name = d3.ns.qualify(name); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - function attrConstant() { - this.setAttribute(name, value); - } - function attrConstantNS() { - this.setAttributeNS(name.space, name.local, value); - } - function attrFunction() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); - } - function attrFunctionNS() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); - } - return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; - } - function d3_collapse(s) { - return s.trim().replace(/\s+/g, " "); - } - d3_selectionPrototype.classed = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; - if (value = node.classList) { - while (++i < n) if (!value.contains(name[i])) return false; - } else { - value = node.getAttribute("class"); - while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; - } - return true; - } - for (value in name) this.each(d3_selection_classed(value, name[value])); - return this; - } - return this.each(d3_selection_classed(name, value)); - }; - function d3_selection_classedRe(name) { - return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); - } - function d3_selection_classed(name, value) { - name = name.trim().split(/\s+/).map(d3_selection_classedName); - var n = name.length; - function classedConstant() { - var i = -1; - while (++i < n) name[i](this, value); - } - function classedFunction() { - var i = -1, x = value.apply(this, arguments); - while (++i < n) name[i](this, x); - } - return typeof value === "function" ? classedFunction : classedConstant; - } - function d3_selection_classedName(name) { - var re = d3_selection_classedRe(name); - return function(node, value) { - if (c = node.classList) return value ? c.add(name) : c.remove(name); - var c = node.getAttribute("class") || ""; - if (value) { - re.lastIndex = 0; - if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); - } else { - node.setAttribute("class", d3_collapse(c.replace(re, " "))); - } - }; - } - d3_selectionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); - return this; - } - if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); - priority = ""; - } - return this.each(d3_selection_style(name, value, priority)); - }; - function d3_selection_style(name, value, priority) { - function styleNull() { - this.style.removeProperty(name); - } - function styleConstant() { - this.style.setProperty(name, value, priority); - } - function styleFunction() { - var x = value.apply(this, arguments); - if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); - } - return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; - } - d3_selectionPrototype.property = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") return this.node()[name]; - for (value in name) this.each(d3_selection_property(value, name[value])); - return this; - } - return this.each(d3_selection_property(name, value)); - }; - function d3_selection_property(name, value) { - function propertyNull() { - delete this[name]; - } - function propertyConstant() { - this[name] = value; - } - function propertyFunction() { - var x = value.apply(this, arguments); - if (x == null) delete this[name]; else this[name] = x; - } - return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; - } - d3_selectionPrototype.text = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.textContent = v == null ? "" : v; - } : value == null ? function() { - this.textContent = ""; - } : function() { - this.textContent = value; - }) : this.node().textContent; - }; - d3_selectionPrototype.html = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.innerHTML = v == null ? "" : v; - } : value == null ? function() { - this.innerHTML = ""; - } : function() { - this.innerHTML = value; - }) : this.node().innerHTML; - }; - d3_selectionPrototype.append = function(name) { - name = d3_selection_creator(name); - return this.select(function() { - return this.appendChild(name.apply(this, arguments)); - }); - }; - function d3_selection_creator(name) { - return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { - return d3_document.createElementNS(name.space, name.local); - } : function() { - return d3_document.createElementNS(this.namespaceURI, name); - }; - } - d3_selectionPrototype.insert = function(name, before) { - name = d3_selection_creator(name); - before = d3_selection_selector(before); - return this.select(function() { - return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); - }); - }; - d3_selectionPrototype.remove = function() { - return this.each(function() { - var parent = this.parentNode; - if (parent) parent.removeChild(this); - }); - }; - d3_selectionPrototype.data = function(value, key) { - var i = -1, n = this.length, group, node; - if (!arguments.length) { - value = new Array(n = (group = this[0]).length); - while (++i < n) { - if (node = group[i]) { - value[i] = node.__data__; - } - } - return value; - } - function bind(group, groupData) { - var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; - if (key) { - var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; - for (i = -1; ++i < n; ) { - keyValue = key.call(node = group[i], node.__data__, i); - if (nodeByKeyValue.has(keyValue)) { - exitNodes[i] = node; - } else { - nodeByKeyValue.set(keyValue, node); - } - keyValues.push(keyValue); - } - for (i = -1; ++i < m; ) { - keyValue = key.call(groupData, nodeData = groupData[i], i); - if (node = nodeByKeyValue.get(keyValue)) { - updateNodes[i] = node; - node.__data__ = nodeData; - } else if (!dataByKeyValue.has(keyValue)) { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - dataByKeyValue.set(keyValue, nodeData); - nodeByKeyValue.remove(keyValue); - } - for (i = -1; ++i < n; ) { - if (nodeByKeyValue.has(keyValues[i])) { - exitNodes[i] = group[i]; - } - } - } else { - for (i = -1; ++i < n0; ) { - node = group[i]; - nodeData = groupData[i]; - if (node) { - node.__data__ = nodeData; - updateNodes[i] = node; - } else { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - } - for (;i < m; ++i) { - enterNodes[i] = d3_selection_dataNode(groupData[i]); - } - for (;i < n; ++i) { - exitNodes[i] = group[i]; - } - } - enterNodes.update = updateNodes; - enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; - enter.push(enterNodes); - update.push(updateNodes); - exit.push(exitNodes); - } - var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); - if (typeof value === "function") { - while (++i < n) { - bind(group = this[i], value.call(group, group.parentNode.__data__, i)); - } - } else { - while (++i < n) { - bind(group = this[i], value); - } - } - update.enter = function() { - return enter; - }; - update.exit = function() { - return exit; - }; - return update; - }; - function d3_selection_dataNode(data) { - return { - __data__: data - }; - } - d3_selectionPrototype.datum = function(value) { - return arguments.length ? this.property("__data__", value) : this.property("__data__"); - }; - d3_selectionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_filter(selector) { - return function() { - return d3_selectMatches(this, selector); - }; - } - d3_selectionPrototype.order = function() { - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { - if (node = group[i]) { - if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); - next = node; - } - } - } - return this; - }; - d3_selectionPrototype.sort = function(comparator) { - comparator = d3_selection_sortComparator.apply(this, arguments); - for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); - return this.order(); - }; - function d3_selection_sortComparator(comparator) { - if (!arguments.length) comparator = d3.ascending; - return function(a, b) { - return a && b ? comparator(a.__data__, b.__data__) : !a - !b; - }; - } - d3_selectionPrototype.each = function(callback) { - return d3_selection_each(this, function(node, i, j) { - callback.call(node, node.__data__, i, j); - }); - }; - function d3_selection_each(groups, callback) { - for (var j = 0, m = groups.length; j < m; j++) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { - if (node = group[i]) callback(node, i, j); - } - } - return groups; - } - d3_selectionPrototype.call = function(callback) { - var args = d3_array(arguments); - callback.apply(args[0] = this, args); - return this; - }; - d3_selectionPrototype.empty = function() { - return !this.node(); - }; - d3_selectionPrototype.node = function() { - for (var j = 0, m = this.length; j < m; j++) { - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - var node = group[i]; - if (node) return node; - } - } - return null; - }; - d3_selectionPrototype.size = function() { - var n = 0; - this.each(function() { - ++n; - }); - return n; - }; - function d3_selection_enter(selection) { - d3_subclass(selection, d3_selection_enterPrototype); - return selection; - } - var d3_selection_enterPrototype = []; - d3.selection.enter = d3_selection_enter; - d3.selection.enter.prototype = d3_selection_enterPrototype; - d3_selection_enterPrototype.append = d3_selectionPrototype.append; - d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; - d3_selection_enterPrototype.node = d3_selectionPrototype.node; - d3_selection_enterPrototype.call = d3_selectionPrototype.call; - d3_selection_enterPrototype.size = d3_selectionPrototype.size; - d3_selection_enterPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, upgroup, group, node; - for (var j = -1, m = this.length; ++j < m; ) { - upgroup = (group = this[j]).update; - subgroups.push(subgroup = []); - subgroup.parentNode = group.parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); - subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - return d3_selection(subgroups); - }; - d3_selection_enterPrototype.insert = function(name, before) { - if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); - return d3_selectionPrototype.insert.call(this, name, before); - }; - function d3_selection_enterInsertBefore(enter) { - var i0, j0; - return function(d, i, j) { - var group = enter[j].update, n = group.length, node; - if (j != j0) j0 = j, i0 = 0; - if (i >= i0) i0 = i + 1; - while (!(node = group[i0]) && ++i0 < n) ; - return node; - }; - } - d3_selectionPrototype.transition = function() { - var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { - time: Date.now(), - ease: d3_ease_cubicInOut, - delay: 0, - duration: 250 - }; - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) d3_transitionNode(node, i, id, transition); - subgroup.push(node); - } - } - return d3_transition(subgroups, id); - }; - d3.select = function(node) { - var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; - group.parentNode = d3_documentElement; - return d3_selection([ group ]); - }; - d3.selectAll = function(nodes) { - var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); - group.parentNode = d3_documentElement; - return d3_selection([ group ]); - }; - var d3_selectionRoot = d3.select(d3_documentElement); - d3_selectionPrototype.on = function(type, listener, capture) { - var n = arguments.length; - if (n < 3) { - if (typeof type !== "string") { - if (n < 2) listener = false; - for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); - return this; - } - if (n < 2) return (n = this.node()["__on" + type]) && n._; - capture = false; - } - return this.each(d3_selection_on(type, listener, capture)); - }; - function d3_selection_on(type, listener, capture) { - var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; - if (i > 0) type = type.substring(0, i); - var filter = d3_selection_onFilters.get(type); - if (filter) type = filter, wrap = d3_selection_onFilter; - function onRemove() { - var l = this[name]; - if (l) { - this.removeEventListener(type, l, l.$); - delete this[name]; - } - } - function onAdd() { - var l = wrap(listener, d3_array(arguments)); - onRemove.call(this); - this.addEventListener(type, this[name] = l, l.$ = capture); - l._ = listener; - } - function removeAll() { - var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; - for (var name in this) { - if (match = name.match(re)) { - var l = this[name]; - this.removeEventListener(match[1], l, l.$); - delete this[name]; - } - } - } - return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; - } - var d3_selection_onFilters = d3.map({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }); - d3_selection_onFilters.forEach(function(k) { - if ("on" + k in d3_document) d3_selection_onFilters.remove(k); - }); - function d3_selection_onListener(listener, argumentz) { - return function(e) { - var o = d3.event; - d3.event = e; - argumentz[0] = this.__data__; - try { - listener.apply(this, argumentz); - } finally { - d3.event = o; - } - }; - } - function d3_selection_onFilter(listener, argumentz) { - var l = d3_selection_onListener(listener, argumentz); - return function(e) { - var target = this, related = e.relatedTarget; - if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { - l.call(target, e); - } - }; - } - var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; - function d3_event_dragSuppress() { - var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; - style[d3_event_dragSelect] = "none"; - return function(suppressClick) { - w.on(name, null); - style[d3_event_dragSelect] = select; - if (suppressClick) { - function off() { - w.on(click, null); - } - w.on(click, function() { - d3_eventPreventDefault(); - off(); - }, true); - setTimeout(off, 0); - } - }; - } - d3.mouse = function(container) { - return d3_mousePoint(container, d3_eventSource()); - }; - var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; - function d3_mousePoint(container, e) { - var svg = container.ownerSVGElement || container; - if (svg.createSVGPoint) { - var point = svg.createSVGPoint(); - if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { - svg = d3.select("body").append("svg").style({ - position: "absolute", - top: 0, - left: 0, - margin: 0, - padding: 0, - border: "none" - }, "important"); - var ctm = svg[0][0].getScreenCTM(); - d3_mouse_bug44083 = !(ctm.f || ctm.e); - svg.remove(); - } - if (d3_mouse_bug44083) { - point.x = e.pageX; - point.y = e.pageY; - } else { - point.x = e.clientX; - point.y = e.clientY; - } - point = point.matrixTransform(container.getScreenCTM().inverse()); - return [ point.x, point.y ]; - } - var rect = container.getBoundingClientRect(); - return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; - } - d3.touches = function(container, touches) { - if (arguments.length < 2) touches = d3_eventSource().touches; - return touches ? d3_array(touches).map(function(touch) { - var point = d3_mousePoint(container, touch); - point.identifier = touch.identifier; - return point; - }) : []; - }; - d3.behavior.drag = function() { - var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); - function drag() { - this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); - } - function touchid() { - return d3.event.changedTouches[0].identifier; - } - function touchposition(parent, id) { - return d3.touches(parent).filter(function(p) { - return p.identifier === id; - })[0]; - } - function dragstart(id, position, move, end) { - return function() { - var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); - if (origin) { - offset = origin.apply(target, arguments); - offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; - } else { - offset = [ 0, 0 ]; - } - event_({ - type: "dragstart" - }); - function moved() { - if (!parent) return ended(); - var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; - dragged |= dx | dy; - origin_ = p; - event_({ - type: "drag", - x: p[0] + offset[0], - y: p[1] + offset[1], - dx: dx, - dy: dy - }); - } - function ended() { - w.on(move + "." + drag, null).on(end + "." + drag, null); - dragRestore(dragged && d3.event.target === eventTarget); - event_({ - type: "dragend" - }); - } - }; - } - drag.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return drag; - }; - return d3.rebind(drag, event, "on"); - }; - d3.behavior.zoom = function() { - var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1; - function zoom() { - this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); - } - zoom.translate = function(x) { - if (!arguments.length) return translate; - translate = x.map(Number); - rescale(); - return zoom; - }; - zoom.scale = function(x) { - if (!arguments.length) return scale; - scale = +x; - rescale(); - return zoom; - }; - zoom.scaleExtent = function(x) { - if (!arguments.length) return scaleExtent; - scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); - return zoom; - }; - zoom.x = function(z) { - if (!arguments.length) return x1; - x1 = z; - x0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - zoom.y = function(z) { - if (!arguments.length) return y1; - y1 = z; - y0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - function location(p) { - return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; - } - function point(l) { - return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; - } - function scaleTo(s) { - scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); - } - function translateTo(p, l) { - l = point(l); - translate[0] += p[0] - l[0]; - translate[1] += p[1] - l[1]; - } - function rescale() { - if (x1) x1.domain(x0.range().map(function(x) { - return (x - translate[0]) / scale; - }).map(x0.invert)); - if (y1) y1.domain(y0.range().map(function(y) { - return (y - translate[1]) / scale; - }).map(y0.invert)); - } - function dispatch(event) { - rescale(); - event({ - type: "zoom", - scale: scale, - translate: translate - }); - } - function mousedowned() { - var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); - function moved() { - dragged = 1; - translateTo(d3.mouse(target), l); - dispatch(event_); - } - function ended() { - w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); - dragRestore(dragged && d3.event.target === eventTarget); - } - } - function touchstarted() { - var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); - started(); - function relocate() { - var touches = d3.touches(target); - scale0 = scale; - locations0 = {}; - touches.forEach(function(t) { - locations0[t.identifier] = location(t); - }); - return touches; - } - function started() { - var now = Date.now(), touches = relocate(); - if (touches.length === 1) { - if (now - touchtime < 500) { - var p = touches[0], l = locations0[p.identifier]; - scaleTo(scale * 2); - translateTo(p, l); - d3_eventPreventDefault(); - dispatch(event_); - } - touchtime = now; - } else if (touches.length > 1) { - var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; - distance0 = dx * dx + dy * dy; - } - } - function moved() { - var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier]; - if (p1 = touches[1]) { - var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale; - if (scale1 == null) { - var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; - scale1 = distance0 && Math.sqrt(distance1 / distance0); - } - p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; - l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; - scaleTo(scale1 * scale0); - } - touchtime = null; - translateTo(p0, l0); - dispatch(event_); - } - function ended() { - if (d3.event.touches.length) { - relocate(); - } else { - w.on(touchmove, null).on(touchend, null); - t.on(mousedown, mousedowned).on(touchstart, touchstarted); - dragRestore(); - } - } - } - function mousewheeled() { - d3_eventPreventDefault(); - if (!translate0) translate0 = location(d3.mouse(this)); - scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); - translateTo(d3.mouse(this), translate0); - dispatch(event.of(this, arguments)); - } - function mousewheelreset() { - translate0 = null; - } - function dblclicked() { - var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; - scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); - translateTo(p, l); - dispatch(event.of(this, arguments)); - } - return d3.rebind(zoom, event, "on"); - }; - var d3_behavior_zoomInfinity = [ 0, Infinity ]; - var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { - return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); - }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { - return d3.event.wheelDelta; - }, "mousewheel") : (d3_behavior_zoomDelta = function() { - return -d3.event.detail; - }, "MozMousePixelScroll"); - function d3_Color() {} - d3_Color.prototype.toString = function() { - return this.rgb() + ""; - }; - d3.hsl = function(h, s, l) { - return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); - }; - function d3_hsl(h, s, l) { - return new d3_Hsl(h, s, l); - } - function d3_Hsl(h, s, l) { - this.h = h; - this.s = s; - this.l = l; - } - var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); - d3_hslPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, this.l / k); - }; - d3_hslPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, k * this.l); - }; - d3_hslPrototype.rgb = function() { - return d3_hsl_rgb(this.h, this.s, this.l); - }; - function d3_hsl_rgb(h, s, l) { - var m1, m2; - h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; - s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; - l = l < 0 ? 0 : l > 1 ? 1 : l; - m2 = l <= .5 ? l * (1 + s) : l + s - l * s; - m1 = 2 * l - m2; - function v(h) { - if (h > 360) h -= 360; else if (h < 0) h += 360; - if (h < 60) return m1 + (m2 - m1) * h / 60; - if (h < 180) return m2; - if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; - return m1; - } - function vv(h) { - return Math.round(v(h) * 255); - } - return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); - } - var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; - function d3_sgn(x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; - } - function d3_acos(x) { - return x > 1 ? 0 : x < -1 ? π : Math.acos(x); - } - function d3_asin(x) { - return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); - } - function d3_sinh(x) { - return (Math.exp(x) - Math.exp(-x)) / 2; - } - function d3_cosh(x) { - return (Math.exp(x) + Math.exp(-x)) / 2; - } - function d3_haversin(x) { - return (x = Math.sin(x / 2)) * x; - } - d3.hcl = function(h, c, l) { - return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); - }; - function d3_hcl(h, c, l) { - return new d3_Hcl(h, c, l); - } - function d3_Hcl(h, c, l) { - this.h = h; - this.c = c; - this.l = l; - } - var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); - d3_hclPrototype.brighter = function(k) { - return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.darker = function(k) { - return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.rgb = function() { - return d3_hcl_lab(this.h, this.c, this.l).rgb(); - }; - function d3_hcl_lab(h, c, l) { - if (isNaN(h)) h = 0; - if (isNaN(c)) c = 0; - return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); - } - d3.lab = function(l, a, b) { - return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); - }; - function d3_lab(l, a, b) { - return new d3_Lab(l, a, b); - } - function d3_Lab(l, a, b) { - this.l = l; - this.a = a; - this.b = b; - } - var d3_lab_K = 18; - var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; - var d3_labPrototype = d3_Lab.prototype = new d3_Color(); - d3_labPrototype.brighter = function(k) { - return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.darker = function(k) { - return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.rgb = function() { - return d3_lab_rgb(this.l, this.a, this.b); - }; - function d3_lab_rgb(l, a, b) { - var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; - x = d3_lab_xyz(x) * d3_lab_X; - y = d3_lab_xyz(y) * d3_lab_Y; - z = d3_lab_xyz(z) * d3_lab_Z; - return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); - } - function d3_lab_hcl(l, a, b) { - return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); - } - function d3_lab_xyz(x) { - return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; - } - function d3_xyz_lab(x) { - return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; - } - function d3_xyz_rgb(r) { - return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); - } - d3.rgb = function(r, g, b) { - return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); - }; - function d3_rgbNumber(value) { - return d3_rgb(value >> 16, value >> 8 & 255, value & 255); - } - function d3_rgbString(value) { - return d3_rgbNumber(value) + ""; - } - function d3_rgb(r, g, b) { - return new d3_Rgb(r, g, b); - } - function d3_Rgb(r, g, b) { - this.r = r; - this.g = g; - this.b = b; - } - var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); - d3_rgbPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - var r = this.r, g = this.g, b = this.b, i = 30; - if (!r && !g && !b) return d3_rgb(i, i, i); - if (r && r < i) r = i; - if (g && g < i) g = i; - if (b && b < i) b = i; - return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); - }; - d3_rgbPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); - }; - d3_rgbPrototype.hsl = function() { - return d3_rgb_hsl(this.r, this.g, this.b); - }; - d3_rgbPrototype.toString = function() { - return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); - }; - function d3_rgb_hex(v) { - return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); - } - function d3_rgb_parse(format, rgb, hsl) { - var r = 0, g = 0, b = 0, m1, m2, name; - m1 = /([a-z]+)\((.*)\)/i.exec(format); - if (m1) { - m2 = m1[2].split(","); - switch (m1[1]) { - case "hsl": - { - return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); - } - - case "rgb": - { - return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); - } - } - } - if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); - if (format != null && format.charAt(0) === "#") { - if (format.length === 4) { - r = format.charAt(1); - r += r; - g = format.charAt(2); - g += g; - b = format.charAt(3); - b += b; - } else if (format.length === 7) { - r = format.substring(1, 3); - g = format.substring(3, 5); - b = format.substring(5, 7); - } - r = parseInt(r, 16); - g = parseInt(g, 16); - b = parseInt(b, 16); - } - return rgb(r, g, b); - } - function d3_rgb_hsl(r, g, b) { - var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; - if (d) { - s = l < .5 ? d / (max + min) : d / (2 - max - min); - if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; - h *= 60; - } else { - h = NaN; - s = l > 0 && l < 1 ? 0 : h; - } - return d3_hsl(h, s, l); - } - function d3_rgb_lab(r, g, b) { - r = d3_rgb_xyz(r); - g = d3_rgb_xyz(g); - b = d3_rgb_xyz(b); - var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); - return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); - } - function d3_rgb_xyz(r) { - return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); - } - function d3_rgb_parseNumber(c) { - var f = parseFloat(c); - return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; - } - var d3_rgb_names = d3.map({ - aliceblue: 15792383, - antiquewhite: 16444375, - aqua: 65535, - aquamarine: 8388564, - azure: 15794175, - beige: 16119260, - bisque: 16770244, - black: 0, - blanchedalmond: 16772045, - blue: 255, - blueviolet: 9055202, - brown: 10824234, - burlywood: 14596231, - cadetblue: 6266528, - chartreuse: 8388352, - chocolate: 13789470, - coral: 16744272, - cornflowerblue: 6591981, - cornsilk: 16775388, - crimson: 14423100, - cyan: 65535, - darkblue: 139, - darkcyan: 35723, - darkgoldenrod: 12092939, - darkgray: 11119017, - darkgreen: 25600, - darkgrey: 11119017, - darkkhaki: 12433259, - darkmagenta: 9109643, - darkolivegreen: 5597999, - darkorange: 16747520, - darkorchid: 10040012, - darkred: 9109504, - darksalmon: 15308410, - darkseagreen: 9419919, - darkslateblue: 4734347, - darkslategray: 3100495, - darkslategrey: 3100495, - darkturquoise: 52945, - darkviolet: 9699539, - deeppink: 16716947, - deepskyblue: 49151, - dimgray: 6908265, - dimgrey: 6908265, - dodgerblue: 2003199, - firebrick: 11674146, - floralwhite: 16775920, - forestgreen: 2263842, - fuchsia: 16711935, - gainsboro: 14474460, - ghostwhite: 16316671, - gold: 16766720, - goldenrod: 14329120, - gray: 8421504, - green: 32768, - greenyellow: 11403055, - grey: 8421504, - honeydew: 15794160, - hotpink: 16738740, - indianred: 13458524, - indigo: 4915330, - ivory: 16777200, - khaki: 15787660, - lavender: 15132410, - lavenderblush: 16773365, - lawngreen: 8190976, - lemonchiffon: 16775885, - lightblue: 11393254, - lightcoral: 15761536, - lightcyan: 14745599, - lightgoldenrodyellow: 16448210, - lightgray: 13882323, - lightgreen: 9498256, - lightgrey: 13882323, - lightpink: 16758465, - lightsalmon: 16752762, - lightseagreen: 2142890, - lightskyblue: 8900346, - lightslategray: 7833753, - lightslategrey: 7833753, - lightsteelblue: 11584734, - lightyellow: 16777184, - lime: 65280, - limegreen: 3329330, - linen: 16445670, - magenta: 16711935, - maroon: 8388608, - mediumaquamarine: 6737322, - mediumblue: 205, - mediumorchid: 12211667, - mediumpurple: 9662683, - mediumseagreen: 3978097, - mediumslateblue: 8087790, - mediumspringgreen: 64154, - mediumturquoise: 4772300, - mediumvioletred: 13047173, - midnightblue: 1644912, - mintcream: 16121850, - mistyrose: 16770273, - moccasin: 16770229, - navajowhite: 16768685, - navy: 128, - oldlace: 16643558, - olive: 8421376, - olivedrab: 7048739, - orange: 16753920, - orangered: 16729344, - orchid: 14315734, - palegoldenrod: 15657130, - palegreen: 10025880, - paleturquoise: 11529966, - palevioletred: 14381203, - papayawhip: 16773077, - peachpuff: 16767673, - peru: 13468991, - pink: 16761035, - plum: 14524637, - powderblue: 11591910, - purple: 8388736, - red: 16711680, - rosybrown: 12357519, - royalblue: 4286945, - saddlebrown: 9127187, - salmon: 16416882, - sandybrown: 16032864, - seagreen: 3050327, - seashell: 16774638, - sienna: 10506797, - silver: 12632256, - skyblue: 8900331, - slateblue: 6970061, - slategray: 7372944, - slategrey: 7372944, - snow: 16775930, - springgreen: 65407, - steelblue: 4620980, - tan: 13808780, - teal: 32896, - thistle: 14204888, - tomato: 16737095, - turquoise: 4251856, - violet: 15631086, - wheat: 16113331, - white: 16777215, - whitesmoke: 16119285, - yellow: 16776960, - yellowgreen: 10145074 - }); - d3_rgb_names.forEach(function(key, value) { - d3_rgb_names.set(key, d3_rgbNumber(value)); - }); - function d3_functor(v) { - return typeof v === "function" ? v : function() { - return v; - }; - } - d3.functor = d3_functor; - function d3_identity(d) { - return d; - } - d3.xhr = d3_xhrType(d3_identity); - function d3_xhrType(response) { - return function(url, mimeType, callback) { - if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, - mimeType = null; - return d3_xhr(url, mimeType, response, callback); - }; - } - function d3_xhr(url, mimeType, response, callback) { - var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; - if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); - "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { - request.readyState > 3 && respond(); - }; - function respond() { - var status = request.status, result; - if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { - try { - result = response.call(xhr, request); - } catch (e) { - dispatch.error.call(xhr, e); - return; - } - dispatch.load.call(xhr, result); - } else { - dispatch.error.call(xhr, request); - } - } - request.onprogress = function(event) { - var o = d3.event; - d3.event = event; - try { - dispatch.progress.call(xhr, request); - } finally { - d3.event = o; - } - }; - xhr.header = function(name, value) { - name = (name + "").toLowerCase(); - if (arguments.length < 2) return headers[name]; - if (value == null) delete headers[name]; else headers[name] = value + ""; - return xhr; - }; - xhr.mimeType = function(value) { - if (!arguments.length) return mimeType; - mimeType = value == null ? null : value + ""; - return xhr; - }; - xhr.responseType = function(value) { - if (!arguments.length) return responseType; - responseType = value; - return xhr; - }; - xhr.response = function(value) { - response = value; - return xhr; - }; - [ "get", "post" ].forEach(function(method) { - xhr[method] = function() { - return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); - }; - }); - xhr.send = function(method, data, callback) { - if (arguments.length === 2 && typeof data === "function") callback = data, data = null; - request.open(method, url, true); - if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; - if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); - if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); - if (responseType != null) request.responseType = responseType; - if (callback != null) xhr.on("error", callback).on("load", function(request) { - callback(null, request); - }); - request.send(data == null ? null : data); - return xhr; - }; - xhr.abort = function() { - request.abort(); - return xhr; - }; - d3.rebind(xhr, dispatch, "on"); - return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); - } - function d3_xhr_fixCallback(callback) { - return callback.length === 1 ? function(error, request) { - callback(error == null ? request : null); - } : callback; - } - d3.dsv = function(delimiter, mimeType) { - var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); - function dsv(url, row, callback) { - if (arguments.length < 3) callback = row, row = null; - var xhr = d3.xhr(url, mimeType, callback); - xhr.row = function(_) { - return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; - }; - return xhr.row(row); - } - function response(request) { - return dsv.parse(request.responseText); - } - function typedResponse(f) { - return function(request) { - return dsv.parse(request.responseText, f); - }; - } - dsv.parse = function(text, f) { - var o; - return dsv.parseRows(text, function(row, i) { - if (o) return o(row, i - 1); - var a = new Function("d", "return {" + row.map(function(name, i) { - return JSON.stringify(name) + ": d[" + i + "]"; - }).join(",") + "}"); - o = f ? function(row, i) { - return f(a(row), i); - } : a; - }); - }; - dsv.parseRows = function(text, f) { - var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; - function token() { - if (I >= N) return EOF; - if (eol) return eol = false, EOL; - var j = I; - if (text.charCodeAt(j) === 34) { - var i = j; - while (i++ < N) { - if (text.charCodeAt(i) === 34) { - if (text.charCodeAt(i + 1) !== 34) break; - ++i; - } - } - I = i + 2; - var c = text.charCodeAt(i + 1); - if (c === 13) { - eol = true; - if (text.charCodeAt(i + 2) === 10) ++I; - } else if (c === 10) { - eol = true; - } - return text.substring(j + 1, i).replace(/""/g, '"'); - } - while (I < N) { - var c = text.charCodeAt(I++), k = 1; - if (c === 10) eol = true; else if (c === 13) { - eol = true; - if (text.charCodeAt(I) === 10) ++I, ++k; - } else if (c !== delimiterCode) continue; - return text.substring(j, I - k); - } - return text.substring(j); - } - while ((t = token()) !== EOF) { - var a = []; - while (t !== EOL && t !== EOF) { - a.push(t); - t = token(); - } - if (f && !(a = f(a, n++))) continue; - rows.push(a); - } - return rows; - }; - dsv.format = function(rows) { - if (Array.isArray(rows[0])) return dsv.formatRows(rows); - var fieldSet = new d3_Set(), fields = []; - rows.forEach(function(row) { - for (var field in row) { - if (!fieldSet.has(field)) { - fields.push(fieldSet.add(field)); - } - } - }); - return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { - return fields.map(function(field) { - return formatValue(row[field]); - }).join(delimiter); - })).join("\n"); - }; - dsv.formatRows = function(rows) { - return rows.map(formatRow).join("\n"); - }; - function formatRow(row) { - return row.map(formatValue).join(delimiter); - } - function formatValue(text) { - return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; - } - return dsv; - }; - d3.csv = d3.dsv(",", "text/csv"); - d3.tsv = d3.dsv(" ", "text/tab-separated-values"); - var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { - setTimeout(callback, 17); - }; - d3.timer = function(callback, delay, then) { - var n = arguments.length; - if (n < 2) delay = 0; - if (n < 3) then = Date.now(); - var time = then + delay, timer = { - callback: callback, - time: time, - next: null - }; - if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; - d3_timer_queueTail = timer; - if (!d3_timer_interval) { - d3_timer_timeout = clearTimeout(d3_timer_timeout); - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - }; - function d3_timer_step() { - var now = d3_timer_mark(), delay = d3_timer_sweep() - now; - if (delay > 24) { - if (isFinite(delay)) { - clearTimeout(d3_timer_timeout); - d3_timer_timeout = setTimeout(d3_timer_step, delay); - } - d3_timer_interval = 0; - } else { - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - } - d3.timer.flush = function() { - d3_timer_mark(); - d3_timer_sweep(); - }; - function d3_timer_replace(callback, delay, then) { - var n = arguments.length; - if (n < 2) delay = 0; - if (n < 3) then = Date.now(); - d3_timer_active.callback = callback; - d3_timer_active.time = then + delay; - } - function d3_timer_mark() { - var now = Date.now(); - d3_timer_active = d3_timer_queueHead; - while (d3_timer_active) { - if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); - d3_timer_active = d3_timer_active.next; - } - return now; - } - function d3_timer_sweep() { - var t0, t1 = d3_timer_queueHead, time = Infinity; - while (t1) { - if (t1.flush) { - t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; - } else { - if (t1.time < time) time = t1.time; - t1 = (t0 = t1).next; - } - } - d3_timer_queueTail = t0; - return time; - } - var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; - var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); - d3.formatPrefix = function(value, precision) { - var i = 0; - if (value) { - if (value < 0) value *= -1; - if (precision) value = d3.round(value, d3_format_precision(value, precision)); - i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); - i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); - } - return d3_formatPrefixes[8 + i / 3]; - }; - function d3_formatPrefix(d, i) { - var k = Math.pow(10, Math.abs(8 - i) * 3); - return { - scale: i > 8 ? function(d) { - return d / k; - } : function(d) { - return d * k; - }, - symbol: d - }; - } - d3.round = function(x, n) { - return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); - }; - d3.format = function(specifier) { - var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; - if (precision) precision = +precision.substring(1); - if (zfill || fill === "0" && align === "=") { - zfill = fill = "0"; - align = "="; - if (comma) width -= Math.floor((width - 1) / 4); - } - switch (type) { - case "n": - comma = true; - type = "g"; - break; - - case "%": - scale = 100; - suffix = "%"; - type = "f"; - break; - - case "p": - scale = 100; - suffix = "%"; - type = "r"; - break; - - case "b": - case "o": - case "x": - case "X": - if (symbol === "#") symbol = "0" + type.toLowerCase(); - - case "c": - case "d": - integer = true; - precision = 0; - break; - - case "s": - scale = -1; - type = "r"; - break; - } - if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; - if (type == "r" && !precision) type = "g"; - if (precision != null) { - if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); - } - type = d3_format_types.get(type) || d3_format_typeDefault; - var zcomma = zfill && comma; - return function(value) { - if (integer && value % 1) return ""; - var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; - if (scale < 0) { - var prefix = d3.formatPrefix(value, precision); - value = prefix.scale(value); - suffix = prefix.symbol; - } else { - value *= scale; - } - value = type(value, precision); - var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); - if (!zfill && comma) before = d3_format_group(before); - var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; - if (zcomma) before = d3_format_group(padding + before); - negative += symbol; - value = before + after; - return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; - }; - }; - var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; - var d3_format_types = d3.map({ - b: function(x) { - return x.toString(2); - }, - c: function(x) { - return String.fromCharCode(x); - }, - o: function(x) { - return x.toString(8); - }, - x: function(x) { - return x.toString(16); - }, - X: function(x) { - return x.toString(16).toUpperCase(); - }, - g: function(x, p) { - return x.toPrecision(p); - }, - e: function(x, p) { - return x.toExponential(p); - }, - f: function(x, p) { - return x.toFixed(p); - }, - r: function(x, p) { - return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); - } - }); - function d3_format_precision(x, p) { - return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); - } - function d3_format_typeDefault(x) { - return x + ""; - } - var d3_format_group = d3_identity; - if (d3_format_grouping) { - var d3_format_groupingLength = d3_format_grouping.length; - d3_format_group = function(value) { - var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; - while (i > 0 && g > 0) { - t.push(value.substring(i -= g, i + g)); - g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; - } - return t.reverse().join(d3_format_thousandsSeparator); - }; - } - d3.geo = {}; - function d3_adder() {} - d3_adder.prototype = { - s: 0, - t: 0, - add: function(y) { - d3_adderSum(y, this.t, d3_adderTemp); - d3_adderSum(d3_adderTemp.s, this.s, this); - if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; - }, - reset: function() { - this.s = this.t = 0; - }, - valueOf: function() { - return this.s; - } - }; - var d3_adderTemp = new d3_adder(); - function d3_adderSum(a, b, o) { - var x = o.s = a + b, bv = x - a, av = x - bv; - o.t = a - av + (b - bv); - } - d3.geo.stream = function(object, listener) { - if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { - d3_geo_streamObjectType[object.type](object, listener); - } else { - d3_geo_streamGeometry(object, listener); - } - }; - function d3_geo_streamGeometry(geometry, listener) { - if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { - d3_geo_streamGeometryType[geometry.type](geometry, listener); - } - } - var d3_geo_streamObjectType = { - Feature: function(feature, listener) { - d3_geo_streamGeometry(feature.geometry, listener); - }, - FeatureCollection: function(object, listener) { - var features = object.features, i = -1, n = features.length; - while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); - } - }; - var d3_geo_streamGeometryType = { - Sphere: function(object, listener) { - listener.sphere(); - }, - Point: function(object, listener) { - var coordinate = object.coordinates; - listener.point(coordinate[0], coordinate[1]); - }, - MultiPoint: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); - }, - LineString: function(object, listener) { - d3_geo_streamLine(object.coordinates, listener, 0); - }, - MultiLineString: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); - }, - Polygon: function(object, listener) { - d3_geo_streamPolygon(object.coordinates, listener); - }, - MultiPolygon: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); - }, - GeometryCollection: function(object, listener) { - var geometries = object.geometries, i = -1, n = geometries.length; - while (++i < n) d3_geo_streamGeometry(geometries[i], listener); - } - }; - function d3_geo_streamLine(coordinates, listener, closed) { - var i = -1, n = coordinates.length - closed, coordinate; - listener.lineStart(); - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); - listener.lineEnd(); - } - function d3_geo_streamPolygon(coordinates, listener) { - var i = -1, n = coordinates.length; - listener.polygonStart(); - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); - listener.polygonEnd(); - } - d3.geo.area = function(object) { - d3_geo_areaSum = 0; - d3.geo.stream(object, d3_geo_area); - return d3_geo_areaSum; - }; - var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); - var d3_geo_area = { - sphere: function() { - d3_geo_areaSum += 4 * π; - }, - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: function() { - d3_geo_areaRingSum.reset(); - d3_geo_area.lineStart = d3_geo_areaRingStart; - }, - polygonEnd: function() { - var area = 2 * d3_geo_areaRingSum; - d3_geo_areaSum += area < 0 ? 4 * π + area : area; - d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; - } - }; - function d3_geo_areaRingStart() { - var λ00, φ00, λ0, cosφ0, sinφ0; - d3_geo_area.point = function(λ, φ) { - d3_geo_area.point = nextPoint; - λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), - sinφ0 = Math.sin(φ); - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - φ = φ * d3_radians / 2 + π / 4; - var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); - d3_geo_areaRingSum.add(Math.atan2(v, u)); - λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; - } - d3_geo_area.lineEnd = function() { - nextPoint(λ00, φ00); - }; - } - function d3_geo_cartesian(spherical) { - var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); - return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; - } - function d3_geo_cartesianDot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; - } - function d3_geo_cartesianCross(a, b) { - return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; - } - function d3_geo_cartesianAdd(a, b) { - a[0] += b[0]; - a[1] += b[1]; - a[2] += b[2]; - } - function d3_geo_cartesianScale(vector, k) { - return [ vector[0] * k, vector[1] * k, vector[2] * k ]; - } - function d3_geo_cartesianNormalize(d) { - var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); - d[0] /= l; - d[1] /= l; - d[2] /= l; - } - function d3_geo_spherical(cartesian) { - return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; - } - function d3_geo_sphericalEqual(a, b) { - return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; - } - d3.geo.bounds = function() { - var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; - var bound = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - bound.point = ringPoint; - bound.lineStart = ringStart; - bound.lineEnd = ringEnd; - dλSum = 0; - d3_geo_area.polygonStart(); - }, - polygonEnd: function() { - d3_geo_area.polygonEnd(); - bound.point = point; - bound.lineStart = lineStart; - bound.lineEnd = lineEnd; - if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; - range[0] = λ0, range[1] = λ1; - } - }; - function point(λ, φ) { - ranges.push(range = [ λ0 = λ, λ1 = λ ]); - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - function linePoint(λ, φ) { - var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); - if (p0) { - var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); - d3_geo_cartesianNormalize(inflection); - inflection = d3_geo_spherical(inflection); - var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; - if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = inflection[1] * d3_degrees; - if (φi > φ1) φ1 = φi; - } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = -inflection[1] * d3_degrees; - if (φi < φ0) φ0 = φi; - } else { - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - if (antimeridian) { - if (λ < λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } else { - if (λ1 >= λ0) { - if (λ < λ0) λ0 = λ; - if (λ > λ1) λ1 = λ; - } else { - if (λ > λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } - } - } else { - point(λ, φ); - } - p0 = p, λ_ = λ; - } - function lineStart() { - bound.point = linePoint; - } - function lineEnd() { - range[0] = λ0, range[1] = λ1; - bound.point = point; - p0 = null; - } - function ringPoint(λ, φ) { - if (p0) { - var dλ = λ - λ_; - dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; - } else λ__ = λ, φ__ = φ; - d3_geo_area.point(λ, φ); - linePoint(λ, φ); - } - function ringStart() { - d3_geo_area.lineStart(); - } - function ringEnd() { - ringPoint(λ__, φ__); - d3_geo_area.lineEnd(); - if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); - range[0] = λ0, range[1] = λ1; - p0 = null; - } - function angle(λ0, λ1) { - return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; - } - function compareRanges(a, b) { - return a[0] - b[0]; - } - function withinRange(x, range) { - return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; - } - return function(feature) { - φ1 = λ1 = -(λ0 = φ0 = Infinity); - ranges = []; - d3.geo.stream(feature, bound); - var n = ranges.length; - if (n) { - ranges.sort(compareRanges); - for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { - b = ranges[i]; - if (withinRange(b[0], a) || withinRange(b[1], a)) { - if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; - if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; - } else { - merged.push(a = b); - } - } - var best = -Infinity, dλ; - for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { - b = merged[i]; - if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; - } - } - ranges = range = null; - return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; - }; - }(); - d3.geo.centroid = function(object) { - d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, d3_geo_centroid); - var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; - if (m < ε2) { - x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; - if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; - m = x * x + y * y + z * z; - if (m < ε2) return [ NaN, NaN ]; - } - return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; - }; - var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; - var d3_geo_centroid = { - sphere: d3_noop, - point: d3_geo_centroidPoint, - lineStart: d3_geo_centroidLineStart, - lineEnd: d3_geo_centroidLineEnd, - polygonStart: function() { - d3_geo_centroid.lineStart = d3_geo_centroidRingStart; - }, - polygonEnd: function() { - d3_geo_centroid.lineStart = d3_geo_centroidLineStart; - } - }; - function d3_geo_centroidPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); - } - function d3_geo_centroidPointXYZ(x, y, z) { - ++d3_geo_centroidW0; - d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; - d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; - d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; - } - function d3_geo_centroidLineStart() { - var x0, y0, z0; - d3_geo_centroid.point = function(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroid.point = nextPoint; - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } - } - function d3_geo_centroidLineEnd() { - d3_geo_centroid.point = d3_geo_centroidPoint; - } - function d3_geo_centroidRingStart() { - var λ00, φ00, x0, y0, z0; - d3_geo_centroid.point = function(λ, φ) { - λ00 = λ, φ00 = φ; - d3_geo_centroid.point = nextPoint; - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - d3_geo_centroid.lineEnd = function() { - nextPoint(λ00, φ00); - d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; - d3_geo_centroid.point = d3_geo_centroidPoint; - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); - d3_geo_centroidX2 += v * cx; - d3_geo_centroidY2 += v * cy; - d3_geo_centroidZ2 += v * cz; - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } - } - function d3_true() { - return true; - } - function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { - var subject = [], clip = []; - segments.forEach(function(segment) { - if ((n = segment.length - 1) <= 0) return; - var n, p0 = segment[0], p1 = segment[n]; - if (d3_geo_sphericalEqual(p0, p1)) { - listener.lineStart(); - for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); - listener.lineEnd(); - return; - } - var a = { - point: p0, - points: segment, - other: null, - visited: false, - entry: true, - subject: true - }, b = { - point: p0, - points: [ p0 ], - other: a, - visited: false, - entry: false, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - a = { - point: p1, - points: [ p1 ], - other: null, - visited: false, - entry: false, - subject: true - }; - b = { - point: p1, - points: [ p1 ], - other: a, - visited: false, - entry: true, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - }); - clip.sort(compare); - d3_geo_clipPolygonLinkCircular(subject); - d3_geo_clipPolygonLinkCircular(clip); - if (!subject.length) return; - if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { - clip[i].entry = e = !e; - } - var start = subject[0], current, points, point; - while (1) { - current = start; - while (current.visited) if ((current = current.next) === start) return; - points = current.points; - listener.lineStart(); - do { - current.visited = current.other.visited = true; - if (current.entry) { - if (current.subject) { - for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.next.point, 1, listener); - } - current = current.next; - } else { - if (current.subject) { - points = current.prev.points; - for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.prev.point, -1, listener); - } - current = current.prev; - } - current = current.other; - points = current.points; - } while (!current.visited); - listener.lineEnd(); - } - } - function d3_geo_clipPolygonLinkCircular(array) { - if (!(n = array.length)) return; - var n, i = 0, a = array[0], b; - while (++i < n) { - a.next = b = array[i]; - b.prev = a; - a = b; - } - a.next = b = array[0]; - b.prev = a; - } - function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { - return function(listener) { - var line = clipLine(listener); - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - clip.point = pointRing; - clip.lineStart = ringStart; - clip.lineEnd = ringEnd; - segments = []; - polygon = []; - listener.polygonStart(); - }, - polygonEnd: function() { - clip.point = point; - clip.lineStart = lineStart; - clip.lineEnd = lineEnd; - segments = d3.merge(segments); - if (segments.length) { - d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); - } else if (polygonContains(polygon)) { - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - } - listener.polygonEnd(); - segments = polygon = null; - }, - sphere: function() { - listener.polygonStart(); - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - listener.polygonEnd(); - } - }; - function point(λ, φ) { - if (pointVisible(λ, φ)) listener.point(λ, φ); - } - function pointLine(λ, φ) { - line.point(λ, φ); - } - function lineStart() { - clip.point = pointLine; - line.lineStart(); - } - function lineEnd() { - clip.point = point; - line.lineEnd(); - } - var segments; - var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; - function pointRing(λ, φ) { - ringListener.point(λ, φ); - ring.push([ λ, φ ]); - } - function ringStart() { - ringListener.lineStart(); - ring = []; - } - function ringEnd() { - pointRing(ring[0][0], ring[0][1]); - ringListener.lineEnd(); - var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; - ring.pop(); - polygon.push(ring); - ring = null; - if (!n) return; - if (clean & 1) { - segment = ringSegments[0]; - var n = segment.length - 1, i = -1, point; - listener.lineStart(); - while (++i < n) listener.point((point = segment[i])[0], point[1]); - listener.lineEnd(); - return; - } - if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); - segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); - } - return clip; - }; - } - function d3_geo_clipSegmentLength1(segment) { - return segment.length > 1; - } - function d3_geo_clipBufferListener() { - var lines = [], line; - return { - lineStart: function() { - lines.push(line = []); - }, - point: function(λ, φ) { - line.push([ λ, φ ]); - }, - lineEnd: d3_noop, - buffer: function() { - var buffer = lines; - lines = []; - line = null; - return buffer; - }, - rejoin: function() { - if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); - } - }; - } - function d3_geo_clipSort(a, b) { - return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); - } - function d3_geo_pointInPolygon(point, polygon) { - var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; - d3_geo_areaRingSum.reset(); - for (var i = 0, n = polygon.length; i < n; ++i) { - var ring = polygon[i], m = ring.length; - if (!m) continue; - var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; - while (true) { - if (j === m) j = 0; - point = ring[j]; - var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; - d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); - if (Math.abs(φ) < ε) southPole = true; - polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; - if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { - var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); - d3_geo_cartesianNormalize(arc); - var intersection = d3_geo_cartesianCross(meridianNormal, arc); - d3_geo_cartesianNormalize(intersection); - var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); - if (parallel > φarc) { - winding += antimeridian ^ dλ >= 0 ? 1 : -1; - } - } - if (!j++) break; - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; - } - if (Math.abs(polarAngle) > ε) polar = true; - } - return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; - } - var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); - function d3_geo_clipAntimeridianLine(listener) { - var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; - return { - lineStart: function() { - listener.lineStart(); - clean = 1; - }, - point: function(λ1, φ1) { - var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); - if (Math.abs(dλ - π) < ε) { - listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - listener.point(λ1, φ0); - clean = 0; - } else if (sλ0 !== sλ1 && dλ >= π) { - if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; - if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; - φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - clean = 0; - } - listener.point(λ0 = λ1, φ0 = φ1); - sλ0 = sλ1; - }, - lineEnd: function() { - listener.lineEnd(); - λ0 = φ0 = NaN; - }, - clean: function() { - return 2 - clean; - } - }; - } - function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { - var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); - return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; - } - function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { - var φ; - if (from == null) { - φ = direction * π / 2; - listener.point(-π, φ); - listener.point(0, φ); - listener.point(π, φ); - listener.point(π, 0); - listener.point(π, -φ); - listener.point(0, -φ); - listener.point(-π, -φ); - listener.point(-π, 0); - listener.point(-π, φ); - } else if (Math.abs(from[0] - to[0]) > ε) { - var s = (from[0] < to[0] ? 1 : -1) * π; - φ = direction * s / 2; - listener.point(-s, φ); - listener.point(0, φ); - listener.point(s, φ); - } else { - listener.point(to[0], to[1]); - } - } - var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; - function d3_geo_clipAntimeridianPolygonContains(polygon) { - return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); - } - function d3_geo_clipCircle(radius) { - var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); - return d3_geo_clip(visible, clipLine, interpolate, polygonContains); - function visible(λ, φ) { - return Math.cos(λ) * Math.cos(φ) > cr; - } - function clipLine(listener) { - var point0, c0, v0, v00, clean; - return { - lineStart: function() { - v00 = v0 = false; - clean = 1; - }, - point: function(λ, φ) { - var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; - if (!point0 && (v00 = v0 = v)) listener.lineStart(); - if (v !== v0) { - point2 = intersect(point0, point1); - if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { - point1[0] += ε; - point1[1] += ε; - v = visible(point1[0], point1[1]); - } - } - if (v !== v0) { - clean = 0; - if (v) { - listener.lineStart(); - point2 = intersect(point1, point0); - listener.point(point2[0], point2[1]); - } else { - point2 = intersect(point0, point1); - listener.point(point2[0], point2[1]); - listener.lineEnd(); - } - point0 = point2; - } else if (notHemisphere && point0 && smallRadius ^ v) { - var t; - if (!(c & c0) && (t = intersect(point1, point0, true))) { - clean = 0; - if (smallRadius) { - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - } else { - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - } - } - } - if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { - listener.point(point1[0], point1[1]); - } - point0 = point1, v0 = v, c0 = c; - }, - lineEnd: function() { - if (v0) listener.lineEnd(); - point0 = null; - }, - clean: function() { - return clean | (v00 && v0) << 1; - } - }; - } - function intersect(a, b, two) { - var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); - var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; - if (!determinant) return !two && a; - var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); - d3_geo_cartesianAdd(A, B); - var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); - if (t2 < 0) return; - var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); - d3_geo_cartesianAdd(q, A); - q = d3_geo_spherical(q); - if (!two) return q; - var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; - if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; - var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; - if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; - if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { - var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); - d3_geo_cartesianAdd(q1, A); - return [ q, d3_geo_spherical(q1) ]; - } - } - function code(λ, φ) { - var r = smallRadius ? radius : π - radius, code = 0; - if (λ < -r) code |= 1; else if (λ > r) code |= 2; - if (φ < -r) code |= 4; else if (φ > r) code |= 8; - return code; - } - function polygonContains(polygon) { - return d3_geo_pointInPolygon(point, polygon); - } - } - var d3_geo_clipViewMAX = 1e9; - function d3_geo_clipView(x0, y0, x1, y1) { - return function(listener) { - var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - listener = bufferListener; - segments = []; - polygon = []; - }, - polygonEnd: function() { - listener = listener_; - if ((segments = d3.merge(segments)).length) { - listener.polygonStart(); - d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); - listener.polygonEnd(); - } else if (insidePolygon([ x0, y0 ])) { - listener.polygonStart(), listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(), listener.polygonEnd(); - } - segments = polygon = ring = null; - } - }; - function inside(point) { - var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); - return i; - } - function insidePolygon(p) { - var wn = 0, n = polygon.length, y = p[1]; - for (var i = 0; i < n; ++i) { - for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { - b = v[j]; - if (a[1] <= y) { - if (b[1] > y && isLeft(a, b, p) > 0) ++wn; - } else { - if (b[1] <= y && isLeft(a, b, p) < 0) --wn; - } - a = b; - } - } - return wn !== 0; - } - function isLeft(a, b, c) { - return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); - } - function interpolate(from, to, direction, listener) { - var a = 0, a1 = 0; - if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { - do { - listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); - } while ((a = (a + direction + 4) % 4) !== a1); - } else { - listener.point(to[0], to[1]); - } - } - function visible(x, y) { - return x0 <= x && x <= x1 && y0 <= y && y <= y1; - } - function point(x, y) { - if (visible(x, y)) listener.point(x, y); - } - var x__, y__, v__, x_, y_, v_, first; - function lineStart() { - clip.point = linePoint; - if (polygon) polygon.push(ring = []); - first = true; - v_ = false; - x_ = y_ = NaN; - } - function lineEnd() { - if (segments) { - linePoint(x__, y__); - if (v__ && v_) bufferListener.rejoin(); - segments.push(bufferListener.buffer()); - } - clip.point = point; - if (v_) listener.lineEnd(); - } - function linePoint(x, y) { - x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); - y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); - var v = visible(x, y); - if (polygon) ring.push([ x, y ]); - if (first) { - x__ = x, y__ = y, v__ = v; - first = false; - if (v) { - listener.lineStart(); - listener.point(x, y); - } - } else { - if (v && v_) listener.point(x, y); else { - var a = [ x_, y_ ], b = [ x, y ]; - if (clipLine(a, b)) { - if (!v_) { - listener.lineStart(); - listener.point(a[0], a[1]); - } - listener.point(b[0], b[1]); - if (!v) listener.lineEnd(); - } else if (v) { - listener.lineStart(); - listener.point(x, y); - } - } - } - x_ = x, y_ = y, v_ = v; - } - return clip; - }; - function corner(p, direction) { - return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; - } - function compare(a, b) { - return comparePoints(a.point, b.point); - } - function comparePoints(a, b) { - var ca = corner(a, 1), cb = corner(b, 1); - return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; - } - function clipLine(a, b) { - var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; - if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; - if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { - if (t[1] < 1) { - b[0] = a[0] + t[1] * dx; - b[1] = a[1] + t[1] * dy; - } - if (t[0] > 0) { - a[0] += t[0] * dx; - a[1] += t[0] * dy; - } - return true; - } - return false; - } - } - function d3_geo_clipViewT(num, denominator, t) { - if (Math.abs(denominator) < ε) return num <= 0; - var u = num / denominator; - if (denominator > 0) { - if (u > t[1]) return false; - if (u > t[0]) t[0] = u; - } else { - if (u < t[0]) return false; - if (u < t[1]) t[1] = u; - } - return true; - } - function d3_geo_compose(a, b) { - function compose(x, y) { - return x = a(x, y), b(x[0], x[1]); - } - if (a.invert && b.invert) compose.invert = function(x, y) { - return x = b.invert(x, y), x && a.invert(x[0], x[1]); - }; - return compose; - } - function d3_geo_conic(projectAt) { - var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); - p.parallels = function(_) { - if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; - return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); - }; - return p; - } - function d3_geo_conicEqualArea(φ0, φ1) { - var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; - function forward(λ, φ) { - var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; - return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = ρ0 - y; - return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; - }; - return forward; - } - (d3.geo.conicEqualArea = function() { - return d3_geo_conic(d3_geo_conicEqualArea); - }).raw = d3_geo_conicEqualArea; - d3.geo.albers = function() { - return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); - }; - d3.geo.albersUsa = function() { - var lower48 = d3.geo.albers(); - var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); - var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); - var point, pointStream = { - point: function(x, y) { - point = [ x, y ]; - } - }, lower48Point, alaskaPoint, hawaiiPoint; - function albersUsa(coordinates) { - var x = coordinates[0], y = coordinates[1]; - point = null; - (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); - return point; - } - albersUsa.invert = function(coordinates) { - var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; - return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); - }; - albersUsa.stream = function(stream) { - var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); - return { - point: function(x, y) { - lower48Stream.point(x, y); - alaskaStream.point(x, y); - hawaiiStream.point(x, y); - }, - sphere: function() { - lower48Stream.sphere(); - alaskaStream.sphere(); - hawaiiStream.sphere(); - }, - lineStart: function() { - lower48Stream.lineStart(); - alaskaStream.lineStart(); - hawaiiStream.lineStart(); - }, - lineEnd: function() { - lower48Stream.lineEnd(); - alaskaStream.lineEnd(); - hawaiiStream.lineEnd(); - }, - polygonStart: function() { - lower48Stream.polygonStart(); - alaskaStream.polygonStart(); - hawaiiStream.polygonStart(); - }, - polygonEnd: function() { - lower48Stream.polygonEnd(); - alaskaStream.polygonEnd(); - hawaiiStream.polygonEnd(); - } - }; - }; - albersUsa.precision = function(_) { - if (!arguments.length) return lower48.precision(); - lower48.precision(_); - alaska.precision(_); - hawaii.precision(_); - return albersUsa; - }; - albersUsa.scale = function(_) { - if (!arguments.length) return lower48.scale(); - lower48.scale(_); - alaska.scale(_ * .35); - hawaii.scale(_); - return albersUsa.translate(lower48.translate()); - }; - albersUsa.translate = function(_) { - if (!arguments.length) return lower48.translate(); - var k = lower48.scale(), x = +_[0], y = +_[1]; - lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; - alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; - hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; - return albersUsa; - }; - return albersUsa.scale(1070); - }; - var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: function() { - d3_geo_pathAreaPolygon = 0; - d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; - }, - polygonEnd: function() { - d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; - d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); - } - }; - function d3_geo_pathAreaRingStart() { - var x00, y00, x0, y0; - d3_geo_pathArea.point = function(x, y) { - d3_geo_pathArea.point = nextPoint; - x00 = x0 = x, y00 = y0 = y; - }; - function nextPoint(x, y) { - d3_geo_pathAreaPolygon += y0 * x - x0 * y; - x0 = x, y0 = y; - } - d3_geo_pathArea.lineEnd = function() { - nextPoint(x00, y00); - }; - } - var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; - var d3_geo_pathBounds = { - point: d3_geo_pathBoundsPoint, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop - }; - function d3_geo_pathBoundsPoint(x, y) { - if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; - if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; - if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; - if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; - } - function d3_geo_pathBuffer() { - var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; - var stream = { - point: point, - lineStart: function() { - stream.point = pointLineStart; - }, - lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointCircle = d3_geo_pathBufferCircle(_); - return stream; - }, - result: function() { - if (buffer.length) { - var result = buffer.join(""); - buffer = []; - return result; - } - } - }; - function point(x, y) { - buffer.push("M", x, ",", y, pointCircle); - } - function pointLineStart(x, y) { - buffer.push("M", x, ",", y); - stream.point = pointLine; - } - function pointLine(x, y) { - buffer.push("L", x, ",", y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - buffer.push("Z"); - } - return stream; - } - function d3_geo_pathBufferCircle(radius) { - return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; - } - var d3_geo_pathCentroid = { - point: d3_geo_pathCentroidPoint, - lineStart: d3_geo_pathCentroidLineStart, - lineEnd: d3_geo_pathCentroidLineEnd, - polygonStart: function() { - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; - }, - polygonEnd: function() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; - d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; - } - }; - function d3_geo_pathCentroidPoint(x, y) { - d3_geo_centroidX0 += x; - d3_geo_centroidY0 += y; - ++d3_geo_centroidZ0; - } - function d3_geo_pathCentroidLineStart() { - var x0, y0; - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - }; - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } - } - function d3_geo_pathCentroidLineEnd() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - } - function d3_geo_pathCentroidRingStart() { - var x00, y00, x0, y0; - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); - }; - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - z = y0 * x - x0 * y; - d3_geo_centroidX2 += z * (x0 + x); - d3_geo_centroidY2 += z * (y0 + y); - d3_geo_centroidZ2 += z * 3; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } - d3_geo_pathCentroid.lineEnd = function() { - nextPoint(x00, y00); - }; - } - function d3_geo_pathContext(context) { - var pointRadius = 4.5; - var stream = { - point: point, - lineStart: function() { - stream.point = pointLineStart; - }, - lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointRadius = _; - return stream; - }, - result: d3_noop - }; - function point(x, y) { - context.moveTo(x, y); - context.arc(x, y, pointRadius, 0, 2 * π); - } - function pointLineStart(x, y) { - context.moveTo(x, y); - stream.point = pointLine; - } - function pointLine(x, y) { - context.lineTo(x, y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - context.closePath(); - } - return stream; - } - function d3_geo_resample(project) { - var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; - function resample(stream) { - var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; - var resample = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - stream.polygonStart(); - resample.lineStart = ringStart; - }, - polygonEnd: function() { - stream.polygonEnd(); - resample.lineStart = lineStart; - } - }; - function point(x, y) { - x = project(x, y); - stream.point(x[0], x[1]); - } - function lineStart() { - x0 = NaN; - resample.point = linePoint; - stream.lineStart(); - } - function linePoint(λ, φ) { - var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); - resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); - stream.point(x0, y0); - } - function lineEnd() { - resample.point = point; - stream.lineEnd(); - } - function ringStart() { - lineStart(); - resample.point = ringPoint; - resample.lineEnd = ringEnd; - } - function ringPoint(λ, φ) { - linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; - resample.point = linePoint; - } - function ringEnd() { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); - resample.lineEnd = lineEnd; - lineEnd(); - } - return resample; - } - function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { - var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; - if (d2 > 4 * δ2 && depth--) { - var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; - if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); - stream.point(x2, y2); - resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); - } - } - } - resample.precision = function(_) { - if (!arguments.length) return Math.sqrt(δ2); - maxDepth = (δ2 = _ * _) > 0 && 16; - return resample; - }; - return resample; - } - d3.geo.path = function() { - var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; - function path(object) { - if (object) { - if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); - if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); - d3.geo.stream(object, cacheStream); - } - return contextStream.result(); - } - path.area = function(object) { - d3_geo_pathAreaSum = 0; - d3.geo.stream(object, projectStream(d3_geo_pathArea)); - return d3_geo_pathAreaSum; - }; - path.centroid = function(object) { - d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); - return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; - }; - path.bounds = function(object) { - d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); - d3.geo.stream(object, projectStream(d3_geo_pathBounds)); - return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; - }; - path.projection = function(_) { - if (!arguments.length) return projection; - projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; - return reset(); - }; - path.context = function(_) { - if (!arguments.length) return context; - contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); - if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); - return reset(); - }; - path.pointRadius = function(_) { - if (!arguments.length) return pointRadius; - pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); - return path; - }; - function reset() { - cacheStream = null; - return path; - } - return path.projection(d3.geo.albersUsa()).context(null); - }; - function d3_geo_pathProjectStream(project) { - var resample = d3_geo_resample(function(λ, φ) { - return project([ λ * d3_degrees, φ * d3_degrees ]); - }); - return function(stream) { - stream = resample(stream); - return { - point: function(λ, φ) { - stream.point(λ * d3_radians, φ * d3_radians); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - }; - } - d3.geo.projection = d3_geo_projection; - d3.geo.projectionMutator = d3_geo_projectionMutator; - function d3_geo_projection(project) { - return d3_geo_projectionMutator(function() { - return project; - })(); - } - function d3_geo_projectionMutator(projectAt) { - var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { - x = project(x, y); - return [ x[0] * k + δx, δy - x[1] * k ]; - }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; - function projection(point) { - point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); - return [ point[0] * k + δx, δy - point[1] * k ]; - } - function invert(point) { - point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); - return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; - } - projection.stream = function(output) { - if (stream) stream.valid = false; - stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); - stream.valid = true; - return stream; - }; - projection.clipAngle = function(_) { - if (!arguments.length) return clipAngle; - preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); - return invalidate(); - }; - projection.clipExtent = function(_) { - if (!arguments.length) return clipExtent; - clipExtent = _; - postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); - return invalidate(); - }; - projection.scale = function(_) { - if (!arguments.length) return k; - k = +_; - return reset(); - }; - projection.translate = function(_) { - if (!arguments.length) return [ x, y ]; - x = +_[0]; - y = +_[1]; - return reset(); - }; - projection.center = function(_) { - if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; - λ = _[0] % 360 * d3_radians; - φ = _[1] % 360 * d3_radians; - return reset(); - }; - projection.rotate = function(_) { - if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; - δλ = _[0] % 360 * d3_radians; - δφ = _[1] % 360 * d3_radians; - δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; - return reset(); - }; - d3.rebind(projection, projectResample, "precision"); - function reset() { - projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); - var center = project(λ, φ); - δx = x - center[0] * k; - δy = y + center[1] * k; - return invalidate(); - } - function invalidate() { - if (stream) { - stream.valid = false; - stream = null; - } - return projection; - } - return function() { - project = projectAt.apply(this, arguments); - projection.invert = project.invert && invert; - return reset(); - }; - } - function d3_geo_projectionRadiansRotate(rotate, stream) { - return { - point: function(x, y) { - y = rotate(x * d3_radians, y * d3_radians), x = y[0]; - stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - } - function d3_geo_equirectangular(λ, φ) { - return [ λ, φ ]; - } - (d3.geo.equirectangular = function() { - return d3_geo_projection(d3_geo_equirectangular); - }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; - d3.geo.rotation = function(rotate) { - rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); - function forward(coordinates) { - coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - } - forward.invert = function(coordinates) { - coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - }; - return forward; - }; - function d3_geo_rotation(δλ, δφ, δγ) { - return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; - } - function d3_geo_forwardRotationλ(δλ) { - return function(λ, φ) { - return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; - }; - } - function d3_geo_rotationλ(δλ) { - var rotation = d3_geo_forwardRotationλ(δλ); - rotation.invert = d3_geo_forwardRotationλ(-δλ); - return rotation; - } - function d3_geo_rotationφγ(δφ, δγ) { - var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); - function rotation(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; - return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; - } - rotation.invert = function(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; - return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; - }; - return rotation; - } - d3.geo.circle = function() { - var origin = [ 0, 0 ], angle, precision = 6, interpolate; - function circle() { - var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; - interpolate(null, null, 1, { - point: function(x, y) { - ring.push(x = rotate(x, y)); - x[0] *= d3_degrees, x[1] *= d3_degrees; - } - }); - return { - type: "Polygon", - coordinates: [ ring ] - }; - } - circle.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return circle; - }; - circle.angle = function(x) { - if (!arguments.length) return angle; - interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); - return circle; - }; - circle.precision = function(_) { - if (!arguments.length) return precision; - interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); - return circle; - }; - return circle.angle(90); - }; - function d3_geo_circleInterpolate(radius, precision) { - var cr = Math.cos(radius), sr = Math.sin(radius); - return function(from, to, direction, listener) { - if (from != null) { - from = d3_geo_circleAngle(cr, from); - to = d3_geo_circleAngle(cr, to); - if (direction > 0 ? from < to : from > to) from += direction * 2 * π; - } else { - from = radius + direction * 2 * π; - to = radius; - } - var point; - for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { - listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); - } - }; - } - function d3_geo_circleAngle(cr, point) { - var a = d3_geo_cartesian(point); - a[0] -= cr; - d3_geo_cartesianNormalize(a); - var angle = d3_acos(-a[1]); - return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); - } - d3.geo.distance = function(a, b) { - var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; - return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); - }; - d3.geo.graticule = function() { - var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; - function graticule() { - return { - type: "MultiLineString", - coordinates: lines() - }; - } - function lines() { - return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { - return Math.abs(x % DX) > ε; - }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { - return Math.abs(y % DY) > ε; - }).map(y)); - } - graticule.lines = function() { - return lines().map(function(coordinates) { - return { - type: "LineString", - coordinates: coordinates - }; - }); - }; - graticule.outline = function() { - return { - type: "Polygon", - coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] - }; - }; - graticule.extent = function(_) { - if (!arguments.length) return graticule.minorExtent(); - return graticule.majorExtent(_).minorExtent(_); - }; - graticule.majorExtent = function(_) { - if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; - X0 = +_[0][0], X1 = +_[1][0]; - Y0 = +_[0][1], Y1 = +_[1][1]; - if (X0 > X1) _ = X0, X0 = X1, X1 = _; - if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; - return graticule.precision(precision); - }; - graticule.minorExtent = function(_) { - if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; - x0 = +_[0][0], x1 = +_[1][0]; - y0 = +_[0][1], y1 = +_[1][1]; - if (x0 > x1) _ = x0, x0 = x1, x1 = _; - if (y0 > y1) _ = y0, y0 = y1, y1 = _; - return graticule.precision(precision); - }; - graticule.step = function(_) { - if (!arguments.length) return graticule.minorStep(); - return graticule.majorStep(_).minorStep(_); - }; - graticule.majorStep = function(_) { - if (!arguments.length) return [ DX, DY ]; - DX = +_[0], DY = +_[1]; - return graticule; - }; - graticule.minorStep = function(_) { - if (!arguments.length) return [ dx, dy ]; - dx = +_[0], dy = +_[1]; - return graticule; - }; - graticule.precision = function(_) { - if (!arguments.length) return precision; - precision = +_; - x = d3_geo_graticuleX(y0, y1, 90); - y = d3_geo_graticuleY(x0, x1, precision); - X = d3_geo_graticuleX(Y0, Y1, 90); - Y = d3_geo_graticuleY(X0, X1, precision); - return graticule; - }; - return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); - }; - function d3_geo_graticuleX(y0, y1, dy) { - var y = d3.range(y0, y1 - ε, dy).concat(y1); - return function(x) { - return y.map(function(y) { - return [ x, y ]; - }); - }; - } - function d3_geo_graticuleY(x0, x1, dx) { - var x = d3.range(x0, x1 - ε, dx).concat(x1); - return function(y) { - return x.map(function(x) { - return [ x, y ]; - }); - }; - } - function d3_source(d) { - return d.source; - } - function d3_target(d) { - return d.target; - } - d3.geo.greatArc = function() { - var source = d3_source, source_, target = d3_target, target_; - function greatArc() { - return { - type: "LineString", - coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] - }; - } - greatArc.distance = function() { - return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); - }; - greatArc.source = function(_) { - if (!arguments.length) return source; - source = _, source_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.target = function(_) { - if (!arguments.length) return target; - target = _, target_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.precision = function() { - return arguments.length ? greatArc : 0; - }; - return greatArc; - }; - d3.geo.interpolate = function(source, target) { - return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); - }; - function d3_geo_interpolate(x0, y0, x1, y1) { - var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); - var interpolate = d ? function(t) { - var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; - return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; - } : function() { - return [ x0 * d3_degrees, y0 * d3_degrees ]; - }; - interpolate.distance = d; - return interpolate; - } - d3.geo.length = function(object) { - d3_geo_lengthSum = 0; - d3.geo.stream(object, d3_geo_length); - return d3_geo_lengthSum; - }; - var d3_geo_lengthSum; - var d3_geo_length = { - sphere: d3_noop, - point: d3_noop, - lineStart: d3_geo_lengthLineStart, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop - }; - function d3_geo_lengthLineStart() { - var λ0, sinφ0, cosφ0; - d3_geo_length.point = function(λ, φ) { - λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); - d3_geo_length.point = nextPoint; - }; - d3_geo_length.lineEnd = function() { - d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; - }; - function nextPoint(λ, φ) { - var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); - d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; - } - } - function d3_geo_azimuthal(scale, angle) { - function azimuthal(λ, φ) { - var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); - return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; - } - azimuthal.invert = function(x, y) { - var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); - return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; - }; - return azimuthal; - } - var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { - return Math.sqrt(2 / (1 + cosλcosφ)); - }, function(ρ) { - return 2 * Math.asin(ρ / 2); - }); - (d3.geo.azimuthalEqualArea = function() { - return d3_geo_projection(d3_geo_azimuthalEqualArea); - }).raw = d3_geo_azimuthalEqualArea; - var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { - var c = Math.acos(cosλcosφ); - return c && c / Math.sin(c); - }, d3_identity); - (d3.geo.azimuthalEquidistant = function() { - return d3_geo_projection(d3_geo_azimuthalEquidistant); - }).raw = d3_geo_azimuthalEquidistant; - function d3_geo_conicConformal(φ0, φ1) { - var cosφ0 = Math.cos(φ0), t = function(φ) { - return Math.tan(π / 4 + φ / 2); - }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; - if (!n) return d3_geo_mercator; - function forward(λ, φ) { - var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); - return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); - return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; - }; - return forward; - } - (d3.geo.conicConformal = function() { - return d3_geo_conic(d3_geo_conicConformal); - }).raw = d3_geo_conicConformal; - function d3_geo_conicEquidistant(φ0, φ1) { - var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; - if (Math.abs(n) < ε) return d3_geo_equirectangular; - function forward(λ, φ) { - var ρ = G - φ; - return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = G - y; - return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; - }; - return forward; - } - (d3.geo.conicEquidistant = function() { - return d3_geo_conic(d3_geo_conicEquidistant); - }).raw = d3_geo_conicEquidistant; - var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / cosλcosφ; - }, Math.atan); - (d3.geo.gnomonic = function() { - return d3_geo_projection(d3_geo_gnomonic); - }).raw = d3_geo_gnomonic; - function d3_geo_mercator(λ, φ) { - return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; - } - d3_geo_mercator.invert = function(x, y) { - return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; - }; - function d3_geo_mercatorProjection(project) { - var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; - m.scale = function() { - var v = scale.apply(m, arguments); - return v === m ? clipAuto ? m.clipExtent(null) : m : v; - }; - m.translate = function() { - var v = translate.apply(m, arguments); - return v === m ? clipAuto ? m.clipExtent(null) : m : v; - }; - m.clipExtent = function(_) { - var v = clipExtent.apply(m, arguments); - if (v === m) { - if (clipAuto = _ == null) { - var k = π * scale(), t = translate(); - clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); - } - } else if (clipAuto) { - v = null; - } - return v; - }; - return m.clipExtent(null); - } - (d3.geo.mercator = function() { - return d3_geo_mercatorProjection(d3_geo_mercator); - }).raw = d3_geo_mercator; - var d3_geo_orthographic = d3_geo_azimuthal(function() { - return 1; - }, Math.asin); - (d3.geo.orthographic = function() { - return d3_geo_projection(d3_geo_orthographic); - }).raw = d3_geo_orthographic; - var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / (1 + cosλcosφ); - }, function(ρ) { - return 2 * Math.atan(ρ); - }); - (d3.geo.stereographic = function() { - return d3_geo_projection(d3_geo_stereographic); - }).raw = d3_geo_stereographic; - function d3_geo_transverseMercator(λ, φ) { - var B = Math.cos(φ) * Math.sin(λ); - return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; - } - d3_geo_transverseMercator.invert = function(x, y) { - return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; - }; - (d3.geo.transverseMercator = function() { - return d3_geo_mercatorProjection(d3_geo_transverseMercator); - }).raw = d3_geo_transverseMercator; - d3.geom = {}; - d3.svg = {}; - function d3_svg_line(projection) { - var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; - function line(data) { - var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); - function segment() { - segments.push("M", interpolate(projection(points), tension)); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); - } else if (points.length) { - segment(); - points = []; - } - } - if (points.length) segment(); - return segments.length ? segments.join("") : null; - } - line.x = function(_) { - if (!arguments.length) return x; - x = _; - return line; - }; - line.y = function(_) { - if (!arguments.length) return y; - y = _; - return line; - }; - line.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return line; - }; - line.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - return line; - }; - line.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return line; - }; - return line; - } - d3.svg.line = function() { - return d3_svg_line(d3_identity); - }; - function d3_svg_lineX(d) { - return d[0]; - } - function d3_svg_lineY(d) { - return d[1]; - } - var d3_svg_lineInterpolators = d3.map({ - linear: d3_svg_lineLinear, - "linear-closed": d3_svg_lineLinearClosed, - step: d3_svg_lineStep, - "step-before": d3_svg_lineStepBefore, - "step-after": d3_svg_lineStepAfter, - basis: d3_svg_lineBasis, - "basis-open": d3_svg_lineBasisOpen, - "basis-closed": d3_svg_lineBasisClosed, - bundle: d3_svg_lineBundle, - cardinal: d3_svg_lineCardinal, - "cardinal-open": d3_svg_lineCardinalOpen, - "cardinal-closed": d3_svg_lineCardinalClosed, - monotone: d3_svg_lineMonotone - }); - d3_svg_lineInterpolators.forEach(function(key, value) { - value.key = key; - value.closed = /-closed$/.test(key); - }); - function d3_svg_lineLinear(points) { - return points.join("L"); - } - function d3_svg_lineLinearClosed(points) { - return d3_svg_lineLinear(points) + "Z"; - } - function d3_svg_lineStep(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); - if (n > 1) path.push("H", p[0]); - return path.join(""); - } - function d3_svg_lineStepBefore(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); - return path.join(""); - } - function d3_svg_lineStepAfter(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); - return path.join(""); - } - function d3_svg_lineCardinalOpen(points, tension) { - return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineCardinalClosed(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), - points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); - } - function d3_svg_lineCardinal(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineHermite(points, tangents) { - if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { - return d3_svg_lineLinear(points); - } - var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; - if (quad) { - path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; - p0 = points[1]; - pi = 2; - } - if (tangents.length > 1) { - t = tangents[1]; - p = points[pi]; - pi++; - path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - for (var i = 2; i < tangents.length; i++, pi++) { - p = points[pi]; - t = tangents[i]; - path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - } - } - if (quad) { - var lp = points[pi]; - path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; - } - return path; - } - function d3_svg_lineCardinalTangents(points, tension) { - var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; - while (++i < n) { - p0 = p1; - p1 = p2; - p2 = points[i]; - tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); - } - return tangents; - } - function d3_svg_lineBasis(points) { - if (points.length < 3) return d3_svg_lineLinear(points); - var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; - points.push(points[n - 1]); - while (++i <= n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - points.pop(); - path.push("L", pi); - return path.join(""); - } - function d3_svg_lineBasisOpen(points) { - if (points.length < 4) return d3_svg_lineLinear(points); - var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; - while (++i < 3) { - pi = points[i]; - px.push(pi[0]); - py.push(pi[1]); - } - path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); - --i; - while (++i < n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBasisClosed(points) { - var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; - while (++i < 4) { - pi = points[i % n]; - px.push(pi[0]); - py.push(pi[1]); - } - path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; - --i; - while (++i < m) { - pi = points[i % n]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBundle(points, tension) { - var n = points.length - 1; - if (n) { - var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; - while (++i <= n) { - p = points[i]; - t = i / n; - p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); - p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); - } - } - return d3_svg_lineBasis(points); - } - function d3_svg_lineDot4(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; - } - var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; - function d3_svg_lineBasisBezier(path, x, y) { - path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); - } - function d3_svg_lineSlope(p0, p1) { - return (p1[1] - p0[1]) / (p1[0] - p0[0]); - } - function d3_svg_lineFiniteDifferences(points) { - var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); - while (++i < j) { - m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; - } - m[i] = d; - return m; - } - function d3_svg_lineMonotoneTangents(points) { - var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; - while (++i < j) { - d = d3_svg_lineSlope(points[i], points[i + 1]); - if (Math.abs(d) < 1e-6) { - m[i] = m[i + 1] = 0; - } else { - a = m[i] / d; - b = m[i + 1] / d; - s = a * a + b * b; - if (s > 9) { - s = d * 3 / Math.sqrt(s); - m[i] = s * a; - m[i + 1] = s * b; - } - } - } - i = -1; - while (++i <= j) { - s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); - tangents.push([ s || 0, m[i] * s || 0 ]); - } - return tangents; - } - function d3_svg_lineMonotone(points) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); - } - d3.geom.hull = function(vertices) { - var x = d3_svg_lineX, y = d3_svg_lineY; - if (arguments.length) return hull(vertices); - function hull(data) { - if (data.length < 3) return []; - var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; - if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, - vertices = []; i < n; ++i) { - vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); - } - for (i = 1; i < n; ++i) { - if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; - } - for (i = 0; i < n; ++i) { - if (i === h) continue; - y1 = vertices[i][1] - vertices[h][1]; - x1 = vertices[i][0] - vertices[h][0]; - points.push({ - angle: Math.atan2(y1, x1), - index: i - }); - } - points.sort(function(a, b) { - return a.angle - b.angle; - }); - a = points[0].angle; - v = points[0].index; - u = 0; - for (i = 1; i < plen; ++i) { - j = points[i].index; - if (a == points[i].angle) { - x1 = vertices[v][0] - vertices[h][0]; - y1 = vertices[v][1] - vertices[h][1]; - x2 = vertices[j][0] - vertices[h][0]; - y2 = vertices[j][1] - vertices[h][1]; - if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { - points[i].index = -1; - continue; - } else { - points[u].index = -1; - } - } - a = points[i].angle; - u = i; - v = j; - } - stack.push(h); - for (i = 0, j = 0; i < 2; ++j) { - if (points[j].index > -1) { - stack.push(points[j].index); - i++; - } - } - sp = stack.length; - for (;j < plen; ++j) { - if (points[j].index < 0) continue; - while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { - --sp; - } - stack[sp++] = points[j].index; - } - var poly = []; - for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); - return poly; - } - hull.x = function(_) { - return arguments.length ? (x = _, hull) : x; - }; - hull.y = function(_) { - return arguments.length ? (y = _, hull) : y; - }; - return hull; - }; - function d3_geom_hullCCW(i1, i2, i3, v) { - var t, a, b, c, d, e, f; - t = v[i1]; - a = t[0]; - b = t[1]; - t = v[i2]; - c = t[0]; - d = t[1]; - t = v[i3]; - e = t[0]; - f = t[1]; - return (f - b) * (c - a) - (d - b) * (e - a) > 0; - } - d3.geom.polygon = function(coordinates) { - d3_subclass(coordinates, d3_geom_polygonPrototype); - return coordinates; - }; - var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; - d3_geom_polygonPrototype.area = function() { - var i = -1, n = this.length, a, b = this[n - 1], area = 0; - while (++i < n) { - a = b; - b = this[i]; - area += a[1] * b[0] - a[0] * b[1]; - } - return area * .5; - }; - d3_geom_polygonPrototype.centroid = function(k) { - var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; - if (!arguments.length) k = -1 / (6 * this.area()); - while (++i < n) { - a = b; - b = this[i]; - c = a[0] * b[1] - b[0] * a[1]; - x += (a[0] + b[0]) * c; - y += (a[1] + b[1]) * c; - } - return [ x * k, y * k ]; - }; - d3_geom_polygonPrototype.clip = function(subject) { - var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; - while (++i < n) { - input = subject.slice(); - subject.length = 0; - b = this[i]; - c = input[(m = input.length - closed) - 1]; - j = -1; - while (++j < m) { - d = input[j]; - if (d3_geom_polygonInside(d, a, b)) { - if (!d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - subject.push(d); - } else if (d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - c = d; - } - if (closed) subject.push(subject[0]); - a = b; - } - return subject; - }; - function d3_geom_polygonInside(p, a, b) { - return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); - } - function d3_geom_polygonIntersect(c, d, a, b) { - var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); - return [ x1 + ua * x21, y1 + ua * y21 ]; - } - function d3_geom_polygonClosed(coordinates) { - var a = coordinates[0], b = coordinates[coordinates.length - 1]; - return !(a[0] - b[0] || a[1] - b[1]); - } - d3.geom.delaunay = function(vertices) { - var edges = vertices.map(function() { - return []; - }), triangles = []; - d3_geom_voronoiTessellate(vertices, function(e) { - edges[e.region.l.index].push(vertices[e.region.r.index]); - }); - edges.forEach(function(edge, i) { - var v = vertices[i], cx = v[0], cy = v[1]; - edge.forEach(function(v) { - v.angle = Math.atan2(v[0] - cx, v[1] - cy); - }); - edge.sort(function(a, b) { - return a.angle - b.angle; - }); - for (var j = 0, m = edge.length - 1; j < m; j++) { - triangles.push([ v, edge[j], edge[j + 1] ]); - } - }); - return triangles; - }; - d3.geom.voronoi = function(points) { - var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; - if (arguments.length) return voronoi(points); - function voronoi(data) { - var points, polygons = data.map(function() { - return []; - }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; - if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), - i = 0; i < n; ++i) { - points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; - } - d3_geom_voronoiTessellate(points, function(e) { - var s1, s2, x1, x2, y1, y2; - if (e.a === 1 && e.b >= 0) { - s1 = e.ep.r; - s2 = e.ep.l; - } else { - s1 = e.ep.l; - s2 = e.ep.r; - } - if (e.a === 1) { - y1 = s1 ? s1.y : -Z; - x1 = e.c - e.b * y1; - y2 = s2 ? s2.y : Z; - x2 = e.c - e.b * y2; - } else { - x1 = s1 ? s1.x : -Z; - y1 = e.c - e.a * x1; - x2 = s2 ? s2.x : Z; - y2 = e.c - e.a * x2; - } - var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; - polygons[e.region.l.index].push(v1, v2); - polygons[e.region.r.index].push(v1, v2); - }); - polygons = polygons.map(function(polygon, i) { - var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { - return Math.atan2(v[0] - cx, v[1] - cy); - }), order = d3.range(polygon.length).sort(function(a, b) { - return angle[a] - angle[b]; - }); - return order.filter(function(d, i) { - return !i || angle[d] - angle[order[i - 1]] > ε; - }).map(function(d) { - return polygon[d]; - }); - }); - polygons.forEach(function(polygon, i) { - var n = polygon.length; - if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); - if (n > 2) return; - var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; - if (Math.abs(dy) < ε) { - var y = y0 < y1 ? -Z : Z; - polygon.push([ -Z, y ], [ Z, y ]); - } else if (dx < ε) { - var x = x0 < x1 ? -Z : Z; - polygon.push([ x, -Z ], [ x, Z ]); - } else { - var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; - if (Math.abs(z) < ε) { - polygon.push([ dy < 0 ? y : -y, y ]); - } else { - if (z > 0) y *= -1; - polygon.push([ -Z, y ], [ Z, y ]); - } - } - }); - if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); - for (i = 0; i < n; ++i) polygons[i].point = data[i]; - return polygons; - } - voronoi.x = function(_) { - return arguments.length ? (x = _, voronoi) : x; - }; - voronoi.y = function(_) { - return arguments.length ? (y = _, voronoi) : y; - }; - voronoi.clipExtent = function(_) { - if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; - if (_ == null) clipPolygon = null; else { - var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; - clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); - } - return voronoi; - }; - voronoi.size = function(_) { - if (!arguments.length) return clipPolygon && clipPolygon[2]; - return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); - }; - voronoi.links = function(data) { - var points, graph = data.map(function() { - return []; - }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; - if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), - i = 0; i < n; ++i) { - points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; - } - d3_geom_voronoiTessellate(points, function(e) { - var l = e.region.l.index, r = e.region.r.index; - if (graph[l][r]) return; - graph[l][r] = graph[r][l] = true; - links.push({ - source: data[l], - target: data[r] - }); - }); - return links; - }; - voronoi.triangles = function(data) { - if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); - var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; - while (++i < n) { - (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; - } - return d3.geom.delaunay(points).map(function(triangle) { - return triangle.map(function(point) { - return point.data; - }); - }); - }; - return voronoi; - }; - var d3_geom_voronoiOpposite = { - l: "r", - r: "l" - }; - function d3_geom_voronoiTessellate(points, callback) { - var Sites = { - list: points.map(function(v, i) { - return { - index: i, - x: v[0], - y: v[1] - }; - }).sort(function(a, b) { - return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; - }), - bottomSite: null - }; - var EdgeList = { - list: [], - leftEnd: null, - rightEnd: null, - init: function() { - EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.leftEnd.r = EdgeList.rightEnd; - EdgeList.rightEnd.l = EdgeList.leftEnd; - EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); - }, - createHalfEdge: function(edge, side) { - return { - edge: edge, - side: side, - vertex: null, - l: null, - r: null - }; - }, - insert: function(lb, he) { - he.l = lb; - he.r = lb.r; - lb.r.l = he; - lb.r = he; - }, - leftBound: function(p) { - var he = EdgeList.leftEnd; - do { - he = he.r; - } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); - he = he.l; - return he; - }, - del: function(he) { - he.l.r = he.r; - he.r.l = he.l; - he.edge = null; - }, - right: function(he) { - return he.r; - }, - left: function(he) { - return he.l; - }, - leftRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; - }, - rightRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; - } - }; - var Geom = { - bisect: function(s1, s2) { - var newEdge = { - region: { - l: s1, - r: s2 - }, - ep: { - l: null, - r: null - } - }; - var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; - newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; - if (adx > ady) { - newEdge.a = 1; - newEdge.b = dy / dx; - newEdge.c /= dx; - } else { - newEdge.b = 1; - newEdge.a = dx / dy; - newEdge.c /= dy; - } - return newEdge; - }, - intersect: function(el1, el2) { - var e1 = el1.edge, e2 = el2.edge; - if (!e1 || !e2 || e1.region.r == e2.region.r) { - return null; - } - var d = e1.a * e2.b - e1.b * e2.a; - if (Math.abs(d) < 1e-10) { - return null; - } - var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; - if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { - el = el1; - e = e1; - } else { - el = el2; - e = e2; - } - var rightOfSite = xint >= e.region.r.x; - if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { - return null; - } - return { - x: xint, - y: yint - }; - }, - rightOf: function(he, p) { - var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; - if (rightOfSite && he.side === "l") { - return 1; - } - if (!rightOfSite && he.side === "r") { - return 0; - } - if (e.a === 1) { - var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; - if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { - above = fast = dyp >= e.b * dxp; - } else { - above = p.x + p.y * e.b > e.c; - if (e.b < 0) { - above = !above; - } - if (!above) { - fast = 1; - } - } - if (!fast) { - var dxs = topsite.x - e.region.l.x; - above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); - if (e.b < 0) { - above = !above; - } - } - } else { - var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; - above = t1 * t1 > t2 * t2 + t3 * t3; - } - return he.side === "l" ? above : !above; - }, - endPoint: function(edge, side, site) { - edge.ep[side] = site; - if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; - callback(edge); - }, - distance: function(s, t) { - var dx = s.x - t.x, dy = s.y - t.y; - return Math.sqrt(dx * dx + dy * dy); - } - }; - var EventQueue = { - list: [], - insert: function(he, site, offset) { - he.vertex = site; - he.ystar = site.y + offset; - for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { - var next = list[i]; - if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { - continue; - } else { - break; - } - } - list.splice(i, 0, he); - }, - del: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} - ls.splice(i, 1); - }, - empty: function() { - return EventQueue.list.length === 0; - }, - nextEvent: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { - if (ls[i] == he) return ls[i + 1]; - } - return null; - }, - min: function() { - var elem = EventQueue.list[0]; - return { - x: elem.vertex.x, - y: elem.ystar - }; - }, - extractMin: function() { - return EventQueue.list.shift(); - } - }; - EdgeList.init(); - Sites.bottomSite = Sites.list.shift(); - var newSite = Sites.list.shift(), newIntStar; - var lbnd, rbnd, llbnd, rrbnd, bisector; - var bot, top, temp, p, v; - var e, pm; - while (true) { - if (!EventQueue.empty()) { - newIntStar = EventQueue.min(); - } - if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { - lbnd = EdgeList.leftBound(newSite); - rbnd = EdgeList.right(lbnd); - bot = EdgeList.rightRegion(lbnd); - e = Geom.bisect(bot, newSite); - bisector = EdgeList.createHalfEdge(e, "l"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(lbnd, bisector); - if (p) { - EventQueue.del(lbnd); - EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); - } - lbnd = bisector; - bisector = EdgeList.createHalfEdge(e, "r"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(bisector, rbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, newSite)); - } - newSite = Sites.list.shift(); - } else if (!EventQueue.empty()) { - lbnd = EventQueue.extractMin(); - llbnd = EdgeList.left(lbnd); - rbnd = EdgeList.right(lbnd); - rrbnd = EdgeList.right(rbnd); - bot = EdgeList.leftRegion(lbnd); - top = EdgeList.rightRegion(rbnd); - v = lbnd.vertex; - Geom.endPoint(lbnd.edge, lbnd.side, v); - Geom.endPoint(rbnd.edge, rbnd.side, v); - EdgeList.del(lbnd); - EventQueue.del(rbnd); - EdgeList.del(rbnd); - pm = "l"; - if (bot.y > top.y) { - temp = bot; - bot = top; - top = temp; - pm = "r"; - } - e = Geom.bisect(bot, top); - bisector = EdgeList.createHalfEdge(e, pm); - EdgeList.insert(llbnd, bisector); - Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); - p = Geom.intersect(llbnd, bisector); - if (p) { - EventQueue.del(llbnd); - EventQueue.insert(llbnd, p, Geom.distance(p, bot)); - } - p = Geom.intersect(bisector, rrbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, bot)); - } - } else { - break; - } - } - for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { - callback(lbnd.edge); - } - } - d3.geom.quadtree = function(points, x1, y1, x2, y2) { - var x = d3_svg_lineX, y = d3_svg_lineY, compat; - if (compat = arguments.length) { - x = d3_geom_quadtreeCompatX; - y = d3_geom_quadtreeCompatY; - if (compat === 3) { - y2 = y1; - x2 = x1; - y1 = x1 = 0; - } - return quadtree(points); - } - function quadtree(data) { - var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; - if (x1 != null) { - x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; - } else { - x2_ = y2_ = -(x1_ = y1_ = Infinity); - xs = [], ys = []; - n = data.length; - if (compat) for (i = 0; i < n; ++i) { - d = data[i]; - if (d.x < x1_) x1_ = d.x; - if (d.y < y1_) y1_ = d.y; - if (d.x > x2_) x2_ = d.x; - if (d.y > y2_) y2_ = d.y; - xs.push(d.x); - ys.push(d.y); - } else for (i = 0; i < n; ++i) { - var x_ = +fx(d = data[i], i), y_ = +fy(d, i); - if (x_ < x1_) x1_ = x_; - if (y_ < y1_) y1_ = y_; - if (x_ > x2_) x2_ = x_; - if (y_ > y2_) y2_ = y_; - xs.push(x_); - ys.push(y_); - } - } - var dx = x2_ - x1_, dy = y2_ - y1_; - if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; - function insert(n, d, x, y, x1, y1, x2, y2) { - if (isNaN(x) || isNaN(y)) return; - if (n.leaf) { - var nx = n.x, ny = n.y; - if (nx != null) { - if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { - insertChild(n, d, x, y, x1, y1, x2, y2); - } else { - var nPoint = n.point; - n.x = n.y = n.point = null; - insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); - insertChild(n, d, x, y, x1, y1, x2, y2); - } - } else { - n.x = x, n.y = y, n.point = d; - } - } else { - insertChild(n, d, x, y, x1, y1, x2, y2); - } - } - function insertChild(n, d, x, y, x1, y1, x2, y2) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; - n.leaf = false; - n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); - if (right) x1 = sx; else x2 = sx; - if (bottom) y1 = sy; else y2 = sy; - insert(n, d, x, y, x1, y1, x2, y2); - } - var root = d3_geom_quadtreeNode(); - root.add = function(d) { - insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); - }; - root.visit = function(f) { - d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); - }; - i = -1; - if (x1 == null) { - while (++i < n) { - insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); - } - --i; - } else data.forEach(root.add); - xs = ys = data = d = null; - return root; - } - quadtree.x = function(_) { - return arguments.length ? (x = _, quadtree) : x; - }; - quadtree.y = function(_) { - return arguments.length ? (y = _, quadtree) : y; - }; - quadtree.extent = function(_) { - if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; - if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], - y2 = +_[1][1]; - return quadtree; - }; - quadtree.size = function(_) { - if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; - if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; - return quadtree; - }; - return quadtree; - }; - function d3_geom_quadtreeCompatX(d) { - return d.x; - } - function d3_geom_quadtreeCompatY(d) { - return d.y; - } - function d3_geom_quadtreeNode() { - return { - leaf: true, - nodes: [], - point: null, - x: null, - y: null - }; - } - function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { - if (!f(node, x1, y1, x2, y2)) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; - if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); - if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); - if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); - if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); - } - } - d3.interpolateRgb = d3_interpolateRgb; - function d3_interpolateRgb(a, b) { - a = d3.rgb(a); - b = d3.rgb(b); - var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; - return function(t) { - return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); - }; - } - d3.interpolateObject = d3_interpolateObject; - function d3_interpolateObject(a, b) { - var i = {}, c = {}, k; - for (k in a) { - if (k in b) { - i[k] = d3_interpolate(a[k], b[k]); - } else { - c[k] = a[k]; - } - } - for (k in b) { - if (!(k in a)) { - c[k] = b[k]; - } - } - return function(t) { - for (k in i) c[k] = i[k](t); - return c; - }; - } - d3.interpolateNumber = d3_interpolateNumber; - function d3_interpolateNumber(a, b) { - b -= a = +a; - return function(t) { - return a + b * t; - }; - } - d3.interpolateString = d3_interpolateString; - function d3_interpolateString(a, b) { - var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; - a = a + "", b = b + ""; - d3_interpolate_number.lastIndex = 0; - for (i = 0; m = d3_interpolate_number.exec(b); ++i) { - if (m.index) s.push(b.substring(s0, s1 = m.index)); - q.push({ - i: s.length, - x: m[0] - }); - s.push(null); - s0 = d3_interpolate_number.lastIndex; - } - if (s0 < b.length) s.push(b.substring(s0)); - for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { - o = q[i]; - if (o.x == m[0]) { - if (o.i) { - if (s[o.i + 1] == null) { - s[o.i - 1] += o.x; - s.splice(o.i, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } else { - s[o.i - 1] += o.x + s[o.i + 1]; - s.splice(o.i, 2); - for (j = i + 1; j < n; ++j) q[j].i -= 2; - } - } else { - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } - } - q.splice(i, 1); - n--; - i--; - } else { - o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); - } - } - while (i < n) { - o = q.pop(); - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - } - n--; - } - if (s.length === 1) { - return s[0] == null ? (o = q[0].x, function(t) { - return o(t) + ""; - }) : function() { - return b; - }; - } - return function(t) { - for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; - } - var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; - d3.interpolate = d3_interpolate; - function d3_interpolate(a, b) { - var i = d3.interpolators.length, f; - while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; - return f; - } - d3.interpolators = [ function(a, b) { - var t = typeof b; - return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); - } ]; - d3.interpolateArray = d3_interpolateArray; - function d3_interpolateArray(a, b) { - var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; - for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); - for (;i < na; ++i) c[i] = a[i]; - for (;i < nb; ++i) c[i] = b[i]; - return function(t) { - for (i = 0; i < n0; ++i) c[i] = x[i](t); - return c; - }; - } - var d3_ease_default = function() { - return d3_identity; - }; - var d3_ease = d3.map({ - linear: d3_ease_default, - poly: d3_ease_poly, - quad: function() { - return d3_ease_quad; - }, - cubic: function() { - return d3_ease_cubic; - }, - sin: function() { - return d3_ease_sin; - }, - exp: function() { - return d3_ease_exp; - }, - circle: function() { - return d3_ease_circle; - }, - elastic: d3_ease_elastic, - back: d3_ease_back, - bounce: function() { - return d3_ease_bounce; - } - }); - var d3_ease_mode = d3.map({ - "in": d3_identity, - out: d3_ease_reverse, - "in-out": d3_ease_reflect, - "out-in": function(f) { - return d3_ease_reflect(d3_ease_reverse(f)); - } - }); - d3.ease = function(name) { - var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; - t = d3_ease.get(t) || d3_ease_default; - m = d3_ease_mode.get(m) || d3_identity; - return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); - }; - function d3_ease_clamp(f) { - return function(t) { - return t <= 0 ? 0 : t >= 1 ? 1 : f(t); - }; - } - function d3_ease_reverse(f) { - return function(t) { - return 1 - f(1 - t); - }; - } - function d3_ease_reflect(f) { - return function(t) { - return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); - }; - } - function d3_ease_quad(t) { - return t * t; - } - function d3_ease_cubic(t) { - return t * t * t; - } - function d3_ease_cubicInOut(t) { - if (t <= 0) return 0; - if (t >= 1) return 1; - var t2 = t * t, t3 = t2 * t; - return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); - } - function d3_ease_poly(e) { - return function(t) { - return Math.pow(t, e); - }; - } - function d3_ease_sin(t) { - return 1 - Math.cos(t * π / 2); - } - function d3_ease_exp(t) { - return Math.pow(2, 10 * (t - 1)); - } - function d3_ease_circle(t) { - return 1 - Math.sqrt(1 - t * t); - } - function d3_ease_elastic(a, p) { - var s; - if (arguments.length < 2) p = .45; - if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; - return function(t) { - return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); - }; - } - function d3_ease_back(s) { - if (!s) s = 1.70158; - return function(t) { - return t * t * ((s + 1) * t - s); - }; - } - function d3_ease_bounce(t) { - return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; - } - d3.interpolateHcl = d3_interpolateHcl; - function d3_interpolateHcl(a, b) { - a = d3.hcl(a); - b = d3.hcl(b); - var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; - if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; - if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; - return function(t) { - return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; - }; - } - d3.interpolateHsl = d3_interpolateHsl; - function d3_interpolateHsl(a, b) { - a = d3.hsl(a); - b = d3.hsl(b); - var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; - if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; - if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; - return function(t) { - return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; - }; - } - d3.interpolateLab = d3_interpolateLab; - function d3_interpolateLab(a, b) { - a = d3.lab(a); - b = d3.lab(b); - var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; - return function(t) { - return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; - }; - } - d3.interpolateRound = d3_interpolateRound; - function d3_interpolateRound(a, b) { - b -= a; - return function(t) { - return Math.round(a + b * t); - }; - } - d3.transform = function(string) { - var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); - return (d3.transform = function(string) { - if (string != null) { - g.setAttribute("transform", string); - var t = g.transform.baseVal.consolidate(); - } - return new d3_transform(t ? t.matrix : d3_transformIdentity); - })(string); - }; - function d3_transform(m) { - var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; - if (r0[0] * r1[1] < r1[0] * r0[1]) { - r0[0] *= -1; - r0[1] *= -1; - kx *= -1; - kz *= -1; - } - this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; - this.translate = [ m.e, m.f ]; - this.scale = [ kx, ky ]; - this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; - } - d3_transform.prototype.toString = function() { - return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; - }; - function d3_transformDot(a, b) { - return a[0] * b[0] + a[1] * b[1]; - } - function d3_transformNormalize(a) { - var k = Math.sqrt(d3_transformDot(a, a)); - if (k) { - a[0] /= k; - a[1] /= k; - } - return k; - } - function d3_transformCombine(a, b, k) { - a[0] += k * b[0]; - a[1] += k * b[1]; - return a; - } - var d3_transformIdentity = { - a: 1, - b: 0, - c: 0, - d: 1, - e: 0, - f: 0 - }; - d3.interpolateTransform = d3_interpolateTransform; - function d3_interpolateTransform(a, b) { - var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; - if (ta[0] != tb[0] || ta[1] != tb[1]) { - s.push("translate(", null, ",", null, ")"); - q.push({ - i: 1, - x: d3_interpolateNumber(ta[0], tb[0]) - }, { - i: 3, - x: d3_interpolateNumber(ta[1], tb[1]) - }); - } else if (tb[0] || tb[1]) { - s.push("translate(" + tb + ")"); - } else { - s.push(""); - } - if (ra != rb) { - if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; - q.push({ - i: s.push(s.pop() + "rotate(", null, ")") - 2, - x: d3_interpolateNumber(ra, rb) - }); - } else if (rb) { - s.push(s.pop() + "rotate(" + rb + ")"); - } - if (wa != wb) { - q.push({ - i: s.push(s.pop() + "skewX(", null, ")") - 2, - x: d3_interpolateNumber(wa, wb) - }); - } else if (wb) { - s.push(s.pop() + "skewX(" + wb + ")"); - } - if (ka[0] != kb[0] || ka[1] != kb[1]) { - n = s.push(s.pop() + "scale(", null, ",", null, ")"); - q.push({ - i: n - 4, - x: d3_interpolateNumber(ka[0], kb[0]) - }, { - i: n - 2, - x: d3_interpolateNumber(ka[1], kb[1]) - }); - } else if (kb[0] != 1 || kb[1] != 1) { - s.push(s.pop() + "scale(" + kb + ")"); - } - n = q.length; - return function(t) { - var i = -1, o; - while (++i < n) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; - } - function d3_uninterpolateNumber(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return (x - a) * b; - }; - } - function d3_uninterpolateClamp(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return Math.max(0, Math.min(1, (x - a) * b)); - }; - } - d3.layout = {}; - d3.layout.bundle = function() { - return function(links) { - var paths = [], i = -1, n = links.length; - while (++i < n) paths.push(d3_layout_bundlePath(links[i])); - return paths; - }; - }; - function d3_layout_bundlePath(link) { - var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; - while (start !== lca) { - start = start.parent; - points.push(start); - } - var k = points.length; - while (end !== lca) { - points.splice(k, 0, end); - end = end.parent; - } - return points; - } - function d3_layout_bundleAncestors(node) { - var ancestors = [], parent = node.parent; - while (parent != null) { - ancestors.push(node); - node = parent; - parent = parent.parent; - } - ancestors.push(node); - return ancestors; - } - function d3_layout_bundleLeastCommonAncestor(a, b) { - if (a === b) return a; - var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; - while (aNode === bNode) { - sharedNode = aNode; - aNode = aNodes.pop(); - bNode = bNodes.pop(); - } - return sharedNode; - } - d3.layout.chord = function() { - var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; - function relayout() { - var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; - chords = []; - groups = []; - k = 0, i = -1; - while (++i < n) { - x = 0, j = -1; - while (++j < n) { - x += matrix[i][j]; - } - groupSums.push(x); - subgroupIndex.push(d3.range(n)); - k += x; - } - if (sortGroups) { - groupIndex.sort(function(a, b) { - return sortGroups(groupSums[a], groupSums[b]); - }); - } - if (sortSubgroups) { - subgroupIndex.forEach(function(d, i) { - d.sort(function(a, b) { - return sortSubgroups(matrix[i][a], matrix[i][b]); - }); - }); - } - k = (2 * π - padding * n) / k; - x = 0, i = -1; - while (++i < n) { - x0 = x, j = -1; - while (++j < n) { - var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; - subgroups[di + "-" + dj] = { - index: di, - subindex: dj, - startAngle: a0, - endAngle: a1, - value: v - }; - } - groups[di] = { - index: di, - startAngle: x0, - endAngle: x, - value: (x - x0) / k - }; - x += padding; - } - i = -1; - while (++i < n) { - j = i - 1; - while (++j < n) { - var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; - if (source.value || target.value) { - chords.push(source.value < target.value ? { - source: target, - target: source - } : { - source: source, - target: target - }); - } - } - } - if (sortChords) resort(); - } - function resort() { - chords.sort(function(a, b) { - return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); - }); - } - chord.matrix = function(x) { - if (!arguments.length) return matrix; - n = (matrix = x) && matrix.length; - chords = groups = null; - return chord; - }; - chord.padding = function(x) { - if (!arguments.length) return padding; - padding = x; - chords = groups = null; - return chord; - }; - chord.sortGroups = function(x) { - if (!arguments.length) return sortGroups; - sortGroups = x; - chords = groups = null; - return chord; - }; - chord.sortSubgroups = function(x) { - if (!arguments.length) return sortSubgroups; - sortSubgroups = x; - chords = null; - return chord; - }; - chord.sortChords = function(x) { - if (!arguments.length) return sortChords; - sortChords = x; - if (chords) resort(); - return chord; - }; - chord.chords = function() { - if (!chords) relayout(); - return chords; - }; - chord.groups = function() { - if (!groups) relayout(); - return groups; - }; - return chord; - }; - d3.layout.force = function() { - var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; - function repulse(node) { - return function(quad, x1, _, x2) { - if (quad.point !== node) { - var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); - if ((x2 - x1) * dn < theta) { - var k = quad.charge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - return true; - } - if (quad.point && isFinite(dn)) { - var k = quad.pointCharge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - } - } - return !quad.charge; - }; - } - force.tick = function() { - if ((alpha *= .99) < .005) { - event.end({ - type: "end", - alpha: alpha = 0 - }); - return true; - } - var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; - for (i = 0; i < m; ++i) { - o = links[i]; - s = o.source; - t = o.target; - x = t.x - s.x; - y = t.y - s.y; - if (l = x * x + y * y) { - l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; - x *= l; - y *= l; - t.x -= x * (k = s.weight / (t.weight + s.weight)); - t.y -= y * k; - s.x += x * (k = 1 - k); - s.y += y * k; - } - } - if (k = alpha * gravity) { - x = size[0] / 2; - y = size[1] / 2; - i = -1; - if (k) while (++i < n) { - o = nodes[i]; - o.x += (x - o.x) * k; - o.y += (y - o.y) * k; - } - } - if (charge) { - d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); - i = -1; - while (++i < n) { - if (!(o = nodes[i]).fixed) { - q.visit(repulse(o)); - } - } - } - i = -1; - while (++i < n) { - o = nodes[i]; - if (o.fixed) { - o.x = o.px; - o.y = o.py; - } else { - o.x -= (o.px - (o.px = o.x)) * friction; - o.y -= (o.py - (o.py = o.y)) * friction; - } - } - event.tick({ - type: "tick", - alpha: alpha - }); - }; - force.nodes = function(x) { - if (!arguments.length) return nodes; - nodes = x; - return force; - }; - force.links = function(x) { - if (!arguments.length) return links; - links = x; - return force; - }; - force.size = function(x) { - if (!arguments.length) return size; - size = x; - return force; - }; - force.linkDistance = function(x) { - if (!arguments.length) return linkDistance; - linkDistance = typeof x === "function" ? x : +x; - return force; - }; - force.distance = force.linkDistance; - force.linkStrength = function(x) { - if (!arguments.length) return linkStrength; - linkStrength = typeof x === "function" ? x : +x; - return force; - }; - force.friction = function(x) { - if (!arguments.length) return friction; - friction = +x; - return force; - }; - force.charge = function(x) { - if (!arguments.length) return charge; - charge = typeof x === "function" ? x : +x; - return force; - }; - force.gravity = function(x) { - if (!arguments.length) return gravity; - gravity = +x; - return force; - }; - force.theta = function(x) { - if (!arguments.length) return theta; - theta = +x; - return force; - }; - force.alpha = function(x) { - if (!arguments.length) return alpha; - x = +x; - if (alpha) { - if (x > 0) alpha = x; else alpha = 0; - } else if (x > 0) { - event.start({ - type: "start", - alpha: alpha = x - }); - d3.timer(force.tick); - } - return force; - }; - force.start = function() { - var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; - for (i = 0; i < n; ++i) { - (o = nodes[i]).index = i; - o.weight = 0; - } - for (i = 0; i < m; ++i) { - o = links[i]; - if (typeof o.source == "number") o.source = nodes[o.source]; - if (typeof o.target == "number") o.target = nodes[o.target]; - ++o.source.weight; - ++o.target.weight; - } - for (i = 0; i < n; ++i) { - o = nodes[i]; - if (isNaN(o.x)) o.x = position("x", w); - if (isNaN(o.y)) o.y = position("y", h); - if (isNaN(o.px)) o.px = o.x; - if (isNaN(o.py)) o.py = o.y; - } - distances = []; - if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; - strengths = []; - if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; - charges = []; - if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; - function position(dimension, size) { - var neighbors = neighbor(i), j = -1, m = neighbors.length, x; - while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; - return Math.random() * size; - } - function neighbor() { - if (!neighbors) { - neighbors = []; - for (j = 0; j < n; ++j) { - neighbors[j] = []; - } - for (j = 0; j < m; ++j) { - var o = links[j]; - neighbors[o.source.index].push(o.target); - neighbors[o.target.index].push(o.source); - } - } - return neighbors[i]; - } - return force.resume(); - }; - force.resume = function() { - return force.alpha(.1); - }; - force.stop = function() { - return force.alpha(0); - }; - force.drag = function() { - if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); - if (!arguments.length) return drag; - this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); - }; - function dragmove(d) { - d.px = d3.event.x, d.py = d3.event.y; - force.resume(); - } - return d3.rebind(force, event, "on"); - }; - function d3_layout_forceDragstart(d) { - d.fixed |= 2; - } - function d3_layout_forceDragend(d) { - d.fixed &= ~6; - } - function d3_layout_forceMouseover(d) { - d.fixed |= 4; - d.px = d.x, d.py = d.y; - } - function d3_layout_forceMouseout(d) { - d.fixed &= ~4; - } - function d3_layout_forceAccumulate(quad, alpha, charges) { - var cx = 0, cy = 0; - quad.charge = 0; - if (!quad.leaf) { - var nodes = quad.nodes, n = nodes.length, i = -1, c; - while (++i < n) { - c = nodes[i]; - if (c == null) continue; - d3_layout_forceAccumulate(c, alpha, charges); - quad.charge += c.charge; - cx += c.charge * c.cx; - cy += c.charge * c.cy; - } - } - if (quad.point) { - if (!quad.leaf) { - quad.point.x += Math.random() - .5; - quad.point.y += Math.random() - .5; - } - var k = alpha * charges[quad.point.index]; - quad.charge += quad.pointCharge = k; - cx += k * quad.point.x; - cy += k * quad.point.y; - } - quad.cx = cx / quad.charge; - quad.cy = cy / quad.charge; - } - var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; - d3.layout.hierarchy = function() { - var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; - function recurse(node, depth, nodes) { - var childs = children.call(hierarchy, node, depth); - node.depth = depth; - nodes.push(node); - if (childs && (n = childs.length)) { - var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; - while (++i < n) { - d = recurse(childs[i], j, nodes); - d.parent = node; - c.push(d); - v += d.value; - } - if (sort) c.sort(sort); - if (value) node.value = v; - } else if (value) { - node.value = +value.call(hierarchy, node, depth) || 0; - } - return node; - } - function revalue(node, depth) { - var children = node.children, v = 0; - if (children && (n = children.length)) { - var i = -1, n, j = depth + 1; - while (++i < n) v += revalue(children[i], j); - } else if (value) { - v = +value.call(hierarchy, node, depth) || 0; - } - if (value) node.value = v; - return v; - } - function hierarchy(d) { - var nodes = []; - recurse(d, 0, nodes); - return nodes; - } - hierarchy.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return hierarchy; - }; - hierarchy.children = function(x) { - if (!arguments.length) return children; - children = x; - return hierarchy; - }; - hierarchy.value = function(x) { - if (!arguments.length) return value; - value = x; - return hierarchy; - }; - hierarchy.revalue = function(root) { - revalue(root, 0); - return root; - }; - return hierarchy; - }; - function d3_layout_hierarchyRebind(object, hierarchy) { - d3.rebind(object, hierarchy, "sort", "children", "value"); - object.nodes = object; - object.links = d3_layout_hierarchyLinks; - return object; - } - function d3_layout_hierarchyChildren(d) { - return d.children; - } - function d3_layout_hierarchyValue(d) { - return d.value; - } - function d3_layout_hierarchySort(a, b) { - return b.value - a.value; - } - function d3_layout_hierarchyLinks(nodes) { - return d3.merge(nodes.map(function(parent) { - return (parent.children || []).map(function(child) { - return { - source: parent, - target: child - }; - }); - })); - } - d3.layout.partition = function() { - var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; - function position(node, x, dx, dy) { - var children = node.children; - node.x = x; - node.y = node.depth * dy; - node.dx = dx; - node.dy = dy; - if (children && (n = children.length)) { - var i = -1, n, c, d; - dx = node.value ? dx / node.value : 0; - while (++i < n) { - position(c = children[i], x, d = c.value * dx, dy); - x += d; - } - } - } - function depth(node) { - var children = node.children, d = 0; - if (children && (n = children.length)) { - var i = -1, n; - while (++i < n) d = Math.max(d, depth(children[i])); - } - return 1 + d; - } - function partition(d, i) { - var nodes = hierarchy.call(this, d, i); - position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); - return nodes; - } - partition.size = function(x) { - if (!arguments.length) return size; - size = x; - return partition; - }; - return d3_layout_hierarchyRebind(partition, hierarchy); - }; - d3.layout.pie = function() { - var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; - function pie(data) { - var values = data.map(function(d, i) { - return +value.call(pie, d, i); - }); - var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); - var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); - var index = d3.range(data.length); - if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { - return values[j] - values[i]; - } : function(i, j) { - return sort(data[i], data[j]); - }); - var arcs = []; - index.forEach(function(i) { - var d; - arcs[i] = { - data: data[i], - value: d = values[i], - startAngle: a, - endAngle: a += d * k - }; - }); - return arcs; - } - pie.value = function(x) { - if (!arguments.length) return value; - value = x; - return pie; - }; - pie.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return pie; - }; - pie.startAngle = function(x) { - if (!arguments.length) return startAngle; - startAngle = x; - return pie; - }; - pie.endAngle = function(x) { - if (!arguments.length) return endAngle; - endAngle = x; - return pie; - }; - return pie; - }; - var d3_layout_pieSortByValue = {}; - d3.layout.stack = function() { - var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; - function stack(data, index) { - var series = data.map(function(d, i) { - return values.call(stack, d, i); - }); - var points = series.map(function(d) { - return d.map(function(v, i) { - return [ x.call(stack, v, i), y.call(stack, v, i) ]; - }); - }); - var orders = order.call(stack, points, index); - series = d3.permute(series, orders); - points = d3.permute(points, orders); - var offsets = offset.call(stack, points, index); - var n = series.length, m = series[0].length, i, j, o; - for (j = 0; j < m; ++j) { - out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); - for (i = 1; i < n; ++i) { - out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); - } - } - return data; - } - stack.values = function(x) { - if (!arguments.length) return values; - values = x; - return stack; - }; - stack.order = function(x) { - if (!arguments.length) return order; - order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; - return stack; - }; - stack.offset = function(x) { - if (!arguments.length) return offset; - offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; - return stack; - }; - stack.x = function(z) { - if (!arguments.length) return x; - x = z; - return stack; - }; - stack.y = function(z) { - if (!arguments.length) return y; - y = z; - return stack; - }; - stack.out = function(z) { - if (!arguments.length) return out; - out = z; - return stack; - }; - return stack; - }; - function d3_layout_stackX(d) { - return d.x; - } - function d3_layout_stackY(d) { - return d.y; - } - function d3_layout_stackOut(d, y0, y) { - d.y0 = y0; - d.y = y; - } - var d3_layout_stackOrders = d3.map({ - "inside-out": function(data) { - var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { - return max[a] - max[b]; - }), top = 0, bottom = 0, tops = [], bottoms = []; - for (i = 0; i < n; ++i) { - j = index[i]; - if (top < bottom) { - top += sums[j]; - tops.push(j); - } else { - bottom += sums[j]; - bottoms.push(j); - } - } - return bottoms.reverse().concat(tops); - }, - reverse: function(data) { - return d3.range(data.length).reverse(); - }, - "default": d3_layout_stackOrderDefault - }); - var d3_layout_stackOffsets = d3.map({ - silhouette: function(data) { - var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o > max) max = o; - sums.push(o); - } - for (j = 0; j < m; ++j) { - y0[j] = (max - sums[j]) / 2; - } - return y0; - }, - wiggle: function(data) { - var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; - y0[0] = o = o0 = 0; - for (j = 1; j < m; ++j) { - for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; - for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { - for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { - s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; - } - s2 += s3 * data[i][j][1]; - } - y0[j] = o -= s1 ? s2 / s1 * dx : 0; - if (o < o0) o0 = o; - } - for (j = 0; j < m; ++j) y0[j] -= o0; - return y0; - }, - expand: function(data) { - var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; - } - for (j = 0; j < m; ++j) y0[j] = 0; - return y0; - }, - zero: d3_layout_stackOffsetZero - }); - function d3_layout_stackOrderDefault(data) { - return d3.range(data.length); - } - function d3_layout_stackOffsetZero(data) { - var j = -1, m = data[0].length, y0 = []; - while (++j < m) y0[j] = 0; - return y0; - } - function d3_layout_stackMaxIndex(array) { - var i = 1, j = 0, v = array[0][1], k, n = array.length; - for (;i < n; ++i) { - if ((k = array[i][1]) > v) { - j = i; - v = k; - } - } - return j; - } - function d3_layout_stackReduceSum(d) { - return d.reduce(d3_layout_stackSum, 0); - } - function d3_layout_stackSum(p, d) { - return p + d[1]; - } - d3.layout.histogram = function() { - var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; - function histogram(data, i) { - var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; - while (++i < m) { - bin = bins[i] = []; - bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); - bin.y = 0; - } - if (m > 0) { - i = -1; - while (++i < n) { - x = values[i]; - if (x >= range[0] && x <= range[1]) { - bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; - bin.y += k; - bin.push(data[i]); - } - } - } - return bins; - } - histogram.value = function(x) { - if (!arguments.length) return valuer; - valuer = x; - return histogram; - }; - histogram.range = function(x) { - if (!arguments.length) return ranger; - ranger = d3_functor(x); - return histogram; - }; - histogram.bins = function(x) { - if (!arguments.length) return binner; - binner = typeof x === "number" ? function(range) { - return d3_layout_histogramBinFixed(range, x); - } : d3_functor(x); - return histogram; - }; - histogram.frequency = function(x) { - if (!arguments.length) return frequency; - frequency = !!x; - return histogram; - }; - return histogram; - }; - function d3_layout_histogramBinSturges(range, values) { - return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); - } - function d3_layout_histogramBinFixed(range, n) { - var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; - while (++x <= n) f[x] = m * x + b; - return f; - } - function d3_layout_histogramRange(values) { - return [ d3.min(values), d3.max(values) ]; - } - d3.layout.tree = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; - function tree(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0]; - function firstWalk(node, previousSibling) { - var children = node.children, layout = node._tree; - if (children && (n = children.length)) { - var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; - while (++i < n) { - child = children[i]; - firstWalk(child, previousChild); - ancestor = apportion(child, previousChild, ancestor); - previousChild = child; - } - d3_layout_treeShift(node); - var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - layout.mod = layout.prelim - midpoint; - } else { - layout.prelim = midpoint; - } - } else { - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - } - } - } - function secondWalk(node, x) { - node.x = node._tree.prelim + x; - var children = node.children; - if (children && (n = children.length)) { - var i = -1, n; - x += node._tree.mod; - while (++i < n) { - secondWalk(children[i], x); - } - } - } - function apportion(node, previousSibling, ancestor) { - if (previousSibling) { - var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; - while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { - vom = d3_layout_treeLeft(vom); - vop = d3_layout_treeRight(vop); - vop._tree.ancestor = node; - shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); - if (shift > 0) { - d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); - sip += shift; - sop += shift; - } - sim += vim._tree.mod; - sip += vip._tree.mod; - som += vom._tree.mod; - sop += vop._tree.mod; - } - if (vim && !d3_layout_treeRight(vop)) { - vop._tree.thread = vim; - vop._tree.mod += sim - sop; - } - if (vip && !d3_layout_treeLeft(vom)) { - vom._tree.thread = vip; - vom._tree.mod += sip - som; - ancestor = node; - } - } - return ancestor; - } - d3_layout_treeVisitAfter(root, function(node, previousSibling) { - node._tree = { - ancestor: node, - prelim: 0, - mod: 0, - change: 0, - shift: 0, - number: previousSibling ? previousSibling._tree.number + 1 : 0 - }; - }); - firstWalk(root); - secondWalk(root, -root._tree.prelim); - var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; - d3_layout_treeVisitAfter(root, nodeSize ? function(node) { - node.x *= size[0]; - node.y = node.depth * size[1]; - delete node._tree; - } : function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = node.depth / y1 * size[1]; - delete node._tree; - }); - return nodes; - } - tree.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return tree; - }; - tree.size = function(x) { - if (!arguments.length) return nodeSize ? null : size; - nodeSize = (size = x) == null; - return tree; - }; - tree.nodeSize = function(x) { - if (!arguments.length) return nodeSize ? size : null; - nodeSize = (size = x) != null; - return tree; - }; - return d3_layout_hierarchyRebind(tree, hierarchy); - }; - function d3_layout_treeSeparation(a, b) { - return a.parent == b.parent ? 1 : 2; - } - function d3_layout_treeLeft(node) { - var children = node.children; - return children && children.length ? children[0] : node._tree.thread; - } - function d3_layout_treeRight(node) { - var children = node.children, n; - return children && (n = children.length) ? children[n - 1] : node._tree.thread; - } - function d3_layout_treeSearch(node, compare) { - var children = node.children; - if (children && (n = children.length)) { - var child, n, i = -1; - while (++i < n) { - if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { - node = child; - } - } - } - return node; - } - function d3_layout_treeRightmost(a, b) { - return a.x - b.x; - } - function d3_layout_treeLeftmost(a, b) { - return b.x - a.x; - } - function d3_layout_treeDeepest(a, b) { - return a.depth - b.depth; - } - function d3_layout_treeVisitAfter(node, callback) { - function visit(node, previousSibling) { - var children = node.children; - if (children && (n = children.length)) { - var child, previousChild = null, i = -1, n; - while (++i < n) { - child = children[i]; - visit(child, previousChild); - previousChild = child; - } - } - callback(node, previousSibling); - } - visit(node, null); - } - function d3_layout_treeShift(node) { - var shift = 0, change = 0, children = node.children, i = children.length, child; - while (--i >= 0) { - child = children[i]._tree; - child.prelim += shift; - child.mod += shift; - shift += child.shift + (change += child.change); - } - } - function d3_layout_treeMove(ancestor, node, shift) { - ancestor = ancestor._tree; - node = node._tree; - var change = shift / (node.number - ancestor.number); - ancestor.change += change; - node.change -= change; - node.shift += shift; - node.prelim += shift; - node.mod += shift; - } - function d3_layout_treeAncestor(vim, node, ancestor) { - return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; - } - d3.layout.pack = function() { - var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; - function pack(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { - return radius; - }; - root.x = root.y = 0; - d3_layout_treeVisitAfter(root, function(d) { - d.r = +r(d.value); - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - if (padding) { - var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; - d3_layout_treeVisitAfter(root, function(d) { - d.r += dr; - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - d3_layout_treeVisitAfter(root, function(d) { - d.r -= dr; - }); - } - d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); - return nodes; - } - pack.size = function(_) { - if (!arguments.length) return size; - size = _; - return pack; - }; - pack.radius = function(_) { - if (!arguments.length) return radius; - radius = _ == null || typeof _ === "function" ? _ : +_; - return pack; - }; - pack.padding = function(_) { - if (!arguments.length) return padding; - padding = +_; - return pack; - }; - return d3_layout_hierarchyRebind(pack, hierarchy); - }; - function d3_layout_packSort(a, b) { - return a.value - b.value; - } - function d3_layout_packInsert(a, b) { - var c = a._pack_next; - a._pack_next = b; - b._pack_prev = a; - b._pack_next = c; - c._pack_prev = b; - } - function d3_layout_packSplice(a, b) { - a._pack_next = b; - b._pack_prev = a; - } - function d3_layout_packIntersects(a, b) { - var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; - return .999 * dr * dr > dx * dx + dy * dy; - } - function d3_layout_packSiblings(node) { - if (!(nodes = node.children) || !(n = nodes.length)) return; - var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; - function bound(node) { - xMin = Math.min(node.x - node.r, xMin); - xMax = Math.max(node.x + node.r, xMax); - yMin = Math.min(node.y - node.r, yMin); - yMax = Math.max(node.y + node.r, yMax); - } - nodes.forEach(d3_layout_packLink); - a = nodes[0]; - a.x = -a.r; - a.y = 0; - bound(a); - if (n > 1) { - b = nodes[1]; - b.x = b.r; - b.y = 0; - bound(b); - if (n > 2) { - c = nodes[2]; - d3_layout_packPlace(a, b, c); - bound(c); - d3_layout_packInsert(a, c); - a._pack_prev = c; - d3_layout_packInsert(c, b); - b = a._pack_next; - for (i = 3; i < n; i++) { - d3_layout_packPlace(a, b, c = nodes[i]); - var isect = 0, s1 = 1, s2 = 1; - for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { - if (d3_layout_packIntersects(j, c)) { - isect = 1; - break; - } - } - if (isect == 1) { - for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { - if (d3_layout_packIntersects(k, c)) { - break; - } - } - } - if (isect) { - if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); - i--; - } else { - d3_layout_packInsert(a, c); - b = c; - bound(c); - } - } - } - } - var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; - for (i = 0; i < n; i++) { - c = nodes[i]; - c.x -= cx; - c.y -= cy; - cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); - } - node.r = cr; - nodes.forEach(d3_layout_packUnlink); - } - function d3_layout_packLink(node) { - node._pack_next = node._pack_prev = node; - } - function d3_layout_packUnlink(node) { - delete node._pack_next; - delete node._pack_prev; - } - function d3_layout_packTransform(node, x, y, k) { - var children = node.children; - node.x = x += k * node.x; - node.y = y += k * node.y; - node.r *= k; - if (children) { - var i = -1, n = children.length; - while (++i < n) d3_layout_packTransform(children[i], x, y, k); - } - } - function d3_layout_packPlace(a, b, c) { - var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; - if (db && (dx || dy)) { - var da = b.r + c.r, dc = dx * dx + dy * dy; - da *= da; - db *= db; - var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); - c.x = a.x + x * dx + y * dy; - c.y = a.y + x * dy - y * dx; - } else { - c.x = a.x + db; - c.y = a.y; - } - } - d3.layout.cluster = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; - function cluster(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; - d3_layout_treeVisitAfter(root, function(node) { - var children = node.children; - if (children && children.length) { - node.x = d3_layout_clusterX(children); - node.y = d3_layout_clusterY(children); - } else { - node.x = previousNode ? x += separation(node, previousNode) : 0; - node.y = 0; - previousNode = node; - } - }); - var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; - d3_layout_treeVisitAfter(root, nodeSize ? function(node) { - node.x = (node.x - root.x) * size[0]; - node.y = (root.y - node.y) * size[1]; - } : function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; - }); - return nodes; - } - cluster.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return cluster; - }; - cluster.size = function(x) { - if (!arguments.length) return nodeSize ? null : size; - nodeSize = (size = x) == null; - return cluster; - }; - cluster.nodeSize = function(x) { - if (!arguments.length) return nodeSize ? size : null; - nodeSize = (size = x) != null; - return cluster; - }; - return d3_layout_hierarchyRebind(cluster, hierarchy); - }; - function d3_layout_clusterY(children) { - return 1 + d3.max(children, function(child) { - return child.y; - }); - } - function d3_layout_clusterX(children) { - return children.reduce(function(x, child) { - return x + child.x; - }, 0) / children.length; - } - function d3_layout_clusterLeft(node) { - var children = node.children; - return children && children.length ? d3_layout_clusterLeft(children[0]) : node; - } - function d3_layout_clusterRight(node) { - var children = node.children, n; - return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; - } - d3.layout.treemap = function() { - var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); - function scale(children, k) { - var i = -1, n = children.length, child, area; - while (++i < n) { - area = (child = children[i]).value * (k < 0 ? 0 : k); - child.area = isNaN(area) || area <= 0 ? 0 : area; - } - } - function squarify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while ((n = remaining.length) > 0) { - row.push(child = remaining[n - 1]); - row.area += child.area; - if (mode !== "squarify" || (score = worst(row, u)) <= best) { - remaining.pop(); - best = score; - } else { - row.area -= row.pop().area; - position(row, u, rect, false); - u = Math.min(rect.dx, rect.dy); - row.length = row.area = 0; - best = Infinity; - } - } - if (row.length) { - position(row, u, rect, true); - row.length = row.area = 0; - } - children.forEach(squarify); - } - } - function stickify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), remaining = children.slice(), child, row = []; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while (child = remaining.pop()) { - row.push(child); - row.area += child.area; - if (child.z != null) { - position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); - row.length = row.area = 0; - } - } - children.forEach(stickify); - } - } - function worst(row, u) { - var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; - while (++i < n) { - if (!(r = row[i].area)) continue; - if (r < rmin) rmin = r; - if (r > rmax) rmax = r; - } - s *= s; - u *= u; - return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; - } - function position(row, u, rect, flush) { - var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; - if (u == rect.dx) { - if (flush || v > rect.dy) v = rect.dy; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dy = v; - x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); - } - o.z = true; - o.dx += rect.x + rect.dx - x; - rect.y += v; - rect.dy -= v; - } else { - if (flush || v > rect.dx) v = rect.dx; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dx = v; - y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); - } - o.z = false; - o.dy += rect.y + rect.dy - y; - rect.x += v; - rect.dx -= v; - } - } - function treemap(d) { - var nodes = stickies || hierarchy(d), root = nodes[0]; - root.x = 0; - root.y = 0; - root.dx = size[0]; - root.dy = size[1]; - if (stickies) hierarchy.revalue(root); - scale([ root ], root.dx * root.dy / root.value); - (stickies ? stickify : squarify)(root); - if (sticky) stickies = nodes; - return nodes; - } - treemap.size = function(x) { - if (!arguments.length) return size; - size = x; - return treemap; - }; - treemap.padding = function(x) { - if (!arguments.length) return padding; - function padFunction(node) { - var p = x.call(treemap, node, node.depth); - return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); - } - function padConstant(node) { - return d3_layout_treemapPad(node, x); - } - var type; - pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], - padConstant) : padConstant; - return treemap; - }; - treemap.round = function(x) { - if (!arguments.length) return round != Number; - round = x ? Math.round : Number; - return treemap; - }; - treemap.sticky = function(x) { - if (!arguments.length) return sticky; - sticky = x; - stickies = null; - return treemap; - }; - treemap.ratio = function(x) { - if (!arguments.length) return ratio; - ratio = x; - return treemap; - }; - treemap.mode = function(x) { - if (!arguments.length) return mode; - mode = x + ""; - return treemap; - }; - return d3_layout_hierarchyRebind(treemap, hierarchy); - }; - function d3_layout_treemapPadNull(node) { - return { - x: node.x, - y: node.y, - dx: node.dx, - dy: node.dy - }; - } - function d3_layout_treemapPad(node, padding) { - var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; - if (dx < 0) { - x += dx / 2; - dx = 0; - } - if (dy < 0) { - y += dy / 2; - dy = 0; - } - return { - x: x, - y: y, - dx: dx, - dy: dy - }; - } - d3.random = { - normal: function(µ, σ) { - var n = arguments.length; - if (n < 2) σ = 1; - if (n < 1) µ = 0; - return function() { - var x, y, r; - do { - x = Math.random() * 2 - 1; - y = Math.random() * 2 - 1; - r = x * x + y * y; - } while (!r || r > 1); - return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); - }; - }, - logNormal: function() { - var random = d3.random.normal.apply(d3, arguments); - return function() { - return Math.exp(random()); - }; - }, - irwinHall: function(m) { - return function() { - for (var s = 0, j = 0; j < m; j++) s += Math.random(); - return s / m; - }; - } - }; - d3.scale = {}; - function d3_scaleExtent(domain) { - var start = domain[0], stop = domain[domain.length - 1]; - return start < stop ? [ start, stop ] : [ stop, start ]; - } - function d3_scaleRange(scale) { - return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); - } - function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { - var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); - return function(x) { - return i(u(x)); - }; - } - function d3_scale_nice(domain, nice) { - var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; - if (x1 < x0) { - dx = i0, i0 = i1, i1 = dx; - dx = x0, x0 = x1, x1 = dx; - } - domain[i0] = nice.floor(x0); - domain[i1] = nice.ceil(x1); - return domain; - } - function d3_scale_niceStep(step) { - return step ? { - floor: function(x) { - return Math.floor(x / step) * step; - }, - ceil: function(x) { - return Math.ceil(x / step) * step; - } - } : d3_scale_niceIdentity; - } - var d3_scale_niceIdentity = { - floor: d3_identity, - ceil: d3_identity - }; - function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { - var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; - if (domain[k] < domain[0]) { - domain = domain.slice().reverse(); - range = range.slice().reverse(); - } - while (++j <= k) { - u.push(uninterpolate(domain[j - 1], domain[j])); - i.push(interpolate(range[j - 1], range[j])); - } - return function(x) { - var j = d3.bisect(domain, x, 1, k) - 1; - return i[j](u[j](x)); - }; - } - d3.scale.linear = function() { - return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); - }; - function d3_scale_linear(domain, range, interpolate, clamp) { - var output, input; - function rescale() { - var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; - output = linear(domain, range, uninterpolate, interpolate); - input = linear(range, domain, uninterpolate, d3_interpolate); - return scale; - } - function scale(x) { - return output(x); - } - scale.invert = function(y) { - return input(y); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.map(Number); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.rangeRound = function(x) { - return scale.range(x).interpolate(d3_interpolateRound); - }; - scale.clamp = function(x) { - if (!arguments.length) return clamp; - clamp = x; - return rescale(); - }; - scale.interpolate = function(x) { - if (!arguments.length) return interpolate; - interpolate = x; - return rescale(); - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - scale.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - scale.nice = function(m) { - d3_scale_linearNice(domain, m); - return rescale(); - }; - scale.copy = function() { - return d3_scale_linear(domain, range, interpolate, clamp); - }; - return rescale(); - } - function d3_scale_linearRebind(scale, linear) { - return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); - } - function d3_scale_linearNice(domain, m) { - return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); - } - function d3_scale_linearNiceStep(domain) { - var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; - return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); - } - function d3_scale_linearTickRange(domain, m) { - var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; - if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; - extent[0] = Math.ceil(extent[0] / step) * step; - extent[1] = Math.floor(extent[1] / step) * step + step * .5; - extent[2] = step; - return extent; - } - function d3_scale_linearTicks(domain, m) { - return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); - } - function d3_scale_linearTickFormat(domain, m, format) { - var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); - return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { - return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); - }) : ",." + precision + "f"); - } - d3.scale.log = function() { - return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); - }; - function d3_scale_log(linear, base, positive, domain) { - function log(x) { - return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); - } - function pow(x) { - return positive ? Math.pow(base, x) : -Math.pow(base, -x); - } - function scale(x) { - return linear(log(x)); - } - scale.invert = function(x) { - return pow(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - positive = x[0] >= 0; - linear.domain((domain = x.map(Number)).map(log)); - return scale; - }; - scale.base = function(_) { - if (!arguments.length) return base; - base = +_; - linear.domain(domain.map(log)); - return scale; - }; - scale.nice = function() { - var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); - linear.domain(niced); - domain = niced.map(pow); - return scale; - }; - scale.ticks = function() { - var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; - if (isFinite(j - i)) { - if (positive) { - for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); - ticks.push(pow(i)); - } else { - ticks.push(pow(i)); - for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); - } - for (i = 0; ticks[i] < u; i++) {} - for (j = ticks.length; ticks[j - 1] > v; j--) {} - ticks = ticks.slice(i, j); - } - return ticks; - }; - scale.tickFormat = function(n, format) { - if (!arguments.length) return d3_scale_logFormat; - if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); - var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, - Math.floor), e; - return function(d) { - return d / pow(f(log(d) + e)) <= k ? format(d) : ""; - }; - }; - scale.copy = function() { - return d3_scale_log(linear.copy(), base, positive, domain); - }; - return d3_scale_linearRebind(scale, linear); - } - var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { - floor: function(x) { - return -Math.ceil(-x); - }, - ceil: function(x) { - return -Math.floor(-x); - } - }; - d3.scale.pow = function() { - return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); - }; - function d3_scale_pow(linear, exponent, domain) { - var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); - function scale(x) { - return linear(powp(x)); - } - scale.invert = function(x) { - return powb(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - linear.domain((domain = x.map(Number)).map(powp)); - return scale; - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - scale.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - scale.nice = function(m) { - return scale.domain(d3_scale_linearNice(domain, m)); - }; - scale.exponent = function(x) { - if (!arguments.length) return exponent; - powp = d3_scale_powPow(exponent = x); - powb = d3_scale_powPow(1 / exponent); - linear.domain(domain.map(powp)); - return scale; - }; - scale.copy = function() { - return d3_scale_pow(linear.copy(), exponent, domain); - }; - return d3_scale_linearRebind(scale, linear); - } - function d3_scale_powPow(e) { - return function(x) { - return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); - }; - } - d3.scale.sqrt = function() { - return d3.scale.pow().exponent(.5); - }; - d3.scale.ordinal = function() { - return d3_scale_ordinal([], { - t: "range", - a: [ [] ] - }); - }; - function d3_scale_ordinal(domain, ranger) { - var index, range, rangeBand; - function scale(x) { - return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; - } - function steps(start, step) { - return d3.range(domain.length).map(function(i) { - return start + step * i; - }); - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = []; - index = new d3_Map(); - var i = -1, n = x.length, xi; - while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); - return scale[ranger.t].apply(scale, ranger.a); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - rangeBand = 0; - ranger = { - t: "range", - a: arguments - }; - return scale; - }; - scale.rangePoints = function(x, padding) { - if (arguments.length < 2) padding = 0; - var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); - range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); - rangeBand = 0; - ranger = { - t: "rangePoints", - a: arguments - }; - return scale; - }; - scale.rangeBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); - range = steps(start + step * outerPadding, step); - if (reverse) range.reverse(); - rangeBand = step * (1 - padding); - ranger = { - t: "rangeBands", - a: arguments - }; - return scale; - }; - scale.rangeRoundBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; - range = steps(start + Math.round(error / 2), step); - if (reverse) range.reverse(); - rangeBand = Math.round(step * (1 - padding)); - ranger = { - t: "rangeRoundBands", - a: arguments - }; - return scale; - }; - scale.rangeBand = function() { - return rangeBand; - }; - scale.rangeExtent = function() { - return d3_scaleExtent(ranger.a[0]); - }; - scale.copy = function() { - return d3_scale_ordinal(domain, ranger); - }; - return scale.domain(domain); - } - d3.scale.category10 = function() { - return d3.scale.ordinal().range(d3_category10); - }; - d3.scale.category20 = function() { - return d3.scale.ordinal().range(d3_category20); - }; - d3.scale.category20b = function() { - return d3.scale.ordinal().range(d3_category20b); - }; - d3.scale.category20c = function() { - return d3.scale.ordinal().range(d3_category20c); - }; - var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); - var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); - var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); - var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); - d3.scale.quantile = function() { - return d3_scale_quantile([], []); - }; - function d3_scale_quantile(domain, range) { - var thresholds; - function rescale() { - var k = 0, q = range.length; - thresholds = []; - while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); - return scale; - } - function scale(x) { - if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.filter(function(d) { - return !isNaN(d); - }).sort(d3.ascending); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.quantiles = function() { - return thresholds; - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; - }; - scale.copy = function() { - return d3_scale_quantile(domain, range); - }; - return rescale(); - } - d3.scale.quantize = function() { - return d3_scale_quantize(0, 1, [ 0, 1 ]); - }; - function d3_scale_quantize(x0, x1, range) { - var kx, i; - function scale(x) { - return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; - } - function rescale() { - kx = range.length / (x1 - x0); - i = range.length - 1; - return scale; - } - scale.domain = function(x) { - if (!arguments.length) return [ x0, x1 ]; - x0 = +x[0]; - x1 = +x[x.length - 1]; - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - y = y < 0 ? NaN : y / kx + x0; - return [ y, y + 1 / kx ]; - }; - scale.copy = function() { - return d3_scale_quantize(x0, x1, range); - }; - return rescale(); - } - d3.scale.threshold = function() { - return d3_scale_threshold([ .5 ], [ 0, 1 ]); - }; - function d3_scale_threshold(domain, range) { - function scale(x) { - if (x <= x) return range[d3.bisect(domain, x)]; - } - scale.domain = function(_) { - if (!arguments.length) return domain; - domain = _; - return scale; - }; - scale.range = function(_) { - if (!arguments.length) return range; - range = _; - return scale; - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - return [ domain[y - 1], domain[y] ]; - }; - scale.copy = function() { - return d3_scale_threshold(domain, range); - }; - return scale; - } - d3.scale.identity = function() { - return d3_scale_identity([ 0, 1 ]); - }; - function d3_scale_identity(domain) { - function identity(x) { - return +x; - } - identity.invert = identity; - identity.domain = identity.range = function(x) { - if (!arguments.length) return domain; - domain = x.map(identity); - return identity; - }; - identity.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - identity.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - identity.copy = function() { - return d3_scale_identity(domain); - }; - return identity; - } - d3.svg.arc = function() { - var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function arc() { - var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, - a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); - return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; - } - arc.innerRadius = function(v) { - if (!arguments.length) return innerRadius; - innerRadius = d3_functor(v); - return arc; - }; - arc.outerRadius = function(v) { - if (!arguments.length) return outerRadius; - outerRadius = d3_functor(v); - return arc; - }; - arc.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return arc; - }; - arc.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return arc; - }; - arc.centroid = function() { - var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; - return [ Math.cos(a) * r, Math.sin(a) * r ]; - }; - return arc; - }; - var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; - function d3_svg_arcInnerRadius(d) { - return d.innerRadius; - } - function d3_svg_arcOuterRadius(d) { - return d.outerRadius; - } - function d3_svg_arcStartAngle(d) { - return d.startAngle; - } - function d3_svg_arcEndAngle(d) { - return d.endAngle; - } - d3.svg.line.radial = function() { - var line = d3_svg_line(d3_svg_lineRadial); - line.radius = line.x, delete line.x; - line.angle = line.y, delete line.y; - return line; - }; - function d3_svg_lineRadial(points) { - var point, i = -1, n = points.length, r, a; - while (++i < n) { - point = points[i]; - r = point[0]; - a = point[1] + d3_svg_arcOffset; - point[0] = r * Math.cos(a); - point[1] = r * Math.sin(a); - } - return points; - } - function d3_svg_area(projection) { - var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; - function area(data) { - var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { - return x; - } : d3_functor(x1), fy1 = y0 === y1 ? function() { - return y; - } : d3_functor(y1), x, y; - function segment() { - segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); - points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); - } else if (points0.length) { - segment(); - points0 = []; - points1 = []; - } - } - if (points0.length) segment(); - return segments.length ? segments.join("") : null; - } - area.x = function(_) { - if (!arguments.length) return x1; - x0 = x1 = _; - return area; - }; - area.x0 = function(_) { - if (!arguments.length) return x0; - x0 = _; - return area; - }; - area.x1 = function(_) { - if (!arguments.length) return x1; - x1 = _; - return area; - }; - area.y = function(_) { - if (!arguments.length) return y1; - y0 = y1 = _; - return area; - }; - area.y0 = function(_) { - if (!arguments.length) return y0; - y0 = _; - return area; - }; - area.y1 = function(_) { - if (!arguments.length) return y1; - y1 = _; - return area; - }; - area.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return area; - }; - area.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - interpolateReverse = interpolate.reverse || interpolate; - L = interpolate.closed ? "M" : "L"; - return area; - }; - area.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return area; - }; - return area; - } - d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; - d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; - d3.svg.area = function() { - return d3_svg_area(d3_identity); - }; - d3.svg.area.radial = function() { - var area = d3_svg_area(d3_svg_lineRadial); - area.radius = area.x, delete area.x; - area.innerRadius = area.x0, delete area.x0; - area.outerRadius = area.x1, delete area.x1; - area.angle = area.y, delete area.y; - area.startAngle = area.y0, delete area.y0; - area.endAngle = area.y1, delete area.y1; - return area; - }; - d3.svg.chord = function() { - var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function chord(d, i) { - var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); - return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; - } - function subgroup(self, f, d, i) { - var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; - return { - r: r, - a0: a0, - a1: a1, - p0: [ r * Math.cos(a0), r * Math.sin(a0) ], - p1: [ r * Math.cos(a1), r * Math.sin(a1) ] - }; - } - function equals(a, b) { - return a.a0 == b.a0 && a.a1 == b.a1; - } - function arc(r, p, a) { - return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; - } - function curve(r0, p0, r1, p1) { - return "Q 0,0 " + p1; - } - chord.radius = function(v) { - if (!arguments.length) return radius; - radius = d3_functor(v); - return chord; - }; - chord.source = function(v) { - if (!arguments.length) return source; - source = d3_functor(v); - return chord; - }; - chord.target = function(v) { - if (!arguments.length) return target; - target = d3_functor(v); - return chord; - }; - chord.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return chord; - }; - chord.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return chord; - }; - return chord; - }; - function d3_svg_chordRadius(d) { - return d.radius; - } - d3.svg.diagonal = function() { - var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; - function diagonal(d, i) { - var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { - x: p0.x, - y: m - }, { - x: p3.x, - y: m - }, p3 ]; - p = p.map(projection); - return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; - } - diagonal.source = function(x) { - if (!arguments.length) return source; - source = d3_functor(x); - return diagonal; - }; - diagonal.target = function(x) { - if (!arguments.length) return target; - target = d3_functor(x); - return diagonal; - }; - diagonal.projection = function(x) { - if (!arguments.length) return projection; - projection = x; - return diagonal; - }; - return diagonal; - }; - function d3_svg_diagonalProjection(d) { - return [ d.x, d.y ]; - } - d3.svg.diagonal.radial = function() { - var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; - diagonal.projection = function(x) { - return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; - }; - return diagonal; - }; - function d3_svg_diagonalRadialProjection(projection) { - return function() { - var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; - return [ r * Math.cos(a), r * Math.sin(a) ]; - }; - } - d3.svg.symbol = function() { - var type = d3_svg_symbolType, size = d3_svg_symbolSize; - function symbol(d, i) { - return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); - } - symbol.type = function(x) { - if (!arguments.length) return type; - type = d3_functor(x); - return symbol; - }; - symbol.size = function(x) { - if (!arguments.length) return size; - size = d3_functor(x); - return symbol; - }; - return symbol; - }; - function d3_svg_symbolSize() { - return 64; - } - function d3_svg_symbolType() { - return "circle"; - } - function d3_svg_symbolCircle(size) { - var r = Math.sqrt(size / π); - return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; - } - var d3_svg_symbols = d3.map({ - circle: d3_svg_symbolCircle, - cross: function(size) { - var r = Math.sqrt(size / 5) / 2; - return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; - }, - diamond: function(size) { - var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; - return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; - }, - square: function(size) { - var r = Math.sqrt(size) / 2; - return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; - }, - "triangle-down": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; - }, - "triangle-up": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; - } - }); - d3.svg.symbolTypes = d3_svg_symbols.keys(); - var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); - function d3_transition(groups, id) { - d3_subclass(groups, d3_transitionPrototype); - groups.id = id; - return groups; - } - var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; - d3_transitionPrototype.call = d3_selectionPrototype.call; - d3_transitionPrototype.empty = d3_selectionPrototype.empty; - d3_transitionPrototype.node = d3_selectionPrototype.node; - d3_transitionPrototype.size = d3_selectionPrototype.size; - d3.transition = function(selection) { - return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); - }; - d3.transition.prototype = d3_transitionPrototype; - d3_transitionPrototype.select = function(selector) { - var id = this.id, subgroups = [], subgroup, subnode, node; - selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { - if ("__data__" in node) subnode.__data__ = node.__data__; - d3_transitionNode(subnode, i, id, node.__transition__[id]); - subgroup.push(subnode); - } else { - subgroup.push(null); - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.selectAll = function(selector) { - var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; - selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - transition = node.__transition__[id]; - subnodes = selector.call(node, node.__data__, i, j); - subgroups.push(subgroup = []); - for (var k = -1, o = subnodes.length; ++k < o; ) { - if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); - subgroup.push(subnode); - } - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); - } - } - } - return d3_transition(subgroups, this.id); - }; - d3_transitionPrototype.tween = function(name, tween) { - var id = this.id; - if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); - return d3_selection_each(this, tween == null ? function(node) { - node.__transition__[id].tween.remove(name); - } : function(node) { - node.__transition__[id].tween.set(name, tween); - }); - }; - function d3_transition_tween(groups, name, value, tween) { - var id = groups.id; - return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); - } : (value = tween(value), function(node) { - node.__transition__[id].tween.set(name, value); - })); - } - d3_transitionPrototype.attr = function(nameNS, value) { - if (arguments.length < 2) { - for (value in nameNS) this.attr(value, nameNS[value]); - return this; - } - var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - function attrTween(b) { - return b == null ? attrNull : (b += "", function() { - var a = this.getAttribute(name), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttribute(name, i(t)); - }); - }); - } - function attrTweenNS(b) { - return b == null ? attrNullNS : (b += "", function() { - var a = this.getAttributeNS(name.space, name.local), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttributeNS(name.space, name.local, i(t)); - }); - }); - } - return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); - }; - d3_transitionPrototype.attrTween = function(nameNS, tween) { - var name = d3.ns.qualify(nameNS); - function attrTween(d, i) { - var f = tween.call(this, d, i, this.getAttribute(name)); - return f && function(t) { - this.setAttribute(name, f(t)); - }; - } - function attrTweenNS(d, i) { - var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); - return f && function(t) { - this.setAttributeNS(name.space, name.local, f(t)); - }; - } - return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); - }; - d3_transitionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.style(priority, name[priority], value); - return this; - } - priority = ""; - } - function styleNull() { - this.style.removeProperty(name); - } - function styleString(b) { - return b == null ? styleNull : (b += "", function() { - var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; - return a !== b && (i = d3_interpolate(a, b), function(t) { - this.style.setProperty(name, i(t), priority); - }); - }); - } - return d3_transition_tween(this, "style." + name, value, styleString); - }; - d3_transitionPrototype.styleTween = function(name, tween, priority) { - if (arguments.length < 3) priority = ""; - function styleTween(d, i) { - var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); - return f && function(t) { - this.style.setProperty(name, f(t), priority); - }; - } - return this.tween("style." + name, styleTween); - }; - d3_transitionPrototype.text = function(value) { - return d3_transition_tween(this, "text", value, d3_transition_text); - }; - function d3_transition_text(b) { - if (b == null) b = ""; - return function() { - this.textContent = b; - }; - } - d3_transitionPrototype.remove = function() { - return this.each("end.transition", function() { - var p; - if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); - }); - }; - d3_transitionPrototype.ease = function(value) { - var id = this.id; - if (arguments.length < 1) return this.node().__transition__[id].ease; - if (typeof value !== "function") value = d3.ease.apply(d3, arguments); - return d3_selection_each(this, function(node) { - node.__transition__[id].ease = value; - }); - }; - d3_transitionPrototype.delay = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; - } : (value |= 0, function(node) { - node.__transition__[id].delay = value; - })); - }; - d3_transitionPrototype.duration = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); - } : (value = Math.max(1, value | 0), function(node) { - node.__transition__[id].duration = value; - })); - }; - d3_transitionPrototype.each = function(type, listener) { - var id = this.id; - if (arguments.length < 2) { - var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; - d3_transitionInheritId = id; - d3_selection_each(this, function(node, i, j) { - d3_transitionInherit = node.__transition__[id]; - type.call(node, node.__data__, i, j); - }); - d3_transitionInherit = inherit; - d3_transitionInheritId = inheritId; - } else { - d3_selection_each(this, function(node) { - var transition = node.__transition__[id]; - (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); - }); - } - return this; - }; - d3_transitionPrototype.transition = function() { - var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if (node = group[i]) { - transition = Object.create(node.__transition__[id0]); - transition.delay += transition.duration; - d3_transitionNode(node, i, id1, transition); - } - subgroup.push(node); - } - } - return d3_transition(subgroups, id1); - }; - function d3_transitionNode(node, i, id, inherit) { - var lock = node.__transition__ || (node.__transition__ = { - active: 0, - count: 0 - }), transition = lock[id]; - if (!transition) { - var time = inherit.time; - transition = lock[id] = { - tween: new d3_Map(), - time: time, - ease: inherit.ease, - delay: inherit.delay, - duration: inherit.duration - }; - ++lock.count; - d3.timer(function(elapsed) { - var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; - if (delay <= elapsed) return start(elapsed); - d3_timer_replace(start, delay, time); - function start(elapsed) { - if (lock.active > id) return stop(); - lock.active = id; - transition.event && transition.event.start.call(node, d, i); - transition.tween.forEach(function(key, value) { - if (value = value.call(node, d, i)) { - tweened.push(value); - } - }); - if (tick(elapsed)) return 1; - d3_timer_replace(tick, 0, time); - } - function tick(elapsed) { - if (lock.active !== id) return stop(); - var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; - while (n > 0) { - tweened[--n].call(node, e); - } - if (t >= 1) { - stop(); - transition.event && transition.event.end.call(node, d, i); - return 1; - } - } - function stop() { - if (--lock.count) delete lock[id]; else delete node.__transition__; - return 1; - } - }, 0, time); - } - } - d3.svg.axis = function() { - var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; - function axis(g) { - g.each(function() { - var g = d3.select(this); - var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; - var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); - var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; - var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), - d3.transition(path)); - var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; - this.__chart__ = scale1; - tickEnter.append("line"); - tickEnter.append("text"); - var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); - switch (orient) { - case "bottom": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); - lineEnter.attr("y2", tickMajorSize); - textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); - textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); - text.attr("dy", ".71em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); - break; - } - - case "top": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", -tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); - lineEnter.attr("y2", -tickMajorSize); - textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); - textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - text.attr("dy", "0em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); - break; - } - - case "left": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", -tickMinorSize); - subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", -tickMajorSize); - textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); - textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "end"); - pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); - break; - } - - case "right": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", tickMinorSize); - subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", tickMajorSize); - textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); - textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "start"); - pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); - break; - } - } - if (scale.rangeBand) { - var dx = scale1.rangeBand() / 2, x = function(d) { - return scale1(d) + dx; - }; - tickEnter.call(tickTransform, x); - tickUpdate.call(tickTransform, x); - } else { - tickEnter.call(tickTransform, scale0); - tickUpdate.call(tickTransform, scale1); - tickExit.call(tickTransform, scale1); - subtickEnter.call(tickTransform, scale0); - subtickUpdate.call(tickTransform, scale1); - subtickExit.call(tickTransform, scale1); - } - }); - } - axis.scale = function(x) { - if (!arguments.length) return scale; - scale = x; - return axis; - }; - axis.orient = function(x) { - if (!arguments.length) return orient; - orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; - return axis; - }; - axis.ticks = function() { - if (!arguments.length) return tickArguments_; - tickArguments_ = arguments; - return axis; - }; - axis.tickValues = function(x) { - if (!arguments.length) return tickValues; - tickValues = x; - return axis; - }; - axis.tickFormat = function(x) { - if (!arguments.length) return tickFormat_; - tickFormat_ = x; - return axis; - }; - axis.tickSize = function(x, y) { - if (!arguments.length) return tickMajorSize; - var n = arguments.length - 1; - tickMajorSize = +x; - tickMinorSize = n > 1 ? +y : tickMajorSize; - tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; - return axis; - }; - axis.tickPadding = function(x) { - if (!arguments.length) return tickPadding; - tickPadding = +x; - return axis; - }; - axis.tickSubdivide = function(x) { - if (!arguments.length) return tickSubdivide; - tickSubdivide = +x; - return axis; - }; - return axis; - }; - var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { - top: 1, - right: 1, - bottom: 1, - left: 1 - }; - function d3_svg_axisX(selection, x) { - selection.attr("transform", function(d) { - return "translate(" + x(d) + ",0)"; - }); - } - function d3_svg_axisY(selection, y) { - selection.attr("transform", function(d) { - return "translate(0," + y(d) + ")"; - }); - } - function d3_svg_axisSubdivide(scale, ticks, m) { - subticks = []; - if (m && ticks.length > 1) { - var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; - while (++i < n) { - for (j = m; --j > 0; ) { - if ((v = +ticks[i] - j * d) >= extent[0]) { - subticks.push(v); - } - } - } - for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { - subticks.push(v); - } - } - return subticks; - } - d3.svg.brush = function() { - var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; - function brush(g) { - g.each(function() { - var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; - g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); - bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); - fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); - tz.enter().append("g").attr("class", function(d) { - return "resize " + d; - }).style("cursor", function(d) { - return d3_svg_brushCursor[d]; - }).append("rect").attr("x", function(d) { - return /[ew]$/.test(d) ? -3 : null; - }).attr("y", function(d) { - return /^[ns]/.test(d) ? -3 : null; - }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); - tz.style("display", brush.empty() ? "none" : null); - tz.exit().remove(); - if (x) { - e = d3_scaleRange(x); - bg.attr("x", e[0]).attr("width", e[1] - e[0]); - redrawX(g); - } - if (y) { - e = d3_scaleRange(y); - bg.attr("y", e[0]).attr("height", e[1] - e[0]); - redrawY(g); - } - redraw(g); - }); - } - function redraw(g) { - g.selectAll(".resize").attr("transform", function(d) { - return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; - }); - } - function redrawX(g) { - g.select(".extent").attr("x", extent[0][0]); - g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); - } - function redrawY(g) { - g.select(".extent").attr("y", extent[0][1]); - g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); - } - function brushstart() { - var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = mouse(), offset; - var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); - if (d3.event.changedTouches) { - w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); - } else { - w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); - } - if (dragging) { - origin[0] = extent[0][0] - origin[0]; - origin[1] = extent[0][1] - origin[1]; - } else if (resizing) { - var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); - offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; - origin[0] = extent[ex][0]; - origin[1] = extent[ey][1]; - } else if (d3.event.altKey) center = origin.slice(); - g.style("pointer-events", "none").selectAll(".resize").style("display", null); - d3.select("body").style("cursor", eventTarget.style("cursor")); - event_({ - type: "brushstart" - }); - brushmove(); - function mouse() { - var touches = d3.event.changedTouches; - return touches ? d3.touches(target, touches)[0] : d3.mouse(target); - } - function keydown() { - if (d3.event.keyCode == 32) { - if (!dragging) { - center = null; - origin[0] -= extent[1][0]; - origin[1] -= extent[1][1]; - dragging = 2; - } - d3_eventPreventDefault(); - } - } - function keyup() { - if (d3.event.keyCode == 32 && dragging == 2) { - origin[0] += extent[1][0]; - origin[1] += extent[1][1]; - dragging = 0; - d3_eventPreventDefault(); - } - } - function brushmove() { - var point = mouse(), moved = false; - if (offset) { - point[0] += offset[0]; - point[1] += offset[1]; - } - if (!dragging) { - if (d3.event.altKey) { - if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; - origin[0] = extent[+(point[0] < center[0])][0]; - origin[1] = extent[+(point[1] < center[1])][1]; - } else center = null; - } - if (resizingX && move1(point, x, 0)) { - redrawX(g); - moved = true; - } - if (resizingY && move1(point, y, 1)) { - redrawY(g); - moved = true; - } - if (moved) { - redraw(g); - event_({ - type: "brush", - mode: dragging ? "move" : "resize" - }); - } - } - function move1(point, scale, i) { - var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; - if (dragging) { - r0 -= position; - r1 -= size + position; - } - min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; - if (dragging) { - max = (min += position) + size; - } else { - if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); - if (position < min) { - max = min; - min = position; - } else { - max = position; - } - } - if (extent[0][i] !== min || extent[1][i] !== max) { - extentDomain = null; - extent[0][i] = min; - extent[1][i] = max; - return true; - } - } - function brushend() { - brushmove(); - g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); - d3.select("body").style("cursor", null); - w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); - dragRestore(); - event_({ - type: "brushend" - }); - } - } - brush.x = function(z) { - if (!arguments.length) return x; - x = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.y = function(z) { - if (!arguments.length) return y; - y = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.clamp = function(z) { - if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; - if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; - return brush; - }; - brush.extent = function(z) { - var x0, x1, y0, y1, t; - if (!arguments.length) { - z = extentDomain || extent; - if (x) { - x0 = z[0][0], x1 = z[1][0]; - if (!extentDomain) { - x0 = extent[0][0], x1 = extent[1][0]; - if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - } - } - if (y) { - y0 = z[0][1], y1 = z[1][1]; - if (!extentDomain) { - y0 = extent[0][1], y1 = extent[1][1]; - if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - } - } - return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; - } - extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; - if (x) { - x0 = z[0], x1 = z[1]; - if (y) x0 = x0[0], x1 = x1[0]; - extentDomain[0][0] = x0, extentDomain[1][0] = x1; - if (x.invert) x0 = x(x0), x1 = x(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; - } - if (y) { - y0 = z[0], y1 = z[1]; - if (x) y0 = y0[1], y1 = y1[1]; - extentDomain[0][1] = y0, extentDomain[1][1] = y1; - if (y.invert) y0 = y(y0), y1 = y(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; - } - return brush; - }; - brush.clear = function() { - extentDomain = null; - extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; - return brush; - }; - brush.empty = function() { - return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; - }; - return d3.rebind(brush, event, "on"); - }; - var d3_svg_brushCursor = { - n: "ns-resize", - e: "ew-resize", - s: "ns-resize", - w: "ew-resize", - nw: "nwse-resize", - ne: "nesw-resize", - se: "nwse-resize", - sw: "nesw-resize" - }; - var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; - d3.time = {}; - var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; - function d3_time_utc() { - this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); - } - d3_time_utc.prototype = { - getDate: function() { - return this._.getUTCDate(); - }, - getDay: function() { - return this._.getUTCDay(); - }, - getFullYear: function() { - return this._.getUTCFullYear(); - }, - getHours: function() { - return this._.getUTCHours(); - }, - getMilliseconds: function() { - return this._.getUTCMilliseconds(); - }, - getMinutes: function() { - return this._.getUTCMinutes(); - }, - getMonth: function() { - return this._.getUTCMonth(); - }, - getSeconds: function() { - return this._.getUTCSeconds(); - }, - getTime: function() { - return this._.getTime(); - }, - getTimezoneOffset: function() { - return 0; - }, - valueOf: function() { - return this._.valueOf(); - }, - setDate: function() { - d3_time_prototype.setUTCDate.apply(this._, arguments); - }, - setDay: function() { - d3_time_prototype.setUTCDay.apply(this._, arguments); - }, - setFullYear: function() { - d3_time_prototype.setUTCFullYear.apply(this._, arguments); - }, - setHours: function() { - d3_time_prototype.setUTCHours.apply(this._, arguments); - }, - setMilliseconds: function() { - d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); - }, - setMinutes: function() { - d3_time_prototype.setUTCMinutes.apply(this._, arguments); - }, - setMonth: function() { - d3_time_prototype.setUTCMonth.apply(this._, arguments); - }, - setSeconds: function() { - d3_time_prototype.setUTCSeconds.apply(this._, arguments); - }, - setTime: function() { - d3_time_prototype.setTime.apply(this._, arguments); - } - }; - var d3_time_prototype = Date.prototype; - var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; - var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; - function d3_time_interval(local, step, number) { - function round(date) { - var d0 = local(date), d1 = offset(d0, 1); - return date - d0 < d1 - date ? d0 : d1; - } - function ceil(date) { - step(date = local(new d3_time(date - 1)), 1); - return date; - } - function offset(date, k) { - step(date = new d3_time(+date), k); - return date; - } - function range(t0, t1, dt) { - var time = ceil(t0), times = []; - if (dt > 1) { - while (time < t1) { - if (!(number(time) % dt)) times.push(new Date(+time)); - step(time, 1); - } - } else { - while (time < t1) times.push(new Date(+time)), step(time, 1); - } - return times; - } - function range_utc(t0, t1, dt) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = t0; - return range(utc, t1, dt); - } finally { - d3_time = Date; - } - } - local.floor = local; - local.round = round; - local.ceil = ceil; - local.offset = offset; - local.range = range; - var utc = local.utc = d3_time_interval_utc(local); - utc.floor = utc; - utc.round = d3_time_interval_utc(round); - utc.ceil = d3_time_interval_utc(ceil); - utc.offset = d3_time_interval_utc(offset); - utc.range = range_utc; - return local; - } - function d3_time_interval_utc(method) { - return function(date, k) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = date; - return method(utc, k)._; - } finally { - d3_time = Date; - } - }; - } - d3.time.year = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setMonth(0, 1); - return date; - }, function(date, offset) { - date.setFullYear(date.getFullYear() + offset); - }, function(date) { - return date.getFullYear(); - }); - d3.time.years = d3.time.year.range; - d3.time.years.utc = d3.time.year.utc.range; - d3.time.day = d3_time_interval(function(date) { - var day = new d3_time(2e3, 0); - day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); - return day; - }, function(date, offset) { - date.setDate(date.getDate() + offset); - }, function(date) { - return date.getDate() - 1; - }); - d3.time.days = d3.time.day.range; - d3.time.days.utc = d3.time.day.utc.range; - d3.time.dayOfYear = function(date) { - var year = d3.time.year(date); - return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); - }; - d3_time_daySymbols.forEach(function(day, i) { - day = day.toLowerCase(); - i = 7 - i; - var interval = d3.time[day] = d3_time_interval(function(date) { - (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); - return date; - }, function(date, offset) { - date.setDate(date.getDate() + Math.floor(offset) * 7); - }, function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); - }); - d3.time[day + "s"] = interval.range; - d3.time[day + "s"].utc = interval.utc.range; - d3.time[day + "OfYear"] = function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); - }; - }); - d3.time.week = d3.time.sunday; - d3.time.weeks = d3.time.sunday.range; - d3.time.weeks.utc = d3.time.sunday.utc.range; - d3.time.weekOfYear = d3.time.sundayOfYear; - d3.time.format = function(template) { - var n = template.length; - function format(date) { - var string = [], i = -1, j = 0, c, p, f; - while (++i < n) { - if (template.charCodeAt(i) === 37) { - string.push(template.substring(j, i)); - if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); - if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); - string.push(c); - j = i + 1; - } - } - string.push(template.substring(j, i)); - return string.join(""); - } - format.parse = function(string) { - var d = { - y: 1900, - m: 0, - d: 1, - H: 0, - M: 0, - S: 0, - L: 0 - }, i = d3_time_parse(d, template, string, 0); - if (i != string.length) return null; - if ("p" in d) d.H = d.H % 12 + d.p * 12; - var date = new d3_time(); - if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { - date.setFullYear(d.y, 0, 1); - date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); - } else date.setFullYear(d.y, d.m, d.d); - date.setHours(d.H, d.M, d.S, d.L); - return date; - }; - format.toString = function() { - return template; - }; - return format; - }; - function d3_time_parse(date, template, string, j) { - var c, p, i = 0, n = template.length, m = string.length; - while (i < n) { - if (j >= m) return -1; - c = template.charCodeAt(i++); - if (c === 37) { - p = d3_time_parsers[template.charAt(i++)]; - if (!p || (j = p(date, string, j)) < 0) return -1; - } else if (c != string.charCodeAt(j++)) { - return -1; - } - } - return j; - } - function d3_time_formatRe(names) { - return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); - } - function d3_time_formatLookup(names) { - var map = new d3_Map(), i = -1, n = names.length; - while (++i < n) map.set(names[i].toLowerCase(), i); - return map; - } - function d3_time_formatPad(value, fill, width) { - var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; - return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); - } - var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; - var d3_time_formatPads = { - "-": "", - _: " ", - "0": "0" - }; - var d3_time_formats = { - a: function(d) { - return d3_time_dayAbbreviations[d.getDay()]; - }, - A: function(d) { - return d3_time_days[d.getDay()]; - }, - b: function(d) { - return d3_time_monthAbbreviations[d.getMonth()]; - }, - B: function(d) { - return d3_time_months[d.getMonth()]; - }, - c: d3.time.format(d3_time_formatDateTime), - d: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - e: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - H: function(d, p) { - return d3_time_formatPad(d.getHours(), p, 2); - }, - I: function(d, p) { - return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); - }, - j: function(d, p) { - return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); - }, - L: function(d, p) { - return d3_time_formatPad(d.getMilliseconds(), p, 3); - }, - m: function(d, p) { - return d3_time_formatPad(d.getMonth() + 1, p, 2); - }, - M: function(d, p) { - return d3_time_formatPad(d.getMinutes(), p, 2); - }, - p: function(d) { - return d.getHours() >= 12 ? "PM" : "AM"; - }, - S: function(d, p) { - return d3_time_formatPad(d.getSeconds(), p, 2); - }, - U: function(d, p) { - return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); - }, - w: function(d) { - return d.getDay(); - }, - W: function(d, p) { - return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); - }, - x: d3.time.format(d3_time_formatDate), - X: d3.time.format(d3_time_formatTime), - y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 100, p, 2); - }, - Y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); - }, - Z: d3_time_zone, - "%": function() { - return "%"; - } - }; - var d3_time_parsers = { - a: d3_time_parseWeekdayAbbrev, - A: d3_time_parseWeekday, - b: d3_time_parseMonthAbbrev, - B: d3_time_parseMonth, - c: d3_time_parseLocaleFull, - d: d3_time_parseDay, - e: d3_time_parseDay, - H: d3_time_parseHour24, - I: d3_time_parseHour24, - j: d3_time_parseDayOfYear, - L: d3_time_parseMilliseconds, - m: d3_time_parseMonthNumber, - M: d3_time_parseMinutes, - p: d3_time_parseAmPm, - S: d3_time_parseSeconds, - U: d3_time_parseWeekNumberSunday, - w: d3_time_parseWeekdayNumber, - W: d3_time_parseWeekNumberMonday, - x: d3_time_parseLocaleDate, - X: d3_time_parseLocaleTime, - y: d3_time_parseYear, - Y: d3_time_parseFullYear, - "%": d3_time_parseLiteralPercent - }; - function d3_time_parseWeekdayAbbrev(date, string, i) { - d3_time_dayAbbrevRe.lastIndex = 0; - var n = d3_time_dayAbbrevRe.exec(string.substring(i)); - return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseWeekday(date, string, i) { - d3_time_dayRe.lastIndex = 0; - var n = d3_time_dayRe.exec(string.substring(i)); - return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseWeekdayNumber(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 1)); - return n ? (date.w = +n[0], i + n[0].length) : -1; - } - function d3_time_parseWeekNumberSunday(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i)); - return n ? (date.U = +n[0], i + n[0].length) : -1; - } - function d3_time_parseWeekNumberMonday(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i)); - return n ? (date.W = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMonthAbbrev(date, string, i) { - d3_time_monthAbbrevRe.lastIndex = 0; - var n = d3_time_monthAbbrevRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseMonth(date, string, i) { - d3_time_monthRe.lastIndex = 0; - var n = d3_time_monthRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseLocaleFull(date, string, i) { - return d3_time_parse(date, d3_time_formats.c.toString(), string, i); - } - function d3_time_parseLocaleDate(date, string, i) { - return d3_time_parse(date, d3_time_formats.x.toString(), string, i); - } - function d3_time_parseLocaleTime(date, string, i) { - return d3_time_parse(date, d3_time_formats.X.toString(), string, i); - } - function d3_time_parseFullYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 4)); - return n ? (date.y = +n[0], i + n[0].length) : -1; - } - function d3_time_parseYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; - } - function d3_time_expandYear(d) { - return d + (d > 68 ? 1900 : 2e3); - } - function d3_time_parseMonthNumber(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.m = n[0] - 1, i + n[0].length) : -1; - } - function d3_time_parseDay(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.d = +n[0], i + n[0].length) : -1; - } - function d3_time_parseDayOfYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 3)); - return n ? (date.j = +n[0], i + n[0].length) : -1; - } - function d3_time_parseHour24(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.H = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMinutes(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.M = +n[0], i + n[0].length) : -1; - } - function d3_time_parseSeconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.S = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMilliseconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 3)); - return n ? (date.L = +n[0], i + n[0].length) : -1; - } - var d3_time_numberRe = /^\s*\d+/; - function d3_time_parseAmPm(date, string, i) { - var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); - return n == null ? -1 : (date.p = n, i); - } - var d3_time_amPmLookup = d3.map({ - am: 0, - pm: 1 - }); - function d3_time_zone(d) { - var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; - return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); - } - function d3_time_parseLiteralPercent(date, string, i) { - d3_time_percentRe.lastIndex = 0; - var n = d3_time_percentRe.exec(string.substring(i, i + 1)); - return n ? i + n[0].length : -1; - } - d3.time.format.utc = function(template) { - var local = d3.time.format(template); - function format(date) { - try { - d3_time = d3_time_utc; - var utc = new d3_time(); - utc._ = date; - return local(utc); - } finally { - d3_time = Date; - } - } - format.parse = function(string) { - try { - d3_time = d3_time_utc; - var date = local.parse(string); - return date && date._; - } finally { - d3_time = Date; - } - }; - format.toString = local.toString; - return format; - }; - var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); - d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; - function d3_time_formatIsoNative(date) { - return date.toISOString(); - } - d3_time_formatIsoNative.parse = function(string) { - var date = new Date(string); - return isNaN(date) ? null : date; - }; - d3_time_formatIsoNative.toString = d3_time_formatIso.toString; - d3.time.second = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 1e3) * 1e3); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 1e3); - }, function(date) { - return date.getSeconds(); - }); - d3.time.seconds = d3.time.second.range; - d3.time.seconds.utc = d3.time.second.utc.range; - d3.time.minute = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 6e4) * 6e4); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 6e4); - }, function(date) { - return date.getMinutes(); - }); - d3.time.minutes = d3.time.minute.range; - d3.time.minutes.utc = d3.time.minute.utc.range; - d3.time.hour = d3_time_interval(function(date) { - var timezone = date.getTimezoneOffset() / 60; - return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 36e5); - }, function(date) { - return date.getHours(); - }); - d3.time.hours = d3.time.hour.range; - d3.time.hours.utc = d3.time.hour.utc.range; - d3.time.month = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setDate(1); - return date; - }, function(date, offset) { - date.setMonth(date.getMonth() + offset); - }, function(date) { - return date.getMonth(); - }); - d3.time.months = d3.time.month.range; - d3.time.months.utc = d3.time.month.utc.range; - function d3_time_scale(linear, methods, format) { - function scale(x) { - return linear(x); - } - scale.invert = function(x) { - return d3_time_scaleDate(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return linear.domain().map(d3_time_scaleDate); - linear.domain(x); - return scale; - }; - scale.nice = function(m) { - return scale.domain(d3_scale_nice(scale.domain(), m)); - }; - scale.ticks = function(m, k) { - var extent = d3_scaleExtent(scale.domain()); - if (typeof m !== "function") { - var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); - if (i == d3_time_scaleSteps.length) return methods.year(extent, m); - if (!i) return linear.ticks(m).map(d3_time_scaleDate); - if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; - m = methods[i]; - k = m[1]; - m = m[0].range; - } - return m(extent[0], new Date(+extent[1] + 1), k); - }; - scale.tickFormat = function() { - return format; - }; - scale.copy = function() { - return d3_time_scale(linear.copy(), methods, format); - }; - return d3_scale_linearRebind(scale, linear); - } - function d3_time_scaleDate(t) { - return new Date(t); - } - function d3_time_scaleFormat(formats) { - return function(date) { - var i = formats.length - 1, f = formats[i]; - while (!f[1](date)) f = formats[--i]; - return f[0](date); - }; - } - function d3_time_scaleSetYear(y) { - var d = new Date(y, 0, 1); - d.setFullYear(y); - return d; - } - function d3_time_scaleGetYear(d) { - var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; - var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; - var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { - return d.getMonth(); - } ], [ d3.time.format("%b %d"), function(d) { - return d.getDate() != 1; - } ], [ d3.time.format("%a %d"), function(d) { - return d.getDay() && d.getDate() != 1; - } ], [ d3.time.format("%I %p"), function(d) { - return d.getHours(); - } ], [ d3.time.format("%I:%M"), function(d) { - return d.getMinutes(); - } ], [ d3.time.format(":%S"), function(d) { - return d.getSeconds(); - } ], [ d3.time.format(".%L"), function(d) { - return d.getMilliseconds(); - } ] ]; - var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); - d3_time_scaleLocalMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); - }; - d3.time.scale = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); - }; - var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { - return [ m[0].utc, m[1] ]; - }); - var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { - return d.getUTCMonth(); - } ], [ d3.time.format.utc("%b %d"), function(d) { - return d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%a %d"), function(d) { - return d.getUTCDay() && d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%I %p"), function(d) { - return d.getUTCHours(); - } ], [ d3.time.format.utc("%I:%M"), function(d) { - return d.getUTCMinutes(); - } ], [ d3.time.format.utc(":%S"), function(d) { - return d.getUTCSeconds(); - } ], [ d3.time.format.utc(".%L"), function(d) { - return d.getUTCMilliseconds(); - } ] ]; - var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); - function d3_time_scaleUTCSetYear(y) { - var d = new Date(Date.UTC(y, 0, 1)); - d.setUTCFullYear(y); - return d; - } - function d3_time_scaleUTCGetYear(d) { - var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - d3_time_scaleUTCMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); - }; - d3.time.scale.utc = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); - }; - d3.text = d3_xhrType(function(request) { - return request.responseText; - }); - d3.json = function(url, callback) { - return d3_xhr(url, "application/json", d3_json, callback); - }; - function d3_json(request) { - return JSON.parse(request.responseText); - } - d3.html = function(url, callback) { - return d3_xhr(url, "text/html", d3_html, callback); - }; - function d3_html(request) { - var range = d3_document.createRange(); - range.selectNode(d3_document.body); - return range.createContextualFragment(request.responseText); - } - d3.xml = d3_xhrType(function(request) { - return request.responseXML; - }); - return d3; -}(); -},{}],29:[function(require,module,exports){ -require("./d3"); -module.exports = d3; -(function () { delete this.d3; })(); // unset global - -},{"./d3":28}],30:[function(require,module,exports){ -var ich = require('icanhaz') - -module.exports.ich = ich - -module.exports.getKeywordCount = function(data, keyword) { - var group = [] - data.forEach(function (d) { - for(var key in d) { - var value = d[key].toString().toLowerCase() - if (value.match(keyword.toLowerCase())) group.push(d) - } - }) - return group.length - if (group = []) return "0" -} - -module.exports.getKeyword = function(data, keyword) { - var group = [] - data.forEach(function (d) { - for(var key in d) { - var value = d[key].toString().toLowerCase() - if (value.match(keyword.toLowerCase())) group.push(d) - } - }) - return group - if (group = []) return "no matches" -} - -module.exports.getColumnTotal = function(data, column) { - var total = [] - data.forEach(function (d) { - if (d[column] === "") return - total.push(+d[column]) - }) - return total.reduce(function(a,b) { - return a + b - }) -} - -module.exports.getColumnAverage = function(data, column) { - var total = getColumnTotal(data, column) - var average = total / data.length - return average -} - -module.exports.getMax = function(data, column) { - var result = [] - data.forEach(function (element){ - if (result.length === 0) return result.push(element) - else { - if (element[column].valueOf() > result[0][column].valueOf()) { - result.length = 0 - return result.push(element) - } - if (element[column].valueOf() === result[0][column].valueOf()) { - return result.push(element) - } - } - }) - return result -} - -module.exports.getMin = function(data, column) { - var result = [] - data.forEach(function (element){ - if (result.length === 0) return result.push(element) - else { - if (element[column].valueOf() < result[0][column].valueOf()) { - result.length = 0 - return result.push(element) - } - if (element[column].valueOf() === result[0][column].valueOf()) { - return result.push(element) - } - } - }) - return result -} - -// out of the data, filter something from a category -module.exports.getMatches = function (data, filter, category) { - var matches = [] - data.forEach(function (element) { - var projectType = element[category].toString().toLowerCase() - if (projectType === filter.toLowerCase()) matches.push(element) - }) - return matches -} - -module.exports.mostFrequent = function(data, category) { - var count = {} - for (var i = 0; i < data.length; i++) { - if (!count[data[i][category]]) { - count[data[i][category]] = 0 - } - count[data[i][category]]++ - } - var sortable = [] - for (var category in count) { - sortable.push([category, count[category]]) - } - sortable.sort(function(a, b) {return b[1] - a[1]}) - return sortable - // returns array of arrays, in order -} - -// thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ -module.exports.deepCopy = function(obj) { - if (Object.prototype.toString.call(obj) === '[object Array]') { - var out = [], i = 0, len = obj.length; - for ( ; i < len; i++ ) { - out[i] = arguments.callee(obj[i]); - } - return out; - } - if (typeof obj === 'object') { - var out = {}, i; - for ( i in obj ) { - out[i] = arguments.callee(obj[i]); - } - return out; - } - return obj; -} - -module.exports.getOccurance = function(data, category) { - var occuranceCount = {} - for (var i = 0; i < data.length; i++) { - if (!occuranceCount[data[i][category]]) { - occuranceCount[data[i][category]] = 0 - } - occuranceCount[data[i][category]]++ - } - return occuranceCount - // returns object, keys alphabetical -} - -module.exports.makeColorArrayOfObject = function(data, colors, category) { - var category = category - var keys = Object.keys(data) - var counter = 1 - var colorIndex - return keys.map(function(key){ - if (keys.length > colors.length || keys.length <= colors.length ) { - colorIndex = counter % colors.length - } - var h = {units: data[key], hexcolor: colors[colorIndex]} - h[category] = key - counter++ - colorIndex = counter - return h - }) -} - -module.exports.makeArrayOfObject = function(data) { - var keys = Object.keys(data) - return keys.map(function(key){ - // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} - var h = {label: key, units: data[key]} - return h - }) -} - -},{"icanhaz":31}],31:[function(require,module,exports){ -/*! -ICanHaz.js version 0.10.2 -- by @HenrikJoreteg -More info at: http://icanhazjs.com -*/ -(function () { -/* - mustache.js — Logic-less templates in JavaScript - - See http://mustache.github.com/ for more info. -*/ - -var Mustache = window.Mustache = function () { - var _toString = Object.prototype.toString; - - Array.isArray = Array.isArray || function (obj) { - return _toString.call(obj) == "[object Array]"; - } - - var _trim = String.prototype.trim, trim; - - if (_trim) { - trim = function (text) { - return text == null ? "" : _trim.call(text); - } - } else { - var trimLeft, trimRight; - - // IE doesn't match non-breaking spaces with \s. - if ((/\S/).test("\xA0")) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; - } else { - trimLeft = /^\s+/; - trimRight = /\s+$/; - } - - trim = function (text) { - return text == null ? "" : - text.toString().replace(trimLeft, "").replace(trimRight, ""); - } - } - - var escapeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - - function escapeHTML(string) { - return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { - return escapeMap[s] || s; - }); - } - - var regexCache = {}; - var Renderer = function () {}; - - Renderer.prototype = { - otag: "{{", - ctag: "}}", - pragmas: {}, - buffer: [], - pragmas_implemented: { - "IMPLICIT-ITERATOR": true - }, - context: {}, - - render: function (template, context, partials, in_recursion) { - // reset buffer & set context - if (!in_recursion) { - this.context = context; - this.buffer = []; // TODO: make this non-lazy - } - - // fail fast - if (!this.includes("", template)) { - if (in_recursion) { - return template; - } else { - this.send(template); - return; - } - } - - // get the pragmas together - template = this.render_pragmas(template); - - // render the template - var html = this.render_section(template, context, partials); - - // render_section did not find any sections, we still need to render the tags - if (html === false) { - html = this.render_tags(template, context, partials, in_recursion); - } - - if (in_recursion) { - return html; - } else { - this.sendLines(html); - } - }, - - /* - Sends parsed lines - */ - send: function (line) { - if (line !== "") { - this.buffer.push(line); - } - }, - - sendLines: function (text) { - if (text) { - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) { - this.send(lines[i]); - } - } - }, - - /* - Looks for %PRAGMAS - */ - render_pragmas: function (template) { - // no pragmas - if (!this.includes("%", template)) { - return template; - } - - var that = this; - var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { - return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); - }); - - return template.replace(regex, function (match, pragma, options) { - if (!that.pragmas_implemented[pragma]) { - throw({message: - "This implementation of mustache doesn't understand the '" + - pragma + "' pragma"}); - } - that.pragmas[pragma] = {}; - if (options) { - var opts = options.split("="); - that.pragmas[pragma][opts[0]] = opts[1]; - } - return ""; - // ignore unknown pragmas silently - }); - }, - - /* - Tries to find a partial in the curent scope and render it - */ - render_partial: function (name, context, partials) { - name = trim(name); - if (!partials || partials[name] === undefined) { - throw({message: "unknown_partial '" + name + "'"}); - } - if (!context || typeof context[name] != "object") { - return this.render(partials[name], context, partials, true); - } - return this.render(partials[name], context[name], partials, true); - }, - - /* - Renders inverted (^) and normal (#) sections - */ - render_section: function (template, context, partials) { - if (!this.includes("#", template) && !this.includes("^", template)) { - // did not render anything, there were no sections - return false; - } - - var that = this; - - var regex = this.getCachedRegex("render_section", function (otag, ctag) { - // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder - return new RegExp( - "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) - - otag + // {{ - "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) - ctag + // }} - - "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped - - otag + // {{ - "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). - ctag + // }} - - "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. - - "g"); - }); - - - // for each {{#foo}}{{/foo}} section do... - return template.replace(regex, function (match, before, type, name, content, after) { - // before contains only tags, no sections - var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", - - // after may contain both sections and tags, so use full rendering function - renderedAfter = after ? that.render(after, context, partials, true) : "", - - // will be computed below - renderedContent, - - value = that.find(name, context); - - if (type === "^") { // inverted section - if (!value || Array.isArray(value) && value.length === 0) { - // false or empty list, render it - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } else if (type === "#") { // normal section - if (Array.isArray(value)) { // Enumerable, Let's loop! - renderedContent = that.map(value, function (row) { - return that.render(content, that.create_context(row), partials, true); - }).join(""); - } else if (that.is_object(value)) { // Object, Use it as subcontext! - renderedContent = that.render(content, that.create_context(value), - partials, true); - } else if (typeof value == "function") { - // higher order section - renderedContent = value.call(context, content, function (text) { - return that.render(text, context, partials, true); - }); - } else if (value) { // boolean section - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } - - return renderedBefore + renderedContent + renderedAfter; - }); - }, - - /* - Replace {{foo}} and friends with values from our view - */ - render_tags: function (template, context, partials, in_recursion) { - // tit for tat - var that = this; - - var new_regex = function () { - return that.getCachedRegex("render_tags", function (otag, ctag) { - return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); - }); - }; - - var regex = new_regex(); - var tag_replace_callback = function (match, operator, name) { - switch(operator) { - case "!": // ignore comments - return ""; - case "=": // set new delimiters, rebuild the replace regexp - that.set_delimiters(name); - regex = new_regex(); - return ""; - case ">": // render partial - return that.render_partial(name, context, partials); - case "{": // the triple mustache is unescaped - case "&": // & operator is an alternative unescape method - return that.find(name, context); - default: // escape the value - return escapeHTML(that.find(name, context)); - } - }; - var lines = template.split("\n"); - for(var i = 0; i < lines.length; i++) { - lines[i] = lines[i].replace(regex, tag_replace_callback, this); - if (!in_recursion) { - this.send(lines[i]); - } - } - - if (in_recursion) { - return lines.join("\n"); - } - }, - - set_delimiters: function (delimiters) { - var dels = delimiters.split(" "); - this.otag = this.escape_regex(dels[0]); - this.ctag = this.escape_regex(dels[1]); - }, - - escape_regex: function (text) { - // thank you Simon Willison - if (!arguments.callee.sRE) { - var specials = [ - '/', '.', '*', '+', '?', '|', - '(', ')', '[', ']', '{', '}', '\\' - ]; - arguments.callee.sRE = new RegExp( - '(\\' + specials.join('|\\') + ')', 'g' - ); - } - return text.replace(arguments.callee.sRE, '\\$1'); - }, - - /* - find `name` in current `context`. That is find me a value - from the view object - */ - find: function (name, context) { - name = trim(name); - - // Checks whether a value is thruthy or false or 0 - function is_kinda_truthy(bool) { - return bool === false || bool === 0 || bool; - } - - var value; - - // check for dot notation eg. foo.bar - if (name.match(/([a-z_]+)\./ig)) { - var childValue = this.walk_context(name, context); - if (is_kinda_truthy(childValue)) { - value = childValue; - } - } else { - if (is_kinda_truthy(context[name])) { - value = context[name]; - } else if (is_kinda_truthy(this.context[name])) { - value = this.context[name]; - } - } - - if (typeof value == "function") { - return value.apply(context); - } - if (value !== undefined) { - return value; - } - // silently ignore unkown variables - return ""; - }, - - walk_context: function (name, context) { - var path = name.split('.'); - // if the var doesn't exist in current context, check the top level context - var value_context = (context[path[0]] != undefined) ? context : this.context; - var value = value_context[path.shift()]; - while (value != undefined && path.length > 0) { - value_context = value; - value = value[path.shift()]; - } - // if the value is a function, call it, binding the correct context - if (typeof value == "function") { - return value.apply(value_context); - } - return value; - }, - - // Utility methods - - /* includes tag */ - includes: function (needle, haystack) { - return haystack.indexOf(this.otag + needle) != -1; - }, - - // by @langalex, support for arrays of strings - create_context: function (_context) { - if (this.is_object(_context)) { - return _context; - } else { - var iterator = "."; - if (this.pragmas["IMPLICIT-ITERATOR"]) { - iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; - } - var ctx = {}; - ctx[iterator] = _context; - return ctx; - } - }, - - is_object: function (a) { - return a && typeof a == "object"; - }, - - /* - Why, why, why? Because IE. Cry, cry cry. - */ - map: function (array, fn) { - if (typeof array.map == "function") { - return array.map(fn); - } else { - var r = []; - var l = array.length; - for(var i = 0; i < l; i++) { - r.push(fn(array[i])); - } - return r; - } - }, - - getCachedRegex: function (name, generator) { - var byOtag = regexCache[this.otag]; - if (!byOtag) { - byOtag = regexCache[this.otag] = {}; - } - - var byCtag = byOtag[this.ctag]; - if (!byCtag) { - byCtag = byOtag[this.ctag] = {}; - } - - var regex = byCtag[name]; - if (!regex) { - regex = byCtag[name] = generator(this.otag, this.ctag); - } - - return regex; - } - }; - - return({ - name: "mustache.js", - version: "0.4.0", - - /* - Turns a template and view into HTML - */ - to_html: function (template, view, partials, send_fun) { - var renderer = new Renderer(); - if (send_fun) { - renderer.send = send_fun; - } - renderer.render(template, view || {}, partials); - if (!send_fun) { - return renderer.buffer.join("\n"); - } - } - }); -}(); -/*! - ICanHaz.js -- by @HenrikJoreteg -*/ -/*global */ -(function () { - function trim(stuff) { - if (''.trim) return stuff.trim(); - else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - var ich = { - VERSION: "0.10.2", - templates: {}, - - // grab jquery or zepto if it's there - $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, - - // public function for adding templates - // can take a name and template string arguments - // or can take an object with name/template pairs - // We're enforcing uniqueness to avoid accidental template overwrites. - // If you want a different template, it should have a different name. - addTemplate: function (name, templateString) { - if (typeof name === 'object') { - for (var template in name) { - this.addTemplate(template, name[template]); - } - return; - } - if (ich[name]) { - console.error("Invalid name: " + name + "."); - } else if (ich.templates[name]) { - console.error("Template \"" + name + " \" exists"); - } else { - ich.templates[name] = templateString; - ich[name] = function (data, raw) { - data = data || {}; - var result = Mustache.to_html(ich.templates[name], data, ich.templates); - return (ich.$ && !raw) ? ich.$(trim(result)) : result; - }; - } - }, - - // clears all retrieval functions and empties cache - clearAll: function () { - for (var key in ich.templates) { - delete ich[key]; - } - ich.templates = {}; - }, - - // clears/grabs - refresh: function () { - ich.clearAll(); - ich.grabTemplates(); - }, - - // grabs templates from the DOM and caches them. - // Loop through and add templates. - // Whitespace at beginning and end of all templates inside ``` -Include your d3.js code with the HTML and call it. +_View the [entire source](https://github.com/maxogden/sheetsee-d3bubble)_ -WIP diff --git a/docs/fork-n-go.md b/docs/fork-n-go.md index a369abdc..d54bd540 100644 --- a/docs/fork-n-go.md +++ b/docs/fork-n-go.md @@ -8,9 +8,9 @@ On GitHub, a **fork** is a full copy of a repository, on your account, that you **GitHub Pages** is the hosting service that GitHub provides free to all users, organizations _and_ repositories. This means everyone of these entities or project can have it's own website at a predictable domain: -- **ORGS**: orgname.github.io -- **USER**: username.github.io -- **REPOSITORY**: username.github.io/repositoryname +- **organizations**: orgname.github.io +- **users**: username.github.io +- **repositories**: username.github.io/repositoryname To have a website for a repository all you need is a branch named `gh-pages`. GitHub will then look in that branch for web files and serve them up at the address. @@ -18,4 +18,15 @@ What all of this means is that Sheetsee.js projects, hosted on gh-pages branches A Fork-n-Go example from my [blog post](http://jlord.us/fork-n-go/) on the topic: -### Hack Spots Fork-n-Go \ No newline at end of file +### Hack Spots Fork-n-Go + +I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do: + +- Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing. +- Fork the original repository. +- Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). +Commit your change. + +Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName. + +![forkcommit](http://jlord.s3.amazonaws.com/wp-content/uploads/forkcommit1.png) \ No newline at end of file diff --git a/docs/sheetsee-charts.md b/docs/sheetsee-charts.md index 6c0f948b..89ec2fc5 100644 --- a/docs/sheetsee-charts.md +++ b/docs/sheetsee-charts.md @@ -2,15 +2,15 @@ _[View Demo](/demos/demo-chart.html)_ -Sheetsee.js provides three [d3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. You can also plug in your own custom d3.js chart to sheetsee, read about that [here](custom-charts.md). +Sheetsee.js provides three [d3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also plug in your own custom d3.js chart to sheetsee, read about that [here](custom-charts.md). ## Make a Chart -Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an _array of objects_, with objects containing "label" and "units" key/value pairs. See the section above on Your Data to learn about formatting. +Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an _array of objects_, with objects containing `label` and `units` key/value pairs. See the section above on Your Data to learn about formatting. Experiment with the charts to find the correct size your `
        ` will need to be to hold the chart with your data in it nicely. -You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. Information [here](docs/custom-charts.md) on using your own chart. +You can also make your own d3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information [here](docs/custom-charts.md) on using your own chart. ### Bar Chart @@ -23,7 +23,7 @@ To create a bar chart you'll need to add a placeholder `
        ` in your HTML with In your CSS, give it dimensions. ```CSS -barChart {height: 400px; max-width: 600px; background: #F8CDCD;} +#barChart {height: 400px; max-width: 600px; background: #F8CDCD;} ``` In a ` +``` \ No newline at end of file diff --git a/docs/sheetsee-tables.md b/docs/sheetsee-tables.md index 02a54293..370e3c26 100644 --- a/docs/sheetsee-tables.md +++ b/docs/sheetsee-tables.md @@ -41,9 +41,15 @@ _The variables inside the {{}} must match the column headers in your spreadsheet ```javascript ``` @@ -56,34 +62,44 @@ To create another table, simply repeat the steps except for `initiateTableFilter ``` -Learn more about the things you can do with [mustache.js](http://mustache.github.io/). +Learn more about the things you can do with [ICanHaz.js](http://icanhazjs.com). -### Sheetsee.makeTable(data, targetDiv, pagination) +### Sheetsee.makeTable(tableOptions) -You'll call this to make a table out of a **data** and tell it what **targetDiv** in the html to render it in (this should also be the same id as your script template id) and how many **rows** you want it to show per "page" of the table. If you don't include the pagination number, it will default to showing all rows on one page. +You pass in an object containing: + +- `data` your data array +- `pagination` how many rows displayed at one time, defaults to all +- `tableDiv` the
        placeholder in your HTML +- `filterDiv` the `
        ` containing your `` filter if using search ```javascript -Sheetsee.makeTable(gData, "#siteTable", 10) +var tableOptions = { + "data": gData, + "pagination": 10, + "tableDiv": "#fullTable", + "filterDiv": "#fullTableFilter" + } +Sheetsee.makeTable(tableOptions) ``` #### Pagination -If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, at the bottom of your table it will add this for naviagtion, which you can style in your CSS: +If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for naviagtion, which you can style in your CSS: -HTML: +_HTML_ ```HTML ``` -CSS: +_CSS_ ```CSS

        About

        @@ -80,5 +85,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/basics.html b/site/docs/basics.html index 287c1bc9..f1911b76 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Spreadsheets as Databases

        @@ -110,5 +115,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/building.html b/site/docs/building.html index d25b52c2..99d45478 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Just Right

        @@ -72,5 +77,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 4bc7438a..5ed94ad4 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Sheetsee v3

        @@ -66,5 +71,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index db873807..9e839ffe 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Custom Charts

        @@ -18,11 +23,53 @@

        Custom Charts

        var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
         

        The labels represent the actual thing you're charting and units are how many of those things. Margin, width and height are m, w, h and the div to build your chart in is div. Finally, you can supply a highlight color if you want.

        -

        So, your chart could take the same options, but map them into your d3 code with the correct variables. For instance if what sheetsee calls labels you call itemID you just add at the top of your d3 code:

        -
        labels = itemID
        +

        So, your chart could take the same options, but map them into your d3 code with the correct variables. An example from maxogden/sheetsee-d3bubble:

        +

        Append the d3.js code with a map of your sheetsee options

        +
        Sheetsee.d3BubbleChart = function(data, options) {
        +    var tree = {name: "data", children: []}
        +    var groups = {}
        +
        +    // data needs to look like this:
        +    // var data = { name: "wahtever", children: [
        +    //   { name: "group1", children: [
        +    //     { name: 'bob', size: 3},
        +    //     { name: 'judy', size: 5}
        +    //   ]},
        +    //   { name: "group2", children: [
        +    //     { name: 'jim', size: 10},
        +    //     { name: 'bill', size: 5}
        +    //   ]}
        +    // ]}
        +
        +    data.map(function(r) {
        +        var groupName = r[options.group]
        +        groups[groupName] = true
        +    })
        +
        +    Object.keys(groups).map(function(groupName) {
        +        var groupMembers = []
        +        data.map(function(r) {
        +            if (r[options.group] !== groupName) return
        +            groupMembers.push({name: r[options.name], size: r[options.size]})
        +        })
        +        tree.children.push({name: groupName, children: groupMembers})
        +    })
        +
        +  // the rest of the code
        +
        +

        In your HTML call it like so

        +
        <script type="text/javascript">
        +  document.addEventListener('DOMContentLoaded', function() {
        +    var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
        +    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } ) 
        +  })
        +
        +  function showInfo(data) {
        +    Sheetsee.d3BubbleChart(data, { name: 'name', size: 'cuddlability', group: 'kind', div: '#stuff'})
        +  }
        +</script>
         
        -

        Include your d3.js code with the HTML and call it.

        -

        WIP

        +

        View the entire source

        + \ No newline at end of file diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 4c6922eb..c4f26dc3 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Fork-n-Go

        @@ -18,14 +23,23 @@

        Fork-n-Go

        On GitHub, a fork is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button.

        GitHub Pages is the hosting service that GitHub provides free to all users, organizations and repositories. This means everyone of these entities or project can have it's own website at a predictable domain:

          -
        • ORGS: orgname.github.io
        • -
        • USER: username.github.io
        • -
        • REPOSITORY: username.github.io/repositoryname
        • +
        • organizations: orgname.github.io
        • +
        • users: username.github.io
        • +
        • repositories: username.github.io/repositoryname

        To have a website for a repository all you need is a branch named gh-pages. GitHub will then look in that branch for web files and serve them up at the address.

        What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily.

        A Fork-n-Go example from my blog post on the topic:

        Hack Spots Fork-n-Go

        +

        I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do:

        +
          +
        • Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing.
        • +
        • Fork the original repository.
        • +
        • Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). +Commit your change.
        • +
        +

        Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName.

        +

        forkcommit

        + \ No newline at end of file diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index d7293e92..7730bb88 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -6,25 +6,30 @@ such site, very sheetsee.js + + + + +

        Sheetsee-charts

        View Demo

        -

        Sheetsee.js provides three d3.js chart options to use with your spreadsheet data: a bar chart, line chart and pie graph. You can also plug in your own custom d3.js chart to sheetsee, read about that here.

        +

        Sheetsee.js provides three d3.js chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also plug in your own custom d3.js chart to sheetsee, read about that here.

        Make a Chart

        -

        Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, with objects containing "label" and "units" key/value pairs. See the section above on Your Data to learn about formatting.

        +

        Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, with objects containing label and units key/value pairs. See the section above on Your Data to learn about formatting.

        Experiment with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

        -

        You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. Information here on using your own chart.

        +

        You can also make your own d3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information here on using your own chart.

        Bar Chart

        To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

        <div id="barChart"></div>
         

        In your CSS, give it dimensions.

        -
        barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
        +
        #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
         

        In a <script> tag set up your options.

        var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
        @@ -118,5 +123,6 @@ 

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index fe15eea7..dc2669d3 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Sheetsee-core

        @@ -121,5 +126,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index e0294f6d..f1f0f390 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -6,16 +6,21 @@ such site, very sheetsee.js + + + + +

        Sheetsee-maps

        View Demo

        -

        Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps of your points, polygons, lines or multipolygons (all coordinate based).

        -

        You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags.

        +

        Sheetsee.js uses Mapbox.js and Leaflet.js to make maps of your points, polygons, lines or multipolygons (all coordinate based). Details on what that actually looks like here.

        +

        You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags. You can also customize your popup content.

        Your HTML Placeholder <div>

        Create an empty <div> in your HTML, with an id (name). Add CSS to give it dimensions

        <div id="map"></div>
        @@ -40,22 +45,43 @@ 

        Sheetsee.createGeoJSON(data, o "opts": {the options you pass in}, }}

        -

        Sheetsee.addMarkerLayer(geoJSON, map)

        -

        To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is HTML and can reference the column headers you included in your optionsJSON.

        -
        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
        -
        -

        Example template:

        -
        var popupTemplate = "<h4>Hello {{name}}</h4>"
        -

        Sheetsee.loadMap(mapDiv)

        To create a simple map, with no data, you simply call .loadMap() and pass in a string of the mapDiv (with no '#') from your HTML.

        var map = Sheetsee.loadMap("map")
         

        Sheetsee.addTileLayer(map, tileLayer)

        -

        To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

        +

        To add a tile layer (aka a custom map scheme/design/background) you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
         

        You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

        +

        Sheetsee.addMarkerLayer(geoJSON, map)

        +

        To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

        +
        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
        +
        +

        Example template:

        +
        var popupTemplate = "<h4>Hello {{name}}</h4>"
        +
        +

        Source from the map demo:

        +
        <script type="text/javascript">
        +  document.addEventListener('DOMContentLoaded', function() {
        +    var gData
        +    var URL = "0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc"
        +    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
        +  })
        +
        +  function showInfo(data) {
        +    gData = data
        +    var optionsJSON = ["placename", "photo-url"]
        +    var template = "<ul><li><a href='{{photo-url}}' target='_blank'>"
        +                 + "<img src='{{photo-url}}'></a></li>"
        +                 + "<li><h4>{{placename}}</h4></li></ul>"
        +    var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
        +    var map = Sheetsee.loadMap("map")
        +    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
        +    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, template)
        +  }
        +</script>
        +
        + \ No newline at end of file diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 6a1787c6..17195e60 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        Sheetsee-tables

        @@ -37,9 +42,15 @@

        Sorting

        Your <script> Execution

        <script type="text/javascript">
        -    document.addEventListener('DOMContentLoaded', function() { // IE6 doesn't do DOMContentLoaded
        -        Sheetsee.makeTable(gData, "#siteTable", 10)
        -        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
        +    document.addEventListener('DOMContentLoaded', function() {
        +      var tableOptions = {
        +                          "data": gData, 
        +                          "pagination": 10, 
        +                          "tableDiv": "#fullTable", 
        +                          "filterDiv": "#fullTableFilter"
        +                          }
        +      Sheetsee.makeTable(tableOptions)
        +      Sheetsee.initiateTableFilter(tableOptions)
             })
         </script>
         
        @@ -48,39 +59,51 @@

        Your <script> Execution

        <script id="secondTable"> // your table template here </script> <script>Sheetsee.makeTable(otherData, "#secondTable", 10)</script>
        -

        Learn more about the things you can do with mustache.js.

        -

        Sheetsee.makeTable(data, targetDiv, pagination)

        -

        You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id) and how many rows you want it to show per "page" of the table. If you don't include the pagination number, it will default to showing all rows on one page.

        -
        Sheetsee.makeTable(gData, "#siteTable", 10)
        +

        Learn more about the things you can do with ICanHaz.js.

        +

        Sheetsee.makeTable(tableOptions)

        +

        You pass in an object containing:

        +
          +
        • data your data array
        • +
        • pagination how many rows displayed at one time, defaults to all
        • +
        • tableDiv the
          placeholder in your HTML
        • +
        • filterDiv the <div> containing your <input> filter if using search
        • +
        +
        var tableOptions = {
        +                    "data": gData, 
        +                    "pagination": 10, 
        +                    "tableDiv": "#fullTable", 
        +                    "filterDiv": "#fullTableFilter"
        +                    }
        +Sheetsee.makeTable(tableOptions)
         

        Pagination

        -

        If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, at the bottom of your table it will add this for naviagtion, which you can style in your CSS:

        -

        HTML:

        +

        If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for naviagtion, which you can style in your CSS:

        +

        HTML

        <div id='Pagination' currentPage class='table-pagination'>
        -  Showing page currentPage of totalPages
        +  Showing page {{currentPage}} of {{totalPages}}
           <a class='pagination-pre'>Previous</a><a class='pagination-next'>Next</a>
         </div>
         
        -

        CSS:

        +

        CSS

        <style>
        -  body {font-family: Helvetica Neue; Helvetica, Arial, sans-serif; }
           #Pagination {background: #eee;}
           .pagination-next, .pagination-pre {cursor: hand;}
           .no-pag {color: #acacac;}
         </style>
         
        -

        If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an ide and if you want, placeholder text:

        +

        If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want, placeholder text:

        <input id="tableFilter" type="text" placeholder="filter by.."></input>
         
        -

        Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

        -

        You will then call this function to make that input live:

        -
        Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
        +

        Sheetsee.initiateTableFilter(tableOptions)

        +

        You will then call this function with your tableOptions to make that input live and connected to your table:

        +
        Sheetsee.initiateTableFilter(tableOptions)
         

        It will connect that input to your data as well as inject this HTML for a button, which you can style yourself in your CSS:

        <span class="clear button">Clear</span>
         <span class="noMatches">no matches</span>
         
        +

        View Demo

        + \ No newline at end of file diff --git a/site/docs/tips.html b/site/docs/tips.html index 8c501797..0c257d14 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -6,13 +6,40 @@ such site, very sheetsee.js + + + + +

        Tips

        +

        A few things to think about beyond charts, maps and tables.

        +

        ICanHaz.js

        +

        You can use templates for more than just tables. Use them to create lists ol, ul; array of images... You'll need a placeholder <div> in your HTML, a <script> for your template and a script to call ICanHaz from your Tabletop.js callback.

        +

        HTML

        +
        <div id="divID"></div>
        +
        +

        Tempalte

        +
        <script id="divID" type="text/html">
        +  {{#rows}}
        +    <div><img class="photo" src="{{some-variable}}"></div>
        +  {{/rows}}
        +</script>
        +
        +

        Tempalte

        +
        <script type="text/html">
        +  // your other Sheetsee.js, Tabletop code above
        +  var html = Sheetsee.ich.divID({'rows': data})
        +  $('#divID').html(html)
        +</script>
        +
        +

        non-table template

        +

        lib

        Query Strings

        If your spreadsheet contains address information, using templates (Sheetsee.js uses a form of Mustache), you can embed those elements into a query string (aka a search URL) like Google Maps URL or Yelp. If you search for a location in Google Maps, you'll notice it creates a URL for that search.

        So, if you have information in your spreadsheet that would go inside a query string, make a template for inserting them into a link on your page.

        @@ -28,6 +55,8 @@

        Query Strings

        With a some CSS and such, the resulting website has a table with the hack spots and a button for viewing in Google Maps or Yelp:

        img

        When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM!

        +

        IFTTT

        +

        Ifttt.com offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets.

        + \ No newline at end of file diff --git a/site/index.html b/site/index.html index 057bfa67..7fba0e72 100644 --- a/site/index.html +++ b/site/index.html @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +

        sheetseeimg

        @@ -121,5 +126,6 @@

        Contact

        Home Page

        + \ No newline at end of file diff --git a/site/js/highlight.pack.js b/site/js/highlight.pack.js new file mode 100644 index 00000000..aea9187b --- /dev/null +++ b/site/js/highlight.pack.js @@ -0,0 +1 @@ +var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
        ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js index 7c85f06d..72f45e90 100644 --- a/site/js/sheetsee.js +++ b/site/js/sheetsee.js @@ -1,5 +1,5 @@ ;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o @@ -10168,7 +10168,7 @@ More info at: http://icanhazjs.com See http://mustache.github.com/ for more info. */ -var Mustache = window.Mustache = function () { +var Mustache = function () { var _toString = Object.prototype.toString; Array.isArray = Array.isArray || function (obj) { @@ -14319,6543 +14319,6543 @@ if (typeof module !== 'undefined') module.exports = xhr; (c) 2010-2013, Vladimir Agafonkin (c) 2010-2011, CloudMade */ -(function (window, document, undefined) { -var oldL = window.L, - L = {}; +(function (window, document, undefined) { +var oldL = window.L, + L = {}; + +L.version = '0.6.2'; + +// define Leaflet for Node module pattern loaders, including Browserify +if (typeof module === 'object' && typeof module.exports === 'object') { + module.exports = L; + +// define Leaflet as an AMD module +} else if (typeof define === 'function' && define.amd) { + define(L); +} + +// define Leaflet as a global L variable, saving the original L to restore later if needed + +L.noConflict = function () { + window.L = oldL; + return this; +}; + +window.L = L; + + +/* + * L.Util contains various utility functions used throughout Leaflet code. + */ + +L.Util = { + extend: function (dest) { // (Object[, Object, ...]) -> + var sources = Array.prototype.slice.call(arguments, 1), + i, j, len, src; + + for (j = 0, len = sources.length; j < len; j++) { + src = sources[j] || {}; + for (i in src) { + if (src.hasOwnProperty(i)) { + dest[i] = src[i]; + } + } + } + return dest; + }, + + bind: function (fn, obj) { // (Function, Object) -> Function + var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null; + return function () { + return fn.apply(obj, args || arguments); + }; + }, + + stamp: (function () { + var lastId = 0, + key = '_leaflet_id'; + return function (obj) { + obj[key] = obj[key] || ++lastId; + return obj[key]; + }; + }()), + + invokeEach: function (obj, method, context) { + var i, args; + + if (typeof obj === 'object') { + args = Array.prototype.slice.call(arguments, 3); + + for (i in obj) { + method.apply(context, [i, obj[i]].concat(args)); + } + return true; + } + + return false; + }, + + limitExecByInterval: function (fn, time, context) { + var lock, execOnUnlock; + + return function wrapperFn() { + var args = arguments; + + if (lock) { + execOnUnlock = true; + return; + } + + lock = true; + + setTimeout(function () { + lock = false; + + if (execOnUnlock) { + wrapperFn.apply(context, args); + execOnUnlock = false; + } + }, time); + + fn.apply(context, args); + }; + }, + + falseFn: function () { + return false; + }, + + formatNum: function (num, digits) { + var pow = Math.pow(10, digits || 5); + return Math.round(num * pow) / pow; + }, + + trim: function (str) { + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); + }, + + splitWords: function (str) { + return L.Util.trim(str).split(/\s+/); + }, + + setOptions: function (obj, options) { + obj.options = L.extend({}, obj.options, options); + return obj.options; + }, + + getParamString: function (obj, existingUrl, uppercase) { + var params = []; + for (var i in obj) { + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); + } + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); + }, + + template: function (str, data) { + return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { + var value = data[key]; + if (value === undefined) { + throw new Error('No value provided for variable ' + str); + } else if (typeof value === 'function') { + value = value(data); + } + return value; + }); + }, + + isArray: function (obj) { + return (Object.prototype.toString.call(obj) === '[object Array]'); + }, + + emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' +}; + +(function () { + + // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + + function getPrefixed(name) { + var i, fn, + prefixes = ['webkit', 'moz', 'o', 'ms']; + + for (i = 0; i < prefixes.length && !fn; i++) { + fn = window[prefixes[i] + name]; + } + + return fn; + } + + var lastTime = 0; + + function timeoutDefer(fn) { + var time = +new Date(), + timeToCall = Math.max(0, 16 - (time - lastTime)); + + lastTime = time + timeToCall; + return window.setTimeout(fn, timeToCall); + } + + var requestFn = window.requestAnimationFrame || + getPrefixed('RequestAnimationFrame') || timeoutDefer; + + var cancelFn = window.cancelAnimationFrame || + getPrefixed('CancelAnimationFrame') || + getPrefixed('CancelRequestAnimationFrame') || + function (id) { window.clearTimeout(id); }; + + + L.Util.requestAnimFrame = function (fn, context, immediate, element) { + fn = L.bind(fn, context); + + if (immediate && requestFn === timeoutDefer) { + fn(); + } else { + return requestFn.call(window, fn, element); + } + }; + + L.Util.cancelAnimFrame = function (id) { + if (id) { + cancelFn.call(window, id); + } + }; + +}()); + +// shortcuts for most used utility functions +L.extend = L.Util.extend; +L.bind = L.Util.bind; +L.stamp = L.Util.stamp; +L.setOptions = L.Util.setOptions; + + +/* + * L.Class powers the OOP facilities of the library. + * Thanks to John Resig and Dean Edwards for inspiration! + */ + +L.Class = function () {}; + +L.Class.extend = function (props) { + + // extended class with the new prototype + var NewClass = function () { + + // call the constructor + if (this.initialize) { + this.initialize.apply(this, arguments); + } + + // call all constructor hooks + if (this._initHooks) { + this.callInitHooks(); + } + }; + + // instantiate class without calling constructor + var F = function () {}; + F.prototype = this.prototype; + + var proto = new F(); + proto.constructor = NewClass; + + NewClass.prototype = proto; + + //inherit parent's statics + for (var i in this) { + if (this.hasOwnProperty(i) && i !== 'prototype') { + NewClass[i] = this[i]; + } + } + + // mix static properties into the class + if (props.statics) { + L.extend(NewClass, props.statics); + delete props.statics; + } + + // mix includes into the prototype + if (props.includes) { + L.Util.extend.apply(null, [proto].concat(props.includes)); + delete props.includes; + } + + // merge options + if (props.options && proto.options) { + props.options = L.extend({}, proto.options, props.options); + } + + // mix given properties into the prototype + L.extend(proto, props); + + proto._initHooks = []; + + var parent = this; + // jshint camelcase: false + NewClass.__super__ = parent.prototype; + + // add method for calling all hooks + proto.callInitHooks = function () { + + if (this._initHooksCalled) { return; } + + if (parent.prototype.callInitHooks) { + parent.prototype.callInitHooks.call(this); + } + + this._initHooksCalled = true; + + for (var i = 0, len = proto._initHooks.length; i < len; i++) { + proto._initHooks[i].call(this); + } + }; + + return NewClass; +}; + + +// method for adding properties to prototype +L.Class.include = function (props) { + L.extend(this.prototype, props); +}; + +// merge new default options to the Class +L.Class.mergeOptions = function (options) { + L.extend(this.prototype.options, options); +}; + +// add a constructor hook +L.Class.addInitHook = function (fn) { // (Function) || (String, args...) + var args = Array.prototype.slice.call(arguments, 1); + + var init = typeof fn === 'function' ? fn : function () { + this[fn].apply(this, args); + }; + + this.prototype._initHooks = this.prototype._initHooks || []; + this.prototype._initHooks.push(init); +}; + + +/* + * L.Mixin.Events is used to add custom events functionality to Leaflet classes. + */ + +var eventsKey = '_leaflet_events'; + +L.Mixin = {}; + +L.Mixin.Events = { + + addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object]) + + // types can be a map of types/handlers + if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; } + + var events = this[eventsKey] = this[eventsKey] || {}, + contextId = context && L.stamp(context), + i, len, event, type, indexKey, indexLenKey, typeIndex; + + // types can be a string of space-separated words + types = L.Util.splitWords(types); + + for (i = 0, len = types.length; i < len; i++) { + event = { + action: fn, + context: context || this + }; + type = types[i]; + + if (context) { + // store listeners of a particular context in a separate hash (if it has an id) + // gives a major performance boost when removing thousands of map layers + + indexKey = type + '_idx'; + indexLenKey = indexKey + '_len'; + + typeIndex = events[indexKey] = events[indexKey] || {}; + + if (!typeIndex[contextId]) { + typeIndex[contextId] = []; + + // keep track of the number of keys in the index to quickly check if it's empty + events[indexLenKey] = (events[indexLenKey] || 0) + 1; + } + + typeIndex[contextId].push(event); + + + } else { + events[type] = events[type] || []; + events[type].push(event); + } + } + + return this; + }, + + hasEventListeners: function (type) { // (String) -> Boolean + var events = this[eventsKey]; + return !!events && ((type in events && events[type].length > 0) || + (type + '_idx' in events && events[type + '_idx_len'] > 0)); + }, + + removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object]) + + if (!this[eventsKey]) { + return this; + } + + if (!types) { + return this.clearAllEventListeners(); + } + + if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; } + + var events = this[eventsKey], + contextId = context && L.stamp(context), + i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed; + + types = L.Util.splitWords(types); + + for (i = 0, len = types.length; i < len; i++) { + type = types[i]; + indexKey = type + '_idx'; + indexLenKey = indexKey + '_len'; + + typeIndex = events[indexKey]; + + if (!fn) { + // clear all listeners for a type if function isn't specified + delete events[type]; + delete events[indexKey]; + + } else { + listeners = context && typeIndex ? typeIndex[contextId] : events[type]; + + if (listeners) { + for (j = listeners.length - 1; j >= 0; j--) { + if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) { + removed = listeners.splice(j, 1); + // set the old action to a no-op, because it is possible + // that the listener is being iterated over as part of a dispatch + removed[0].action = L.Util.falseFn; + } + } + + if (context && typeIndex && (listeners.length === 0)) { + delete typeIndex[contextId]; + events[indexLenKey]--; + } + } + } + } + + return this; + }, + + clearAllEventListeners: function () { + delete this[eventsKey]; + return this; + }, + + fireEvent: function (type, data) { // (String[, Object]) + if (!this.hasEventListeners(type)) { + return this; + } + + var event = L.Util.extend({}, data, { type: type, target: this }); + + var events = this[eventsKey], + listeners, i, len, typeIndex, contextId; + + if (events[type]) { + // make sure adding/removing listeners inside other listeners won't cause infinite loop + listeners = events[type].slice(); + + for (i = 0, len = listeners.length; i < len; i++) { + listeners[i].action.call(listeners[i].context || this, event); + } + } + + // fire event for the context-indexed listeners as well + typeIndex = events[type + '_idx']; + + for (contextId in typeIndex) { + listeners = typeIndex[contextId].slice(); + + if (listeners) { + for (i = 0, len = listeners.length; i < len; i++) { + listeners[i].action.call(listeners[i].context || this, event); + } + } + } + + return this; + }, + + addOneTimeEventListener: function (types, fn, context) { + + if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; } + + var handler = L.bind(function () { + this + .removeEventListener(types, fn, context) + .removeEventListener(types, handler, context); + }, this); + + return this + .addEventListener(types, fn, context) + .addEventListener(types, handler, context); + } +}; + +L.Mixin.Events.on = L.Mixin.Events.addEventListener; +L.Mixin.Events.off = L.Mixin.Events.removeEventListener; +L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener; +L.Mixin.Events.fire = L.Mixin.Events.fireEvent; + + +/* + * L.Browser handles different browser and feature detections for internal Leaflet use. + */ + +(function () { + + var ie = !!window.ActiveXObject, + ie6 = ie && !window.XMLHttpRequest, + ie7 = ie && !document.querySelector, + ielt9 = ie && !document.addEventListener, + + // terrible browser detection to work around Safari / iOS / Android browser bugs + ua = navigator.userAgent.toLowerCase(), + webkit = ua.indexOf('webkit') !== -1, + chrome = ua.indexOf('chrome') !== -1, + phantomjs = ua.indexOf('phantom') !== -1, + android = ua.indexOf('android') !== -1, + android23 = ua.search('android [23]') !== -1, + + mobile = typeof orientation !== undefined + '', + msTouch = window.navigator && window.navigator.msPointerEnabled && + window.navigator.msMaxTouchPoints, + retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) || + ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') && + window.matchMedia('(min-resolution:144dpi)').matches), + + doc = document.documentElement, + ie3d = ie && ('transition' in doc.style), + webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()), + gecko3d = 'MozPerspective' in doc.style, + opera3d = 'OTransition' in doc.style, + any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs; + + + // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch. + // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151 + + var touch = !window.L_NO_TOUCH && !phantomjs && (function () { + + var startName = 'ontouchstart'; + + // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc. + if (msTouch || (startName in doc)) { + return true; + } + + // Firefox/Gecko + var div = document.createElement('div'), + supported = false; + + if (!div.setAttribute) { + return false; + } + div.setAttribute(startName, 'return;'); + + if (typeof div[startName] === 'function') { + supported = true; + } + + div.removeAttribute(startName); + div = null; + + return supported; + }()); + + + L.Browser = { + ie: ie, + ie6: ie6, + ie7: ie7, + ielt9: ielt9, + webkit: webkit, + + android: android, + android23: android23, + + chrome: chrome, + + ie3d: ie3d, + webkit3d: webkit3d, + gecko3d: gecko3d, + opera3d: opera3d, + any3d: any3d, + + mobile: mobile, + mobileWebkit: mobile && webkit, + mobileWebkit3d: mobile && webkit3d, + mobileOpera: mobile && window.opera, + + touch: touch, + msTouch: msTouch, + + retina: retina + }; + +}()); + + +/* + * L.Point represents a point with x and y coordinates. + */ + +L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { + this.x = (round ? Math.round(x) : x); + this.y = (round ? Math.round(y) : y); +}; + +L.Point.prototype = { + + clone: function () { + return new L.Point(this.x, this.y); + }, + + // non-destructive, returns a new point + add: function (point) { + return this.clone()._add(L.point(point)); + }, + + // destructive, used directly for performance in situations where it's safe to modify existing point + _add: function (point) { + this.x += point.x; + this.y += point.y; + return this; + }, + + subtract: function (point) { + return this.clone()._subtract(L.point(point)); + }, + + _subtract: function (point) { + this.x -= point.x; + this.y -= point.y; + return this; + }, + + divideBy: function (num) { + return this.clone()._divideBy(num); + }, + + _divideBy: function (num) { + this.x /= num; + this.y /= num; + return this; + }, + + multiplyBy: function (num) { + return this.clone()._multiplyBy(num); + }, + + _multiplyBy: function (num) { + this.x *= num; + this.y *= num; + return this; + }, + + round: function () { + return this.clone()._round(); + }, + + _round: function () { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + }, + + floor: function () { + return this.clone()._floor(); + }, + + _floor: function () { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + return this; + }, + + distanceTo: function (point) { + point = L.point(point); + + var x = point.x - this.x, + y = point.y - this.y; + + return Math.sqrt(x * x + y * y); + }, + + equals: function (point) { + point = L.point(point); + + return point.x === this.x && + point.y === this.y; + }, + + contains: function (point) { + point = L.point(point); + + return Math.abs(point.x) <= Math.abs(this.x) && + Math.abs(point.y) <= Math.abs(this.y); + }, + + toString: function () { + return 'Point(' + + L.Util.formatNum(this.x) + ', ' + + L.Util.formatNum(this.y) + ')'; + } +}; + +L.point = function (x, y, round) { + if (x instanceof L.Point) { + return x; + } + if (L.Util.isArray(x)) { + return new L.Point(x[0], x[1]); + } + if (x === undefined || x === null) { + return x; + } + return new L.Point(x, y, round); +}; + + +/* + * L.Bounds represents a rectangular area on the screen in pixel coordinates. + */ + +L.Bounds = function (a, b) { //(Point, Point) or Point[] + if (!a) { return; } + + var points = b ? [a, b] : a; + + for (var i = 0, len = points.length; i < len; i++) { + this.extend(points[i]); + } +}; + +L.Bounds.prototype = { + // extend the bounds to contain the given point + extend: function (point) { // (Point) + point = L.point(point); + + if (!this.min && !this.max) { + this.min = point.clone(); + this.max = point.clone(); + } else { + this.min.x = Math.min(point.x, this.min.x); + this.max.x = Math.max(point.x, this.max.x); + this.min.y = Math.min(point.y, this.min.y); + this.max.y = Math.max(point.y, this.max.y); + } + return this; + }, + + getCenter: function (round) { // (Boolean) -> Point + return new L.Point( + (this.min.x + this.max.x) / 2, + (this.min.y + this.max.y) / 2, round); + }, + + getBottomLeft: function () { // -> Point + return new L.Point(this.min.x, this.max.y); + }, + + getTopRight: function () { // -> Point + return new L.Point(this.max.x, this.min.y); + }, + + getSize: function () { + return this.max.subtract(this.min); + }, + + contains: function (obj) { // (Bounds) or (Point) -> Boolean + var min, max; + + if (typeof obj[0] === 'number' || obj instanceof L.Point) { + obj = L.point(obj); + } else { + obj = L.bounds(obj); + } + + if (obj instanceof L.Bounds) { + min = obj.min; + max = obj.max; + } else { + min = max = obj; + } + + return (min.x >= this.min.x) && + (max.x <= this.max.x) && + (min.y >= this.min.y) && + (max.y <= this.max.y); + }, + + intersects: function (bounds) { // (Bounds) -> Boolean + bounds = L.bounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; + }, + + isValid: function () { + return !!(this.min && this.max); + } +}; + +L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[]) + if (!a || a instanceof L.Bounds) { + return a; + } + return new L.Bounds(a, b); +}; + + +/* + * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. + */ + +L.Transformation = function (a, b, c, d) { + this._a = a; + this._b = b; + this._c = c; + this._d = d; +}; + +L.Transformation.prototype = { + transform: function (point, scale) { // (Point, Number) -> Point + return this._transform(point.clone(), scale); + }, + + // destructive transform (faster) + _transform: function (point, scale) { + scale = scale || 1; + point.x = scale * (this._a * point.x + this._b); + point.y = scale * (this._c * point.y + this._d); + return point; + }, + + untransform: function (point, scale) { + scale = scale || 1; + return new L.Point( + (point.x / scale - this._b) / this._a, + (point.y / scale - this._d) / this._c); + } +}; + + +/* + * L.DomUtil contains various utility functions for working with DOM. + */ + +L.DomUtil = { + get: function (id) { + return (typeof id === 'string' ? document.getElementById(id) : id); + }, + + getStyle: function (el, style) { + + var value = el.style[style]; + + if (!value && el.currentStyle) { + value = el.currentStyle[style]; + } + + if ((!value || value === 'auto') && document.defaultView) { + var css = document.defaultView.getComputedStyle(el, null); + value = css ? css[style] : null; + } + + return value === 'auto' ? null : value; + }, + + getViewportOffset: function (element) { + + var top = 0, + left = 0, + el = element, + docBody = document.body, + docEl = document.documentElement, + pos, + ie7 = L.Browser.ie7; + + do { + top += el.offsetTop || 0; + left += el.offsetLeft || 0; + + //add borders + top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0; + left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0; + + pos = L.DomUtil.getStyle(el, 'position'); + + if (el.offsetParent === docBody && pos === 'absolute') { break; } + + if (pos === 'fixed') { + top += docBody.scrollTop || docEl.scrollTop || 0; + left += docBody.scrollLeft || docEl.scrollLeft || 0; + break; + } + + if (pos === 'relative' && !el.offsetLeft) { + var width = L.DomUtil.getStyle(el, 'width'), + maxWidth = L.DomUtil.getStyle(el, 'max-width'), + r = el.getBoundingClientRect(); + + if (width !== 'none' || maxWidth !== 'none') { + left += r.left + el.clientLeft; + } + + //calculate full y offset since we're breaking out of the loop + top += r.top + (docBody.scrollTop || docEl.scrollTop || 0); + + break; + } + + el = el.offsetParent; + + } while (el); + + el = element; + + do { + if (el === docBody) { break; } + + top -= el.scrollTop || 0; + left -= el.scrollLeft || 0; + + // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else + // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js + if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) { + left += el.scrollWidth - el.clientWidth; + + // ie7 shows the scrollbar by default and provides clientWidth counting it, so we + // need to add it back in if it is visible; scrollbar is on the left as we are RTL + if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' && + L.DomUtil.getStyle(el, 'overflow') !== 'hidden') { + left += 17; + } + } + + el = el.parentNode; + } while (el); + + return new L.Point(left, top); + }, + + documentIsLtr: function () { + if (!L.DomUtil._docIsLtrCached) { + L.DomUtil._docIsLtrCached = true; + L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr'; + } + return L.DomUtil._docIsLtr; + }, + + create: function (tagName, className, container) { + + var el = document.createElement(tagName); + el.className = className; + + if (container) { + container.appendChild(el); + } + + return el; + }, + + hasClass: function (el, name) { + return (el.className.length > 0) && + new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className); + }, + + addClass: function (el, name) { + if (!L.DomUtil.hasClass(el, name)) { + el.className += (el.className ? ' ' : '') + name; + } + }, + + removeClass: function (el, name) { + el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' ')); + }, + + setOpacity: function (el, value) { + + if ('opacity' in el.style) { + el.style.opacity = value; + + } else if ('filter' in el.style) { + + var filter = false, + filterName = 'DXImageTransform.Microsoft.Alpha'; + + // filters collection throws an error if we try to retrieve a filter that doesn't exist + try { + filter = el.filters.item(filterName); + } catch (e) { + // don't set opacity to 1 if we haven't already set an opacity, + // it isn't needed and breaks transparent pngs. + if (value === 1) { return; } + } + + value = Math.round(value * 100); + + if (filter) { + filter.Enabled = (value !== 100); + filter.Opacity = value; + } else { + el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; + } + } + }, + + testProp: function (props) { + + var style = document.documentElement.style; + + for (var i = 0; i < props.length; i++) { + if (props[i] in style) { + return props[i]; + } + } + return false; + }, + + getTranslateString: function (point) { + // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate + // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care + // (same speed either way), Opera 12 doesn't support translate3d + + var is3d = L.Browser.webkit3d, + open = 'translate' + (is3d ? '3d' : '') + '(', + close = (is3d ? ',0' : '') + ')'; + + return open + point.x + 'px,' + point.y + 'px' + close; + }, + + getScaleString: function (scale, origin) { + + var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))), + scaleStr = ' scale(' + scale + ') '; + + return preTranslateStr + scaleStr; + }, + + setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) + + // jshint camelcase: false + el._leaflet_pos = point; + + if (!disable3D && L.Browser.any3d) { + el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); + + // workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69) + if (L.Browser.mobileWebkit3d) { + el.style.WebkitBackfaceVisibility = 'hidden'; + } + } else { + el.style.left = point.x + 'px'; + el.style.top = point.y + 'px'; + } + }, + + getPosition: function (el) { + // this method is only used for elements previously positioned using setPosition, + // so it's safe to cache the position for performance + + // jshint camelcase: false + return el._leaflet_pos; + } +}; + + +// prefix style property names + +L.DomUtil.TRANSFORM = L.DomUtil.testProp( + ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + +// webkitTransition comes first because some browser versions that drop vendor prefix don't do +// the same for the transitionend event, in particular the Android 4.1 stock browser + +L.DomUtil.TRANSITION = L.DomUtil.testProp( + ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); + +L.DomUtil.TRANSITION_END = + L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? + L.DomUtil.TRANSITION + 'End' : 'transitionend'; + +(function () { + var userSelectProperty = L.DomUtil.testProp( + ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); + + var userDragProperty = L.DomUtil.testProp( + ['userDrag', 'WebkitUserDrag', 'OUserDrag', 'MozUserDrag', 'msUserDrag']); + + L.extend(L.DomUtil, { + disableTextSelection: function () { + if (userSelectProperty) { + var style = document.documentElement.style; + this._userSelect = style[userSelectProperty]; + style[userSelectProperty] = 'none'; + } else { + L.DomEvent.on(window, 'selectstart', L.DomEvent.stop); + } + }, + + enableTextSelection: function () { + if (userSelectProperty) { + document.documentElement.style[userSelectProperty] = this._userSelect; + delete this._userSelect; + } else { + L.DomEvent.off(window, 'selectstart', L.DomEvent.stop); + } + }, + + disableImageDrag: function () { + if (userDragProperty) { + var style = document.documentElement.style; + this._userDrag = style[userDragProperty]; + style[userDragProperty] = 'none'; + } else { + L.DomEvent.on(window, 'dragstart', L.DomEvent.stop); + } + }, + + enableImageDrag: function () { + if (userDragProperty) { + document.documentElement.style[userDragProperty] = this._userDrag; + delete this._userDrag; + } else { + L.DomEvent.off(window, 'dragstart', L.DomEvent.stop); + } + } + }); +})(); + + +/* + * L.LatLng represents a geographical point with latitude and longitude coordinates. + */ + +L.LatLng = function (rawLat, rawLng) { // (Number, Number) + var lat = parseFloat(rawLat), + lng = parseFloat(rawLng); + + if (isNaN(lat) || isNaN(lng)) { + throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')'); + } + + this.lat = lat; + this.lng = lng; +}; + +L.extend(L.LatLng, { + DEG_TO_RAD: Math.PI / 180, + RAD_TO_DEG: 180 / Math.PI, + MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check +}); + +L.LatLng.prototype = { + equals: function (obj) { // (LatLng) -> Boolean + if (!obj) { return false; } + + obj = L.latLng(obj); + + var margin = Math.max( + Math.abs(this.lat - obj.lat), + Math.abs(this.lng - obj.lng)); + + return margin <= L.LatLng.MAX_MARGIN; + }, + + toString: function (precision) { // (Number) -> String + return 'LatLng(' + + L.Util.formatNum(this.lat, precision) + ', ' + + L.Util.formatNum(this.lng, precision) + ')'; + }, + + // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula + // TODO move to projection code, LatLng shouldn't know about Earth + distanceTo: function (other) { // (LatLng) -> Number + other = L.latLng(other); + + var R = 6378137, // earth radius in meters + d2r = L.LatLng.DEG_TO_RAD, + dLat = (other.lat - this.lat) * d2r, + dLon = (other.lng - this.lng) * d2r, + lat1 = this.lat * d2r, + lat2 = other.lat * d2r, + sin1 = Math.sin(dLat / 2), + sin2 = Math.sin(dLon / 2); + + var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); + + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + }, + + wrap: function (a, b) { // (Number, Number) -> LatLng + var lng = this.lng; + + a = a || -180; + b = b || 180; + + lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a); + + return new L.LatLng(this.lat, lng); + } +}; + +L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number) + if (a instanceof L.LatLng) { + return a; + } + if (L.Util.isArray(a)) { + return new L.LatLng(a[0], a[1]); + } + if (a === undefined || a === null) { + return a; + } + if (typeof a === 'object' && 'lat' in a) { + return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon); + } + return new L.LatLng(a, b); +}; + + + +/* + * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. + */ + +L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) + if (!southWest) { return; } + + var latlngs = northEast ? [southWest, northEast] : southWest; + + for (var i = 0, len = latlngs.length; i < len; i++) { + this.extend(latlngs[i]); + } +}; + +L.LatLngBounds.prototype = { + // extend the bounds to contain the given point or bounds + extend: function (obj) { // (LatLng) or (LatLngBounds) + if (!obj) { return this; } + + if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) { + obj = L.latLng(obj); + } else { + obj = L.latLngBounds(obj); + } + + if (obj instanceof L.LatLng) { + if (!this._southWest && !this._northEast) { + this._southWest = new L.LatLng(obj.lat, obj.lng); + this._northEast = new L.LatLng(obj.lat, obj.lng); + } else { + this._southWest.lat = Math.min(obj.lat, this._southWest.lat); + this._southWest.lng = Math.min(obj.lng, this._southWest.lng); + + this._northEast.lat = Math.max(obj.lat, this._northEast.lat); + this._northEast.lng = Math.max(obj.lng, this._northEast.lng); + } + } else if (obj instanceof L.LatLngBounds) { + this.extend(obj._southWest); + this.extend(obj._northEast); + } + return this; + }, + + // extend the bounds by a percentage + pad: function (bufferRatio) { // (Number) -> LatLngBounds + var sw = this._southWest, + ne = this._northEast, + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; + + return new L.LatLngBounds( + new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), + new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); + }, + + getCenter: function () { // -> LatLng + return new L.LatLng( + (this._southWest.lat + this._northEast.lat) / 2, + (this._southWest.lng + this._northEast.lng) / 2); + }, + + getSouthWest: function () { + return this._southWest; + }, + + getNorthEast: function () { + return this._northEast; + }, + + getNorthWest: function () { + return new L.LatLng(this.getNorth(), this.getWest()); + }, + + getSouthEast: function () { + return new L.LatLng(this.getSouth(), this.getEast()); + }, + + getWest: function () { + return this._southWest.lng; + }, + + getSouth: function () { + return this._southWest.lat; + }, + + getEast: function () { + return this._northEast.lng; + }, + + getNorth: function () { + return this._northEast.lat; + }, + + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean + if (typeof obj[0] === 'number' || obj instanceof L.LatLng) { + obj = L.latLng(obj); + } else { + obj = L.latLngBounds(obj); + } + + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof L.LatLngBounds) { + sw2 = obj.getSouthWest(); + ne2 = obj.getNorthEast(); + } else { + sw2 = ne2 = obj; + } + + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); + }, + + intersects: function (bounds) { // (LatLngBounds) + bounds = L.latLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); + + return latIntersects && lngIntersects; + }, + + toBBoxString: function () { + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); + }, + + equals: function (bounds) { // (LatLngBounds) + if (!bounds) { return false; } + + bounds = L.latLngBounds(bounds); + + return this._southWest.equals(bounds.getSouthWest()) && + this._northEast.equals(bounds.getNorthEast()); + }, + + isValid: function () { + return !!(this._southWest && this._northEast); + } +}; + +//TODO International date line? + +L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng) + if (!a || a instanceof L.LatLngBounds) { + return a; + } + return new L.LatLngBounds(a, b); +}; + + +/* + * L.Projection contains various geographical projections used by CRS classes. + */ + +L.Projection = {}; + + +/* + * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default. + */ + +L.Projection.SphericalMercator = { + MAX_LATITUDE: 85.0511287798, + + project: function (latlng) { // (LatLng) -> Point + var d = L.LatLng.DEG_TO_RAD, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + x = latlng.lng * d, + y = lat * d; + + y = Math.log(Math.tan((Math.PI / 4) + (y / 2))); + + return new L.Point(x, y); + }, + + unproject: function (point) { // (Point, Boolean) -> LatLng + var d = L.LatLng.RAD_TO_DEG, + lng = point.x * d, + lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d; + + return new L.LatLng(lat, lng); + } +}; + + +/* + * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple. + */ + +L.Projection.LonLat = { + project: function (latlng) { + return new L.Point(latlng.lng, latlng.lat); + }, + + unproject: function (point) { + return new L.LatLng(point.y, point.x); + } +}; + + +/* + * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet. + */ + +L.CRS = { + latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point + var projectedPoint = this.projection.project(latlng), + scale = this.scale(zoom); + + return this.transformation._transform(projectedPoint, scale); + }, + + pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng + var scale = this.scale(zoom), + untransformedPoint = this.transformation.untransform(point, scale); + + return this.projection.unproject(untransformedPoint); + }, + + project: function (latlng) { + return this.projection.project(latlng); + }, + + scale: function (zoom) { + return 256 * Math.pow(2, zoom); + } +}; -L.version = '0.6.2'; -// define Leaflet for Node module pattern loaders, including Browserify -if (typeof module === 'object' && typeof module.exports === 'object') { - module.exports = L; - -// define Leaflet as an AMD module -} else if (typeof define === 'function' && define.amd) { - define(L); -} - -// define Leaflet as a global L variable, saving the original L to restore later if needed - -L.noConflict = function () { - window.L = oldL; - return this; -}; - -window.L = L; - - -/* - * L.Util contains various utility functions used throughout Leaflet code. - */ - -L.Util = { - extend: function (dest) { // (Object[, Object, ...]) -> - var sources = Array.prototype.slice.call(arguments, 1), - i, j, len, src; - - for (j = 0, len = sources.length; j < len; j++) { - src = sources[j] || {}; - for (i in src) { - if (src.hasOwnProperty(i)) { - dest[i] = src[i]; - } - } - } - return dest; - }, - - bind: function (fn, obj) { // (Function, Object) -> Function - var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null; - return function () { - return fn.apply(obj, args || arguments); - }; - }, - - stamp: (function () { - var lastId = 0, - key = '_leaflet_id'; - return function (obj) { - obj[key] = obj[key] || ++lastId; - return obj[key]; - }; - }()), - - invokeEach: function (obj, method, context) { - var i, args; - - if (typeof obj === 'object') { - args = Array.prototype.slice.call(arguments, 3); - - for (i in obj) { - method.apply(context, [i, obj[i]].concat(args)); - } - return true; - } - - return false; - }, - - limitExecByInterval: function (fn, time, context) { - var lock, execOnUnlock; - - return function wrapperFn() { - var args = arguments; - - if (lock) { - execOnUnlock = true; - return; - } - - lock = true; - - setTimeout(function () { - lock = false; - - if (execOnUnlock) { - wrapperFn.apply(context, args); - execOnUnlock = false; - } - }, time); - - fn.apply(context, args); - }; - }, - - falseFn: function () { - return false; - }, - - formatNum: function (num, digits) { - var pow = Math.pow(10, digits || 5); - return Math.round(num * pow) / pow; - }, - - trim: function (str) { - return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); - }, - - splitWords: function (str) { - return L.Util.trim(str).split(/\s+/); - }, - - setOptions: function (obj, options) { - obj.options = L.extend({}, obj.options, options); - return obj.options; - }, - - getParamString: function (obj, existingUrl, uppercase) { - var params = []; - for (var i in obj) { - params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); - } - return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); - }, - - template: function (str, data) { - return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { - var value = data[key]; - if (value === undefined) { - throw new Error('No value provided for variable ' + str); - } else if (typeof value === 'function') { - value = value(data); - } - return value; - }); - }, - - isArray: function (obj) { - return (Object.prototype.toString.call(obj) === '[object Array]'); - }, - - emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=' -}; - -(function () { - - // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/ - - function getPrefixed(name) { - var i, fn, - prefixes = ['webkit', 'moz', 'o', 'ms']; - - for (i = 0; i < prefixes.length && !fn; i++) { - fn = window[prefixes[i] + name]; - } - - return fn; - } - - var lastTime = 0; - - function timeoutDefer(fn) { - var time = +new Date(), - timeToCall = Math.max(0, 16 - (time - lastTime)); - - lastTime = time + timeToCall; - return window.setTimeout(fn, timeToCall); - } - - var requestFn = window.requestAnimationFrame || - getPrefixed('RequestAnimationFrame') || timeoutDefer; - - var cancelFn = window.cancelAnimationFrame || - getPrefixed('CancelAnimationFrame') || - getPrefixed('CancelRequestAnimationFrame') || - function (id) { window.clearTimeout(id); }; - - - L.Util.requestAnimFrame = function (fn, context, immediate, element) { - fn = L.bind(fn, context); - - if (immediate && requestFn === timeoutDefer) { - fn(); - } else { - return requestFn.call(window, fn, element); - } - }; - - L.Util.cancelAnimFrame = function (id) { - if (id) { - cancelFn.call(window, id); - } - }; - -}()); - -// shortcuts for most used utility functions -L.extend = L.Util.extend; -L.bind = L.Util.bind; -L.stamp = L.Util.stamp; -L.setOptions = L.Util.setOptions; - - -/* - * L.Class powers the OOP facilities of the library. - * Thanks to John Resig and Dean Edwards for inspiration! - */ - -L.Class = function () {}; - -L.Class.extend = function (props) { - - // extended class with the new prototype - var NewClass = function () { - - // call the constructor - if (this.initialize) { - this.initialize.apply(this, arguments); - } - - // call all constructor hooks - if (this._initHooks) { - this.callInitHooks(); - } - }; - - // instantiate class without calling constructor - var F = function () {}; - F.prototype = this.prototype; - - var proto = new F(); - proto.constructor = NewClass; - - NewClass.prototype = proto; - - //inherit parent's statics - for (var i in this) { - if (this.hasOwnProperty(i) && i !== 'prototype') { - NewClass[i] = this[i]; - } - } - - // mix static properties into the class - if (props.statics) { - L.extend(NewClass, props.statics); - delete props.statics; - } - - // mix includes into the prototype - if (props.includes) { - L.Util.extend.apply(null, [proto].concat(props.includes)); - delete props.includes; - } - - // merge options - if (props.options && proto.options) { - props.options = L.extend({}, proto.options, props.options); - } - - // mix given properties into the prototype - L.extend(proto, props); - - proto._initHooks = []; - - var parent = this; - // jshint camelcase: false - NewClass.__super__ = parent.prototype; - - // add method for calling all hooks - proto.callInitHooks = function () { - - if (this._initHooksCalled) { return; } - - if (parent.prototype.callInitHooks) { - parent.prototype.callInitHooks.call(this); - } - - this._initHooksCalled = true; - - for (var i = 0, len = proto._initHooks.length; i < len; i++) { - proto._initHooks[i].call(this); - } - }; - - return NewClass; -}; - - -// method for adding properties to prototype -L.Class.include = function (props) { - L.extend(this.prototype, props); -}; - -// merge new default options to the Class -L.Class.mergeOptions = function (options) { - L.extend(this.prototype.options, options); -}; - -// add a constructor hook -L.Class.addInitHook = function (fn) { // (Function) || (String, args...) - var args = Array.prototype.slice.call(arguments, 1); - - var init = typeof fn === 'function' ? fn : function () { - this[fn].apply(this, args); - }; - - this.prototype._initHooks = this.prototype._initHooks || []; - this.prototype._initHooks.push(init); -}; - - -/* - * L.Mixin.Events is used to add custom events functionality to Leaflet classes. - */ - -var eventsKey = '_leaflet_events'; - -L.Mixin = {}; - -L.Mixin.Events = { - - addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object]) - - // types can be a map of types/handlers - if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; } - - var events = this[eventsKey] = this[eventsKey] || {}, - contextId = context && L.stamp(context), - i, len, event, type, indexKey, indexLenKey, typeIndex; - - // types can be a string of space-separated words - types = L.Util.splitWords(types); - - for (i = 0, len = types.length; i < len; i++) { - event = { - action: fn, - context: context || this - }; - type = types[i]; - - if (context) { - // store listeners of a particular context in a separate hash (if it has an id) - // gives a major performance boost when removing thousands of map layers - - indexKey = type + '_idx'; - indexLenKey = indexKey + '_len'; - - typeIndex = events[indexKey] = events[indexKey] || {}; - - if (!typeIndex[contextId]) { - typeIndex[contextId] = []; - - // keep track of the number of keys in the index to quickly check if it's empty - events[indexLenKey] = (events[indexLenKey] || 0) + 1; - } - - typeIndex[contextId].push(event); - - - } else { - events[type] = events[type] || []; - events[type].push(event); - } - } - - return this; - }, - - hasEventListeners: function (type) { // (String) -> Boolean - var events = this[eventsKey]; - return !!events && ((type in events && events[type].length > 0) || - (type + '_idx' in events && events[type + '_idx_len'] > 0)); - }, - - removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object]) - - if (!this[eventsKey]) { - return this; - } - - if (!types) { - return this.clearAllEventListeners(); - } - - if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; } - - var events = this[eventsKey], - contextId = context && L.stamp(context), - i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed; - - types = L.Util.splitWords(types); - - for (i = 0, len = types.length; i < len; i++) { - type = types[i]; - indexKey = type + '_idx'; - indexLenKey = indexKey + '_len'; - - typeIndex = events[indexKey]; - - if (!fn) { - // clear all listeners for a type if function isn't specified - delete events[type]; - delete events[indexKey]; - - } else { - listeners = context && typeIndex ? typeIndex[contextId] : events[type]; - - if (listeners) { - for (j = listeners.length - 1; j >= 0; j--) { - if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) { - removed = listeners.splice(j, 1); - // set the old action to a no-op, because it is possible - // that the listener is being iterated over as part of a dispatch - removed[0].action = L.Util.falseFn; - } - } - - if (context && typeIndex && (listeners.length === 0)) { - delete typeIndex[contextId]; - events[indexLenKey]--; - } - } - } - } - - return this; - }, - - clearAllEventListeners: function () { - delete this[eventsKey]; - return this; - }, - - fireEvent: function (type, data) { // (String[, Object]) - if (!this.hasEventListeners(type)) { - return this; - } - - var event = L.Util.extend({}, data, { type: type, target: this }); - - var events = this[eventsKey], - listeners, i, len, typeIndex, contextId; - - if (events[type]) { - // make sure adding/removing listeners inside other listeners won't cause infinite loop - listeners = events[type].slice(); - - for (i = 0, len = listeners.length; i < len; i++) { - listeners[i].action.call(listeners[i].context || this, event); - } - } - - // fire event for the context-indexed listeners as well - typeIndex = events[type + '_idx']; - - for (contextId in typeIndex) { - listeners = typeIndex[contextId].slice(); - - if (listeners) { - for (i = 0, len = listeners.length; i < len; i++) { - listeners[i].action.call(listeners[i].context || this, event); - } - } - } - - return this; - }, - - addOneTimeEventListener: function (types, fn, context) { - - if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; } - - var handler = L.bind(function () { - this - .removeEventListener(types, fn, context) - .removeEventListener(types, handler, context); - }, this); - - return this - .addEventListener(types, fn, context) - .addEventListener(types, handler, context); - } -}; - -L.Mixin.Events.on = L.Mixin.Events.addEventListener; -L.Mixin.Events.off = L.Mixin.Events.removeEventListener; -L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener; -L.Mixin.Events.fire = L.Mixin.Events.fireEvent; - - -/* - * L.Browser handles different browser and feature detections for internal Leaflet use. - */ - -(function () { - - var ie = !!window.ActiveXObject, - ie6 = ie && !window.XMLHttpRequest, - ie7 = ie && !document.querySelector, - ielt9 = ie && !document.addEventListener, - - // terrible browser detection to work around Safari / iOS / Android browser bugs - ua = navigator.userAgent.toLowerCase(), - webkit = ua.indexOf('webkit') !== -1, - chrome = ua.indexOf('chrome') !== -1, - phantomjs = ua.indexOf('phantom') !== -1, - android = ua.indexOf('android') !== -1, - android23 = ua.search('android [23]') !== -1, - - mobile = typeof orientation !== undefined + '', - msTouch = window.navigator && window.navigator.msPointerEnabled && - window.navigator.msMaxTouchPoints, - retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) || - ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') && - window.matchMedia('(min-resolution:144dpi)').matches), - - doc = document.documentElement, - ie3d = ie && ('transition' in doc.style), - webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()), - gecko3d = 'MozPerspective' in doc.style, - opera3d = 'OTransition' in doc.style, - any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs; - - - // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch. - // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151 - - var touch = !window.L_NO_TOUCH && !phantomjs && (function () { - - var startName = 'ontouchstart'; - - // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.MsTouch) or WebKit, etc. - if (msTouch || (startName in doc)) { - return true; - } - - // Firefox/Gecko - var div = document.createElement('div'), - supported = false; - - if (!div.setAttribute) { - return false; - } - div.setAttribute(startName, 'return;'); - - if (typeof div[startName] === 'function') { - supported = true; - } - - div.removeAttribute(startName); - div = null; - - return supported; - }()); - - - L.Browser = { - ie: ie, - ie6: ie6, - ie7: ie7, - ielt9: ielt9, - webkit: webkit, - - android: android, - android23: android23, - - chrome: chrome, - - ie3d: ie3d, - webkit3d: webkit3d, - gecko3d: gecko3d, - opera3d: opera3d, - any3d: any3d, - - mobile: mobile, - mobileWebkit: mobile && webkit, - mobileWebkit3d: mobile && webkit3d, - mobileOpera: mobile && window.opera, - - touch: touch, - msTouch: msTouch, - - retina: retina - }; - -}()); - - -/* - * L.Point represents a point with x and y coordinates. - */ - -L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) { - this.x = (round ? Math.round(x) : x); - this.y = (round ? Math.round(y) : y); -}; - -L.Point.prototype = { - - clone: function () { - return new L.Point(this.x, this.y); - }, - - // non-destructive, returns a new point - add: function (point) { - return this.clone()._add(L.point(point)); - }, - - // destructive, used directly for performance in situations where it's safe to modify existing point - _add: function (point) { - this.x += point.x; - this.y += point.y; - return this; - }, - - subtract: function (point) { - return this.clone()._subtract(L.point(point)); - }, - - _subtract: function (point) { - this.x -= point.x; - this.y -= point.y; - return this; - }, - - divideBy: function (num) { - return this.clone()._divideBy(num); - }, - - _divideBy: function (num) { - this.x /= num; - this.y /= num; - return this; - }, - - multiplyBy: function (num) { - return this.clone()._multiplyBy(num); - }, - - _multiplyBy: function (num) { - this.x *= num; - this.y *= num; - return this; - }, - - round: function () { - return this.clone()._round(); - }, - - _round: function () { - this.x = Math.round(this.x); - this.y = Math.round(this.y); - return this; - }, - - floor: function () { - return this.clone()._floor(); - }, - - _floor: function () { - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - return this; - }, - - distanceTo: function (point) { - point = L.point(point); - - var x = point.x - this.x, - y = point.y - this.y; - - return Math.sqrt(x * x + y * y); - }, - - equals: function (point) { - point = L.point(point); - - return point.x === this.x && - point.y === this.y; - }, - - contains: function (point) { - point = L.point(point); - - return Math.abs(point.x) <= Math.abs(this.x) && - Math.abs(point.y) <= Math.abs(this.y); - }, - - toString: function () { - return 'Point(' + - L.Util.formatNum(this.x) + ', ' + - L.Util.formatNum(this.y) + ')'; - } -}; - -L.point = function (x, y, round) { - if (x instanceof L.Point) { - return x; - } - if (L.Util.isArray(x)) { - return new L.Point(x[0], x[1]); - } - if (x === undefined || x === null) { - return x; - } - return new L.Point(x, y, round); -}; - - -/* - * L.Bounds represents a rectangular area on the screen in pixel coordinates. - */ - -L.Bounds = function (a, b) { //(Point, Point) or Point[] - if (!a) { return; } - - var points = b ? [a, b] : a; - - for (var i = 0, len = points.length; i < len; i++) { - this.extend(points[i]); - } -}; - -L.Bounds.prototype = { - // extend the bounds to contain the given point - extend: function (point) { // (Point) - point = L.point(point); - - if (!this.min && !this.max) { - this.min = point.clone(); - this.max = point.clone(); - } else { - this.min.x = Math.min(point.x, this.min.x); - this.max.x = Math.max(point.x, this.max.x); - this.min.y = Math.min(point.y, this.min.y); - this.max.y = Math.max(point.y, this.max.y); - } - return this; - }, - - getCenter: function (round) { // (Boolean) -> Point - return new L.Point( - (this.min.x + this.max.x) / 2, - (this.min.y + this.max.y) / 2, round); - }, - - getBottomLeft: function () { // -> Point - return new L.Point(this.min.x, this.max.y); - }, - - getTopRight: function () { // -> Point - return new L.Point(this.max.x, this.min.y); - }, - - getSize: function () { - return this.max.subtract(this.min); - }, - - contains: function (obj) { // (Bounds) or (Point) -> Boolean - var min, max; - - if (typeof obj[0] === 'number' || obj instanceof L.Point) { - obj = L.point(obj); - } else { - obj = L.bounds(obj); - } - - if (obj instanceof L.Bounds) { - min = obj.min; - max = obj.max; - } else { - min = max = obj; - } - - return (min.x >= this.min.x) && - (max.x <= this.max.x) && - (min.y >= this.min.y) && - (max.y <= this.max.y); - }, - - intersects: function (bounds) { // (Bounds) -> Boolean - bounds = L.bounds(bounds); - - var min = this.min, - max = this.max, - min2 = bounds.min, - max2 = bounds.max, - xIntersects = (max2.x >= min.x) && (min2.x <= max.x), - yIntersects = (max2.y >= min.y) && (min2.y <= max.y); - - return xIntersects && yIntersects; - }, - - isValid: function () { - return !!(this.min && this.max); - } -}; - -L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[]) - if (!a || a instanceof L.Bounds) { - return a; - } - return new L.Bounds(a, b); -}; - - -/* - * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix. - */ - -L.Transformation = function (a, b, c, d) { - this._a = a; - this._b = b; - this._c = c; - this._d = d; -}; - -L.Transformation.prototype = { - transform: function (point, scale) { // (Point, Number) -> Point - return this._transform(point.clone(), scale); - }, - - // destructive transform (faster) - _transform: function (point, scale) { - scale = scale || 1; - point.x = scale * (this._a * point.x + this._b); - point.y = scale * (this._c * point.y + this._d); - return point; - }, - - untransform: function (point, scale) { - scale = scale || 1; - return new L.Point( - (point.x / scale - this._b) / this._a, - (point.y / scale - this._d) / this._c); - } -}; - - -/* - * L.DomUtil contains various utility functions for working with DOM. - */ - -L.DomUtil = { - get: function (id) { - return (typeof id === 'string' ? document.getElementById(id) : id); - }, - - getStyle: function (el, style) { - - var value = el.style[style]; - - if (!value && el.currentStyle) { - value = el.currentStyle[style]; - } - - if ((!value || value === 'auto') && document.defaultView) { - var css = document.defaultView.getComputedStyle(el, null); - value = css ? css[style] : null; - } - - return value === 'auto' ? null : value; - }, - - getViewportOffset: function (element) { - - var top = 0, - left = 0, - el = element, - docBody = document.body, - docEl = document.documentElement, - pos, - ie7 = L.Browser.ie7; - - do { - top += el.offsetTop || 0; - left += el.offsetLeft || 0; - - //add borders - top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0; - left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0; - - pos = L.DomUtil.getStyle(el, 'position'); - - if (el.offsetParent === docBody && pos === 'absolute') { break; } - - if (pos === 'fixed') { - top += docBody.scrollTop || docEl.scrollTop || 0; - left += docBody.scrollLeft || docEl.scrollLeft || 0; - break; - } - - if (pos === 'relative' && !el.offsetLeft) { - var width = L.DomUtil.getStyle(el, 'width'), - maxWidth = L.DomUtil.getStyle(el, 'max-width'), - r = el.getBoundingClientRect(); - - if (width !== 'none' || maxWidth !== 'none') { - left += r.left + el.clientLeft; - } - - //calculate full y offset since we're breaking out of the loop - top += r.top + (docBody.scrollTop || docEl.scrollTop || 0); - - break; - } - - el = el.offsetParent; - - } while (el); - - el = element; - - do { - if (el === docBody) { break; } - - top -= el.scrollTop || 0; - left -= el.scrollLeft || 0; - - // webkit (and ie <= 7) handles RTL scrollLeft different to everyone else - // https://code.google.com/p/closure-library/source/browse/trunk/closure/goog/style/bidi.js - if (!L.DomUtil.documentIsLtr() && (L.Browser.webkit || ie7)) { - left += el.scrollWidth - el.clientWidth; - - // ie7 shows the scrollbar by default and provides clientWidth counting it, so we - // need to add it back in if it is visible; scrollbar is on the left as we are RTL - if (ie7 && L.DomUtil.getStyle(el, 'overflow-y') !== 'hidden' && - L.DomUtil.getStyle(el, 'overflow') !== 'hidden') { - left += 17; - } - } - - el = el.parentNode; - } while (el); - - return new L.Point(left, top); - }, - - documentIsLtr: function () { - if (!L.DomUtil._docIsLtrCached) { - L.DomUtil._docIsLtrCached = true; - L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr'; - } - return L.DomUtil._docIsLtr; - }, - - create: function (tagName, className, container) { - - var el = document.createElement(tagName); - el.className = className; - - if (container) { - container.appendChild(el); - } - - return el; - }, - - hasClass: function (el, name) { - return (el.className.length > 0) && - new RegExp('(^|\\s)' + name + '(\\s|$)').test(el.className); - }, - - addClass: function (el, name) { - if (!L.DomUtil.hasClass(el, name)) { - el.className += (el.className ? ' ' : '') + name; - } - }, - - removeClass: function (el, name) { - el.className = L.Util.trim((' ' + el.className + ' ').replace(' ' + name + ' ', ' ')); - }, - - setOpacity: function (el, value) { - - if ('opacity' in el.style) { - el.style.opacity = value; - - } else if ('filter' in el.style) { - - var filter = false, - filterName = 'DXImageTransform.Microsoft.Alpha'; - - // filters collection throws an error if we try to retrieve a filter that doesn't exist - try { - filter = el.filters.item(filterName); - } catch (e) { - // don't set opacity to 1 if we haven't already set an opacity, - // it isn't needed and breaks transparent pngs. - if (value === 1) { return; } - } - - value = Math.round(value * 100); - - if (filter) { - filter.Enabled = (value !== 100); - filter.Opacity = value; - } else { - el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; - } - } - }, - - testProp: function (props) { - - var style = document.documentElement.style; - - for (var i = 0; i < props.length; i++) { - if (props[i] in style) { - return props[i]; - } - } - return false; - }, - - getTranslateString: function (point) { - // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate - // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care - // (same speed either way), Opera 12 doesn't support translate3d - - var is3d = L.Browser.webkit3d, - open = 'translate' + (is3d ? '3d' : '') + '(', - close = (is3d ? ',0' : '') + ')'; - - return open + point.x + 'px,' + point.y + 'px' + close; - }, - - getScaleString: function (scale, origin) { - - var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))), - scaleStr = ' scale(' + scale + ') '; - - return preTranslateStr + scaleStr; - }, - - setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean]) - - // jshint camelcase: false - el._leaflet_pos = point; - - if (!disable3D && L.Browser.any3d) { - el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point); - - // workaround for Android 2/3 stability (https://github.com/CloudMade/Leaflet/issues/69) - if (L.Browser.mobileWebkit3d) { - el.style.WebkitBackfaceVisibility = 'hidden'; - } - } else { - el.style.left = point.x + 'px'; - el.style.top = point.y + 'px'; - } - }, - - getPosition: function (el) { - // this method is only used for elements previously positioned using setPosition, - // so it's safe to cache the position for performance - - // jshint camelcase: false - return el._leaflet_pos; - } -}; - - -// prefix style property names - -L.DomUtil.TRANSFORM = L.DomUtil.testProp( - ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']); - -// webkitTransition comes first because some browser versions that drop vendor prefix don't do -// the same for the transitionend event, in particular the Android 4.1 stock browser - -L.DomUtil.TRANSITION = L.DomUtil.testProp( - ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); - -L.DomUtil.TRANSITION_END = - L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ? - L.DomUtil.TRANSITION + 'End' : 'transitionend'; - -(function () { - var userSelectProperty = L.DomUtil.testProp( - ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); - - var userDragProperty = L.DomUtil.testProp( - ['userDrag', 'WebkitUserDrag', 'OUserDrag', 'MozUserDrag', 'msUserDrag']); - - L.extend(L.DomUtil, { - disableTextSelection: function () { - if (userSelectProperty) { - var style = document.documentElement.style; - this._userSelect = style[userSelectProperty]; - style[userSelectProperty] = 'none'; - } else { - L.DomEvent.on(window, 'selectstart', L.DomEvent.stop); - } - }, - - enableTextSelection: function () { - if (userSelectProperty) { - document.documentElement.style[userSelectProperty] = this._userSelect; - delete this._userSelect; - } else { - L.DomEvent.off(window, 'selectstart', L.DomEvent.stop); - } - }, - - disableImageDrag: function () { - if (userDragProperty) { - var style = document.documentElement.style; - this._userDrag = style[userDragProperty]; - style[userDragProperty] = 'none'; - } else { - L.DomEvent.on(window, 'dragstart', L.DomEvent.stop); - } - }, - - enableImageDrag: function () { - if (userDragProperty) { - document.documentElement.style[userDragProperty] = this._userDrag; - delete this._userDrag; - } else { - L.DomEvent.off(window, 'dragstart', L.DomEvent.stop); - } - } - }); -})(); - - -/* - * L.LatLng represents a geographical point with latitude and longitude coordinates. - */ - -L.LatLng = function (rawLat, rawLng) { // (Number, Number) - var lat = parseFloat(rawLat), - lng = parseFloat(rawLng); - - if (isNaN(lat) || isNaN(lng)) { - throw new Error('Invalid LatLng object: (' + rawLat + ', ' + rawLng + ')'); - } - - this.lat = lat; - this.lng = lng; -}; - -L.extend(L.LatLng, { - DEG_TO_RAD: Math.PI / 180, - RAD_TO_DEG: 180 / Math.PI, - MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check -}); - -L.LatLng.prototype = { - equals: function (obj) { // (LatLng) -> Boolean - if (!obj) { return false; } - - obj = L.latLng(obj); - - var margin = Math.max( - Math.abs(this.lat - obj.lat), - Math.abs(this.lng - obj.lng)); - - return margin <= L.LatLng.MAX_MARGIN; - }, - - toString: function (precision) { // (Number) -> String - return 'LatLng(' + - L.Util.formatNum(this.lat, precision) + ', ' + - L.Util.formatNum(this.lng, precision) + ')'; - }, - - // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula - // TODO move to projection code, LatLng shouldn't know about Earth - distanceTo: function (other) { // (LatLng) -> Number - other = L.latLng(other); - - var R = 6378137, // earth radius in meters - d2r = L.LatLng.DEG_TO_RAD, - dLat = (other.lat - this.lat) * d2r, - dLon = (other.lng - this.lng) * d2r, - lat1 = this.lat * d2r, - lat2 = other.lat * d2r, - sin1 = Math.sin(dLat / 2), - sin2 = Math.sin(dLon / 2); - - var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2); - - return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - }, - - wrap: function (a, b) { // (Number, Number) -> LatLng - var lng = this.lng; - - a = a || -180; - b = b || 180; - - lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a); - - return new L.LatLng(this.lat, lng); - } -}; - -L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number) - if (a instanceof L.LatLng) { - return a; - } - if (L.Util.isArray(a)) { - return new L.LatLng(a[0], a[1]); - } - if (a === undefined || a === null) { - return a; - } - if (typeof a === 'object' && 'lat' in a) { - return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon); - } - return new L.LatLng(a, b); -}; - - - -/* - * L.LatLngBounds represents a rectangular area on the map in geographical coordinates. - */ - -L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[]) - if (!southWest) { return; } - - var latlngs = northEast ? [southWest, northEast] : southWest; - - for (var i = 0, len = latlngs.length; i < len; i++) { - this.extend(latlngs[i]); - } -}; - -L.LatLngBounds.prototype = { - // extend the bounds to contain the given point or bounds - extend: function (obj) { // (LatLng) or (LatLngBounds) - if (!obj) { return this; } - - if (typeof obj[0] === 'number' || typeof obj[0] === 'string' || obj instanceof L.LatLng) { - obj = L.latLng(obj); - } else { - obj = L.latLngBounds(obj); - } - - if (obj instanceof L.LatLng) { - if (!this._southWest && !this._northEast) { - this._southWest = new L.LatLng(obj.lat, obj.lng); - this._northEast = new L.LatLng(obj.lat, obj.lng); - } else { - this._southWest.lat = Math.min(obj.lat, this._southWest.lat); - this._southWest.lng = Math.min(obj.lng, this._southWest.lng); - - this._northEast.lat = Math.max(obj.lat, this._northEast.lat); - this._northEast.lng = Math.max(obj.lng, this._northEast.lng); - } - } else if (obj instanceof L.LatLngBounds) { - this.extend(obj._southWest); - this.extend(obj._northEast); - } - return this; - }, - - // extend the bounds by a percentage - pad: function (bufferRatio) { // (Number) -> LatLngBounds - var sw = this._southWest, - ne = this._northEast, - heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, - widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; - - return new L.LatLngBounds( - new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), - new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); - }, - - getCenter: function () { // -> LatLng - return new L.LatLng( - (this._southWest.lat + this._northEast.lat) / 2, - (this._southWest.lng + this._northEast.lng) / 2); - }, - - getSouthWest: function () { - return this._southWest; - }, - - getNorthEast: function () { - return this._northEast; - }, - - getNorthWest: function () { - return new L.LatLng(this.getNorth(), this.getWest()); - }, - - getSouthEast: function () { - return new L.LatLng(this.getSouth(), this.getEast()); - }, - - getWest: function () { - return this._southWest.lng; - }, - - getSouth: function () { - return this._southWest.lat; - }, - - getEast: function () { - return this._northEast.lng; - }, - - getNorth: function () { - return this._northEast.lat; - }, - - contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean - if (typeof obj[0] === 'number' || obj instanceof L.LatLng) { - obj = L.latLng(obj); - } else { - obj = L.latLngBounds(obj); - } - - var sw = this._southWest, - ne = this._northEast, - sw2, ne2; - - if (obj instanceof L.LatLngBounds) { - sw2 = obj.getSouthWest(); - ne2 = obj.getNorthEast(); - } else { - sw2 = ne2 = obj; - } - - return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && - (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); - }, - - intersects: function (bounds) { // (LatLngBounds) - bounds = L.latLngBounds(bounds); - - var sw = this._southWest, - ne = this._northEast, - sw2 = bounds.getSouthWest(), - ne2 = bounds.getNorthEast(), - - latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), - lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); - - return latIntersects && lngIntersects; - }, - - toBBoxString: function () { - return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); - }, - - equals: function (bounds) { // (LatLngBounds) - if (!bounds) { return false; } - - bounds = L.latLngBounds(bounds); - - return this._southWest.equals(bounds.getSouthWest()) && - this._northEast.equals(bounds.getNorthEast()); - }, - - isValid: function () { - return !!(this._southWest && this._northEast); - } -}; - -//TODO International date line? - -L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng) - if (!a || a instanceof L.LatLngBounds) { - return a; - } - return new L.LatLngBounds(a, b); -}; - - -/* - * L.Projection contains various geographical projections used by CRS classes. - */ - -L.Projection = {}; - - -/* - * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default. - */ - -L.Projection.SphericalMercator = { - MAX_LATITUDE: 85.0511287798, - - project: function (latlng) { // (LatLng) -> Point - var d = L.LatLng.DEG_TO_RAD, - max = this.MAX_LATITUDE, - lat = Math.max(Math.min(max, latlng.lat), -max), - x = latlng.lng * d, - y = lat * d; - - y = Math.log(Math.tan((Math.PI / 4) + (y / 2))); - - return new L.Point(x, y); - }, - - unproject: function (point) { // (Point, Boolean) -> LatLng - var d = L.LatLng.RAD_TO_DEG, - lng = point.x * d, - lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d; - - return new L.LatLng(lat, lng); - } -}; - - -/* - * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple. - */ - -L.Projection.LonLat = { - project: function (latlng) { - return new L.Point(latlng.lng, latlng.lat); - }, - - unproject: function (point) { - return new L.LatLng(point.y, point.x); - } -}; - - -/* - * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet. - */ - -L.CRS = { - latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point - var projectedPoint = this.projection.project(latlng), - scale = this.scale(zoom); - - return this.transformation._transform(projectedPoint, scale); - }, - - pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng - var scale = this.scale(zoom), - untransformedPoint = this.transformation.untransform(point, scale); - - return this.projection.unproject(untransformedPoint); - }, - - project: function (latlng) { - return this.projection.project(latlng); - }, - - scale: function (zoom) { - return 256 * Math.pow(2, zoom); - } -}; - - -/* - * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps. - */ - -L.CRS.Simple = L.extend({}, L.CRS, { - projection: L.Projection.LonLat, - transformation: new L.Transformation(1, 0, -1, 0), - - scale: function (zoom) { - return Math.pow(2, zoom); - } -}); - - -/* - * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping - * and is used by Leaflet by default. - */ - -L.CRS.EPSG3857 = L.extend({}, L.CRS, { - code: 'EPSG:3857', - - projection: L.Projection.SphericalMercator, - transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5), - - project: function (latlng) { // (LatLng) -> Point - var projectedPoint = this.projection.project(latlng), - earthRadius = 6378137; - return projectedPoint.multiplyBy(earthRadius); - } -}); - -L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, { - code: 'EPSG:900913' -}); - - -/* - * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists. - */ - -L.CRS.EPSG4326 = L.extend({}, L.CRS, { - code: 'EPSG:4326', - - projection: L.Projection.LonLat, - transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5) -}); - - -/* - * L.Map is the central class of the API - it is used to create a map. - */ - -L.Map = L.Class.extend({ - - includes: L.Mixin.Events, - - options: { - crs: L.CRS.EPSG3857, - - /* - center: LatLng, - zoom: Number, - layers: Array, - */ - - fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23, - trackResize: true, - markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d - }, - - initialize: function (id, options) { // (HTMLElement or String, Object) - options = L.setOptions(this, options); - - this._initContainer(id); - this._initLayout(); - this._initEvents(); - - if (options.maxBounds) { - this.setMaxBounds(options.maxBounds); - } - - if (options.center && options.zoom !== undefined) { - this.setView(L.latLng(options.center), options.zoom, {reset: true}); - } - - this._handlers = []; - - this._layers = {}; - this._zoomBoundLayers = {}; - this._tileLayersNum = 0; - - this.callInitHooks(); - - this._addLayers(options.layers); - }, - - - // public methods that modify map state - - // replaced by animation-powered implementation in Map.PanAnimation.js - setView: function (center, zoom) { - this._resetView(L.latLng(center), this._limitZoom(zoom)); - return this; - }, - - setZoom: function (zoom, options) { - return this.setView(this.getCenter(), zoom, {zoom: options}); - }, - - zoomIn: function (delta, options) { - return this.setZoom(this._zoom + (delta || 1), options); - }, - - zoomOut: function (delta, options) { - return this.setZoom(this._zoom - (delta || 1), options); - }, - - setZoomAround: function (latlng, zoom, options) { - var scale = this.getZoomScale(zoom), - viewHalf = this.getSize().divideBy(2), - containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng), - - centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), - newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); - - return this.setView(newCenter, zoom, {zoom: options}); - }, - - fitBounds: function (bounds, options) { - - options = options || {}; - bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds); - - var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]), - paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]), - - zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)), - paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), - - swPoint = this.project(bounds.getSouthWest(), zoom), - nePoint = this.project(bounds.getNorthEast(), zoom), - center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); - - return this.setView(center, zoom, options); - }, - - fitWorld: function (options) { - return this.fitBounds([[-90, -180], [90, 180]], options); - }, - - panTo: function (center, options) { // (LatLng) - return this.setView(center, this._zoom, {pan: options}); - }, - - panBy: function (offset) { // (Point) - // replaced with animated panBy in Map.Animation.js - this.fire('movestart'); - - this._rawPanBy(L.point(offset)); - - this.fire('move'); - return this.fire('moveend'); - }, - - setMaxBounds: function (bounds) { - bounds = L.latLngBounds(bounds); - - this.options.maxBounds = bounds; - - if (!bounds) { - this._boundsMinZoom = null; - this.off('moveend', this._panInsideMaxBounds, this); - return this; - } - - var minZoom = this.getBoundsZoom(bounds, true); - - this._boundsMinZoom = minZoom; - - if (this._loaded) { - if (this._zoom < minZoom) { - this.setView(bounds.getCenter(), minZoom); - } else { - this.panInsideBounds(bounds); - } - } - - this.on('moveend', this._panInsideMaxBounds, this); - - return this; - }, - - panInsideBounds: function (bounds) { - bounds = L.latLngBounds(bounds); - - var viewBounds = this.getPixelBounds(), - viewSw = viewBounds.getBottomLeft(), - viewNe = viewBounds.getTopRight(), - sw = this.project(bounds.getSouthWest()), - ne = this.project(bounds.getNorthEast()), - dx = 0, - dy = 0; - - if (viewNe.y < ne.y) { // north - dy = Math.ceil(ne.y - viewNe.y); - } - if (viewNe.x > ne.x) { // east - dx = Math.floor(ne.x - viewNe.x); - } - if (viewSw.y > sw.y) { // south - dy = Math.floor(sw.y - viewSw.y); - } - if (viewSw.x < sw.x) { // west - dx = Math.ceil(sw.x - viewSw.x); - } - - if (dx || dy) { - return this.panBy([dx, dy]); - } - - return this; - }, - - addLayer: function (layer) { - // TODO method is too big, refactor - - var id = L.stamp(layer); - - if (this._layers[id]) { return this; } - - this._layers[id] = layer; - - // TODO getMaxZoom, getMinZoom in ILayer (instead of options) - if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) { - this._zoomBoundLayers[id] = layer; - this._updateZoomLevels(); - } - - // TODO looks ugly, refactor!!! - if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { - this._tileLayersNum++; - this._tileLayersToLoad++; - layer.on('load', this._onTileLayerLoad, this); - } - - if (this._loaded) { - this._layerAdd(layer); - } - - return this; - }, - - removeLayer: function (layer) { - var id = L.stamp(layer); - - if (!this._layers[id]) { return; } - - if (this._loaded) { - layer.onRemove(this); - this.fire('layerremove', {layer: layer}); - } - - delete this._layers[id]; - if (this._zoomBoundLayers[id]) { - delete this._zoomBoundLayers[id]; - this._updateZoomLevels(); - } - - // TODO looks ugly, refactor - if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { - this._tileLayersNum--; - this._tileLayersToLoad--; - layer.off('load', this._onTileLayerLoad, this); - } - - return this; - }, - - hasLayer: function (layer) { - if (!layer) { return false; } - - return (L.stamp(layer) in this._layers); - }, - - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - invalidateSize: function (options) { - options = L.extend({ - animate: false, - pan: true - }, options === true ? {animate: true} : options); - - var oldSize = this.getSize(); - this._sizeChanged = true; - - if (this.options.maxBounds) { - this.setMaxBounds(this.options.maxBounds); - } - - if (!this._loaded) { return this; } - - var newSize = this.getSize(), - offset = oldSize.subtract(newSize).divideBy(2).round(); - - if (!offset.x && !offset.y) { return this; } - - if (options.animate && options.pan) { - this.panBy(offset); - - } else { - if (options.pan) { - this._rawPanBy(offset); - } - - this.fire('move'); - - // make sure moveend is not fired too often on resize - clearTimeout(this._sizeTimer); - this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200); - } - - return this.fire('resize', { - oldSize: oldSize, - newSize: newSize - }); - }, - - // TODO handler.addTo - addHandler: function (name, HandlerClass) { - if (!HandlerClass) { return; } - - var handler = this[name] = new HandlerClass(this); - - this._handlers.push(handler); - - if (this.options[name]) { - handler.enable(); - } - - return this; - }, - - remove: function () { - if (this._loaded) { - this.fire('unload'); - } - - this._initEvents('off'); - - delete this._container._leaflet; - - this._clearPanes(); - if (this._clearControlPos) { - this._clearControlPos(); - } - - this._clearHandlers(); - - return this; - }, - - - // public methods for getting map state - - getCenter: function () { // (Boolean) -> LatLng - this._checkIfLoaded(); - - if (!this._moved()) { - return this._initialCenter; - } - return this.layerPointToLatLng(this._getCenterLayerPoint()); - }, - - getZoom: function () { - return this._zoom; - }, - - getBounds: function () { - var bounds = this.getPixelBounds(), - sw = this.unproject(bounds.getBottomLeft()), - ne = this.unproject(bounds.getTopRight()); - - return new L.LatLngBounds(sw, ne); - }, - - getMinZoom: function () { - var z1 = this.options.minZoom || 0, - z2 = this._layersMinZoom || 0, - z3 = this._boundsMinZoom || 0; - - return Math.max(z1, z2, z3); - }, - - getMaxZoom: function () { - var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom, - z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom; - - return Math.min(z1, z2); - }, - - getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number - bounds = L.latLngBounds(bounds); - - var zoom = this.getMinZoom() - (inside ? 1 : 0), - maxZoom = this.getMaxZoom(), - size = this.getSize(), - - nw = bounds.getNorthWest(), - se = bounds.getSouthEast(), - - zoomNotFound = true, - boundsSize; - - padding = L.point(padding || [0, 0]); - - do { - zoom++; - boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding); - zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y; - - } while (zoomNotFound && zoom <= maxZoom); - - if (zoomNotFound && inside) { - return null; - } - - return inside ? zoom : zoom - 1; - }, - - getSize: function () { - if (!this._size || this._sizeChanged) { - this._size = new L.Point( - this._container.clientWidth, - this._container.clientHeight); - - this._sizeChanged = false; - } - return this._size.clone(); - }, - - getPixelBounds: function () { - var topLeftPoint = this._getTopLeftPoint(); - return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); - }, - - getPixelOrigin: function () { - this._checkIfLoaded(); - return this._initialTopLeftPoint; - }, - - getPanes: function () { - return this._panes; - }, - - getContainer: function () { - return this._container; - }, - - - // TODO replace with universal implementation after refactoring projections - - getZoomScale: function (toZoom) { - var crs = this.options.crs; - return crs.scale(toZoom) / crs.scale(this._zoom); - }, - - getScaleZoom: function (scale) { - return this._zoom + (Math.log(scale) / Math.LN2); - }, - - - // conversion methods - - project: function (latlng, zoom) { // (LatLng[, Number]) -> Point - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.latLngToPoint(L.latLng(latlng), zoom); - }, - - unproject: function (point, zoom) { // (Point[, Number]) -> LatLng - zoom = zoom === undefined ? this._zoom : zoom; - return this.options.crs.pointToLatLng(L.point(point), zoom); - }, - - layerPointToLatLng: function (point) { // (Point) - var projectedPoint = L.point(point).add(this.getPixelOrigin()); - return this.unproject(projectedPoint); - }, - - latLngToLayerPoint: function (latlng) { // (LatLng) - var projectedPoint = this.project(L.latLng(latlng))._round(); - return projectedPoint._subtract(this.getPixelOrigin()); - }, - - containerPointToLayerPoint: function (point) { // (Point) - return L.point(point).subtract(this._getMapPanePos()); - }, - - layerPointToContainerPoint: function (point) { // (Point) - return L.point(point).add(this._getMapPanePos()); - }, - - containerPointToLatLng: function (point) { - var layerPoint = this.containerPointToLayerPoint(L.point(point)); - return this.layerPointToLatLng(layerPoint); - }, - - latLngToContainerPoint: function (latlng) { - return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng))); - }, - - mouseEventToContainerPoint: function (e) { // (MouseEvent) - return L.DomEvent.getMousePosition(e, this._container); - }, - - mouseEventToLayerPoint: function (e) { // (MouseEvent) - return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); - }, - - mouseEventToLatLng: function (e) { // (MouseEvent) - return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); - }, - - - // map initialization methods - - _initContainer: function (id) { - var container = this._container = L.DomUtil.get(id); - - if (!container) { - throw new Error('Map container not found.'); - } else if (container._leaflet) { - throw new Error('Map container is already initialized.'); - } - - container._leaflet = true; - }, - - _initLayout: function () { - var container = this._container; - - L.DomUtil.addClass(container, 'leaflet-container' + - (L.Browser.touch ? ' leaflet-touch' : '') + - (L.Browser.retina ? ' leaflet-retina' : '') + - (this.options.fadeAnimation ? ' leaflet-fade-anim' : '')); - - var position = L.DomUtil.getStyle(container, 'position'); - - if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') { - container.style.position = 'relative'; - } - - this._initPanes(); - - if (this._initControlPos) { - this._initControlPos(); - } - }, - - _initPanes: function () { - var panes = this._panes = {}; - - this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container); - - this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); - panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); - panes.shadowPane = this._createPane('leaflet-shadow-pane'); - panes.overlayPane = this._createPane('leaflet-overlay-pane'); - panes.markerPane = this._createPane('leaflet-marker-pane'); - panes.popupPane = this._createPane('leaflet-popup-pane'); - - var zoomHide = ' leaflet-zoom-hide'; - - if (!this.options.markerZoomAnimation) { - L.DomUtil.addClass(panes.markerPane, zoomHide); - L.DomUtil.addClass(panes.shadowPane, zoomHide); - L.DomUtil.addClass(panes.popupPane, zoomHide); - } - }, - - _createPane: function (className, container) { - return L.DomUtil.create('div', className, container || this._panes.objectsPane); - }, - - _clearPanes: function () { - this._container.removeChild(this._mapPane); - }, - - _addLayers: function (layers) { - layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : []; - - for (var i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - }, - - - // private methods that modify map state - - _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) { - - var zoomChanged = (this._zoom !== zoom); - - if (!afterZoomAnim) { - this.fire('movestart'); - - if (zoomChanged) { - this.fire('zoomstart'); - } - } - - this._zoom = zoom; - this._initialCenter = center; - - this._initialTopLeftPoint = this._getNewTopLeftPoint(center); - - if (!preserveMapOffset) { - L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); - } else { - this._initialTopLeftPoint._add(this._getMapPanePos()); - } - - this._tileLayersToLoad = this._tileLayersNum; - - var loading = !this._loaded; - this._loaded = true; - - if (loading) { - this.fire('load'); - this.eachLayer(this._layerAdd, this); - } - - this.fire('viewreset', {hard: !preserveMapOffset}); - - this.fire('move'); - - if (zoomChanged || afterZoomAnim) { - this.fire('zoomend'); - } - - this.fire('moveend', {hard: !preserveMapOffset}); - }, - - _rawPanBy: function (offset) { - L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); - }, - - _getZoomSpan: function () { - return this.getMaxZoom() - this.getMinZoom(); - }, - - _updateZoomLevels: function () { - var i, - minZoom = Infinity, - maxZoom = -Infinity, - oldZoomSpan = this._getZoomSpan(); - - for (i in this._zoomBoundLayers) { - var layer = this._zoomBoundLayers[i]; - if (!isNaN(layer.options.minZoom)) { - minZoom = Math.min(minZoom, layer.options.minZoom); - } - if (!isNaN(layer.options.maxZoom)) { - maxZoom = Math.max(maxZoom, layer.options.maxZoom); - } - } - - if (i === undefined) { // we have no tilelayers - this._layersMaxZoom = this._layersMinZoom = undefined; - } else { - this._layersMaxZoom = maxZoom; - this._layersMinZoom = minZoom; - } - - if (oldZoomSpan !== this._getZoomSpan()) { - this.fire('zoomlevelschange'); - } - }, - - _panInsideMaxBounds: function () { - this.panInsideBounds(this.options.maxBounds); - }, - - _checkIfLoaded: function () { - if (!this._loaded) { - throw new Error('Set map center and zoom first.'); - } - }, - - // map events - - _initEvents: function (onOff) { - if (!L.DomEvent) { return; } - - onOff = onOff || 'on'; - - L.DomEvent[onOff](this._container, 'click', this._onMouseClick, this); - - var events = ['dblclick', 'mousedown', 'mouseup', 'mouseenter', - 'mouseleave', 'mousemove', 'contextmenu'], - i, len; - - for (i = 0, len = events.length; i < len; i++) { - L.DomEvent[onOff](this._container, events[i], this._fireMouseEvent, this); - } - - if (this.options.trackResize) { - L.DomEvent[onOff](window, 'resize', this._onResize, this); - } - }, - - _onResize: function () { - L.Util.cancelAnimFrame(this._resizeRequest); - this._resizeRequest = L.Util.requestAnimFrame( - this.invalidateSize, this, false, this._container); - }, - - _onMouseClick: function (e) { - // jshint camelcase: false - if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; } - - this.fire('preclick'); - this._fireMouseEvent(e); - }, - - _fireMouseEvent: function (e) { - // jshint camelcase: false - if (!this._loaded || e._leaflet_stop) { return; } - - var type = e.type; - - type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type)); - - if (!this.hasEventListeners(type)) { return; } - - if (type === 'contextmenu') { - L.DomEvent.preventDefault(e); - } - - var containerPoint = this.mouseEventToContainerPoint(e), - layerPoint = this.containerPointToLayerPoint(containerPoint), - latlng = this.layerPointToLatLng(layerPoint); - - this.fire(type, { - latlng: latlng, - layerPoint: layerPoint, - containerPoint: containerPoint, - originalEvent: e - }); - }, - - _onTileLayerLoad: function () { - this._tileLayersToLoad--; - if (this._tileLayersNum && !this._tileLayersToLoad) { - this.fire('tilelayersload'); - } - }, - - _clearHandlers: function () { - for (var i = 0, len = this._handlers.length; i < len; i++) { - this._handlers[i].disable(); - } - }, - - whenReady: function (callback, context) { - if (this._loaded) { - callback.call(context || this, this); - } else { - this.on('load', callback, context); - } - return this; - }, - - _layerAdd: function (layer) { - layer.onAdd(this); - this.fire('layeradd', {layer: layer}); - }, - - - // private methods for getting map state - - _getMapPanePos: function () { - return L.DomUtil.getPosition(this._mapPane); - }, - - _moved: function () { - var pos = this._getMapPanePos(); - return pos && !pos.equals([0, 0]); - }, - - _getTopLeftPoint: function () { - return this.getPixelOrigin().subtract(this._getMapPanePos()); - }, - - _getNewTopLeftPoint: function (center, zoom) { - var viewHalf = this.getSize()._divideBy(2); - // TODO round on display, not calculation to increase precision? - return this.project(center, zoom)._subtract(viewHalf)._round(); - }, - - _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) { - var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos()); - return this.project(latlng, newZoom)._subtract(topLeft); - }, - - // layer point of the current center - _getCenterLayerPoint: function () { - return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); - }, - - // offset of the specified place to the current center in pixels - _getCenterOffset: function (latlng) { - return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); - }, - - _limitZoom: function (zoom) { - var min = this.getMinZoom(), - max = this.getMaxZoom(); - - return Math.max(min, Math.min(max, zoom)); - } -}); - -L.map = function (id, options) { - return new L.Map(id, options); -}; - - -/* - * Mercator projection that takes into account that the Earth is not a perfect sphere. - * Less popular than spherical mercator; used by projections like EPSG:3395. - */ - -L.Projection.Mercator = { - MAX_LATITUDE: 85.0840591556, - - R_MINOR: 6356752.314245179, - R_MAJOR: 6378137, - - project: function (latlng) { // (LatLng) -> Point - var d = L.LatLng.DEG_TO_RAD, - max = this.MAX_LATITUDE, - lat = Math.max(Math.min(max, latlng.lat), -max), - r = this.R_MAJOR, - r2 = this.R_MINOR, - x = latlng.lng * d * r, - y = lat * d, - tmp = r2 / r, - eccent = Math.sqrt(1.0 - tmp * tmp), - con = eccent * Math.sin(y); - - con = Math.pow((1 - con) / (1 + con), eccent * 0.5); - - var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con; - y = -r * Math.log(ts); - - return new L.Point(x, y); - }, - - unproject: function (point) { // (Point, Boolean) -> LatLng - var d = L.LatLng.RAD_TO_DEG, - r = this.R_MAJOR, - r2 = this.R_MINOR, - lng = point.x * d / r, - tmp = r2 / r, - eccent = Math.sqrt(1 - (tmp * tmp)), - ts = Math.exp(- point.y / r), - phi = (Math.PI / 2) - 2 * Math.atan(ts), - numIter = 15, - tol = 1e-7, - i = numIter, - dphi = 0.1, - con; - - while ((Math.abs(dphi) > tol) && (--i > 0)) { - con = eccent * Math.sin(phi); - dphi = (Math.PI / 2) - 2 * Math.atan(ts * - Math.pow((1.0 - con) / (1.0 + con), 0.5 * eccent)) - phi; - phi += dphi; - } - - return new L.LatLng(phi * d, lng); - } -}; - - - -L.CRS.EPSG3395 = L.extend({}, L.CRS, { - code: 'EPSG:3395', - - projection: L.Projection.Mercator, - - transformation: (function () { - var m = L.Projection.Mercator, - r = m.R_MAJOR, - r2 = m.R_MINOR; - - return new L.Transformation(0.5 / (Math.PI * r), 0.5, -0.5 / (Math.PI * r2), 0.5); - }()) -}); - - -/* - * L.TileLayer is used for standard xyz-numbered tile layers. - */ - -L.TileLayer = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - minZoom: 0, - maxZoom: 18, - tileSize: 256, - subdomains: 'abc', - errorTileUrl: '', - attribution: '', - zoomOffset: 0, - opacity: 1, - /* (undefined works too) - zIndex: null, - tms: false, - continuousWorld: false, - noWrap: false, - zoomReverse: false, - detectRetina: false, - reuseTiles: false, - bounds: false, - */ - unloadInvisibleTiles: L.Browser.mobile, - updateWhenIdle: L.Browser.mobile - }, - - initialize: function (url, options) { - options = L.setOptions(this, options); - - // detecting retina displays, adjusting tileSize and zoom levels - if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) { - - options.tileSize = Math.floor(options.tileSize / 2); - options.zoomOffset++; - - if (options.minZoom > 0) { - options.minZoom--; - } - this.options.maxZoom--; - } - - if (options.bounds) { - options.bounds = L.latLngBounds(options.bounds); - } - - this._url = url; - - var subdomains = this.options.subdomains; - - if (typeof subdomains === 'string') { - this.options.subdomains = subdomains.split(''); - } - }, - - onAdd: function (map) { - this._map = map; - this._animated = map._zoomAnimated; - - // create a container div for tiles - this._initContainer(); - - // create an image to clone for tiles - this._createTileProto(); - - // set up events - map.on({ - 'viewreset': this._reset, - 'moveend': this._update - }, this); - - if (this._animated) { - map.on({ - 'zoomanim': this._animateZoom, - 'zoomend': this._endZoomAnim - }, this); - } - - if (!this.options.updateWhenIdle) { - this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this); - map.on('move', this._limitedUpdate, this); - } - - this._reset(); - this._update(); - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - this._container.parentNode.removeChild(this._container); - - map.off({ - 'viewreset': this._reset, - 'moveend': this._update - }, this); - - if (this._animated) { - map.off({ - 'zoomanim': this._animateZoom, - 'zoomend': this._endZoomAnim - }, this); - } - - if (!this.options.updateWhenIdle) { - map.off('move', this._limitedUpdate, this); - } - - this._container = null; - this._map = null; - }, - - bringToFront: function () { - var pane = this._map._panes.tilePane; - - if (this._container) { - pane.appendChild(this._container); - this._setAutoZIndex(pane, Math.max); - } - - return this; - }, - - bringToBack: function () { - var pane = this._map._panes.tilePane; - - if (this._container) { - pane.insertBefore(this._container, pane.firstChild); - this._setAutoZIndex(pane, Math.min); - } - - return this; - }, - - getAttribution: function () { - return this.options.attribution; - }, - - getContainer: function () { - return this._container; - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - - if (this._map) { - this._updateOpacity(); - } - - return this; - }, - - setZIndex: function (zIndex) { - this.options.zIndex = zIndex; - this._updateZIndex(); - - return this; - }, - - setUrl: function (url, noRedraw) { - this._url = url; - - if (!noRedraw) { - this.redraw(); - } - - return this; - }, - - redraw: function () { - if (this._map) { - this._reset({hard: true}); - this._update(); - } - return this; - }, - - _updateZIndex: function () { - if (this._container && this.options.zIndex !== undefined) { - this._container.style.zIndex = this.options.zIndex; - } - }, - - _setAutoZIndex: function (pane, compare) { - - var layers = pane.children, - edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min - zIndex, i, len; - - for (i = 0, len = layers.length; i < len; i++) { - - if (layers[i] !== this._container) { - zIndex = parseInt(layers[i].style.zIndex, 10); - - if (!isNaN(zIndex)) { - edgeZIndex = compare(edgeZIndex, zIndex); - } - } - } - - this.options.zIndex = this._container.style.zIndex = - (isFinite(edgeZIndex) ? edgeZIndex : 0) + compare(1, -1); - }, - - _updateOpacity: function () { - var i, - tiles = this._tiles; - - if (L.Browser.ielt9) { - for (i in tiles) { - L.DomUtil.setOpacity(tiles[i], this.options.opacity); - } - } else { - L.DomUtil.setOpacity(this._container, this.options.opacity); - } - }, - - _initContainer: function () { - var tilePane = this._map._panes.tilePane; - - if (!this._container) { - this._container = L.DomUtil.create('div', 'leaflet-layer'); - - this._updateZIndex(); - - if (this._animated) { - var className = 'leaflet-tile-container leaflet-zoom-animated'; - - this._bgBuffer = L.DomUtil.create('div', className, this._container); - this._tileContainer = L.DomUtil.create('div', className, this._container); - - } else { - this._tileContainer = this._container; - } - - tilePane.appendChild(this._container); - - if (this.options.opacity < 1) { - this._updateOpacity(); - } - } - }, - - _reset: function (e) { - for (var key in this._tiles) { - this.fire('tileunload', {tile: this._tiles[key]}); - } - - this._tiles = {}; - this._tilesToLoad = 0; - - if (this.options.reuseTiles) { - this._unusedTiles = []; - } - - this._tileContainer.innerHTML = ''; - - if (this._animated && e && e.hard) { - this._clearBgBuffer(); - } - - this._initContainer(); - }, - - _update: function () { - - if (!this._map) { return; } - - var bounds = this._map.getPixelBounds(), - zoom = this._map.getZoom(), - tileSize = this.options.tileSize; - - if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { - return; - } - - var tileBounds = L.bounds( - bounds.min.divideBy(tileSize)._floor(), - bounds.max.divideBy(tileSize)._floor()); - - this._addTilesFromCenterOut(tileBounds); - - if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { - this._removeOtherTiles(tileBounds); - } - }, - - _addTilesFromCenterOut: function (bounds) { - var queue = [], - center = bounds.getCenter(); - - var j, i, point; - - for (j = bounds.min.y; j <= bounds.max.y; j++) { - for (i = bounds.min.x; i <= bounds.max.x; i++) { - point = new L.Point(i, j); - - if (this._tileShouldBeLoaded(point)) { - queue.push(point); - } - } - } - - var tilesToLoad = queue.length; - - if (tilesToLoad === 0) { return; } - - // load tiles in order of their distance to center - queue.sort(function (a, b) { - return a.distanceTo(center) - b.distanceTo(center); - }); - - var fragment = document.createDocumentFragment(); - - // if its the first batch of tiles to load - if (!this._tilesToLoad) { - this.fire('loading'); - } - - this._tilesToLoad += tilesToLoad; - - for (i = 0; i < tilesToLoad; i++) { - this._addTile(queue[i], fragment); - } - - this._tileContainer.appendChild(fragment); - }, - - _tileShouldBeLoaded: function (tilePoint) { - if ((tilePoint.x + ':' + tilePoint.y) in this._tiles) { - return false; // already loaded - } - - var options = this.options; - - if (!options.continuousWorld) { - var limit = this._getWrapTileNum(); - - // don't load if exceeds world bounds - if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit)) || - tilePoint.y < 0 || tilePoint.y >= limit) { return false; } - } - - if (options.bounds) { - var tileSize = options.tileSize, - nwPoint = tilePoint.multiplyBy(tileSize), - sePoint = nwPoint.add([tileSize, tileSize]), - nw = this._map.unproject(nwPoint), - se = this._map.unproject(sePoint); - - // TODO temporary hack, will be removed after refactoring projections - // https://github.com/Leaflet/Leaflet/issues/1618 - if (!options.continuousWorld && !options.noWrap) { - nw = nw.wrap(); - se = se.wrap(); - } - - if (!options.bounds.intersects([nw, se])) { return false; } - } - - return true; - }, - - _removeOtherTiles: function (bounds) { - var kArr, x, y, key; - - for (key in this._tiles) { - kArr = key.split(':'); - x = parseInt(kArr[0], 10); - y = parseInt(kArr[1], 10); - - // remove tile if it's out of bounds - if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { - this._removeTile(key); - } - } - }, - - _removeTile: function (key) { - var tile = this._tiles[key]; - - this.fire('tileunload', {tile: tile, url: tile.src}); - - if (this.options.reuseTiles) { - L.DomUtil.removeClass(tile, 'leaflet-tile-loaded'); - this._unusedTiles.push(tile); - - } else if (tile.parentNode === this._tileContainer) { - this._tileContainer.removeChild(tile); - } - - // for https://github.com/CloudMade/Leaflet/issues/137 - if (!L.Browser.android) { - tile.onload = null; - tile.src = L.Util.emptyImageUrl; - } - - delete this._tiles[key]; - }, - - _addTile: function (tilePoint, container) { - var tilePos = this._getTilePos(tilePoint); - - // get unused tile - or create a new tile - var tile = this._getTile(); - - /* - Chrome 20 layouts much faster with top/left (verify with timeline, frames) - Android 4 browser has display issues with top/left and requires transform instead - Android 2 browser requires top/left or tiles disappear on load or first drag - (reappear after zoom) https://github.com/CloudMade/Leaflet/issues/866 - (other browsers don't currently care) - see debug/hacks/jitter.html for an example - */ - L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome || L.Browser.android23); - - this._tiles[tilePoint.x + ':' + tilePoint.y] = tile; - - this._loadTile(tile, tilePoint); - - if (tile.parentNode !== this._tileContainer) { - container.appendChild(tile); - } - }, - - _getZoomForUrl: function () { - - var options = this.options, - zoom = this._map.getZoom(); - - if (options.zoomReverse) { - zoom = options.maxZoom - zoom; - } - - return zoom + options.zoomOffset; - }, - - _getTilePos: function (tilePoint) { - var origin = this._map.getPixelOrigin(), - tileSize = this.options.tileSize; - - return tilePoint.multiplyBy(tileSize).subtract(origin); - }, - - // image-specific code (override to implement e.g. Canvas or SVG tile layer) - - getTileUrl: function (tilePoint) { - return L.Util.template(this._url, L.extend({ - s: this._getSubdomain(tilePoint), - z: tilePoint.z, - x: tilePoint.x, - y: tilePoint.y - }, this.options)); - }, - - _getWrapTileNum: function () { - // TODO refactor, limit is not valid for non-standard projections - return Math.pow(2, this._getZoomForUrl()); - }, - - _adjustTilePoint: function (tilePoint) { - - var limit = this._getWrapTileNum(); - - // wrap tile coordinates - if (!this.options.continuousWorld && !this.options.noWrap) { - tilePoint.x = ((tilePoint.x % limit) + limit) % limit; - } - - if (this.options.tms) { - tilePoint.y = limit - tilePoint.y - 1; - } - - tilePoint.z = this._getZoomForUrl(); - }, - - _getSubdomain: function (tilePoint) { - var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length; - return this.options.subdomains[index]; - }, - - _createTileProto: function () { - var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile'); - img.style.width = img.style.height = this.options.tileSize + 'px'; - img.galleryimg = 'no'; - }, - - _getTile: function () { - if (this.options.reuseTiles && this._unusedTiles.length > 0) { - var tile = this._unusedTiles.pop(); - this._resetTile(tile); - return tile; - } - return this._createTile(); - }, - - // Override if data stored on a tile needs to be cleaned up before reuse - _resetTile: function (/*tile*/) {}, - - _createTile: function () { - var tile = this._tileImg.cloneNode(false); - tile.onselectstart = tile.onmousemove = L.Util.falseFn; - - if (L.Browser.ielt9 && this.options.opacity !== undefined) { - L.DomUtil.setOpacity(tile, this.options.opacity); - } - return tile; - }, - - _loadTile: function (tile, tilePoint) { - tile._layer = this; - tile.onload = this._tileOnLoad; - tile.onerror = this._tileOnError; - - this._adjustTilePoint(tilePoint); - tile.src = this.getTileUrl(tilePoint); - }, - - _tileLoaded: function () { - this._tilesToLoad--; - if (!this._tilesToLoad) { - this.fire('load'); - - if (this._animated) { - // clear scaled tiles after all new tiles are loaded (for performance) - clearTimeout(this._clearBgBufferTimer); - this._clearBgBufferTimer = setTimeout(L.bind(this._clearBgBuffer, this), 500); - } - } - }, - - _tileOnLoad: function () { - var layer = this._layer; - - //Only if we are loading an actual image - if (this.src !== L.Util.emptyImageUrl) { - L.DomUtil.addClass(this, 'leaflet-tile-loaded'); - - layer.fire('tileload', { - tile: this, - url: this.src - }); - } - - layer._tileLoaded(); - }, - - _tileOnError: function () { - var layer = this._layer; - - layer.fire('tileerror', { - tile: this, - url: this.src - }); - - var newUrl = layer.options.errorTileUrl; - if (newUrl) { - this.src = newUrl; - } - - layer._tileLoaded(); - } -}); - -L.tileLayer = function (url, options) { - return new L.TileLayer(url, options); -}; - - -/* - * L.TileLayer.WMS is used for putting WMS tile layers on the map. - */ - -L.TileLayer.WMS = L.TileLayer.extend({ - - defaultWmsParams: { - service: 'WMS', - request: 'GetMap', - version: '1.1.1', - layers: '', - styles: '', - format: 'image/jpeg', - transparent: false - }, - - initialize: function (url, options) { // (String, Object) - - this._url = url; - - var wmsParams = L.extend({}, this.defaultWmsParams), - tileSize = options.tileSize || this.options.tileSize; - - if (options.detectRetina && L.Browser.retina) { - wmsParams.width = wmsParams.height = tileSize * 2; - } else { - wmsParams.width = wmsParams.height = tileSize; - } - - for (var i in options) { - // all keys that are not TileLayer options go to WMS params - if (!this.options.hasOwnProperty(i) && i !== 'crs') { - wmsParams[i] = options[i]; - } - } - - this.wmsParams = wmsParams; - - L.setOptions(this, options); - }, - - onAdd: function (map) { - - this._crs = this.options.crs || map.options.crs; - - var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs'; - this.wmsParams[projectionKey] = this._crs.code; - - L.TileLayer.prototype.onAdd.call(this, map); - }, - - getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String - - var map = this._map, - tileSize = this.options.tileSize, - - nwPoint = tilePoint.multiplyBy(tileSize), - sePoint = nwPoint.add([tileSize, tileSize]), - - nw = this._crs.project(map.unproject(nwPoint, zoom)), - se = this._crs.project(map.unproject(sePoint, zoom)), - - bbox = [nw.x, se.y, se.x, nw.y].join(','), - - url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)}); - - return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox; - }, - - setParams: function (params, noRedraw) { - - L.extend(this.wmsParams, params); - - if (!noRedraw) { - this.redraw(); - } - - return this; - } -}); - -L.tileLayer.wms = function (url, options) { - return new L.TileLayer.WMS(url, options); -}; - - -/* - * L.TileLayer.Canvas is a class that you can use as a base for creating - * dynamically drawn Canvas-based tile layers. - */ - -L.TileLayer.Canvas = L.TileLayer.extend({ - options: { - async: false - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - redraw: function () { - for (var i in this._tiles) { - this._redrawTile(this._tiles[i]); - } - return this; - }, - - _redrawTile: function (tile) { - this.drawTile(tile, tile._tilePoint, this._map._zoom); - }, - - _createTileProto: function () { - var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); - proto.width = proto.height = this.options.tileSize; - }, - - _createTile: function () { - var tile = this._canvasProto.cloneNode(false); - tile.onselectstart = tile.onmousemove = L.Util.falseFn; - return tile; - }, - - _loadTile: function (tile, tilePoint) { - tile._layer = this; - tile._tilePoint = tilePoint; - - this._redrawTile(tile); - - if (!this.options.async) { - this.tileDrawn(tile); - } - }, - - drawTile: function (/*tile, tilePoint*/) { - // override with rendering code - }, - - tileDrawn: function (tile) { - this._tileOnLoad.call(tile); - } -}); - - -L.tileLayer.canvas = function (options) { - return new L.TileLayer.Canvas(options); -}; - - -/* - * L.ImageOverlay is used to overlay images over the map (to specific geographical bounds). - */ - -L.ImageOverlay = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - opacity: 1 - }, - - initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) - this._url = url; - this._bounds = L.latLngBounds(bounds); - - L.setOptions(this, options); - }, - - onAdd: function (map) { - this._map = map; - - if (!this._image) { - this._initImage(); - } - - map._panes.overlayPane.appendChild(this._image); - - map.on('viewreset', this._reset, this); - - if (map.options.zoomAnimation && L.Browser.any3d) { - map.on('zoomanim', this._animateZoom, this); - } - - this._reset(); - }, - - onRemove: function (map) { - map.getPanes().overlayPane.removeChild(this._image); - - map.off('viewreset', this._reset, this); - - if (map.options.zoomAnimation) { - map.off('zoomanim', this._animateZoom, this); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - this._updateOpacity(); - return this; - }, - - // TODO remove bringToFront/bringToBack duplication from TileLayer/Path - bringToFront: function () { - if (this._image) { - this._map._panes.overlayPane.appendChild(this._image); - } - return this; - }, - - bringToBack: function () { - var pane = this._map._panes.overlayPane; - if (this._image) { - pane.insertBefore(this._image, pane.firstChild); - } - return this; - }, - - _initImage: function () { - this._image = L.DomUtil.create('img', 'leaflet-image-layer'); - - if (this._map.options.zoomAnimation && L.Browser.any3d) { - L.DomUtil.addClass(this._image, 'leaflet-zoom-animated'); - } else { - L.DomUtil.addClass(this._image, 'leaflet-zoom-hide'); - } - - this._updateOpacity(); - - //TODO createImage util method to remove duplication - L.extend(this._image, { - galleryimg: 'no', - onselectstart: L.Util.falseFn, - onmousemove: L.Util.falseFn, - onload: L.bind(this._onImageLoad, this), - src: this._url - }); - }, - - _animateZoom: function (e) { - var map = this._map, - image = this._image, - scale = map.getZoomScale(e.zoom), - nw = this._bounds.getNorthWest(), - se = this._bounds.getSouthEast(), - - topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center), - size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft), - origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale))); - - image.style[L.DomUtil.TRANSFORM] = - L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') '; - }, - - _reset: function () { - var image = this._image, - topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), - size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft); - - L.DomUtil.setPosition(image, topLeft); - - image.style.width = size.x + 'px'; - image.style.height = size.y + 'px'; - }, - - _onImageLoad: function () { - this.fire('load'); - }, - - _updateOpacity: function () { - L.DomUtil.setOpacity(this._image, this.options.opacity); - } -}); - -L.imageOverlay = function (url, bounds, options) { - return new L.ImageOverlay(url, bounds, options); -}; - - -/* - * L.Icon is an image-based icon class that you can use with L.Marker for custom markers. - */ - -L.Icon = L.Class.extend({ - options: { - /* - iconUrl: (String) (required) - iconRetinaUrl: (String) (optional, used for retina devices if detected) - iconSize: (Point) (can be set through CSS) - iconAnchor: (Point) (centered by default, can be set in CSS with negative margins) - popupAnchor: (Point) (if not specified, popup opens in the anchor point) - shadowUrl: (String) (no shadow by default) - shadowRetinaUrl: (String) (optional, used for retina devices if detected) - shadowSize: (Point) - shadowAnchor: (Point) - */ - className: '' - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - createIcon: function (oldIcon) { - return this._createIcon('icon', oldIcon); - }, - - createShadow: function (oldIcon) { - return this._createIcon('shadow', oldIcon); - }, - - _createIcon: function (name, oldIcon) { - var src = this._getIconUrl(name); - - if (!src) { - if (name === 'icon') { - throw new Error('iconUrl not set in Icon options (see the docs).'); - } - return null; - } - - var img; - if (!oldIcon || oldIcon.tagName !== 'IMG') { - img = this._createImg(src); - } else { - img = this._createImg(src, oldIcon); - } - this._setIconStyles(img, name); - - return img; - }, - - _setIconStyles: function (img, name) { - var options = this.options, - size = L.point(options[name + 'Size']), - anchor; - - if (name === 'shadow') { - anchor = L.point(options.shadowAnchor || options.iconAnchor); - } else { - anchor = L.point(options.iconAnchor); - } - - if (!anchor && size) { - anchor = size.divideBy(2, true); - } - - img.className = 'leaflet-marker-' + name + ' ' + options.className; - - if (anchor) { - img.style.marginLeft = (-anchor.x) + 'px'; - img.style.marginTop = (-anchor.y) + 'px'; - } - - if (size) { - img.style.width = size.x + 'px'; - img.style.height = size.y + 'px'; - } - }, - - _createImg: function (src, el) { - - if (!L.Browser.ie6) { - if (!el) { - el = document.createElement('img'); - } - el.src = src; - } else { - if (!el) { - el = document.createElement('div'); - } - el.style.filter = - 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; - } - return el; - }, - - _getIconUrl: function (name) { - if (L.Browser.retina && this.options[name + 'RetinaUrl']) { - return this.options[name + 'RetinaUrl']; - } - return this.options[name + 'Url']; - } -}); - -L.icon = function (options) { - return new L.Icon(options); -}; - - -/* - * L.Icon.Default is the blue marker icon used by default in Leaflet. - */ - -L.Icon.Default = L.Icon.extend({ - - options: { - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - - shadowSize: [41, 41] - }, - - _getIconUrl: function (name) { - var key = name + 'Url'; - - if (this.options[key]) { - return this.options[key]; - } - - if (L.Browser.retina && name === 'icon') { - name += '-2x'; - } - - var path = L.Icon.Default.imagePath; - - if (!path) { - throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.'); - } - - return path + '/marker-' + name + '.png'; - } -}); - -L.Icon.Default.imagePath = (function () { - var scripts = document.getElementsByTagName('script'), - leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/; - - var i, len, src, matches, path; - - for (i = 0, len = scripts.length; i < len; i++) { - src = scripts[i].src; - matches = src.match(leafletRe); - - if (matches) { - path = src.split(leafletRe)[0]; - return (path ? path + '/' : '') + 'images'; - } - } -}()); - - -/* - * L.Marker is used to display clickable/draggable icons on the map. - */ - -L.Marker = L.Class.extend({ - - includes: L.Mixin.Events, - - options: { - icon: new L.Icon.Default(), - title: '', - clickable: true, - draggable: false, - keyboard: true, - zIndexOffset: 0, - opacity: 1, - riseOnHover: false, - riseOffset: 250 - }, - - initialize: function (latlng, options) { - L.setOptions(this, options); - this._latlng = L.latLng(latlng); - }, - - onAdd: function (map) { - this._map = map; - - map.on('viewreset', this.update, this); - - this._initIcon(); - this.update(); - - if (map.options.zoomAnimation && map.options.markerZoomAnimation) { - map.on('zoomanim', this._animateZoom, this); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - if (this.dragging) { - this.dragging.disable(); - } - - this._removeIcon(); - this._removeShadow(); - - this.fire('remove'); - - map.off({ - 'viewreset': this.update, - 'zoomanim': this._animateZoom - }, this); - - this._map = null; - }, - - getLatLng: function () { - return this._latlng; - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - - this.update(); - - return this.fire('move', { latlng: this._latlng }); - }, - - setZIndexOffset: function (offset) { - this.options.zIndexOffset = offset; - this.update(); - - return this; - }, - - setIcon: function (icon) { - - this.options.icon = icon; - - if (this._map) { - this._initIcon(); - this.update(); - } - - return this; - }, - - update: function () { - if (this._icon) { - var pos = this._map.latLngToLayerPoint(this._latlng).round(); - this._setPos(pos); - } - - return this; - }, - - _initIcon: function () { - var options = this.options, - map = this._map, - animation = (map.options.zoomAnimation && map.options.markerZoomAnimation), - classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide'; - - var icon = options.icon.createIcon(this._icon), - addIcon = false; - - // if we're not reusing the icon, remove the old one and init new one - if (icon !== this._icon) { - if (this._icon) { - this._removeIcon(); - } - addIcon = true; - - if (options.title) { - icon.title = options.title; - } - } - - L.DomUtil.addClass(icon, classToAdd); - - if (options.keyboard) { - icon.tabIndex = '0'; - } - - this._icon = icon; - - this._initInteraction(); - - if (options.riseOnHover) { - L.DomEvent - .on(icon, 'mouseover', this._bringToFront, this) - .on(icon, 'mouseout', this._resetZIndex, this); - } - - var newShadow = options.icon.createShadow(this._shadow), - addShadow = false; - - if (newShadow !== this._shadow) { - this._removeShadow(); - addShadow = true; - - if (newShadow) { - L.DomUtil.addClass(newShadow, classToAdd); - } - } - this._shadow = newShadow; - - - if (options.opacity < 1) { - this._updateOpacity(); - } - - - var panes = this._map._panes; - - if (addIcon) { - panes.markerPane.appendChild(this._icon); - } - - if (newShadow && addShadow) { - panes.shadowPane.appendChild(this._shadow); - } - }, - - _removeIcon: function () { - if (this.options.riseOnHover) { - L.DomEvent - .off(this._icon, 'mouseover', this._bringToFront) - .off(this._icon, 'mouseout', this._resetZIndex); - } - - this._map._panes.markerPane.removeChild(this._icon); - - this._icon = null; - }, - - _removeShadow: function () { - if (this._shadow) { - this._map._panes.shadowPane.removeChild(this._shadow); - } - this._shadow = null; - }, - - _setPos: function (pos) { - L.DomUtil.setPosition(this._icon, pos); - - if (this._shadow) { - L.DomUtil.setPosition(this._shadow, pos); - } - - this._zIndex = pos.y + this.options.zIndexOffset; - - this._resetZIndex(); - }, - - _updateZIndex: function (offset) { - this._icon.style.zIndex = this._zIndex + offset; - }, - - _animateZoom: function (opt) { - var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); - - this._setPos(pos); - }, - - _initInteraction: function () { - - if (!this.options.clickable) { return; } - - // TODO refactor into something shared with Map/Path/etc. to DRY it up - - var icon = this._icon, - events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; - - L.DomUtil.addClass(icon, 'leaflet-clickable'); - L.DomEvent.on(icon, 'click', this._onMouseClick, this); - L.DomEvent.on(icon, 'keypress', this._onKeyPress, this); - - for (var i = 0; i < events.length; i++) { - L.DomEvent.on(icon, events[i], this._fireMouseEvent, this); - } - - if (L.Handler.MarkerDrag) { - this.dragging = new L.Handler.MarkerDrag(this); - - if (this.options.draggable) { - this.dragging.enable(); - } - } - }, - - _onMouseClick: function (e) { - var wasDragged = this.dragging && this.dragging.moved(); - - if (this.hasEventListeners(e.type) || wasDragged) { - L.DomEvent.stopPropagation(e); - } - - if (wasDragged) { return; } - - if ((!this.dragging || !this.dragging._enabled) && this._map.dragging && this._map.dragging.moved()) { return; } - - this.fire(e.type, { - originalEvent: e, - latlng: this._latlng - }); - }, - - _onKeyPress: function (e) { - if (e.keyCode === 13) { - this.fire('click', { - originalEvent: e, - latlng: this._latlng - }); - } - }, - - _fireMouseEvent: function (e) { - - this.fire(e.type, { - originalEvent: e, - latlng: this._latlng - }); - - // TODO proper custom event propagation - // this line will always be called if marker is in a FeatureGroup - if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { - L.DomEvent.preventDefault(e); - } - if (e.type !== 'mousedown') { - L.DomEvent.stopPropagation(e); - } else { - L.DomEvent.preventDefault(e); - } - }, - - setOpacity: function (opacity) { - this.options.opacity = opacity; - if (this._map) { - this._updateOpacity(); - } - }, - - _updateOpacity: function () { - L.DomUtil.setOpacity(this._icon, this.options.opacity); - if (this._shadow) { - L.DomUtil.setOpacity(this._shadow, this.options.opacity); - } - }, - - _bringToFront: function () { - this._updateZIndex(this.options.riseOffset); - }, - - _resetZIndex: function () { - this._updateZIndex(0); - } -}); - -L.marker = function (latlng, options) { - return new L.Marker(latlng, options); -}; - - -/* - * L.DivIcon is a lightweight HTML-based icon class (as opposed to the image-based L.Icon) - * to use with L.Marker. - */ - -L.DivIcon = L.Icon.extend({ - options: { - iconSize: [12, 12], // also can be set through CSS - /* - iconAnchor: (Point) - popupAnchor: (Point) - html: (String) - bgPos: (Point) - */ - className: 'leaflet-div-icon', - html: false - }, - - createIcon: function (oldIcon) { - var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'), - options = this.options; - - if (options.html !== false) { - div.innerHTML = options.html; - } else { - div.innerHTML = ''; - } - - if (options.bgPos) { - div.style.backgroundPosition = - (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px'; - } - - this._setIconStyles(div, 'icon'); - return div; - }, - - createShadow: function () { - return null; - } -}); - -L.divIcon = function (options) { - return new L.DivIcon(options); -}; - - -/* - * L.Popup is used for displaying popups on the map. - */ - -L.Map.mergeOptions({ - closePopupOnClick: true -}); - -L.Popup = L.Class.extend({ - includes: L.Mixin.Events, - - options: { - minWidth: 50, - maxWidth: 300, - maxHeight: null, - autoPan: true, - closeButton: true, - offset: [0, 7], - autoPanPadding: [5, 5], - keepInView: false, - className: '', - zoomAnimation: true - }, - - initialize: function (options, source) { - L.setOptions(this, options); - - this._source = source; - this._animated = L.Browser.any3d && this.options.zoomAnimation; - this._isOpen = false; - }, - - onAdd: function (map) { - this._map = map; - - if (!this._container) { - this._initLayout(); - } - this._updateContent(); - - var animFade = map.options.fadeAnimation; - - if (animFade) { - L.DomUtil.setOpacity(this._container, 0); - } - map._panes.popupPane.appendChild(this._container); - - map.on(this._getEvents(), this); - - this._update(); - - if (animFade) { - L.DomUtil.setOpacity(this._container, 1); - } - - this.fire('open'); - - map.fire('popupopen', {popup: this}); - - if (this._source) { - this._source.fire('popupopen', {popup: this}); - } - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - openOn: function (map) { - map.openPopup(this); - return this; - }, - - onRemove: function (map) { - map._panes.popupPane.removeChild(this._container); - - L.Util.falseFn(this._container.offsetWidth); // force reflow - - map.off(this._getEvents(), this); - - if (map.options.fadeAnimation) { - L.DomUtil.setOpacity(this._container, 0); - } - - this._map = null; - - this.fire('close'); - - map.fire('popupclose', {popup: this}); - - if (this._source) { - this._source.fire('popupclose', {popup: this}); - } - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - this._update(); - return this; - }, - - setContent: function (content) { - this._content = content; - this._update(); - return this; - }, - - _getEvents: function () { - var events = { - viewreset: this._updatePosition - }; - - if (this._animated) { - events.zoomanim = this._zoomAnimation; - } - if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) { - events.preclick = this._close; - } - if (this.options.keepInView) { - events.moveend = this._adjustPan; - } - - return events; - }, - - _close: function () { - if (this._map) { - this._map.closePopup(this); - } - }, - - _initLayout: function () { - var prefix = 'leaflet-popup', - containerClass = prefix + ' ' + this.options.className + ' leaflet-zoom-' + - (this._animated ? 'animated' : 'hide'), - container = this._container = L.DomUtil.create('div', containerClass), - closeButton; - - if (this.options.closeButton) { - closeButton = this._closeButton = - L.DomUtil.create('a', prefix + '-close-button', container); - closeButton.href = '#close'; - closeButton.innerHTML = '×'; - L.DomEvent.disableClickPropagation(closeButton); - - L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this); - } - - var wrapper = this._wrapper = - L.DomUtil.create('div', prefix + '-content-wrapper', container); - L.DomEvent.disableClickPropagation(wrapper); - - this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); - L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation); - L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); - this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); - this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); - }, - - _update: function () { - if (!this._map) { return; } - - this._container.style.visibility = 'hidden'; - - this._updateContent(); - this._updateLayout(); - this._updatePosition(); - - this._container.style.visibility = ''; - - this._adjustPan(); - }, - - _updateContent: function () { - if (!this._content) { return; } - - if (typeof this._content === 'string') { - this._contentNode.innerHTML = this._content; - } else { - while (this._contentNode.hasChildNodes()) { - this._contentNode.removeChild(this._contentNode.firstChild); - } - this._contentNode.appendChild(this._content); - } - this.fire('contentupdate'); - }, - - _updateLayout: function () { - var container = this._contentNode, - style = container.style; - - style.width = ''; - style.whiteSpace = 'nowrap'; - - var width = container.offsetWidth; - width = Math.min(width, this.options.maxWidth); - width = Math.max(width, this.options.minWidth); - - style.width = (width + 1) + 'px'; - style.whiteSpace = ''; - - style.height = ''; - - var height = container.offsetHeight, - maxHeight = this.options.maxHeight, - scrolledClass = 'leaflet-popup-scrolled'; - - if (maxHeight && height > maxHeight) { - style.height = maxHeight + 'px'; - L.DomUtil.addClass(container, scrolledClass); - } else { - L.DomUtil.removeClass(container, scrolledClass); - } - - this._containerWidth = this._container.offsetWidth; - }, - - _updatePosition: function () { - if (!this._map) { return; } - - var pos = this._map.latLngToLayerPoint(this._latlng), - animated = this._animated, - offset = L.point(this.options.offset); - - if (animated) { - L.DomUtil.setPosition(this._container, pos); - } - - this._containerBottom = -offset.y - (animated ? 0 : pos.y); - this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x + (animated ? 0 : pos.x); - - // bottom position the popup in case the height of the popup changes (images loading etc) - this._container.style.bottom = this._containerBottom + 'px'; - this._container.style.left = this._containerLeft + 'px'; - }, - - _zoomAnimation: function (opt) { - var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); - - L.DomUtil.setPosition(this._container, pos); - }, - - _adjustPan: function () { - if (!this.options.autoPan) { return; } - - var map = this._map, - containerHeight = this._container.offsetHeight, - containerWidth = this._containerWidth, - - layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom); - - if (this._animated) { - layerPos._add(L.DomUtil.getPosition(this._container)); - } - - var containerPos = map.layerPointToContainerPoint(layerPos), - padding = L.point(this.options.autoPanPadding), - size = map.getSize(), - dx = 0, - dy = 0; - - if (containerPos.x + containerWidth > size.x) { // right - dx = containerPos.x + containerWidth - size.x + padding.x; - } - if (containerPos.x - dx < 0) { // left - dx = containerPos.x - padding.x; - } - if (containerPos.y + containerHeight > size.y) { // bottom - dy = containerPos.y + containerHeight - size.y + padding.y; - } - if (containerPos.y - dy < 0) { // top - dy = containerPos.y - padding.y; - } - - if (dx || dy) { - map - .fire('autopanstart') - .panBy([dx, dy]); - } - }, - - _onCloseButtonClick: function (e) { - this._close(); - L.DomEvent.stop(e); - } -}); - -L.popup = function (options, source) { - return new L.Popup(options, source); -}; - - -L.Map.include({ - openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object]) - this.closePopup(); - - if (!(popup instanceof L.Popup)) { - var content = popup; - - popup = new L.Popup(options) - .setLatLng(latlng) - .setContent(content); - } - popup._isOpen = true; - - this._popup = popup; - return this.addLayer(popup); - }, - - closePopup: function (popup) { - if (!popup || popup === this._popup) { - popup = this._popup; - this._popup = null; - } - if (popup) { - this.removeLayer(popup); - popup._isOpen = false; - } - return this; - } -}); - - -/* - * Popup extension to L.Marker, adding popup-related methods. - */ - -L.Marker.include({ - openPopup: function () { - if (this._popup && this._map && !this._map.hasLayer(this._popup)) { - this._popup.setLatLng(this._latlng); - this._map.openPopup(this._popup); - } - - return this; - }, - - closePopup: function () { - if (this._popup) { - this._popup._close(); - } - return this; - }, - - togglePopup: function () { - if (this._popup) { - if (this._popup._isOpen) { - this.closePopup(); - } else { - this.openPopup(); - } - } - return this; - }, - - bindPopup: function (content, options) { - var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]); - - anchor = anchor.add(L.Popup.prototype.options.offset); - - if (options && options.offset) { - anchor = anchor.add(options.offset); - } - - options = L.extend({offset: anchor}, options); - - if (!this._popup) { - this - .on('click', this.togglePopup, this) - .on('remove', this.closePopup, this) - .on('move', this._movePopup, this); - } - - if (content instanceof L.Popup) { - L.setOptions(content, options); - this._popup = content; - } else { - this._popup = new L.Popup(options, this) - .setContent(content); - } - - return this; - }, - - setPopupContent: function (content) { - if (this._popup) { - this._popup.setContent(content); - } - return this; - }, - - unbindPopup: function () { - if (this._popup) { - this._popup = null; - this - .off('click', this.togglePopup) - .off('remove', this.closePopup) - .off('move', this._movePopup); - } - return this; - }, - - _movePopup: function (e) { - this._popup.setLatLng(e.latlng); - } -}); - - -/* - * L.LayerGroup is a class to combine several layers into one so that - * you can manipulate the group (e.g. add/remove it) as one layer. - */ - -L.LayerGroup = L.Class.extend({ - initialize: function (layers) { - this._layers = {}; - - var i, len; - - if (layers) { - for (i = 0, len = layers.length; i < len; i++) { - this.addLayer(layers[i]); - } - } - }, - - addLayer: function (layer) { - var id = this.getLayerId(layer); - - this._layers[id] = layer; - - if (this._map) { - this._map.addLayer(layer); - } - - return this; - }, - - removeLayer: function (layer) { - var id = layer in this._layers ? layer : this.getLayerId(layer); - - if (this._map && this._layers[id]) { - this._map.removeLayer(this._layers[id]); - } - - delete this._layers[id]; - - return this; - }, - - hasLayer: function (layer) { - if (!layer) { return false; } - - return (layer in this._layers || this.getLayerId(layer) in this._layers); - }, - - clearLayers: function () { - this.eachLayer(this.removeLayer, this); - return this; - }, - - invoke: function (methodName) { - var args = Array.prototype.slice.call(arguments, 1), - i, layer; - - for (i in this._layers) { - layer = this._layers[i]; - - if (layer[methodName]) { - layer[methodName].apply(layer, args); - } - } - - return this; - }, - - onAdd: function (map) { - this._map = map; - this.eachLayer(map.addLayer, map); - }, - - onRemove: function (map) { - this.eachLayer(map.removeLayer, map); - this._map = null; - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - eachLayer: function (method, context) { - for (var i in this._layers) { - method.call(context, this._layers[i]); - } - return this; - }, - - getLayer: function (id) { - return this._layers[id]; - }, - - getLayers: function () { - var layers = []; - - for (var i in this._layers) { - layers.push(this._layers[i]); - } - return layers; - }, - - setZIndex: function (zIndex) { - return this.invoke('setZIndex', zIndex); - }, - - getLayerId: function (layer) { - return L.stamp(layer); - } -}); - -L.layerGroup = function (layers) { - return new L.LayerGroup(layers); -}; - - -/* - * L.FeatureGroup extends L.LayerGroup by introducing mouse events and additional methods - * shared between a group of interactive layers (like vectors or markers). - */ - -L.FeatureGroup = L.LayerGroup.extend({ - includes: L.Mixin.Events, - - statics: { - EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose' - }, - - addLayer: function (layer) { - if (this.hasLayer(layer)) { - return this; - } - - layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this); - - L.LayerGroup.prototype.addLayer.call(this, layer); - - if (this._popupContent && layer.bindPopup) { - layer.bindPopup(this._popupContent, this._popupOptions); - } - - return this.fire('layeradd', {layer: layer}); - }, - - removeLayer: function (layer) { - if (layer in this._layers) { - layer = this._layers[layer]; - } - - layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this); - - L.LayerGroup.prototype.removeLayer.call(this, layer); - - if (this._popupContent) { - this.invoke('unbindPopup'); - } - - return this.fire('layerremove', {layer: layer}); - }, - - bindPopup: function (content, options) { - this._popupContent = content; - this._popupOptions = options; - return this.invoke('bindPopup', content, options); - }, - - setStyle: function (style) { - return this.invoke('setStyle', style); - }, - - bringToFront: function () { - return this.invoke('bringToFront'); - }, - - bringToBack: function () { - return this.invoke('bringToBack'); - }, - - getBounds: function () { - var bounds = new L.LatLngBounds(); - - this.eachLayer(function (layer) { - bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds()); - }); - - return bounds; - }, - - _propagateEvent: function (e) { - if (!e.layer) { - e.layer = e.target; - } - e.target = this; - - this.fire(e.type, e); - } -}); - -L.featureGroup = function (layers) { - return new L.FeatureGroup(layers); -}; - - -/* - * L.Path is a base class for rendering vector paths on a map. Inherited by Polyline, Circle, etc. - */ - -L.Path = L.Class.extend({ - includes: [L.Mixin.Events], - - statics: { - // how much to extend the clip area around the map view - // (relative to its size, e.g. 0.5 is half the screen in each direction) - // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is) - CLIP_PADDING: L.Browser.mobile ? - Math.max(0, Math.min(0.5, - (1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5 - }, - - options: { - stroke: true, - color: '#0033ff', - dashArray: null, - weight: 5, - opacity: 0.5, - - fill: false, - fillColor: null, //same as color by default - fillOpacity: 0.2, - - clickable: true - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - onAdd: function (map) { - this._map = map; - - if (!this._container) { - this._initElements(); - this._initEvents(); - } - - this.projectLatlngs(); - this._updatePath(); - - if (this._container) { - this._map._pathRoot.appendChild(this._container); - } - - this.fire('add'); - - map.on({ - 'viewreset': this.projectLatlngs, - 'moveend': this._updatePath - }, this); - }, - - addTo: function (map) { - map.addLayer(this); - return this; - }, - - onRemove: function (map) { - map._pathRoot.removeChild(this._container); - - // Need to fire remove event before we set _map to null as the event hooks might need the object - this.fire('remove'); - this._map = null; - - if (L.Browser.vml) { - this._container = null; - this._stroke = null; - this._fill = null; - } - - map.off({ - 'viewreset': this.projectLatlngs, - 'moveend': this._updatePath - }, this); - }, - - projectLatlngs: function () { - // do all projection stuff here - }, - - setStyle: function (style) { - L.setOptions(this, style); - - if (this._container) { - this._updateStyle(); - } - - return this; - }, - - redraw: function () { - if (this._map) { - this.projectLatlngs(); - this._updatePath(); - } - return this; - } -}); - -L.Map.include({ - _updatePathViewport: function () { - var p = L.Path.CLIP_PADDING, - size = this.getSize(), - panePos = L.DomUtil.getPosition(this._mapPane), - min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()), - max = min.add(size.multiplyBy(1 + p * 2)._round()); - - this._pathViewport = new L.Bounds(min, max); - } -}); - - -/* - * Extends L.Path with SVG-specific rendering code. - */ - -L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; - -L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); - -L.Path = L.Path.extend({ - statics: { - SVG: L.Browser.svg - }, - - bringToFront: function () { - var root = this._map._pathRoot, - path = this._container; - - if (path && root.lastChild !== path) { - root.appendChild(path); - } - return this; - }, - - bringToBack: function () { - var root = this._map._pathRoot, - path = this._container, - first = root.firstChild; - - if (path && first !== path) { - root.insertBefore(path, first); - } - return this; - }, - - getPathString: function () { - // form path string here - }, - - _createElement: function (name) { - return document.createElementNS(L.Path.SVG_NS, name); - }, - - _initElements: function () { - this._map._initPathRoot(); - this._initPath(); - this._initStyle(); - }, - - _initPath: function () { - this._container = this._createElement('g'); - - this._path = this._createElement('path'); - this._container.appendChild(this._path); - }, - - _initStyle: function () { - if (this.options.stroke) { - this._path.setAttribute('stroke-linejoin', 'round'); - this._path.setAttribute('stroke-linecap', 'round'); - } - if (this.options.fill) { - this._path.setAttribute('fill-rule', 'evenodd'); - } - if (this.options.pointerEvents) { - this._path.setAttribute('pointer-events', this.options.pointerEvents); - } - if (!this.options.clickable && !this.options.pointerEvents) { - this._path.setAttribute('pointer-events', 'none'); - } - this._updateStyle(); - }, - - _updateStyle: function () { - if (this.options.stroke) { - this._path.setAttribute('stroke', this.options.color); - this._path.setAttribute('stroke-opacity', this.options.opacity); - this._path.setAttribute('stroke-width', this.options.weight); - if (this.options.dashArray) { - this._path.setAttribute('stroke-dasharray', this.options.dashArray); - } else { - this._path.removeAttribute('stroke-dasharray'); - } - } else { - this._path.setAttribute('stroke', 'none'); - } - if (this.options.fill) { - this._path.setAttribute('fill', this.options.fillColor || this.options.color); - this._path.setAttribute('fill-opacity', this.options.fillOpacity); - } else { - this._path.setAttribute('fill', 'none'); - } - }, - - _updatePath: function () { - var str = this.getPathString(); - if (!str) { - // fix webkit empty string parsing bug - str = 'M0 0'; - } - this._path.setAttribute('d', str); - }, - - // TODO remove duplication with L.Map - _initEvents: function () { - if (this.options.clickable) { - if (L.Browser.svg || !L.Browser.vml) { - this._path.setAttribute('class', 'leaflet-clickable'); - } - - L.DomEvent.on(this._container, 'click', this._onMouseClick, this); - - var events = ['dblclick', 'mousedown', 'mouseover', - 'mouseout', 'mousemove', 'contextmenu']; - for (var i = 0; i < events.length; i++) { - L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this); - } - } - }, - - _onMouseClick: function (e) { - if (this._map.dragging && this._map.dragging.moved()) { return; } - - this._fireMouseEvent(e); - }, - - _fireMouseEvent: function (e) { - if (!this.hasEventListeners(e.type)) { return; } - - var map = this._map, - containerPoint = map.mouseEventToContainerPoint(e), - layerPoint = map.containerPointToLayerPoint(containerPoint), - latlng = map.layerPointToLatLng(layerPoint); - - this.fire(e.type, { - latlng: latlng, - layerPoint: layerPoint, - containerPoint: containerPoint, - originalEvent: e - }); - - if (e.type === 'contextmenu') { - L.DomEvent.preventDefault(e); - } - if (e.type !== 'mousemove') { - L.DomEvent.stopPropagation(e); - } - } -}); - -L.Map.include({ - _initPathRoot: function () { - if (!this._pathRoot) { - this._pathRoot = L.Path.prototype._createElement('svg'); - this._panes.overlayPane.appendChild(this._pathRoot); - - if (this.options.zoomAnimation && L.Browser.any3d) { - this._pathRoot.setAttribute('class', ' leaflet-zoom-animated'); - - this.on({ - 'zoomanim': this._animatePathZoom, - 'zoomend': this._endPathZoom - }); - } else { - this._pathRoot.setAttribute('class', ' leaflet-zoom-hide'); - } - - this.on('moveend', this._updateSvgViewport); - this._updateSvgViewport(); - } - }, - - _animatePathZoom: function (e) { - var scale = this.getZoomScale(e.zoom), - offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min); - - this._pathRoot.style[L.DomUtil.TRANSFORM] = - L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') '; - - this._pathZooming = true; - }, - - _endPathZoom: function () { - this._pathZooming = false; - }, - - _updateSvgViewport: function () { - - if (this._pathZooming) { - // Do not update SVGs while a zoom animation is going on otherwise the animation will break. - // When the zoom animation ends we will be updated again anyway - // This fixes the case where you do a momentum move and zoom while the move is still ongoing. - return; - } - - this._updatePathViewport(); - - var vp = this._pathViewport, - min = vp.min, - max = vp.max, - width = max.x - min.x, - height = max.y - min.y, - root = this._pathRoot, - pane = this._panes.overlayPane; - - // Hack to make flicker on drag end on mobile webkit less irritating - if (L.Browser.mobileWebkit) { - pane.removeChild(root); - } - - L.DomUtil.setPosition(root, min); - root.setAttribute('width', width); - root.setAttribute('height', height); - root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); - - if (L.Browser.mobileWebkit) { - pane.appendChild(root); - } - } -}); - - -/* - * Popup extension to L.Path (polylines, polygons, circles), adding popup-related methods. - */ - -L.Path.include({ - - bindPopup: function (content, options) { - - if (content instanceof L.Popup) { - this._popup = content; - } else { - if (!this._popup || options) { - this._popup = new L.Popup(options, this); - } - this._popup.setContent(content); - } - - if (!this._popupHandlersAdded) { - this - .on('click', this._openPopup, this) - .on('remove', this.closePopup, this); - - this._popupHandlersAdded = true; - } - - return this; - }, - - unbindPopup: function () { - if (this._popup) { - this._popup = null; - this - .off('click', this._openPopup) - .off('remove', this.closePopup); - - this._popupHandlersAdded = false; - } - return this; - }, - - openPopup: function (latlng) { - - if (this._popup) { - // open the popup from one of the path's points if not specified - latlng = latlng || this._latlng || - this._latlngs[Math.floor(this._latlngs.length / 2)]; - - this._openPopup({latlng: latlng}); - } - - return this; - }, - - closePopup: function () { - if (this._popup) { - this._popup._close(); - } - return this; - }, - - _openPopup: function (e) { - this._popup.setLatLng(e.latlng); - this._map.openPopup(this._popup); - } -}); - - -/* - * Vector rendering for IE6-8 through VML. - * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! - */ - -L.Browser.vml = !L.Browser.svg && (function () { - try { - var div = document.createElement('div'); - div.innerHTML = ''; - - var shape = div.firstChild; - shape.style.behavior = 'url(#default#VML)'; - - return shape && (typeof shape.adj === 'object'); - - } catch (e) { - return false; - } -}()); - -L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({ - statics: { - VML: true, - CLIP_PADDING: 0.02 - }, - - _createElement: (function () { - try { - document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); - return function (name) { - return document.createElement(''); - }; - } catch (e) { - return function (name) { - return document.createElement( - '<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); - }; - } - }()), - - _initPath: function () { - var container = this._container = this._createElement('shape'); - L.DomUtil.addClass(container, 'leaflet-vml-shape'); - if (this.options.clickable) { - L.DomUtil.addClass(container, 'leaflet-clickable'); - } - container.coordsize = '1 1'; - - this._path = this._createElement('path'); - container.appendChild(this._path); - - this._map._pathRoot.appendChild(container); - }, - - _initStyle: function () { - this._updateStyle(); - }, - - _updateStyle: function () { - var stroke = this._stroke, - fill = this._fill, - options = this.options, - container = this._container; - - container.stroked = options.stroke; - container.filled = options.fill; - - if (options.stroke) { - if (!stroke) { - stroke = this._stroke = this._createElement('stroke'); - stroke.endcap = 'round'; - container.appendChild(stroke); - } - stroke.weight = options.weight + 'px'; - stroke.color = options.color; - stroke.opacity = options.opacity; - - if (options.dashArray) { - stroke.dashStyle = options.dashArray instanceof Array ? - options.dashArray.join(' ') : - options.dashArray.replace(/( *, *)/g, ' '); - } else { - stroke.dashStyle = ''; - } - - } else if (stroke) { - container.removeChild(stroke); - this._stroke = null; - } - - if (options.fill) { - if (!fill) { - fill = this._fill = this._createElement('fill'); - container.appendChild(fill); - } - fill.color = options.fillColor || options.color; - fill.opacity = options.fillOpacity; - - } else if (fill) { - container.removeChild(fill); - this._fill = null; - } - }, - - _updatePath: function () { - var style = this._container.style; - - style.display = 'none'; - this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug - style.display = ''; - } -}); - -L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : { - _initPathRoot: function () { - if (this._pathRoot) { return; } - - var root = this._pathRoot = document.createElement('div'); - root.className = 'leaflet-vml-container'; - this._panes.overlayPane.appendChild(root); - - this.on('moveend', this._updatePathViewport); - this._updatePathViewport(); - } -}); - - -/* - * Vector rendering for all browsers that support canvas. - */ - -L.Browser.canvas = (function () { - return !!document.createElement('canvas').getContext; -}()); - -L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path : L.Path.extend({ - statics: { - //CLIP_PADDING: 0.02, // not sure if there's a need to set it to a small value - CANVAS: true, - SVG: false - }, - - redraw: function () { - if (this._map) { - this.projectLatlngs(); - this._requestUpdate(); - } - return this; - }, - - setStyle: function (style) { - L.setOptions(this, style); - - if (this._map) { - this._updateStyle(); - this._requestUpdate(); - } - return this; - }, - - onRemove: function (map) { - map - .off('viewreset', this.projectLatlngs, this) - .off('moveend', this._updatePath, this); - - if (this.options.clickable) { - this._map.off('click', this._onClick, this); - this._map.off('mousemove', this._onMouseMove, this); - } - - this._requestUpdate(); - - this._map = null; - }, - - _requestUpdate: function () { - if (this._map && !L.Path._updateRequest) { - L.Path._updateRequest = L.Util.requestAnimFrame(this._fireMapMoveEnd, this._map); - } - }, - - _fireMapMoveEnd: function () { - L.Path._updateRequest = null; - this.fire('moveend'); - }, - - _initElements: function () { - this._map._initPathRoot(); - this._ctx = this._map._canvasCtx; - }, - - _updateStyle: function () { - var options = this.options; - - if (options.stroke) { - this._ctx.lineWidth = options.weight; - this._ctx.strokeStyle = options.color; - } - if (options.fill) { - this._ctx.fillStyle = options.fillColor || options.color; - } - }, - - _drawPath: function () { - var i, j, len, len2, point, drawMethod; - - this._ctx.beginPath(); - - for (i = 0, len = this._parts.length; i < len; i++) { - for (j = 0, len2 = this._parts[i].length; j < len2; j++) { - point = this._parts[i][j]; - drawMethod = (j === 0 ? 'move' : 'line') + 'To'; - - this._ctx[drawMethod](point.x, point.y); - } - // TODO refactor ugly hack - if (this instanceof L.Polygon) { - this._ctx.closePath(); - } - } - }, - - _checkIfEmpty: function () { - return !this._parts.length; - }, - - _updatePath: function () { - if (this._checkIfEmpty()) { return; } - - var ctx = this._ctx, - options = this.options; - - this._drawPath(); - ctx.save(); - this._updateStyle(); - - if (options.fill) { - ctx.globalAlpha = options.fillOpacity; - ctx.fill(); - } - - if (options.stroke) { - ctx.globalAlpha = options.opacity; - ctx.stroke(); - } - - ctx.restore(); - - // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature - }, - - _initEvents: function () { - if (this.options.clickable) { - // TODO dblclick - this._map.on('mousemove', this._onMouseMove, this); - this._map.on('click', this._onClick, this); - } - }, - - _onClick: function (e) { - if (this._containsPoint(e.layerPoint)) { - this.fire('click', e); - } - }, - - _onMouseMove: function (e) { - if (!this._map || this._map._animatingZoom) { return; } - - // TODO don't do on each move - if (this._containsPoint(e.layerPoint)) { - this._ctx.canvas.style.cursor = 'pointer'; - this._mouseInside = true; - this.fire('mouseover', e); - - } else if (this._mouseInside) { - this._ctx.canvas.style.cursor = ''; - this._mouseInside = false; - this.fire('mouseout', e); - } - } -}); - -L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {} : { - _initPathRoot: function () { - var root = this._pathRoot, - ctx; - - if (!root) { - root = this._pathRoot = document.createElement('canvas'); - root.style.position = 'absolute'; - ctx = this._canvasCtx = root.getContext('2d'); - - ctx.lineCap = 'round'; - ctx.lineJoin = 'round'; - - this._panes.overlayPane.appendChild(root); - - if (this.options.zoomAnimation) { - this._pathRoot.className = 'leaflet-zoom-animated'; - this.on('zoomanim', this._animatePathZoom); - this.on('zoomend', this._endPathZoom); - } - this.on('moveend', this._updateCanvasViewport); - this._updateCanvasViewport(); - } - }, - - _updateCanvasViewport: function () { - // don't redraw while zooming. See _updateSvgViewport for more details - if (this._pathZooming) { return; } - this._updatePathViewport(); - - var vp = this._pathViewport, - min = vp.min, - size = vp.max.subtract(min), - root = this._pathRoot; - - //TODO check if this works properly on mobile webkit - L.DomUtil.setPosition(root, min); - root.width = size.x; - root.height = size.y; - root.getContext('2d').translate(-min.x, -min.y); - } -}); - - -/* - * L.LineUtil contains different utility functions for line segments - * and polylines (clipping, simplification, distances, etc.) - */ - -/*jshint bitwise:false */ // allow bitwise oprations for this file - -L.LineUtil = { - - // Simplify polyline with vertex reduction and Douglas-Peucker simplification. - // Improves rendering performance dramatically by lessening the number of points to draw. - - simplify: function (/*Point[]*/ points, /*Number*/ tolerance) { - if (!tolerance || !points.length) { - return points.slice(); - } - - var sqTolerance = tolerance * tolerance; - - // stage 1: vertex reduction - points = this._reducePoints(points, sqTolerance); - - // stage 2: Douglas-Peucker simplification - points = this._simplifyDP(points, sqTolerance); - - return points; - }, - - // distance from a point to a segment between two points - pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); - }, - - closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { - return this._sqClosestPointOnSegment(p, p1, p2); - }, - - // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm - _simplifyDP: function (points, sqTolerance) { - - var len = points.length, - ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, - markers = new ArrayConstructor(len); - - markers[0] = markers[len - 1] = 1; - - this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); - - var i, - newPoints = []; - - for (i = 0; i < len; i++) { - if (markers[i]) { - newPoints.push(points[i]); - } - } - - return newPoints; - }, - - _simplifyDPStep: function (points, markers, sqTolerance, first, last) { - - var maxSqDist = 0, - index, i, sqDist; - - for (i = first + 1; i <= last - 1; i++) { - sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); - - if (sqDist > maxSqDist) { - index = i; - maxSqDist = sqDist; - } - } - - if (maxSqDist > sqTolerance) { - markers[index] = 1; - - this._simplifyDPStep(points, markers, sqTolerance, first, index); - this._simplifyDPStep(points, markers, sqTolerance, index, last); - } - }, - - // reduce points that are too close to each other to a single point - _reducePoints: function (points, sqTolerance) { - var reducedPoints = [points[0]]; - - for (var i = 1, prev = 0, len = points.length; i < len; i++) { - if (this._sqDist(points[i], points[prev]) > sqTolerance) { - reducedPoints.push(points[i]); - prev = i; - } - } - if (prev < len - 1) { - reducedPoints.push(points[len - 1]); - } - return reducedPoints; - }, - - // Cohen-Sutherland line clipping algorithm. - // Used to avoid rendering parts of a polyline that are not currently visible. - - clipSegment: function (a, b, bounds, useLastCode) { - var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds), - codeB = this._getBitCode(b, bounds), - - codeOut, p, newCode; - - // save 2nd code to avoid calculating it on the next segment - this._lastCode = codeB; - - while (true) { - // if a,b is inside the clip window (trivial accept) - if (!(codeA | codeB)) { - return [a, b]; - // if a,b is outside the clip window (trivial reject) - } else if (codeA & codeB) { - return false; - // other cases - } else { - codeOut = codeA || codeB; - p = this._getEdgeIntersection(a, b, codeOut, bounds); - newCode = this._getBitCode(p, bounds); - - if (codeOut === codeA) { - a = p; - codeA = newCode; - } else { - b = p; - codeB = newCode; - } - } - } - }, - - _getEdgeIntersection: function (a, b, code, bounds) { - var dx = b.x - a.x, - dy = b.y - a.y, - min = bounds.min, - max = bounds.max; - - if (code & 8) { // top - return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y); - } else if (code & 4) { // bottom - return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y); - } else if (code & 2) { // right - return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx); - } else if (code & 1) { // left - return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx); - } - }, - - _getBitCode: function (/*Point*/ p, bounds) { - var code = 0; - - if (p.x < bounds.min.x) { // left - code |= 1; - } else if (p.x > bounds.max.x) { // right - code |= 2; - } - if (p.y < bounds.min.y) { // bottom - code |= 4; - } else if (p.y > bounds.max.y) { // top - code |= 8; - } - - return code; - }, - - // square distance (to avoid unnecessary Math.sqrt calls) - _sqDist: function (p1, p2) { - var dx = p2.x - p1.x, - dy = p2.y - p1.y; - return dx * dx + dy * dy; - }, - - // return closest point on segment or distance to that point - _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { - var x = p1.x, - y = p1.y, - dx = p2.x - x, - dy = p2.y - y, - dot = dx * dx + dy * dy, - t; - - if (dot > 0) { - t = ((p.x - x) * dx + (p.y - y) * dy) / dot; - - if (t > 1) { - x = p2.x; - y = p2.y; - } else if (t > 0) { - x += dx * t; - y += dy * t; - } - } - - dx = p.x - x; - dy = p.y - y; - - return sqDist ? dx * dx + dy * dy : new L.Point(x, y); - } -}; - - -/* - * L.Polyline is used to display polylines on a map. - */ - -L.Polyline = L.Path.extend({ - initialize: function (latlngs, options) { - L.Path.prototype.initialize.call(this, options); - - this._latlngs = this._convertLatLngs(latlngs); - }, - - options: { - // how much to simplify the polyline on each zoom level - // more = better performance and smoother look, less = more accurate - smoothFactor: 1.0, - noClip: false - }, - - projectLatlngs: function () { - this._originalPoints = []; - - for (var i = 0, len = this._latlngs.length; i < len; i++) { - this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]); - } - }, - - getPathString: function () { - for (var i = 0, len = this._parts.length, str = ''; i < len; i++) { - str += this._getPathPartStr(this._parts[i]); - } - return str; - }, - - getLatLngs: function () { - return this._latlngs; - }, - - setLatLngs: function (latlngs) { - this._latlngs = this._convertLatLngs(latlngs); - return this.redraw(); - }, - - addLatLng: function (latlng) { - this._latlngs.push(L.latLng(latlng)); - return this.redraw(); - }, - - spliceLatLngs: function () { // (Number index, Number howMany) - var removed = [].splice.apply(this._latlngs, arguments); - this._convertLatLngs(this._latlngs, true); - this.redraw(); - return removed; - }, - - closestLayerPoint: function (p) { - var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null; - - for (var j = 0, jLen = parts.length; j < jLen; j++) { - var points = parts[j]; - for (var i = 1, len = points.length; i < len; i++) { - p1 = points[i - 1]; - p2 = points[i]; - var sqDist = L.LineUtil._sqClosestPointOnSegment(p, p1, p2, true); - if (sqDist < minDistance) { - minDistance = sqDist; - minPoint = L.LineUtil._sqClosestPointOnSegment(p, p1, p2); - } - } - } - if (minPoint) { - minPoint.distance = Math.sqrt(minDistance); - } - return minPoint; - }, - - getBounds: function () { - return new L.LatLngBounds(this.getLatLngs()); - }, - - _convertLatLngs: function (latlngs, overwrite) { - var i, len, target = overwrite ? latlngs : []; - - for (i = 0, len = latlngs.length; i < len; i++) { - if (L.Util.isArray(latlngs[i]) && typeof latlngs[i][0] !== 'number') { - return; - } - target[i] = L.latLng(latlngs[i]); - } - return target; - }, - - _initEvents: function () { - L.Path.prototype._initEvents.call(this); - }, - - _getPathPartStr: function (points) { - var round = L.Path.VML; - - for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) { - p = points[j]; - if (round) { - p._round(); - } - str += (j ? 'L' : 'M') + p.x + ' ' + p.y; - } - return str; - }, - - _clipPoints: function () { - var points = this._originalPoints, - len = points.length, - i, k, segment; - - if (this.options.noClip) { - this._parts = [points]; - return; - } - - this._parts = []; - - var parts = this._parts, - vp = this._map._pathViewport, - lu = L.LineUtil; - - for (i = 0, k = 0; i < len - 1; i++) { - segment = lu.clipSegment(points[i], points[i + 1], vp, i); - if (!segment) { - continue; - } - - parts[k] = parts[k] || []; - parts[k].push(segment[0]); - - // if segment goes out of screen, or it's the last one, it's the end of the line part - if ((segment[1] !== points[i + 1]) || (i === len - 2)) { - parts[k].push(segment[1]); - k++; - } - } - }, - - // simplify each clipped part of the polyline - _simplifyPoints: function () { - var parts = this._parts, - lu = L.LineUtil; - - for (var i = 0, len = parts.length; i < len; i++) { - parts[i] = lu.simplify(parts[i], this.options.smoothFactor); - } - }, - - _updatePath: function () { - if (!this._map) { return; } - - this._clipPoints(); - this._simplifyPoints(); - - L.Path.prototype._updatePath.call(this); - } -}); - -L.polyline = function (latlngs, options) { - return new L.Polyline(latlngs, options); -}; - - -/* - * L.PolyUtil contains utility functions for polygons (clipping, etc.). - */ - -/*jshint bitwise:false */ // allow bitwise operations here - -L.PolyUtil = {}; - -/* - * Sutherland-Hodgeman polygon clipping algorithm. - * Used to avoid rendering parts of a polygon that are not currently visible. - */ -L.PolyUtil.clipPolygon = function (points, bounds) { - var clippedPoints, - edges = [1, 4, 2, 8], - i, j, k, - a, b, - len, edge, p, - lu = L.LineUtil; - - for (i = 0, len = points.length; i < len; i++) { - points[i]._code = lu._getBitCode(points[i], bounds); - } - - // for each edge (left, bottom, right, top) - for (k = 0; k < 4; k++) { - edge = edges[k]; - clippedPoints = []; - - for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { - a = points[i]; - b = points[j]; - - // if a is inside the clip window - if (!(a._code & edge)) { - // if b is outside the clip window (a->b goes out of screen) - if (b._code & edge) { - p = lu._getEdgeIntersection(b, a, edge, bounds); - p._code = lu._getBitCode(p, bounds); - clippedPoints.push(p); - } - clippedPoints.push(a); - - // else if b is inside the clip window (a->b enters the screen) - } else if (!(b._code & edge)) { - p = lu._getEdgeIntersection(b, a, edge, bounds); - p._code = lu._getBitCode(p, bounds); - clippedPoints.push(p); - } - } - points = clippedPoints; - } - - return points; -}; - - -/* - * L.Polygon is used to display polygons on a map. - */ - -L.Polygon = L.Polyline.extend({ - options: { - fill: true - }, - - initialize: function (latlngs, options) { - var i, len, hole; - - L.Polyline.prototype.initialize.call(this, latlngs, options); - - if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) { - this._latlngs = this._convertLatLngs(latlngs[0]); - this._holes = latlngs.slice(1); - - for (i = 0, len = this._holes.length; i < len; i++) { - hole = this._holes[i] = this._convertLatLngs(this._holes[i]); - if (hole[0].equals(hole[hole.length - 1])) { - hole.pop(); - } - } - } - - // filter out last point if its equal to the first one - latlngs = this._latlngs; - - if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) { - latlngs.pop(); - } - }, - - projectLatlngs: function () { - L.Polyline.prototype.projectLatlngs.call(this); - - // project polygon holes points - // TODO move this logic to Polyline to get rid of duplication - this._holePoints = []; - - if (!this._holes) { return; } - - var i, j, len, len2; - - for (i = 0, len = this._holes.length; i < len; i++) { - this._holePoints[i] = []; - - for (j = 0, len2 = this._holes[i].length; j < len2; j++) { - this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]); - } - } - }, - - _clipPoints: function () { - var points = this._originalPoints, - newParts = []; - - this._parts = [points].concat(this._holePoints); - - if (this.options.noClip) { return; } - - for (var i = 0, len = this._parts.length; i < len; i++) { - var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport); - if (clipped.length) { - newParts.push(clipped); - } - } - - this._parts = newParts; - }, - - _getPathPartStr: function (points) { - var str = L.Polyline.prototype._getPathPartStr.call(this, points); - return str + (L.Browser.svg ? 'z' : 'x'); - } -}); - -L.polygon = function (latlngs, options) { - return new L.Polygon(latlngs, options); -}; - - -/* - * Contains L.MultiPolyline and L.MultiPolygon layers. - */ - -(function () { - function createMulti(Klass) { - - return L.FeatureGroup.extend({ - - initialize: function (latlngs, options) { - this._layers = {}; - this._options = options; - this.setLatLngs(latlngs); - }, - - setLatLngs: function (latlngs) { - var i = 0, - len = latlngs.length; - - this.eachLayer(function (layer) { - if (i < len) { - layer.setLatLngs(latlngs[i++]); - } else { - this.removeLayer(layer); - } - }, this); - - while (i < len) { - this.addLayer(new Klass(latlngs[i++], this._options)); - } - - return this; - } - }); - } - - L.MultiPolyline = createMulti(L.Polyline); - L.MultiPolygon = createMulti(L.Polygon); - - L.multiPolyline = function (latlngs, options) { - return new L.MultiPolyline(latlngs, options); - }; - - L.multiPolygon = function (latlngs, options) { - return new L.MultiPolygon(latlngs, options); - }; -}()); - - -/* - * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object. - */ - -L.Rectangle = L.Polygon.extend({ - initialize: function (latLngBounds, options) { - L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options); - }, - - setBounds: function (latLngBounds) { - this.setLatLngs(this._boundsToLatLngs(latLngBounds)); - }, - - _boundsToLatLngs: function (latLngBounds) { - latLngBounds = L.latLngBounds(latLngBounds); - return [ - latLngBounds.getSouthWest(), - latLngBounds.getNorthWest(), - latLngBounds.getNorthEast(), - latLngBounds.getSouthEast() - ]; - } -}); - -L.rectangle = function (latLngBounds, options) { - return new L.Rectangle(latLngBounds, options); -}; - - -/* - * L.Circle is a circle overlay (with a certain radius in meters). - */ - -L.Circle = L.Path.extend({ - initialize: function (latlng, radius, options) { - L.Path.prototype.initialize.call(this, options); - - this._latlng = L.latLng(latlng); - this._mRadius = radius; - }, - - options: { - fill: true - }, - - setLatLng: function (latlng) { - this._latlng = L.latLng(latlng); - return this.redraw(); - }, - - setRadius: function (radius) { - this._mRadius = radius; - return this.redraw(); - }, - - projectLatlngs: function () { - var lngRadius = this._getLngRadius(), - latlng = this._latlng, - pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]); - - this._point = this._map.latLngToLayerPoint(latlng); - this._radius = Math.max(this._point.x - pointLeft.x, 1); - }, - - getBounds: function () { - var lngRadius = this._getLngRadius(), - latRadius = (this._mRadius / 40075017) * 360, - latlng = this._latlng; - - return new L.LatLngBounds( - [latlng.lat - latRadius, latlng.lng - lngRadius], - [latlng.lat + latRadius, latlng.lng + lngRadius]); - }, - - getLatLng: function () { - return this._latlng; - }, - - getPathString: function () { - var p = this._point, - r = this._radius; - - if (this._checkIfEmpty()) { - return ''; - } - - if (L.Browser.svg) { - return 'M' + p.x + ',' + (p.y - r) + - 'A' + r + ',' + r + ',0,1,1,' + - (p.x - 0.1) + ',' + (p.y - r) + ' z'; - } else { - p._round(); - r = Math.round(r); - return 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r + ' 0,' + (65535 * 360); - } - }, - - getRadius: function () { - return this._mRadius; - }, - - // TODO Earth hardcoded, move into projection code! - - _getLatRadius: function () { - return (this._mRadius / 40075017) * 360; - }, - - _getLngRadius: function () { - return this._getLatRadius() / Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat); - }, - - _checkIfEmpty: function () { - if (!this._map) { - return false; - } - var vp = this._map._pathViewport, - r = this._radius, - p = this._point; - - return p.x - r > vp.max.x || p.y - r > vp.max.y || - p.x + r < vp.min.x || p.y + r < vp.min.y; - } -}); - -L.circle = function (latlng, radius, options) { - return new L.Circle(latlng, radius, options); -}; - - -/* - * L.CircleMarker is a circle overlay with a permanent pixel radius. - */ - -L.CircleMarker = L.Circle.extend({ - options: { - radius: 10, - weight: 2 - }, - - initialize: function (latlng, options) { - L.Circle.prototype.initialize.call(this, latlng, null, options); - this._radius = this.options.radius; - }, - - projectLatlngs: function () { - this._point = this._map.latLngToLayerPoint(this._latlng); - }, - - _updateStyle : function () { - L.Circle.prototype._updateStyle.call(this); - this.setRadius(this.options.radius); - }, - - setRadius: function (radius) { - this.options.radius = this._radius = radius; - return this.redraw(); - } -}); - -L.circleMarker = function (latlng, options) { - return new L.CircleMarker(latlng, options); -}; - - -/* - * Extends L.Polyline to be able to manually detect clicks on Canvas-rendered polylines. - */ - -L.Polyline.include(!L.Path.CANVAS ? {} : { - _containsPoint: function (p, closed) { - var i, j, k, len, len2, dist, part, - w = this.options.weight / 2; - - if (L.Browser.touch) { - w += 10; // polyline click tolerance on touch devices - } - - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - if (!closed && (j === 0)) { - continue; - } - - dist = L.LineUtil.pointToSegmentDistance(p, part[k], part[j]); - - if (dist <= w) { - return true; - } - } - } - return false; - } -}); - - -/* - * Extends L.Polygon to be able to manually detect clicks on Canvas-rendered polygons. - */ - -L.Polygon.include(!L.Path.CANVAS ? {} : { - _containsPoint: function (p) { - var inside = false, - part, p1, p2, - i, j, k, - len, len2; - - // TODO optimization: check if within bounds first - - if (L.Polyline.prototype._containsPoint.call(this, p, true)) { - // click on polygon border - return true; - } - - // ray casting algorithm for detecting if point is in polygon - - for (i = 0, len = this._parts.length; i < len; i++) { - part = this._parts[i]; - - for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { - p1 = part[j]; - p2 = part[k]; - - if (((p1.y > p.y) !== (p2.y > p.y)) && - (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { - inside = !inside; - } - } - } - - return inside; - } -}); - - -/* - * Extends L.Circle with Canvas-specific code. - */ - -L.Circle.include(!L.Path.CANVAS ? {} : { - _drawPath: function () { - var p = this._point; - this._ctx.beginPath(); - this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false); - }, - - _containsPoint: function (p) { - var center = this._point, - w2 = this.options.stroke ? this.options.weight / 2 : 0; - - return (p.distanceTo(center) <= this._radius + w2); - } -}); - - -/* - * CircleMarker canvas specific drawing parts. - */ - -L.CircleMarker.include(!L.Path.CANVAS ? {} : { - _updateStyle: function () { - L.Path.prototype._updateStyle.call(this); - } -}); - - -/* - * L.GeoJSON turns any GeoJSON data into a Leaflet layer. - */ - -L.GeoJSON = L.FeatureGroup.extend({ - - initialize: function (geojson, options) { - L.setOptions(this, options); - - this._layers = {}; - - if (geojson) { - this.addData(geojson); - } - }, - - addData: function (geojson) { - var features = L.Util.isArray(geojson) ? geojson : geojson.features, - i, len; - - if (features) { - for (i = 0, len = features.length; i < len; i++) { - // Only add this if geometry or geometries are set and not null - if (features[i].geometries || features[i].geometry || features[i].features) { - this.addData(features[i]); - } - } - return this; - } - - var options = this.options; - - if (options.filter && !options.filter(geojson)) { return; } - - var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng); - layer.feature = L.GeoJSON.asFeature(geojson); - - layer.defaultOptions = layer.options; - this.resetStyle(layer); - - if (options.onEachFeature) { - options.onEachFeature(geojson, layer); - } - - return this.addLayer(layer); - }, - - resetStyle: function (layer) { - var style = this.options.style; - if (style) { - // reset any custom styles - L.Util.extend(layer.options, layer.defaultOptions); - - this._setLayerStyle(layer, style); - } - }, +/* + * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps. + */ - setStyle: function (style) { - this.eachLayer(function (layer) { - this._setLayerStyle(layer, style); - }, this); - }, +L.CRS.Simple = L.extend({}, L.CRS, { + projection: L.Projection.LonLat, + transformation: new L.Transformation(1, 0, -1, 0), - _setLayerStyle: function (layer, style) { - if (typeof style === 'function') { - style = style(layer.feature); - } - if (layer.setStyle) { - layer.setStyle(style); - } + scale: function (zoom) { + return Math.pow(2, zoom); } }); -L.extend(L.GeoJSON, { - geometryToLayer: function (geojson, pointToLayer, coordsToLatLng) { - var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, - coords = geometry.coordinates, - layers = [], - latlng, latlngs, i, len, layer; - - coordsToLatLng = coordsToLatLng || this.coordsToLatLng; - - switch (geometry.type) { - case 'Point': - latlng = coordsToLatLng(coords); - return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); - - case 'MultiPoint': - for (i = 0, len = coords.length; i < len; i++) { - latlng = coordsToLatLng(coords[i]); - layer = pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); - layers.push(layer); - } - return new L.FeatureGroup(layers); - - case 'LineString': - latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng); - return new L.Polyline(latlngs); - case 'Polygon': - latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); - return new L.Polygon(latlngs); +/* + * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping + * and is used by Leaflet by default. + */ + +L.CRS.EPSG3857 = L.extend({}, L.CRS, { + code: 'EPSG:3857', + + projection: L.Projection.SphericalMercator, + transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5), + + project: function (latlng) { // (LatLng) -> Point + var projectedPoint = this.projection.project(latlng), + earthRadius = 6378137; + return projectedPoint.multiplyBy(earthRadius); + } +}); + +L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, { + code: 'EPSG:900913' +}); + + +/* + * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists. + */ + +L.CRS.EPSG4326 = L.extend({}, L.CRS, { + code: 'EPSG:4326', + + projection: L.Projection.LonLat, + transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5) +}); + + +/* + * L.Map is the central class of the API - it is used to create a map. + */ + +L.Map = L.Class.extend({ + + includes: L.Mixin.Events, + + options: { + crs: L.CRS.EPSG3857, + + /* + center: LatLng, + zoom: Number, + layers: Array, + */ + + fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23, + trackResize: true, + markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d + }, + + initialize: function (id, options) { // (HTMLElement or String, Object) + options = L.setOptions(this, options); + + this._initContainer(id); + this._initLayout(); + this._initEvents(); + + if (options.maxBounds) { + this.setMaxBounds(options.maxBounds); + } + + if (options.center && options.zoom !== undefined) { + this.setView(L.latLng(options.center), options.zoom, {reset: true}); + } + + this._handlers = []; + + this._layers = {}; + this._zoomBoundLayers = {}; + this._tileLayersNum = 0; + + this.callInitHooks(); + + this._addLayers(options.layers); + }, + + + // public methods that modify map state + + // replaced by animation-powered implementation in Map.PanAnimation.js + setView: function (center, zoom) { + this._resetView(L.latLng(center), this._limitZoom(zoom)); + return this; + }, + + setZoom: function (zoom, options) { + return this.setView(this.getCenter(), zoom, {zoom: options}); + }, + + zoomIn: function (delta, options) { + return this.setZoom(this._zoom + (delta || 1), options); + }, + + zoomOut: function (delta, options) { + return this.setZoom(this._zoom - (delta || 1), options); + }, + + setZoomAround: function (latlng, zoom, options) { + var scale = this.getZoomScale(zoom), + viewHalf = this.getSize().divideBy(2), + containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng), + + centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), + newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); + + return this.setView(newCenter, zoom, {zoom: options}); + }, + + fitBounds: function (bounds, options) { + + options = options || {}; + bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds); + + var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]), + paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]), + + zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)), + paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), + + swPoint = this.project(bounds.getSouthWest(), zoom), + nePoint = this.project(bounds.getNorthEast(), zoom), + center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); + + return this.setView(center, zoom, options); + }, + + fitWorld: function (options) { + return this.fitBounds([[-90, -180], [90, 180]], options); + }, + + panTo: function (center, options) { // (LatLng) + return this.setView(center, this._zoom, {pan: options}); + }, + + panBy: function (offset) { // (Point) + // replaced with animated panBy in Map.Animation.js + this.fire('movestart'); + + this._rawPanBy(L.point(offset)); + + this.fire('move'); + return this.fire('moveend'); + }, + + setMaxBounds: function (bounds) { + bounds = L.latLngBounds(bounds); + + this.options.maxBounds = bounds; + + if (!bounds) { + this._boundsMinZoom = null; + this.off('moveend', this._panInsideMaxBounds, this); + return this; + } + + var minZoom = this.getBoundsZoom(bounds, true); + + this._boundsMinZoom = minZoom; + + if (this._loaded) { + if (this._zoom < minZoom) { + this.setView(bounds.getCenter(), minZoom); + } else { + this.panInsideBounds(bounds); + } + } + + this.on('moveend', this._panInsideMaxBounds, this); + + return this; + }, + + panInsideBounds: function (bounds) { + bounds = L.latLngBounds(bounds); + + var viewBounds = this.getPixelBounds(), + viewSw = viewBounds.getBottomLeft(), + viewNe = viewBounds.getTopRight(), + sw = this.project(bounds.getSouthWest()), + ne = this.project(bounds.getNorthEast()), + dx = 0, + dy = 0; + + if (viewNe.y < ne.y) { // north + dy = Math.ceil(ne.y - viewNe.y); + } + if (viewNe.x > ne.x) { // east + dx = Math.floor(ne.x - viewNe.x); + } + if (viewSw.y > sw.y) { // south + dy = Math.floor(sw.y - viewSw.y); + } + if (viewSw.x < sw.x) { // west + dx = Math.ceil(sw.x - viewSw.x); + } + + if (dx || dy) { + return this.panBy([dx, dy]); + } + + return this; + }, + + addLayer: function (layer) { + // TODO method is too big, refactor + + var id = L.stamp(layer); + + if (this._layers[id]) { return this; } + + this._layers[id] = layer; + + // TODO getMaxZoom, getMinZoom in ILayer (instead of options) + if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) { + this._zoomBoundLayers[id] = layer; + this._updateZoomLevels(); + } + + // TODO looks ugly, refactor!!! + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { + this._tileLayersNum++; + this._tileLayersToLoad++; + layer.on('load', this._onTileLayerLoad, this); + } + + if (this._loaded) { + this._layerAdd(layer); + } + + return this; + }, + + removeLayer: function (layer) { + var id = L.stamp(layer); + + if (!this._layers[id]) { return; } + + if (this._loaded) { + layer.onRemove(this); + this.fire('layerremove', {layer: layer}); + } + + delete this._layers[id]; + if (this._zoomBoundLayers[id]) { + delete this._zoomBoundLayers[id]; + this._updateZoomLevels(); + } + + // TODO looks ugly, refactor + if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) { + this._tileLayersNum--; + this._tileLayersToLoad--; + layer.off('load', this._onTileLayerLoad, this); + } + + return this; + }, + + hasLayer: function (layer) { + if (!layer) { return false; } + + return (L.stamp(layer) in this._layers); + }, + + eachLayer: function (method, context) { + for (var i in this._layers) { + method.call(context, this._layers[i]); + } + return this; + }, + + invalidateSize: function (options) { + options = L.extend({ + animate: false, + pan: true + }, options === true ? {animate: true} : options); + + var oldSize = this.getSize(); + this._sizeChanged = true; + + if (this.options.maxBounds) { + this.setMaxBounds(this.options.maxBounds); + } + + if (!this._loaded) { return this; } + + var newSize = this.getSize(), + offset = oldSize.subtract(newSize).divideBy(2).round(); + + if (!offset.x && !offset.y) { return this; } + + if (options.animate && options.pan) { + this.panBy(offset); + + } else { + if (options.pan) { + this._rawPanBy(offset); + } + + this.fire('move'); + + // make sure moveend is not fired too often on resize + clearTimeout(this._sizeTimer); + this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200); + } + + return this.fire('resize', { + oldSize: oldSize, + newSize: newSize + }); + }, + + // TODO handler.addTo + addHandler: function (name, HandlerClass) { + if (!HandlerClass) { return; } + + var handler = this[name] = new HandlerClass(this); + + this._handlers.push(handler); + + if (this.options[name]) { + handler.enable(); + } + + return this; + }, + + remove: function () { + if (this._loaded) { + this.fire('unload'); + } + + this._initEvents('off'); + + delete this._container._leaflet; + + this._clearPanes(); + if (this._clearControlPos) { + this._clearControlPos(); + } + + this._clearHandlers(); + + return this; + }, + + + // public methods for getting map state + + getCenter: function () { // (Boolean) -> LatLng + this._checkIfLoaded(); + + if (!this._moved()) { + return this._initialCenter; + } + return this.layerPointToLatLng(this._getCenterLayerPoint()); + }, + + getZoom: function () { + return this._zoom; + }, + + getBounds: function () { + var bounds = this.getPixelBounds(), + sw = this.unproject(bounds.getBottomLeft()), + ne = this.unproject(bounds.getTopRight()); + + return new L.LatLngBounds(sw, ne); + }, + + getMinZoom: function () { + var z1 = this.options.minZoom || 0, + z2 = this._layersMinZoom || 0, + z3 = this._boundsMinZoom || 0; + + return Math.max(z1, z2, z3); + }, + + getMaxZoom: function () { + var z1 = this.options.maxZoom === undefined ? Infinity : this.options.maxZoom, + z2 = this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom; + + return Math.min(z1, z2); + }, + + getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number + bounds = L.latLngBounds(bounds); + + var zoom = this.getMinZoom() - (inside ? 1 : 0), + maxZoom = this.getMaxZoom(), + size = this.getSize(), + + nw = bounds.getNorthWest(), + se = bounds.getSouthEast(), + + zoomNotFound = true, + boundsSize; + + padding = L.point(padding || [0, 0]); + + do { + zoom++; + boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding); + zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y; + + } while (zoomNotFound && zoom <= maxZoom); + + if (zoomNotFound && inside) { + return null; + } + + return inside ? zoom : zoom - 1; + }, + + getSize: function () { + if (!this._size || this._sizeChanged) { + this._size = new L.Point( + this._container.clientWidth, + this._container.clientHeight); + + this._sizeChanged = false; + } + return this._size.clone(); + }, + + getPixelBounds: function () { + var topLeftPoint = this._getTopLeftPoint(); + return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); + }, + + getPixelOrigin: function () { + this._checkIfLoaded(); + return this._initialTopLeftPoint; + }, + + getPanes: function () { + return this._panes; + }, + + getContainer: function () { + return this._container; + }, + + + // TODO replace with universal implementation after refactoring projections + + getZoomScale: function (toZoom) { + var crs = this.options.crs; + return crs.scale(toZoom) / crs.scale(this._zoom); + }, + + getScaleZoom: function (scale) { + return this._zoom + (Math.log(scale) / Math.LN2); + }, + + + // conversion methods + + project: function (latlng, zoom) { // (LatLng[, Number]) -> Point + zoom = zoom === undefined ? this._zoom : zoom; + return this.options.crs.latLngToPoint(L.latLng(latlng), zoom); + }, + + unproject: function (point, zoom) { // (Point[, Number]) -> LatLng + zoom = zoom === undefined ? this._zoom : zoom; + return this.options.crs.pointToLatLng(L.point(point), zoom); + }, + + layerPointToLatLng: function (point) { // (Point) + var projectedPoint = L.point(point).add(this.getPixelOrigin()); + return this.unproject(projectedPoint); + }, + + latLngToLayerPoint: function (latlng) { // (LatLng) + var projectedPoint = this.project(L.latLng(latlng))._round(); + return projectedPoint._subtract(this.getPixelOrigin()); + }, + + containerPointToLayerPoint: function (point) { // (Point) + return L.point(point).subtract(this._getMapPanePos()); + }, + + layerPointToContainerPoint: function (point) { // (Point) + return L.point(point).add(this._getMapPanePos()); + }, + + containerPointToLatLng: function (point) { + var layerPoint = this.containerPointToLayerPoint(L.point(point)); + return this.layerPointToLatLng(layerPoint); + }, + + latLngToContainerPoint: function (latlng) { + return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng))); + }, + + mouseEventToContainerPoint: function (e) { // (MouseEvent) + return L.DomEvent.getMousePosition(e, this._container); + }, + + mouseEventToLayerPoint: function (e) { // (MouseEvent) + return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); + }, + + mouseEventToLatLng: function (e) { // (MouseEvent) + return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); + }, + + + // map initialization methods + + _initContainer: function (id) { + var container = this._container = L.DomUtil.get(id); + + if (!container) { + throw new Error('Map container not found.'); + } else if (container._leaflet) { + throw new Error('Map container is already initialized.'); + } + + container._leaflet = true; + }, + + _initLayout: function () { + var container = this._container; + + L.DomUtil.addClass(container, 'leaflet-container' + + (L.Browser.touch ? ' leaflet-touch' : '') + + (L.Browser.retina ? ' leaflet-retina' : '') + + (this.options.fadeAnimation ? ' leaflet-fade-anim' : '')); + + var position = L.DomUtil.getStyle(container, 'position'); + + if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') { + container.style.position = 'relative'; + } + + this._initPanes(); + + if (this._initControlPos) { + this._initControlPos(); + } + }, + + _initPanes: function () { + var panes = this._panes = {}; + + this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container); + + this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane); + panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane); + panes.shadowPane = this._createPane('leaflet-shadow-pane'); + panes.overlayPane = this._createPane('leaflet-overlay-pane'); + panes.markerPane = this._createPane('leaflet-marker-pane'); + panes.popupPane = this._createPane('leaflet-popup-pane'); + + var zoomHide = ' leaflet-zoom-hide'; + + if (!this.options.markerZoomAnimation) { + L.DomUtil.addClass(panes.markerPane, zoomHide); + L.DomUtil.addClass(panes.shadowPane, zoomHide); + L.DomUtil.addClass(panes.popupPane, zoomHide); + } + }, + + _createPane: function (className, container) { + return L.DomUtil.create('div', className, container || this._panes.objectsPane); + }, + + _clearPanes: function () { + this._container.removeChild(this._mapPane); + }, + + _addLayers: function (layers) { + layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : []; + + for (var i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + }, + + + // private methods that modify map state + + _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) { + + var zoomChanged = (this._zoom !== zoom); + + if (!afterZoomAnim) { + this.fire('movestart'); + + if (zoomChanged) { + this.fire('zoomstart'); + } + } + + this._zoom = zoom; + this._initialCenter = center; + + this._initialTopLeftPoint = this._getNewTopLeftPoint(center); + + if (!preserveMapOffset) { + L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0)); + } else { + this._initialTopLeftPoint._add(this._getMapPanePos()); + } + + this._tileLayersToLoad = this._tileLayersNum; + + var loading = !this._loaded; + this._loaded = true; + + if (loading) { + this.fire('load'); + this.eachLayer(this._layerAdd, this); + } + + this.fire('viewreset', {hard: !preserveMapOffset}); + + this.fire('move'); + + if (zoomChanged || afterZoomAnim) { + this.fire('zoomend'); + } + + this.fire('moveend', {hard: !preserveMapOffset}); + }, + + _rawPanBy: function (offset) { + L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); + }, + + _getZoomSpan: function () { + return this.getMaxZoom() - this.getMinZoom(); + }, + + _updateZoomLevels: function () { + var i, + minZoom = Infinity, + maxZoom = -Infinity, + oldZoomSpan = this._getZoomSpan(); + + for (i in this._zoomBoundLayers) { + var layer = this._zoomBoundLayers[i]; + if (!isNaN(layer.options.minZoom)) { + minZoom = Math.min(minZoom, layer.options.minZoom); + } + if (!isNaN(layer.options.maxZoom)) { + maxZoom = Math.max(maxZoom, layer.options.maxZoom); + } + } + + if (i === undefined) { // we have no tilelayers + this._layersMaxZoom = this._layersMinZoom = undefined; + } else { + this._layersMaxZoom = maxZoom; + this._layersMinZoom = minZoom; + } + + if (oldZoomSpan !== this._getZoomSpan()) { + this.fire('zoomlevelschange'); + } + }, + + _panInsideMaxBounds: function () { + this.panInsideBounds(this.options.maxBounds); + }, + + _checkIfLoaded: function () { + if (!this._loaded) { + throw new Error('Set map center and zoom first.'); + } + }, + + // map events + + _initEvents: function (onOff) { + if (!L.DomEvent) { return; } + + onOff = onOff || 'on'; + + L.DomEvent[onOff](this._container, 'click', this._onMouseClick, this); + + var events = ['dblclick', 'mousedown', 'mouseup', 'mouseenter', + 'mouseleave', 'mousemove', 'contextmenu'], + i, len; + + for (i = 0, len = events.length; i < len; i++) { + L.DomEvent[onOff](this._container, events[i], this._fireMouseEvent, this); + } + + if (this.options.trackResize) { + L.DomEvent[onOff](window, 'resize', this._onResize, this); + } + }, + + _onResize: function () { + L.Util.cancelAnimFrame(this._resizeRequest); + this._resizeRequest = L.Util.requestAnimFrame( + this.invalidateSize, this, false, this._container); + }, + + _onMouseClick: function (e) { + // jshint camelcase: false + if (!this._loaded || (!e._simulated && this.dragging && this.dragging.moved()) || e._leaflet_stop) { return; } + + this.fire('preclick'); + this._fireMouseEvent(e); + }, + + _fireMouseEvent: function (e) { + // jshint camelcase: false + if (!this._loaded || e._leaflet_stop) { return; } + + var type = e.type; + + type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type)); + + if (!this.hasEventListeners(type)) { return; } + + if (type === 'contextmenu') { + L.DomEvent.preventDefault(e); + } + + var containerPoint = this.mouseEventToContainerPoint(e), + layerPoint = this.containerPointToLayerPoint(containerPoint), + latlng = this.layerPointToLatLng(layerPoint); + + this.fire(type, { + latlng: latlng, + layerPoint: layerPoint, + containerPoint: containerPoint, + originalEvent: e + }); + }, + + _onTileLayerLoad: function () { + this._tileLayersToLoad--; + if (this._tileLayersNum && !this._tileLayersToLoad) { + this.fire('tilelayersload'); + } + }, + + _clearHandlers: function () { + for (var i = 0, len = this._handlers.length; i < len; i++) { + this._handlers[i].disable(); + } + }, + + whenReady: function (callback, context) { + if (this._loaded) { + callback.call(context || this, this); + } else { + this.on('load', callback, context); + } + return this; + }, + + _layerAdd: function (layer) { + layer.onAdd(this); + this.fire('layeradd', {layer: layer}); + }, + + + // private methods for getting map state + + _getMapPanePos: function () { + return L.DomUtil.getPosition(this._mapPane); + }, + + _moved: function () { + var pos = this._getMapPanePos(); + return pos && !pos.equals([0, 0]); + }, + + _getTopLeftPoint: function () { + return this.getPixelOrigin().subtract(this._getMapPanePos()); + }, + + _getNewTopLeftPoint: function (center, zoom) { + var viewHalf = this.getSize()._divideBy(2); + // TODO round on display, not calculation to increase precision? + return this.project(center, zoom)._subtract(viewHalf)._round(); + }, + + _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) { + var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos()); + return this.project(latlng, newZoom)._subtract(topLeft); + }, + + // layer point of the current center + _getCenterLayerPoint: function () { + return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); + }, + + // offset of the specified place to the current center in pixels + _getCenterOffset: function (latlng) { + return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); + }, + + _limitZoom: function (zoom) { + var min = this.getMinZoom(), + max = this.getMaxZoom(); + + return Math.max(min, Math.min(max, zoom)); + } +}); + +L.map = function (id, options) { + return new L.Map(id, options); +}; + + +/* + * Mercator projection that takes into account that the Earth is not a perfect sphere. + * Less popular than spherical mercator; used by projections like EPSG:3395. + */ + +L.Projection.Mercator = { + MAX_LATITUDE: 85.0840591556, + + R_MINOR: 6356752.314245179, + R_MAJOR: 6378137, + + project: function (latlng) { // (LatLng) -> Point + var d = L.LatLng.DEG_TO_RAD, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + r = this.R_MAJOR, + r2 = this.R_MINOR, + x = latlng.lng * d * r, + y = lat * d, + tmp = r2 / r, + eccent = Math.sqrt(1.0 - tmp * tmp), + con = eccent * Math.sin(y); + + con = Math.pow((1 - con) / (1 + con), eccent * 0.5); + + var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con; + y = -r * Math.log(ts); + + return new L.Point(x, y); + }, + + unproject: function (point) { // (Point, Boolean) -> LatLng + var d = L.LatLng.RAD_TO_DEG, + r = this.R_MAJOR, + r2 = this.R_MINOR, + lng = point.x * d / r, + tmp = r2 / r, + eccent = Math.sqrt(1 - (tmp * tmp)), + ts = Math.exp(- point.y / r), + phi = (Math.PI / 2) - 2 * Math.atan(ts), + numIter = 15, + tol = 1e-7, + i = numIter, + dphi = 0.1, + con; + + while ((Math.abs(dphi) > tol) && (--i > 0)) { + con = eccent * Math.sin(phi); + dphi = (Math.PI / 2) - 2 * Math.atan(ts * + Math.pow((1.0 - con) / (1.0 + con), 0.5 * eccent)) - phi; + phi += dphi; + } + + return new L.LatLng(phi * d, lng); + } +}; + + + +L.CRS.EPSG3395 = L.extend({}, L.CRS, { + code: 'EPSG:3395', + + projection: L.Projection.Mercator, + + transformation: (function () { + var m = L.Projection.Mercator, + r = m.R_MAJOR, + r2 = m.R_MINOR; + + return new L.Transformation(0.5 / (Math.PI * r), 0.5, -0.5 / (Math.PI * r2), 0.5); + }()) +}); + + +/* + * L.TileLayer is used for standard xyz-numbered tile layers. + */ + +L.TileLayer = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + minZoom: 0, + maxZoom: 18, + tileSize: 256, + subdomains: 'abc', + errorTileUrl: '', + attribution: '', + zoomOffset: 0, + opacity: 1, + /* (undefined works too) + zIndex: null, + tms: false, + continuousWorld: false, + noWrap: false, + zoomReverse: false, + detectRetina: false, + reuseTiles: false, + bounds: false, + */ + unloadInvisibleTiles: L.Browser.mobile, + updateWhenIdle: L.Browser.mobile + }, + + initialize: function (url, options) { + options = L.setOptions(this, options); + + // detecting retina displays, adjusting tileSize and zoom levels + if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) { + + options.tileSize = Math.floor(options.tileSize / 2); + options.zoomOffset++; + + if (options.minZoom > 0) { + options.minZoom--; + } + this.options.maxZoom--; + } + + if (options.bounds) { + options.bounds = L.latLngBounds(options.bounds); + } + + this._url = url; + + var subdomains = this.options.subdomains; + + if (typeof subdomains === 'string') { + this.options.subdomains = subdomains.split(''); + } + }, + + onAdd: function (map) { + this._map = map; + this._animated = map._zoomAnimated; + + // create a container div for tiles + this._initContainer(); + + // create an image to clone for tiles + this._createTileProto(); + + // set up events + map.on({ + 'viewreset': this._reset, + 'moveend': this._update + }, this); + + if (this._animated) { + map.on({ + 'zoomanim': this._animateZoom, + 'zoomend': this._endZoomAnim + }, this); + } + + if (!this.options.updateWhenIdle) { + this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this); + map.on('move', this._limitedUpdate, this); + } + + this._reset(); + this._update(); + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + onRemove: function (map) { + this._container.parentNode.removeChild(this._container); + + map.off({ + 'viewreset': this._reset, + 'moveend': this._update + }, this); + + if (this._animated) { + map.off({ + 'zoomanim': this._animateZoom, + 'zoomend': this._endZoomAnim + }, this); + } + + if (!this.options.updateWhenIdle) { + map.off('move', this._limitedUpdate, this); + } + + this._container = null; + this._map = null; + }, + + bringToFront: function () { + var pane = this._map._panes.tilePane; + + if (this._container) { + pane.appendChild(this._container); + this._setAutoZIndex(pane, Math.max); + } + + return this; + }, + + bringToBack: function () { + var pane = this._map._panes.tilePane; + + if (this._container) { + pane.insertBefore(this._container, pane.firstChild); + this._setAutoZIndex(pane, Math.min); + } + + return this; + }, + + getAttribution: function () { + return this.options.attribution; + }, + + getContainer: function () { + return this._container; + }, + + setOpacity: function (opacity) { + this.options.opacity = opacity; + + if (this._map) { + this._updateOpacity(); + } + + return this; + }, + + setZIndex: function (zIndex) { + this.options.zIndex = zIndex; + this._updateZIndex(); + + return this; + }, + + setUrl: function (url, noRedraw) { + this._url = url; + + if (!noRedraw) { + this.redraw(); + } + + return this; + }, + + redraw: function () { + if (this._map) { + this._reset({hard: true}); + this._update(); + } + return this; + }, + + _updateZIndex: function () { + if (this._container && this.options.zIndex !== undefined) { + this._container.style.zIndex = this.options.zIndex; + } + }, + + _setAutoZIndex: function (pane, compare) { + + var layers = pane.children, + edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min + zIndex, i, len; + + for (i = 0, len = layers.length; i < len; i++) { + + if (layers[i] !== this._container) { + zIndex = parseInt(layers[i].style.zIndex, 10); + + if (!isNaN(zIndex)) { + edgeZIndex = compare(edgeZIndex, zIndex); + } + } + } + + this.options.zIndex = this._container.style.zIndex = + (isFinite(edgeZIndex) ? edgeZIndex : 0) + compare(1, -1); + }, + + _updateOpacity: function () { + var i, + tiles = this._tiles; + + if (L.Browser.ielt9) { + for (i in tiles) { + L.DomUtil.setOpacity(tiles[i], this.options.opacity); + } + } else { + L.DomUtil.setOpacity(this._container, this.options.opacity); + } + }, + + _initContainer: function () { + var tilePane = this._map._panes.tilePane; + + if (!this._container) { + this._container = L.DomUtil.create('div', 'leaflet-layer'); + + this._updateZIndex(); + + if (this._animated) { + var className = 'leaflet-tile-container leaflet-zoom-animated'; + + this._bgBuffer = L.DomUtil.create('div', className, this._container); + this._tileContainer = L.DomUtil.create('div', className, this._container); + + } else { + this._tileContainer = this._container; + } + + tilePane.appendChild(this._container); + + if (this.options.opacity < 1) { + this._updateOpacity(); + } + } + }, + + _reset: function (e) { + for (var key in this._tiles) { + this.fire('tileunload', {tile: this._tiles[key]}); + } + + this._tiles = {}; + this._tilesToLoad = 0; + + if (this.options.reuseTiles) { + this._unusedTiles = []; + } + + this._tileContainer.innerHTML = ''; + + if (this._animated && e && e.hard) { + this._clearBgBuffer(); + } + + this._initContainer(); + }, + + _update: function () { + + if (!this._map) { return; } + + var bounds = this._map.getPixelBounds(), + zoom = this._map.getZoom(), + tileSize = this.options.tileSize; + + if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { + return; + } + + var tileBounds = L.bounds( + bounds.min.divideBy(tileSize)._floor(), + bounds.max.divideBy(tileSize)._floor()); + + this._addTilesFromCenterOut(tileBounds); + + if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { + this._removeOtherTiles(tileBounds); + } + }, + + _addTilesFromCenterOut: function (bounds) { + var queue = [], + center = bounds.getCenter(); + + var j, i, point; + + for (j = bounds.min.y; j <= bounds.max.y; j++) { + for (i = bounds.min.x; i <= bounds.max.x; i++) { + point = new L.Point(i, j); + + if (this._tileShouldBeLoaded(point)) { + queue.push(point); + } + } + } + + var tilesToLoad = queue.length; + + if (tilesToLoad === 0) { return; } + + // load tiles in order of their distance to center + queue.sort(function (a, b) { + return a.distanceTo(center) - b.distanceTo(center); + }); + + var fragment = document.createDocumentFragment(); + + // if its the first batch of tiles to load + if (!this._tilesToLoad) { + this.fire('loading'); + } + + this._tilesToLoad += tilesToLoad; + + for (i = 0; i < tilesToLoad; i++) { + this._addTile(queue[i], fragment); + } + + this._tileContainer.appendChild(fragment); + }, + + _tileShouldBeLoaded: function (tilePoint) { + if ((tilePoint.x + ':' + tilePoint.y) in this._tiles) { + return false; // already loaded + } + + var options = this.options; + + if (!options.continuousWorld) { + var limit = this._getWrapTileNum(); + + // don't load if exceeds world bounds + if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit)) || + tilePoint.y < 0 || tilePoint.y >= limit) { return false; } + } + + if (options.bounds) { + var tileSize = options.tileSize, + nwPoint = tilePoint.multiplyBy(tileSize), + sePoint = nwPoint.add([tileSize, tileSize]), + nw = this._map.unproject(nwPoint), + se = this._map.unproject(sePoint); + + // TODO temporary hack, will be removed after refactoring projections + // https://github.com/Leaflet/Leaflet/issues/1618 + if (!options.continuousWorld && !options.noWrap) { + nw = nw.wrap(); + se = se.wrap(); + } + + if (!options.bounds.intersects([nw, se])) { return false; } + } + + return true; + }, + + _removeOtherTiles: function (bounds) { + var kArr, x, y, key; + + for (key in this._tiles) { + kArr = key.split(':'); + x = parseInt(kArr[0], 10); + y = parseInt(kArr[1], 10); + + // remove tile if it's out of bounds + if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) { + this._removeTile(key); + } + } + }, + + _removeTile: function (key) { + var tile = this._tiles[key]; + + this.fire('tileunload', {tile: tile, url: tile.src}); + + if (this.options.reuseTiles) { + L.DomUtil.removeClass(tile, 'leaflet-tile-loaded'); + this._unusedTiles.push(tile); + + } else if (tile.parentNode === this._tileContainer) { + this._tileContainer.removeChild(tile); + } + + // for https://github.com/CloudMade/Leaflet/issues/137 + if (!L.Browser.android) { + tile.onload = null; + tile.src = L.Util.emptyImageUrl; + } + + delete this._tiles[key]; + }, + + _addTile: function (tilePoint, container) { + var tilePos = this._getTilePos(tilePoint); + + // get unused tile - or create a new tile + var tile = this._getTile(); + + /* + Chrome 20 layouts much faster with top/left (verify with timeline, frames) + Android 4 browser has display issues with top/left and requires transform instead + Android 2 browser requires top/left or tiles disappear on load or first drag + (reappear after zoom) https://github.com/CloudMade/Leaflet/issues/866 + (other browsers don't currently care) - see debug/hacks/jitter.html for an example + */ + L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome || L.Browser.android23); + + this._tiles[tilePoint.x + ':' + tilePoint.y] = tile; + + this._loadTile(tile, tilePoint); + + if (tile.parentNode !== this._tileContainer) { + container.appendChild(tile); + } + }, + + _getZoomForUrl: function () { + + var options = this.options, + zoom = this._map.getZoom(); + + if (options.zoomReverse) { + zoom = options.maxZoom - zoom; + } + + return zoom + options.zoomOffset; + }, + + _getTilePos: function (tilePoint) { + var origin = this._map.getPixelOrigin(), + tileSize = this.options.tileSize; + + return tilePoint.multiplyBy(tileSize).subtract(origin); + }, + + // image-specific code (override to implement e.g. Canvas or SVG tile layer) + + getTileUrl: function (tilePoint) { + return L.Util.template(this._url, L.extend({ + s: this._getSubdomain(tilePoint), + z: tilePoint.z, + x: tilePoint.x, + y: tilePoint.y + }, this.options)); + }, + + _getWrapTileNum: function () { + // TODO refactor, limit is not valid for non-standard projections + return Math.pow(2, this._getZoomForUrl()); + }, + + _adjustTilePoint: function (tilePoint) { + + var limit = this._getWrapTileNum(); + + // wrap tile coordinates + if (!this.options.continuousWorld && !this.options.noWrap) { + tilePoint.x = ((tilePoint.x % limit) + limit) % limit; + } + + if (this.options.tms) { + tilePoint.y = limit - tilePoint.y - 1; + } + + tilePoint.z = this._getZoomForUrl(); + }, + + _getSubdomain: function (tilePoint) { + var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length; + return this.options.subdomains[index]; + }, + + _createTileProto: function () { + var img = this._tileImg = L.DomUtil.create('img', 'leaflet-tile'); + img.style.width = img.style.height = this.options.tileSize + 'px'; + img.galleryimg = 'no'; + }, + + _getTile: function () { + if (this.options.reuseTiles && this._unusedTiles.length > 0) { + var tile = this._unusedTiles.pop(); + this._resetTile(tile); + return tile; + } + return this._createTile(); + }, + + // Override if data stored on a tile needs to be cleaned up before reuse + _resetTile: function (/*tile*/) {}, + + _createTile: function () { + var tile = this._tileImg.cloneNode(false); + tile.onselectstart = tile.onmousemove = L.Util.falseFn; + + if (L.Browser.ielt9 && this.options.opacity !== undefined) { + L.DomUtil.setOpacity(tile, this.options.opacity); + } + return tile; + }, + + _loadTile: function (tile, tilePoint) { + tile._layer = this; + tile.onload = this._tileOnLoad; + tile.onerror = this._tileOnError; + + this._adjustTilePoint(tilePoint); + tile.src = this.getTileUrl(tilePoint); + }, + + _tileLoaded: function () { + this._tilesToLoad--; + if (!this._tilesToLoad) { + this.fire('load'); + + if (this._animated) { + // clear scaled tiles after all new tiles are loaded (for performance) + clearTimeout(this._clearBgBufferTimer); + this._clearBgBufferTimer = setTimeout(L.bind(this._clearBgBuffer, this), 500); + } + } + }, + + _tileOnLoad: function () { + var layer = this._layer; + + //Only if we are loading an actual image + if (this.src !== L.Util.emptyImageUrl) { + L.DomUtil.addClass(this, 'leaflet-tile-loaded'); + + layer.fire('tileload', { + tile: this, + url: this.src + }); + } + + layer._tileLoaded(); + }, + + _tileOnError: function () { + var layer = this._layer; + + layer.fire('tileerror', { + tile: this, + url: this.src + }); + + var newUrl = layer.options.errorTileUrl; + if (newUrl) { + this.src = newUrl; + } + + layer._tileLoaded(); + } +}); + +L.tileLayer = function (url, options) { + return new L.TileLayer(url, options); +}; + + +/* + * L.TileLayer.WMS is used for putting WMS tile layers on the map. + */ + +L.TileLayer.WMS = L.TileLayer.extend({ + + defaultWmsParams: { + service: 'WMS', + request: 'GetMap', + version: '1.1.1', + layers: '', + styles: '', + format: 'image/jpeg', + transparent: false + }, + + initialize: function (url, options) { // (String, Object) + + this._url = url; + + var wmsParams = L.extend({}, this.defaultWmsParams), + tileSize = options.tileSize || this.options.tileSize; + + if (options.detectRetina && L.Browser.retina) { + wmsParams.width = wmsParams.height = tileSize * 2; + } else { + wmsParams.width = wmsParams.height = tileSize; + } + + for (var i in options) { + // all keys that are not TileLayer options go to WMS params + if (!this.options.hasOwnProperty(i) && i !== 'crs') { + wmsParams[i] = options[i]; + } + } + + this.wmsParams = wmsParams; + + L.setOptions(this, options); + }, + + onAdd: function (map) { + + this._crs = this.options.crs || map.options.crs; + + var projectionKey = parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs'; + this.wmsParams[projectionKey] = this._crs.code; + + L.TileLayer.prototype.onAdd.call(this, map); + }, + + getTileUrl: function (tilePoint, zoom) { // (Point, Number) -> String + + var map = this._map, + tileSize = this.options.tileSize, + + nwPoint = tilePoint.multiplyBy(tileSize), + sePoint = nwPoint.add([tileSize, tileSize]), + + nw = this._crs.project(map.unproject(nwPoint, zoom)), + se = this._crs.project(map.unproject(sePoint, zoom)), + + bbox = [nw.x, se.y, se.x, nw.y].join(','), + + url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)}); + + return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox; + }, + + setParams: function (params, noRedraw) { + + L.extend(this.wmsParams, params); + + if (!noRedraw) { + this.redraw(); + } + + return this; + } +}); + +L.tileLayer.wms = function (url, options) { + return new L.TileLayer.WMS(url, options); +}; + + +/* + * L.TileLayer.Canvas is a class that you can use as a base for creating + * dynamically drawn Canvas-based tile layers. + */ + +L.TileLayer.Canvas = L.TileLayer.extend({ + options: { + async: false + }, + + initialize: function (options) { + L.setOptions(this, options); + }, + + redraw: function () { + for (var i in this._tiles) { + this._redrawTile(this._tiles[i]); + } + return this; + }, + + _redrawTile: function (tile) { + this.drawTile(tile, tile._tilePoint, this._map._zoom); + }, + + _createTileProto: function () { + var proto = this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile'); + proto.width = proto.height = this.options.tileSize; + }, + + _createTile: function () { + var tile = this._canvasProto.cloneNode(false); + tile.onselectstart = tile.onmousemove = L.Util.falseFn; + return tile; + }, + + _loadTile: function (tile, tilePoint) { + tile._layer = this; + tile._tilePoint = tilePoint; + + this._redrawTile(tile); + + if (!this.options.async) { + this.tileDrawn(tile); + } + }, + + drawTile: function (/*tile, tilePoint*/) { + // override with rendering code + }, + + tileDrawn: function (tile) { + this._tileOnLoad.call(tile); + } +}); + + +L.tileLayer.canvas = function (options) { + return new L.TileLayer.Canvas(options); +}; + + +/* + * L.ImageOverlay is used to overlay images over the map (to specific geographical bounds). + */ + +L.ImageOverlay = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + opacity: 1 + }, + + initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) + this._url = url; + this._bounds = L.latLngBounds(bounds); + + L.setOptions(this, options); + }, + + onAdd: function (map) { + this._map = map; + + if (!this._image) { + this._initImage(); + } + + map._panes.overlayPane.appendChild(this._image); + + map.on('viewreset', this._reset, this); + + if (map.options.zoomAnimation && L.Browser.any3d) { + map.on('zoomanim', this._animateZoom, this); + } + + this._reset(); + }, + + onRemove: function (map) { + map.getPanes().overlayPane.removeChild(this._image); + + map.off('viewreset', this._reset, this); + + if (map.options.zoomAnimation) { + map.off('zoomanim', this._animateZoom, this); + } + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + setOpacity: function (opacity) { + this.options.opacity = opacity; + this._updateOpacity(); + return this; + }, + + // TODO remove bringToFront/bringToBack duplication from TileLayer/Path + bringToFront: function () { + if (this._image) { + this._map._panes.overlayPane.appendChild(this._image); + } + return this; + }, + + bringToBack: function () { + var pane = this._map._panes.overlayPane; + if (this._image) { + pane.insertBefore(this._image, pane.firstChild); + } + return this; + }, + + _initImage: function () { + this._image = L.DomUtil.create('img', 'leaflet-image-layer'); + + if (this._map.options.zoomAnimation && L.Browser.any3d) { + L.DomUtil.addClass(this._image, 'leaflet-zoom-animated'); + } else { + L.DomUtil.addClass(this._image, 'leaflet-zoom-hide'); + } + + this._updateOpacity(); + + //TODO createImage util method to remove duplication + L.extend(this._image, { + galleryimg: 'no', + onselectstart: L.Util.falseFn, + onmousemove: L.Util.falseFn, + onload: L.bind(this._onImageLoad, this), + src: this._url + }); + }, + + _animateZoom: function (e) { + var map = this._map, + image = this._image, + scale = map.getZoomScale(e.zoom), + nw = this._bounds.getNorthWest(), + se = this._bounds.getSouthEast(), + + topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center), + size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft), + origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale))); + + image.style[L.DomUtil.TRANSFORM] = + L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') '; + }, + + _reset: function () { + var image = this._image, + topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()), + size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft); + + L.DomUtil.setPosition(image, topLeft); + + image.style.width = size.x + 'px'; + image.style.height = size.y + 'px'; + }, + + _onImageLoad: function () { + this.fire('load'); + }, + + _updateOpacity: function () { + L.DomUtil.setOpacity(this._image, this.options.opacity); + } +}); + +L.imageOverlay = function (url, bounds, options) { + return new L.ImageOverlay(url, bounds, options); +}; + + +/* + * L.Icon is an image-based icon class that you can use with L.Marker for custom markers. + */ + +L.Icon = L.Class.extend({ + options: { + /* + iconUrl: (String) (required) + iconRetinaUrl: (String) (optional, used for retina devices if detected) + iconSize: (Point) (can be set through CSS) + iconAnchor: (Point) (centered by default, can be set in CSS with negative margins) + popupAnchor: (Point) (if not specified, popup opens in the anchor point) + shadowUrl: (String) (no shadow by default) + shadowRetinaUrl: (String) (optional, used for retina devices if detected) + shadowSize: (Point) + shadowAnchor: (Point) + */ + className: '' + }, + + initialize: function (options) { + L.setOptions(this, options); + }, + + createIcon: function (oldIcon) { + return this._createIcon('icon', oldIcon); + }, + + createShadow: function (oldIcon) { + return this._createIcon('shadow', oldIcon); + }, + + _createIcon: function (name, oldIcon) { + var src = this._getIconUrl(name); + + if (!src) { + if (name === 'icon') { + throw new Error('iconUrl not set in Icon options (see the docs).'); + } + return null; + } + + var img; + if (!oldIcon || oldIcon.tagName !== 'IMG') { + img = this._createImg(src); + } else { + img = this._createImg(src, oldIcon); + } + this._setIconStyles(img, name); + + return img; + }, + + _setIconStyles: function (img, name) { + var options = this.options, + size = L.point(options[name + 'Size']), + anchor; + + if (name === 'shadow') { + anchor = L.point(options.shadowAnchor || options.iconAnchor); + } else { + anchor = L.point(options.iconAnchor); + } + + if (!anchor && size) { + anchor = size.divideBy(2, true); + } + + img.className = 'leaflet-marker-' + name + ' ' + options.className; + + if (anchor) { + img.style.marginLeft = (-anchor.x) + 'px'; + img.style.marginTop = (-anchor.y) + 'px'; + } + + if (size) { + img.style.width = size.x + 'px'; + img.style.height = size.y + 'px'; + } + }, + + _createImg: function (src, el) { + + if (!L.Browser.ie6) { + if (!el) { + el = document.createElement('img'); + } + el.src = src; + } else { + if (!el) { + el = document.createElement('div'); + } + el.style.filter = + 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")'; + } + return el; + }, + + _getIconUrl: function (name) { + if (L.Browser.retina && this.options[name + 'RetinaUrl']) { + return this.options[name + 'RetinaUrl']; + } + return this.options[name + 'Url']; + } +}); + +L.icon = function (options) { + return new L.Icon(options); +}; - case 'MultiLineString': - latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); - return new L.MultiPolyline(latlngs); - case 'MultiPolygon': - latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng); - return new L.MultiPolygon(latlngs); - - case 'GeometryCollection': - for (i = 0, len = geometry.geometries.length; i < len; i++) { - - layer = this.geometryToLayer({ - geometry: geometry.geometries[i], - type: 'Feature', - properties: geojson.properties - }, pointToLayer, coordsToLatLng); +/* + * L.Icon.Default is the blue marker icon used by default in Leaflet. + */ - layers.push(layer); - } - return new L.FeatureGroup(layers); +L.Icon.Default = L.Icon.extend({ - default: - throw new Error('Invalid GeoJSON object.'); - } - }, + options: { + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], - coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng - return new L.LatLng(coords[1], coords[0]); + shadowSize: [41, 41] }, - coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array - var latlng, i, len, - latlngs = []; - - for (i = 0, len = coords.length; i < len; i++) { - latlng = levelsDeep ? - this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) : - (coordsToLatLng || this.coordsToLatLng)(coords[i]); + _getIconUrl: function (name) { + var key = name + 'Url'; - latlngs.push(latlng); + if (this.options[key]) { + return this.options[key]; } - return latlngs; - }, - - latLngToCoords: function (latLng) { - return [latLng.lng, latLng.lat]; - }, - - latLngsToCoords: function (latLngs) { - var coords = []; - - for (var i = 0, len = latLngs.length; i < len; i++) { - coords.push(L.GeoJSON.latLngToCoords(latLngs[i])); + if (L.Browser.retina && name === 'icon') { + name += '-2x'; } - return coords; - }, - - getFeature: function (layer, newGeometry) { - return layer.feature ? L.extend({}, layer.feature, {geometry: newGeometry}) : L.GeoJSON.asFeature(newGeometry); - }, + var path = L.Icon.Default.imagePath; - asFeature: function (geoJSON) { - if (geoJSON.type === 'Feature') { - return geoJSON; + if (!path) { + throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.'); } - return { - type: 'Feature', - properties: {}, - geometry: geoJSON - }; + return path + '/marker-' + name + '.png'; } }); -var PointToGeoJSON = { - toGeoJSON: function () { - return L.GeoJSON.getFeature(this, { - type: 'Point', - coordinates: L.GeoJSON.latLngToCoords(this.getLatLng()) - }); - } -}; - -L.Marker.include(PointToGeoJSON); -L.Circle.include(PointToGeoJSON); -L.CircleMarker.include(PointToGeoJSON); - -L.Polyline.include({ - toGeoJSON: function () { - return L.GeoJSON.getFeature(this, { - type: 'LineString', - coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs()) - }); - } -}); +L.Icon.Default.imagePath = (function () { + var scripts = document.getElementsByTagName('script'), + leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/; -L.Polygon.include({ - toGeoJSON: function () { - var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())], - i, len, hole; + var i, len, src, matches, path; - coords[0].push(coords[0][0]); + for (i = 0, len = scripts.length; i < len; i++) { + src = scripts[i].src; + matches = src.match(leafletRe); - if (this._holes) { - for (i = 0, len = this._holes.length; i < len; i++) { - hole = L.GeoJSON.latLngsToCoords(this._holes[i]); - hole.push(hole[0]); - coords.push(hole); - } + if (matches) { + path = src.split(leafletRe)[0]; + return (path ? path + '/' : '') + 'images'; } - - return L.GeoJSON.getFeature(this, { - type: 'Polygon', - coordinates: coords - }); - } -}); - -(function () { - function includeMulti(Klass, type) { - Klass.include({ - toGeoJSON: function () { - var coords = []; - - this.eachLayer(function (layer) { - coords.push(layer.toGeoJSON().geometry.coordinates); - }); - - return L.GeoJSON.getFeature(this, { - type: type, - coordinates: coords - }); - } - }); } - - includeMulti(L.MultiPolyline, 'MultiLineString'); - includeMulti(L.MultiPolygon, 'MultiPolygon'); }()); -L.LayerGroup.include({ - toGeoJSON: function () { - var features = []; - - this.eachLayer(function (layer) { - if (layer.toGeoJSON) { - features.push(L.GeoJSON.asFeature(layer.toGeoJSON())); - } - }); - - return { - type: 'FeatureCollection', - features: features - }; - } -}); - -L.geoJson = function (geojson, options) { - return new L.GeoJSON(geojson, options); -}; - - -/* - * L.DomEvent contains functions for working with DOM events. - */ - -L.DomEvent = { - /* inspired by John Resig, Dean Edwards and YUI addEvent implementations */ - addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) - - var id = L.stamp(fn), - key = '_leaflet_' + type + id, - handler, originalHandler, newType; - - if (obj[key]) { return this; } - - handler = function (e) { - return fn.call(context || obj, e || L.DomEvent._getEvent()); - }; - - if (L.Browser.msTouch && type.indexOf('touch') === 0) { - return this.addMsTouchListener(obj, type, handler, id); - } - if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) { - this.addDoubleTapListener(obj, handler, id); - } - - if ('addEventListener' in obj) { - - if (type === 'mousewheel') { - obj.addEventListener('DOMMouseScroll', handler, false); - obj.addEventListener(type, handler, false); - - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - - originalHandler = handler; - newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout'); - - handler = function (e) { - if (!L.DomEvent._checkMouse(obj, e)) { return; } - return originalHandler(e); - }; - - obj.addEventListener(newType, handler, false); - - } else if (type === 'click' && L.Browser.android) { - originalHandler = handler; - handler = function (e) { - return L.DomEvent._filterClick(e, originalHandler); - }; - - obj.addEventListener(type, handler, false); - } else { - obj.addEventListener(type, handler, false); - } - - } else if ('attachEvent' in obj) { - obj.attachEvent('on' + type, handler); - } - - obj[key] = handler; - - return this; - }, - - removeListener: function (obj, type, fn) { // (HTMLElement, String, Function) - - var id = L.stamp(fn), - key = '_leaflet_' + type + id, - handler = obj[key]; - - if (!handler) { return this; } - - if (L.Browser.msTouch && type.indexOf('touch') === 0) { - this.removeMsTouchListener(obj, type, id); - } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) { - this.removeDoubleTapListener(obj, id); - } else if ('removeEventListener' in obj) { - - if (type === 'mousewheel') { - obj.removeEventListener('DOMMouseScroll', handler, false); - obj.removeEventListener(type, handler, false); - - } else if ((type === 'mouseenter') || (type === 'mouseleave')) { - obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false); - } else { - obj.removeEventListener(type, handler, false); - } - } else if ('detachEvent' in obj) { - obj.detachEvent('on' + type, handler); - } - - obj[key] = null; - - return this; - }, - - stopPropagation: function (e) { - - if (e.stopPropagation) { - e.stopPropagation(); - } else { - e.cancelBubble = true; - } - return this; - }, - - disableClickPropagation: function (el) { - var stop = L.DomEvent.stopPropagation; - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.addListener(el, L.Draggable.START[i], stop); - } - - return L.DomEvent - .addListener(el, 'click', L.DomEvent._fakeStop) - .addListener(el, 'dblclick', stop); - }, - - preventDefault: function (e) { - - if (e.preventDefault) { - e.preventDefault(); - } else { - e.returnValue = false; - } - return this; - }, - - stop: function (e) { - return L.DomEvent.preventDefault(e).stopPropagation(e); - }, - - getMousePosition: function (e, container) { - - var body = document.body, - docEl = document.documentElement, - x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft, - y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop, - pos = new L.Point(x, y); - - return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos); - }, - - getWheelDelta: function (e) { - - var delta = 0; - - if (e.wheelDelta) { - delta = e.wheelDelta / 120; - } - if (e.detail) { - delta = -e.detail / 3; - } - return delta; - }, - - _fakeStop: function stop(e) { - // fakes stopPropagation by setting a special event flag checked in Map mouse events handler - // jshint camelcase: false - e._leaflet_stop = true; - }, - - // check if element really left/entered the event target (for mouseenter/mouseleave) - _checkMouse: function (el, e) { - - var related = e.relatedTarget; - - if (!related) { return true; } - - try { - while (related && (related !== el)) { - related = related.parentNode; - } - } catch (err) { - return false; - } - return (related !== el); - }, - - _getEvent: function () { // evil magic for IE - /*jshint noarg:false */ - var e = window.event; - if (!e) { - var caller = arguments.callee.caller; - while (caller) { - e = caller['arguments'][0]; - if (e && window.Event === e.constructor) { - break; - } - caller = caller.caller; - } - } - return e; - }, - - // this is a horrible workaround for a bug in Android where a single touch triggers two click events - _filterClick: function (e, handler) { - var timeStamp = (e.timeStamp || e.originalEvent.timeStamp), - elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick); - - // are they closer together than 1000ms yet more than 100ms? - // Android typically triggers them ~300ms apart while multiple listeners - // on the same event should be triggered far faster; - // or check if click is simulated on the element, and if it is, reject any non-simulated events - - if ((elapsed && elapsed > 100 && elapsed < 1000) || (e.target._simulatedClick && !e._simulated)) { - L.DomEvent.stop(e); - return; - } - L.DomEvent._lastClick = timeStamp; - - return handler(e); - } -}; - -L.DomEvent.on = L.DomEvent.addListener; -L.DomEvent.off = L.DomEvent.removeListener; +/* + * L.Marker is used to display clickable/draggable icons on the map. + */ + +L.Marker = L.Class.extend({ + + includes: L.Mixin.Events, + + options: { + icon: new L.Icon.Default(), + title: '', + clickable: true, + draggable: false, + keyboard: true, + zIndexOffset: 0, + opacity: 1, + riseOnHover: false, + riseOffset: 250 + }, + + initialize: function (latlng, options) { + L.setOptions(this, options); + this._latlng = L.latLng(latlng); + }, + + onAdd: function (map) { + this._map = map; + + map.on('viewreset', this.update, this); + + this._initIcon(); + this.update(); + + if (map.options.zoomAnimation && map.options.markerZoomAnimation) { + map.on('zoomanim', this._animateZoom, this); + } + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + onRemove: function (map) { + if (this.dragging) { + this.dragging.disable(); + } + + this._removeIcon(); + this._removeShadow(); + + this.fire('remove'); + + map.off({ + 'viewreset': this.update, + 'zoomanim': this._animateZoom + }, this); + + this._map = null; + }, + + getLatLng: function () { + return this._latlng; + }, + + setLatLng: function (latlng) { + this._latlng = L.latLng(latlng); + + this.update(); + + return this.fire('move', { latlng: this._latlng }); + }, + + setZIndexOffset: function (offset) { + this.options.zIndexOffset = offset; + this.update(); + + return this; + }, + + setIcon: function (icon) { + + this.options.icon = icon; + + if (this._map) { + this._initIcon(); + this.update(); + } + + return this; + }, + + update: function () { + if (this._icon) { + var pos = this._map.latLngToLayerPoint(this._latlng).round(); + this._setPos(pos); + } + + return this; + }, + + _initIcon: function () { + var options = this.options, + map = this._map, + animation = (map.options.zoomAnimation && map.options.markerZoomAnimation), + classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide'; + + var icon = options.icon.createIcon(this._icon), + addIcon = false; + + // if we're not reusing the icon, remove the old one and init new one + if (icon !== this._icon) { + if (this._icon) { + this._removeIcon(); + } + addIcon = true; + + if (options.title) { + icon.title = options.title; + } + } + + L.DomUtil.addClass(icon, classToAdd); + + if (options.keyboard) { + icon.tabIndex = '0'; + } + + this._icon = icon; + + this._initInteraction(); + + if (options.riseOnHover) { + L.DomEvent + .on(icon, 'mouseover', this._bringToFront, this) + .on(icon, 'mouseout', this._resetZIndex, this); + } + + var newShadow = options.icon.createShadow(this._shadow), + addShadow = false; + + if (newShadow !== this._shadow) { + this._removeShadow(); + addShadow = true; + + if (newShadow) { + L.DomUtil.addClass(newShadow, classToAdd); + } + } + this._shadow = newShadow; + + + if (options.opacity < 1) { + this._updateOpacity(); + } + + + var panes = this._map._panes; + + if (addIcon) { + panes.markerPane.appendChild(this._icon); + } + + if (newShadow && addShadow) { + panes.shadowPane.appendChild(this._shadow); + } + }, + + _removeIcon: function () { + if (this.options.riseOnHover) { + L.DomEvent + .off(this._icon, 'mouseover', this._bringToFront) + .off(this._icon, 'mouseout', this._resetZIndex); + } + + this._map._panes.markerPane.removeChild(this._icon); + + this._icon = null; + }, + + _removeShadow: function () { + if (this._shadow) { + this._map._panes.shadowPane.removeChild(this._shadow); + } + this._shadow = null; + }, + + _setPos: function (pos) { + L.DomUtil.setPosition(this._icon, pos); + + if (this._shadow) { + L.DomUtil.setPosition(this._shadow, pos); + } + + this._zIndex = pos.y + this.options.zIndexOffset; + + this._resetZIndex(); + }, + + _updateZIndex: function (offset) { + this._icon.style.zIndex = this._zIndex + offset; + }, + + _animateZoom: function (opt) { + var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); + + this._setPos(pos); + }, + + _initInteraction: function () { + + if (!this.options.clickable) { return; } + + // TODO refactor into something shared with Map/Path/etc. to DRY it up + + var icon = this._icon, + events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu']; + + L.DomUtil.addClass(icon, 'leaflet-clickable'); + L.DomEvent.on(icon, 'click', this._onMouseClick, this); + L.DomEvent.on(icon, 'keypress', this._onKeyPress, this); + + for (var i = 0; i < events.length; i++) { + L.DomEvent.on(icon, events[i], this._fireMouseEvent, this); + } + + if (L.Handler.MarkerDrag) { + this.dragging = new L.Handler.MarkerDrag(this); + + if (this.options.draggable) { + this.dragging.enable(); + } + } + }, + + _onMouseClick: function (e) { + var wasDragged = this.dragging && this.dragging.moved(); + + if (this.hasEventListeners(e.type) || wasDragged) { + L.DomEvent.stopPropagation(e); + } + + if (wasDragged) { return; } + + if ((!this.dragging || !this.dragging._enabled) && this._map.dragging && this._map.dragging.moved()) { return; } + + this.fire(e.type, { + originalEvent: e, + latlng: this._latlng + }); + }, + + _onKeyPress: function (e) { + if (e.keyCode === 13) { + this.fire('click', { + originalEvent: e, + latlng: this._latlng + }); + } + }, + + _fireMouseEvent: function (e) { + + this.fire(e.type, { + originalEvent: e, + latlng: this._latlng + }); + + // TODO proper custom event propagation + // this line will always be called if marker is in a FeatureGroup + if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) { + L.DomEvent.preventDefault(e); + } + if (e.type !== 'mousedown') { + L.DomEvent.stopPropagation(e); + } else { + L.DomEvent.preventDefault(e); + } + }, + + setOpacity: function (opacity) { + this.options.opacity = opacity; + if (this._map) { + this._updateOpacity(); + } + }, + + _updateOpacity: function () { + L.DomUtil.setOpacity(this._icon, this.options.opacity); + if (this._shadow) { + L.DomUtil.setOpacity(this._shadow, this.options.opacity); + } + }, + + _bringToFront: function () { + this._updateZIndex(this.options.riseOffset); + }, + + _resetZIndex: function () { + this._updateZIndex(0); + } +}); + +L.marker = function (latlng, options) { + return new L.Marker(latlng, options); +}; /* - * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too. + * L.DivIcon is a lightweight HTML-based icon class (as opposed to the image-based L.Icon) + * to use with L.Marker. */ -L.Draggable = L.Class.extend({ - includes: L.Mixin.Events, - - statics: { - START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'], - END: { - mousedown: 'mouseup', - touchstart: 'touchend', - MSPointerDown: 'touchend' - }, - MOVE: { - mousedown: 'mousemove', - touchstart: 'touchmove', - MSPointerDown: 'touchmove' - } - }, - - initialize: function (element, dragStartTarget) { - this._element = element; - this._dragStartTarget = dragStartTarget || element; - }, - - enable: function () { - if (this._enabled) { return; } - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); - } - - this._enabled = true; - }, - - disable: function () { - if (!this._enabled) { return; } - - for (var i = L.Draggable.START.length - 1; i >= 0; i--) { - L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); - } - - this._enabled = false; - this._moved = false; - }, - - _onDown: function (e) { - if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } - - L.DomEvent - .stopPropagation(e); - - if (L.Draggable._disabled) { return; } - - L.DomUtil.disableImageDrag(); - L.DomUtil.disableTextSelection(); - - var first = e.touches ? e.touches[0] : e, - el = first.target; - - // if touching a link, highlight it - if (L.Browser.touch && el.tagName.toLowerCase() === 'a') { - L.DomUtil.addClass(el, 'leaflet-active'); - } - - this._moved = false; - - if (this._moving) { return; } - - this._startPoint = new L.Point(first.clientX, first.clientY); - this._startPos = this._newPos = L.DomUtil.getPosition(this._element); - - L.DomEvent - .on(document, L.Draggable.MOVE[e.type], this._onMove, this) - .on(document, L.Draggable.END[e.type], this._onUp, this); - }, - - _onMove: function (e) { - if (e.touches && e.touches.length > 1) { return; } - - var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), - newPoint = new L.Point(first.clientX, first.clientY), - offset = newPoint.subtract(this._startPoint); - - if (!offset.x && !offset.y) { return; } - - L.DomEvent.preventDefault(e); - - if (!this._moved) { - this.fire('dragstart'); +L.DivIcon = L.Icon.extend({ + options: { + iconSize: [12, 12], // also can be set through CSS + /* + iconAnchor: (Point) + popupAnchor: (Point) + html: (String) + bgPos: (Point) + */ + className: 'leaflet-div-icon', + html: false + }, - this._moved = true; - this._startPos = L.DomUtil.getPosition(this._element).subtract(offset); + createIcon: function (oldIcon) { + var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'), + options = this.options; - if (!L.Browser.touch) { - L.DomUtil.addClass(document.body, 'leaflet-dragging'); - } + if (options.html !== false) { + div.innerHTML = options.html; + } else { + div.innerHTML = ''; } - this._newPos = this._startPos.add(offset); - this._moving = true; + if (options.bgPos) { + div.style.backgroundPosition = + (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px'; + } - L.Util.cancelAnimFrame(this._animRequest); - this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget); + this._setIconStyles(div, 'icon'); + return div; }, - _updatePosition: function () { - this.fire('predrag'); - L.DomUtil.setPosition(this._element, this._newPos); - this.fire('drag'); - }, + createShadow: function () { + return null; + } +}); - _onUp: function () { - if (!L.Browser.touch) { - L.DomUtil.removeClass(document.body, 'leaflet-dragging'); - } +L.divIcon = function (options) { + return new L.DivIcon(options); +}; - for (var i in L.Draggable.MOVE) { - L.DomEvent - .off(document, L.Draggable.MOVE[i], this._onMove) - .off(document, L.Draggable.END[i], this._onUp); - } - L.DomUtil.enableImageDrag(); - L.DomUtil.enableTextSelection(); +/* + * L.Popup is used for displaying popups on the map. + */ + +L.Map.mergeOptions({ + closePopupOnClick: true +}); + +L.Popup = L.Class.extend({ + includes: L.Mixin.Events, + + options: { + minWidth: 50, + maxWidth: 300, + maxHeight: null, + autoPan: true, + closeButton: true, + offset: [0, 7], + autoPanPadding: [5, 5], + keepInView: false, + className: '', + zoomAnimation: true + }, + + initialize: function (options, source) { + L.setOptions(this, options); + + this._source = source; + this._animated = L.Browser.any3d && this.options.zoomAnimation; + this._isOpen = false; + }, + + onAdd: function (map) { + this._map = map; + + if (!this._container) { + this._initLayout(); + } + this._updateContent(); + + var animFade = map.options.fadeAnimation; + + if (animFade) { + L.DomUtil.setOpacity(this._container, 0); + } + map._panes.popupPane.appendChild(this._container); + + map.on(this._getEvents(), this); + + this._update(); + + if (animFade) { + L.DomUtil.setOpacity(this._container, 1); + } + + this.fire('open'); + + map.fire('popupopen', {popup: this}); + + if (this._source) { + this._source.fire('popupopen', {popup: this}); + } + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + openOn: function (map) { + map.openPopup(this); + return this; + }, + + onRemove: function (map) { + map._panes.popupPane.removeChild(this._container); + + L.Util.falseFn(this._container.offsetWidth); // force reflow + + map.off(this._getEvents(), this); + + if (map.options.fadeAnimation) { + L.DomUtil.setOpacity(this._container, 0); + } + + this._map = null; + + this.fire('close'); + + map.fire('popupclose', {popup: this}); + + if (this._source) { + this._source.fire('popupclose', {popup: this}); + } + }, + + setLatLng: function (latlng) { + this._latlng = L.latLng(latlng); + this._update(); + return this; + }, + + setContent: function (content) { + this._content = content; + this._update(); + return this; + }, + + _getEvents: function () { + var events = { + viewreset: this._updatePosition + }; + + if (this._animated) { + events.zoomanim = this._zoomAnimation; + } + if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) { + events.preclick = this._close; + } + if (this.options.keepInView) { + events.moveend = this._adjustPan; + } + + return events; + }, + + _close: function () { + if (this._map) { + this._map.closePopup(this); + } + }, + + _initLayout: function () { + var prefix = 'leaflet-popup', + containerClass = prefix + ' ' + this.options.className + ' leaflet-zoom-' + + (this._animated ? 'animated' : 'hide'), + container = this._container = L.DomUtil.create('div', containerClass), + closeButton; + + if (this.options.closeButton) { + closeButton = this._closeButton = + L.DomUtil.create('a', prefix + '-close-button', container); + closeButton.href = '#close'; + closeButton.innerHTML = '×'; + L.DomEvent.disableClickPropagation(closeButton); + + L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this); + } + + var wrapper = this._wrapper = + L.DomUtil.create('div', prefix + '-content-wrapper', container); + L.DomEvent.disableClickPropagation(wrapper); + + this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper); + L.DomEvent.on(this._contentNode, 'mousewheel', L.DomEvent.stopPropagation); + L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation); + this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container); + this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer); + }, + + _update: function () { + if (!this._map) { return; } + + this._container.style.visibility = 'hidden'; + + this._updateContent(); + this._updateLayout(); + this._updatePosition(); + + this._container.style.visibility = ''; + + this._adjustPan(); + }, + + _updateContent: function () { + if (!this._content) { return; } + + if (typeof this._content === 'string') { + this._contentNode.innerHTML = this._content; + } else { + while (this._contentNode.hasChildNodes()) { + this._contentNode.removeChild(this._contentNode.firstChild); + } + this._contentNode.appendChild(this._content); + } + this.fire('contentupdate'); + }, + + _updateLayout: function () { + var container = this._contentNode, + style = container.style; + + style.width = ''; + style.whiteSpace = 'nowrap'; + + var width = container.offsetWidth; + width = Math.min(width, this.options.maxWidth); + width = Math.max(width, this.options.minWidth); + + style.width = (width + 1) + 'px'; + style.whiteSpace = ''; + + style.height = ''; + + var height = container.offsetHeight, + maxHeight = this.options.maxHeight, + scrolledClass = 'leaflet-popup-scrolled'; + + if (maxHeight && height > maxHeight) { + style.height = maxHeight + 'px'; + L.DomUtil.addClass(container, scrolledClass); + } else { + L.DomUtil.removeClass(container, scrolledClass); + } + + this._containerWidth = this._container.offsetWidth; + }, + + _updatePosition: function () { + if (!this._map) { return; } + + var pos = this._map.latLngToLayerPoint(this._latlng), + animated = this._animated, + offset = L.point(this.options.offset); + + if (animated) { + L.DomUtil.setPosition(this._container, pos); + } + + this._containerBottom = -offset.y - (animated ? 0 : pos.y); + this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x + (animated ? 0 : pos.x); + + // bottom position the popup in case the height of the popup changes (images loading etc) + this._container.style.bottom = this._containerBottom + 'px'; + this._container.style.left = this._containerLeft + 'px'; + }, + + _zoomAnimation: function (opt) { + var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center); + + L.DomUtil.setPosition(this._container, pos); + }, + + _adjustPan: function () { + if (!this.options.autoPan) { return; } + + var map = this._map, + containerHeight = this._container.offsetHeight, + containerWidth = this._containerWidth, + + layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom); + + if (this._animated) { + layerPos._add(L.DomUtil.getPosition(this._container)); + } + + var containerPos = map.layerPointToContainerPoint(layerPos), + padding = L.point(this.options.autoPanPadding), + size = map.getSize(), + dx = 0, + dy = 0; + + if (containerPos.x + containerWidth > size.x) { // right + dx = containerPos.x + containerWidth - size.x + padding.x; + } + if (containerPos.x - dx < 0) { // left + dx = containerPos.x - padding.x; + } + if (containerPos.y + containerHeight > size.y) { // bottom + dy = containerPos.y + containerHeight - size.y + padding.y; + } + if (containerPos.y - dy < 0) { // top + dy = containerPos.y - padding.y; + } + + if (dx || dy) { + map + .fire('autopanstart') + .panBy([dx, dy]); + } + }, + + _onCloseButtonClick: function (e) { + this._close(); + L.DomEvent.stop(e); + } +}); + +L.popup = function (options, source) { + return new L.Popup(options, source); +}; + + +L.Map.include({ + openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object]) + this.closePopup(); + + if (!(popup instanceof L.Popup)) { + var content = popup; + + popup = new L.Popup(options) + .setLatLng(latlng) + .setContent(content); + } + popup._isOpen = true; + + this._popup = popup; + return this.addLayer(popup); + }, + + closePopup: function (popup) { + if (!popup || popup === this._popup) { + popup = this._popup; + this._popup = null; + } + if (popup) { + this.removeLayer(popup); + popup._isOpen = false; + } + return this; + } +}); + + +/* + * Popup extension to L.Marker, adding popup-related methods. + */ + +L.Marker.include({ + openPopup: function () { + if (this._popup && this._map && !this._map.hasLayer(this._popup)) { + this._popup.setLatLng(this._latlng); + this._map.openPopup(this._popup); + } + + return this; + }, + + closePopup: function () { + if (this._popup) { + this._popup._close(); + } + return this; + }, + + togglePopup: function () { + if (this._popup) { + if (this._popup._isOpen) { + this.closePopup(); + } else { + this.openPopup(); + } + } + return this; + }, + + bindPopup: function (content, options) { + var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]); + + anchor = anchor.add(L.Popup.prototype.options.offset); + + if (options && options.offset) { + anchor = anchor.add(options.offset); + } + + options = L.extend({offset: anchor}, options); + + if (!this._popup) { + this + .on('click', this.togglePopup, this) + .on('remove', this.closePopup, this) + .on('move', this._movePopup, this); + } + + if (content instanceof L.Popup) { + L.setOptions(content, options); + this._popup = content; + } else { + this._popup = new L.Popup(options, this) + .setContent(content); + } + + return this; + }, + + setPopupContent: function (content) { + if (this._popup) { + this._popup.setContent(content); + } + return this; + }, + + unbindPopup: function () { + if (this._popup) { + this._popup = null; + this + .off('click', this.togglePopup) + .off('remove', this.closePopup) + .off('move', this._movePopup); + } + return this; + }, + + _movePopup: function (e) { + this._popup.setLatLng(e.latlng); + } +}); + + +/* + * L.LayerGroup is a class to combine several layers into one so that + * you can manipulate the group (e.g. add/remove it) as one layer. + */ + +L.LayerGroup = L.Class.extend({ + initialize: function (layers) { + this._layers = {}; + + var i, len; + + if (layers) { + for (i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + } + }, + + addLayer: function (layer) { + var id = this.getLayerId(layer); + + this._layers[id] = layer; + + if (this._map) { + this._map.addLayer(layer); + } + + return this; + }, + + removeLayer: function (layer) { + var id = layer in this._layers ? layer : this.getLayerId(layer); + + if (this._map && this._layers[id]) { + this._map.removeLayer(this._layers[id]); + } + + delete this._layers[id]; + + return this; + }, + + hasLayer: function (layer) { + if (!layer) { return false; } + + return (layer in this._layers || this.getLayerId(layer) in this._layers); + }, + + clearLayers: function () { + this.eachLayer(this.removeLayer, this); + return this; + }, + + invoke: function (methodName) { + var args = Array.prototype.slice.call(arguments, 1), + i, layer; + + for (i in this._layers) { + layer = this._layers[i]; + + if (layer[methodName]) { + layer[methodName].apply(layer, args); + } + } + + return this; + }, + + onAdd: function (map) { + this._map = map; + this.eachLayer(map.addLayer, map); + }, + + onRemove: function (map) { + this.eachLayer(map.removeLayer, map); + this._map = null; + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + eachLayer: function (method, context) { + for (var i in this._layers) { + method.call(context, this._layers[i]); + } + return this; + }, + + getLayer: function (id) { + return this._layers[id]; + }, + + getLayers: function () { + var layers = []; + + for (var i in this._layers) { + layers.push(this._layers[i]); + } + return layers; + }, + + setZIndex: function (zIndex) { + return this.invoke('setZIndex', zIndex); + }, + + getLayerId: function (layer) { + return L.stamp(layer); + } +}); + +L.layerGroup = function (layers) { + return new L.LayerGroup(layers); +}; + + +/* + * L.FeatureGroup extends L.LayerGroup by introducing mouse events and additional methods + * shared between a group of interactive layers (like vectors or markers). + */ + +L.FeatureGroup = L.LayerGroup.extend({ + includes: L.Mixin.Events, + + statics: { + EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose' + }, + + addLayer: function (layer) { + if (this.hasLayer(layer)) { + return this; + } + + layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this); + + L.LayerGroup.prototype.addLayer.call(this, layer); + + if (this._popupContent && layer.bindPopup) { + layer.bindPopup(this._popupContent, this._popupOptions); + } + + return this.fire('layeradd', {layer: layer}); + }, + + removeLayer: function (layer) { + if (layer in this._layers) { + layer = this._layers[layer]; + } + + layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this); + + L.LayerGroup.prototype.removeLayer.call(this, layer); + + if (this._popupContent) { + this.invoke('unbindPopup'); + } + + return this.fire('layerremove', {layer: layer}); + }, + + bindPopup: function (content, options) { + this._popupContent = content; + this._popupOptions = options; + return this.invoke('bindPopup', content, options); + }, + + setStyle: function (style) { + return this.invoke('setStyle', style); + }, + + bringToFront: function () { + return this.invoke('bringToFront'); + }, + + bringToBack: function () { + return this.invoke('bringToBack'); + }, + + getBounds: function () { + var bounds = new L.LatLngBounds(); + + this.eachLayer(function (layer) { + bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds()); + }); + + return bounds; + }, + + _propagateEvent: function (e) { + if (!e.layer) { + e.layer = e.target; + } + e.target = this; + + this.fire(e.type, e); + } +}); + +L.featureGroup = function (layers) { + return new L.FeatureGroup(layers); +}; + + +/* + * L.Path is a base class for rendering vector paths on a map. Inherited by Polyline, Circle, etc. + */ + +L.Path = L.Class.extend({ + includes: [L.Mixin.Events], + + statics: { + // how much to extend the clip area around the map view + // (relative to its size, e.g. 0.5 is half the screen in each direction) + // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is) + CLIP_PADDING: L.Browser.mobile ? + Math.max(0, Math.min(0.5, + (1280 / Math.max(window.innerWidth, window.innerHeight) - 1) / 2)) : 0.5 + }, + + options: { + stroke: true, + color: '#0033ff', + dashArray: null, + weight: 5, + opacity: 0.5, + + fill: false, + fillColor: null, //same as color by default + fillOpacity: 0.2, + + clickable: true + }, + + initialize: function (options) { + L.setOptions(this, options); + }, + + onAdd: function (map) { + this._map = map; + + if (!this._container) { + this._initElements(); + this._initEvents(); + } + + this.projectLatlngs(); + this._updatePath(); + + if (this._container) { + this._map._pathRoot.appendChild(this._container); + } + + this.fire('add'); + + map.on({ + 'viewreset': this.projectLatlngs, + 'moveend': this._updatePath + }, this); + }, + + addTo: function (map) { + map.addLayer(this); + return this; + }, + + onRemove: function (map) { + map._pathRoot.removeChild(this._container); + + // Need to fire remove event before we set _map to null as the event hooks might need the object + this.fire('remove'); + this._map = null; + + if (L.Browser.vml) { + this._container = null; + this._stroke = null; + this._fill = null; + } + + map.off({ + 'viewreset': this.projectLatlngs, + 'moveend': this._updatePath + }, this); + }, + + projectLatlngs: function () { + // do all projection stuff here + }, + + setStyle: function (style) { + L.setOptions(this, style); + + if (this._container) { + this._updateStyle(); + } + + return this; + }, + + redraw: function () { + if (this._map) { + this.projectLatlngs(); + this._updatePath(); + } + return this; + } +}); + +L.Map.include({ + _updatePathViewport: function () { + var p = L.Path.CLIP_PADDING, + size = this.getSize(), + panePos = L.DomUtil.getPosition(this._mapPane), + min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()), + max = min.add(size.multiplyBy(1 + p * 2)._round()); + + this._pathViewport = new L.Bounds(min, max); + } +}); + + +/* + * Extends L.Path with SVG-specific rendering code. + */ + +L.Path.SVG_NS = 'http://www.w3.org/2000/svg'; + +L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect); + +L.Path = L.Path.extend({ + statics: { + SVG: L.Browser.svg + }, + + bringToFront: function () { + var root = this._map._pathRoot, + path = this._container; + + if (path && root.lastChild !== path) { + root.appendChild(path); + } + return this; + }, + + bringToBack: function () { + var root = this._map._pathRoot, + path = this._container, + first = root.firstChild; + + if (path && first !== path) { + root.insertBefore(path, first); + } + return this; + }, + + getPathString: function () { + // form path string here + }, + + _createElement: function (name) { + return document.createElementNS(L.Path.SVG_NS, name); + }, + + _initElements: function () { + this._map._initPathRoot(); + this._initPath(); + this._initStyle(); + }, + + _initPath: function () { + this._container = this._createElement('g'); + + this._path = this._createElement('path'); + this._container.appendChild(this._path); + }, + + _initStyle: function () { + if (this.options.stroke) { + this._path.setAttribute('stroke-linejoin', 'round'); + this._path.setAttribute('stroke-linecap', 'round'); + } + if (this.options.fill) { + this._path.setAttribute('fill-rule', 'evenodd'); + } + if (this.options.pointerEvents) { + this._path.setAttribute('pointer-events', this.options.pointerEvents); + } + if (!this.options.clickable && !this.options.pointerEvents) { + this._path.setAttribute('pointer-events', 'none'); + } + this._updateStyle(); + }, + + _updateStyle: function () { + if (this.options.stroke) { + this._path.setAttribute('stroke', this.options.color); + this._path.setAttribute('stroke-opacity', this.options.opacity); + this._path.setAttribute('stroke-width', this.options.weight); + if (this.options.dashArray) { + this._path.setAttribute('stroke-dasharray', this.options.dashArray); + } else { + this._path.removeAttribute('stroke-dasharray'); + } + } else { + this._path.setAttribute('stroke', 'none'); + } + if (this.options.fill) { + this._path.setAttribute('fill', this.options.fillColor || this.options.color); + this._path.setAttribute('fill-opacity', this.options.fillOpacity); + } else { + this._path.setAttribute('fill', 'none'); + } + }, + + _updatePath: function () { + var str = this.getPathString(); + if (!str) { + // fix webkit empty string parsing bug + str = 'M0 0'; + } + this._path.setAttribute('d', str); + }, + + // TODO remove duplication with L.Map + _initEvents: function () { + if (this.options.clickable) { + if (L.Browser.svg || !L.Browser.vml) { + this._path.setAttribute('class', 'leaflet-clickable'); + } + + L.DomEvent.on(this._container, 'click', this._onMouseClick, this); + + var events = ['dblclick', 'mousedown', 'mouseover', + 'mouseout', 'mousemove', 'contextmenu']; + for (var i = 0; i < events.length; i++) { + L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this); + } + } + }, + + _onMouseClick: function (e) { + if (this._map.dragging && this._map.dragging.moved()) { return; } + + this._fireMouseEvent(e); + }, + + _fireMouseEvent: function (e) { + if (!this.hasEventListeners(e.type)) { return; } + + var map = this._map, + containerPoint = map.mouseEventToContainerPoint(e), + layerPoint = map.containerPointToLayerPoint(containerPoint), + latlng = map.layerPointToLatLng(layerPoint); + + this.fire(e.type, { + latlng: latlng, + layerPoint: layerPoint, + containerPoint: containerPoint, + originalEvent: e + }); + + if (e.type === 'contextmenu') { + L.DomEvent.preventDefault(e); + } + if (e.type !== 'mousemove') { + L.DomEvent.stopPropagation(e); + } + } +}); + +L.Map.include({ + _initPathRoot: function () { + if (!this._pathRoot) { + this._pathRoot = L.Path.prototype._createElement('svg'); + this._panes.overlayPane.appendChild(this._pathRoot); + + if (this.options.zoomAnimation && L.Browser.any3d) { + this._pathRoot.setAttribute('class', ' leaflet-zoom-animated'); + + this.on({ + 'zoomanim': this._animatePathZoom, + 'zoomend': this._endPathZoom + }); + } else { + this._pathRoot.setAttribute('class', ' leaflet-zoom-hide'); + } + + this.on('moveend', this._updateSvgViewport); + this._updateSvgViewport(); + } + }, + + _animatePathZoom: function (e) { + var scale = this.getZoomScale(e.zoom), + offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min); + + this._pathRoot.style[L.DomUtil.TRANSFORM] = + L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') '; + + this._pathZooming = true; + }, + + _endPathZoom: function () { + this._pathZooming = false; + }, + + _updateSvgViewport: function () { + + if (this._pathZooming) { + // Do not update SVGs while a zoom animation is going on otherwise the animation will break. + // When the zoom animation ends we will be updated again anyway + // This fixes the case where you do a momentum move and zoom while the move is still ongoing. + return; + } + + this._updatePathViewport(); + + var vp = this._pathViewport, + min = vp.min, + max = vp.max, + width = max.x - min.x, + height = max.y - min.y, + root = this._pathRoot, + pane = this._panes.overlayPane; + + // Hack to make flicker on drag end on mobile webkit less irritating + if (L.Browser.mobileWebkit) { + pane.removeChild(root); + } + + L.DomUtil.setPosition(root, min); + root.setAttribute('width', width); + root.setAttribute('height', height); + root.setAttribute('viewBox', [min.x, min.y, width, height].join(' ')); + + if (L.Browser.mobileWebkit) { + pane.appendChild(root); + } + } +}); + + +/* + * Popup extension to L.Path (polylines, polygons, circles), adding popup-related methods. + */ + +L.Path.include({ + + bindPopup: function (content, options) { + + if (content instanceof L.Popup) { + this._popup = content; + } else { + if (!this._popup || options) { + this._popup = new L.Popup(options, this); + } + this._popup.setContent(content); + } + + if (!this._popupHandlersAdded) { + this + .on('click', this._openPopup, this) + .on('remove', this.closePopup, this); + + this._popupHandlersAdded = true; + } + + return this; + }, + + unbindPopup: function () { + if (this._popup) { + this._popup = null; + this + .off('click', this._openPopup) + .off('remove', this.closePopup); + + this._popupHandlersAdded = false; + } + return this; + }, + + openPopup: function (latlng) { + + if (this._popup) { + // open the popup from one of the path's points if not specified + latlng = latlng || this._latlng || + this._latlngs[Math.floor(this._latlngs.length / 2)]; + + this._openPopup({latlng: latlng}); + } + + return this; + }, + + closePopup: function () { + if (this._popup) { + this._popup._close(); + } + return this; + }, + + _openPopup: function (e) { + this._popup.setLatLng(e.latlng); + this._map.openPopup(this._popup); + } +}); + + +/* + * Vector rendering for IE6-8 through VML. + * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! + */ + +L.Browser.vml = !L.Browser.svg && (function () { + try { + var div = document.createElement('div'); + div.innerHTML = ''; + + var shape = div.firstChild; + shape.style.behavior = 'url(#default#VML)'; + + return shape && (typeof shape.adj === 'object'); + + } catch (e) { + return false; + } +}()); + +L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({ + statics: { + VML: true, + CLIP_PADDING: 0.02 + }, + + _createElement: (function () { + try { + document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); + return function (name) { + return document.createElement(''); + }; + } catch (e) { + return function (name) { + return document.createElement( + '<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); + }; + } + }()), + + _initPath: function () { + var container = this._container = this._createElement('shape'); + L.DomUtil.addClass(container, 'leaflet-vml-shape'); + if (this.options.clickable) { + L.DomUtil.addClass(container, 'leaflet-clickable'); + } + container.coordsize = '1 1'; + + this._path = this._createElement('path'); + container.appendChild(this._path); + + this._map._pathRoot.appendChild(container); + }, + + _initStyle: function () { + this._updateStyle(); + }, + + _updateStyle: function () { + var stroke = this._stroke, + fill = this._fill, + options = this.options, + container = this._container; + + container.stroked = options.stroke; + container.filled = options.fill; + + if (options.stroke) { + if (!stroke) { + stroke = this._stroke = this._createElement('stroke'); + stroke.endcap = 'round'; + container.appendChild(stroke); + } + stroke.weight = options.weight + 'px'; + stroke.color = options.color; + stroke.opacity = options.opacity; + + if (options.dashArray) { + stroke.dashStyle = options.dashArray instanceof Array ? + options.dashArray.join(' ') : + options.dashArray.replace(/( *, *)/g, ' '); + } else { + stroke.dashStyle = ''; + } + + } else if (stroke) { + container.removeChild(stroke); + this._stroke = null; + } + + if (options.fill) { + if (!fill) { + fill = this._fill = this._createElement('fill'); + container.appendChild(fill); + } + fill.color = options.fillColor || options.color; + fill.opacity = options.fillOpacity; + + } else if (fill) { + container.removeChild(fill); + this._fill = null; + } + }, + + _updatePath: function () { + var style = this._container.style; + + style.display = 'none'; + this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug + style.display = ''; + } +}); + +L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : { + _initPathRoot: function () { + if (this._pathRoot) { return; } + + var root = this._pathRoot = document.createElement('div'); + root.className = 'leaflet-vml-container'; + this._panes.overlayPane.appendChild(root); + + this.on('moveend', this._updatePathViewport); + this._updatePathViewport(); + } +}); + + +/* + * Vector rendering for all browsers that support canvas. + */ + +L.Browser.canvas = (function () { + return !!document.createElement('canvas').getContext; +}()); + +L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path : L.Path.extend({ + statics: { + //CLIP_PADDING: 0.02, // not sure if there's a need to set it to a small value + CANVAS: true, + SVG: false + }, + + redraw: function () { + if (this._map) { + this.projectLatlngs(); + this._requestUpdate(); + } + return this; + }, + + setStyle: function (style) { + L.setOptions(this, style); + + if (this._map) { + this._updateStyle(); + this._requestUpdate(); + } + return this; + }, + + onRemove: function (map) { + map + .off('viewreset', this.projectLatlngs, this) + .off('moveend', this._updatePath, this); + + if (this.options.clickable) { + this._map.off('click', this._onClick, this); + this._map.off('mousemove', this._onMouseMove, this); + } + + this._requestUpdate(); + + this._map = null; + }, + + _requestUpdate: function () { + if (this._map && !L.Path._updateRequest) { + L.Path._updateRequest = L.Util.requestAnimFrame(this._fireMapMoveEnd, this._map); + } + }, + + _fireMapMoveEnd: function () { + L.Path._updateRequest = null; + this.fire('moveend'); + }, + + _initElements: function () { + this._map._initPathRoot(); + this._ctx = this._map._canvasCtx; + }, + + _updateStyle: function () { + var options = this.options; + + if (options.stroke) { + this._ctx.lineWidth = options.weight; + this._ctx.strokeStyle = options.color; + } + if (options.fill) { + this._ctx.fillStyle = options.fillColor || options.color; + } + }, + + _drawPath: function () { + var i, j, len, len2, point, drawMethod; + + this._ctx.beginPath(); + + for (i = 0, len = this._parts.length; i < len; i++) { + for (j = 0, len2 = this._parts[i].length; j < len2; j++) { + point = this._parts[i][j]; + drawMethod = (j === 0 ? 'move' : 'line') + 'To'; + + this._ctx[drawMethod](point.x, point.y); + } + // TODO refactor ugly hack + if (this instanceof L.Polygon) { + this._ctx.closePath(); + } + } + }, + + _checkIfEmpty: function () { + return !this._parts.length; + }, + + _updatePath: function () { + if (this._checkIfEmpty()) { return; } + + var ctx = this._ctx, + options = this.options; + + this._drawPath(); + ctx.save(); + this._updateStyle(); + + if (options.fill) { + ctx.globalAlpha = options.fillOpacity; + ctx.fill(); + } + + if (options.stroke) { + ctx.globalAlpha = options.opacity; + ctx.stroke(); + } + + ctx.restore(); + + // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature + }, + + _initEvents: function () { + if (this.options.clickable) { + // TODO dblclick + this._map.on('mousemove', this._onMouseMove, this); + this._map.on('click', this._onClick, this); + } + }, + + _onClick: function (e) { + if (this._containsPoint(e.layerPoint)) { + this.fire('click', e); + } + }, + + _onMouseMove: function (e) { + if (!this._map || this._map._animatingZoom) { return; } + + // TODO don't do on each move + if (this._containsPoint(e.layerPoint)) { + this._ctx.canvas.style.cursor = 'pointer'; + this._mouseInside = true; + this.fire('mouseover', e); + + } else if (this._mouseInside) { + this._ctx.canvas.style.cursor = ''; + this._mouseInside = false; + this.fire('mouseout', e); + } + } +}); + +L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {} : { + _initPathRoot: function () { + var root = this._pathRoot, + ctx; + + if (!root) { + root = this._pathRoot = document.createElement('canvas'); + root.style.position = 'absolute'; + ctx = this._canvasCtx = root.getContext('2d'); + + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + + this._panes.overlayPane.appendChild(root); + + if (this.options.zoomAnimation) { + this._pathRoot.className = 'leaflet-zoom-animated'; + this.on('zoomanim', this._animatePathZoom); + this.on('zoomend', this._endPathZoom); + } + this.on('moveend', this._updateCanvasViewport); + this._updateCanvasViewport(); + } + }, + + _updateCanvasViewport: function () { + // don't redraw while zooming. See _updateSvgViewport for more details + if (this._pathZooming) { return; } + this._updatePathViewport(); + + var vp = this._pathViewport, + min = vp.min, + size = vp.max.subtract(min), + root = this._pathRoot; + + //TODO check if this works properly on mobile webkit + L.DomUtil.setPosition(root, min); + root.width = size.x; + root.height = size.y; + root.getContext('2d').translate(-min.x, -min.y); + } +}); + + +/* + * L.LineUtil contains different utility functions for line segments + * and polylines (clipping, simplification, distances, etc.) + */ + +/*jshint bitwise:false */ // allow bitwise oprations for this file + +L.LineUtil = { + + // Simplify polyline with vertex reduction and Douglas-Peucker simplification. + // Improves rendering performance dramatically by lessening the number of points to draw. + + simplify: function (/*Point[]*/ points, /*Number*/ tolerance) { + if (!tolerance || !points.length) { + return points.slice(); + } + + var sqTolerance = tolerance * tolerance; + + // stage 1: vertex reduction + points = this._reducePoints(points, sqTolerance); + + // stage 2: Douglas-Peucker simplification + points = this._simplifyDP(points, sqTolerance); + + return points; + }, + + // distance from a point to a segment between two points + pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { + return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true)); + }, + + closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { + return this._sqClosestPointOnSegment(p, p1, p2); + }, + + // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm + _simplifyDP: function (points, sqTolerance) { + + var len = points.length, + ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, + markers = new ArrayConstructor(len); + + markers[0] = markers[len - 1] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1); + + var i, + newPoints = []; + + for (i = 0; i < len; i++) { + if (markers[i]) { + newPoints.push(points[i]); + } + } + + return newPoints; + }, + + _simplifyDPStep: function (points, markers, sqTolerance, first, last) { + + var maxSqDist = 0, + index, i, sqDist; + + for (i = first + 1; i <= last - 1; i++) { + sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true); + + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; + } + } + + if (maxSqDist > sqTolerance) { + markers[index] = 1; + + this._simplifyDPStep(points, markers, sqTolerance, first, index); + this._simplifyDPStep(points, markers, sqTolerance, index, last); + } + }, + + // reduce points that are too close to each other to a single point + _reducePoints: function (points, sqTolerance) { + var reducedPoints = [points[0]]; + + for (var i = 1, prev = 0, len = points.length; i < len; i++) { + if (this._sqDist(points[i], points[prev]) > sqTolerance) { + reducedPoints.push(points[i]); + prev = i; + } + } + if (prev < len - 1) { + reducedPoints.push(points[len - 1]); + } + return reducedPoints; + }, + + // Cohen-Sutherland line clipping algorithm. + // Used to avoid rendering parts of a polyline that are not currently visible. + + clipSegment: function (a, b, bounds, useLastCode) { + var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds), + codeB = this._getBitCode(b, bounds), + + codeOut, p, newCode; + + // save 2nd code to avoid calculating it on the next segment + this._lastCode = codeB; + + while (true) { + // if a,b is inside the clip window (trivial accept) + if (!(codeA | codeB)) { + return [a, b]; + // if a,b is outside the clip window (trivial reject) + } else if (codeA & codeB) { + return false; + // other cases + } else { + codeOut = codeA || codeB; + p = this._getEdgeIntersection(a, b, codeOut, bounds); + newCode = this._getBitCode(p, bounds); + + if (codeOut === codeA) { + a = p; + codeA = newCode; + } else { + b = p; + codeB = newCode; + } + } + } + }, + + _getEdgeIntersection: function (a, b, code, bounds) { + var dx = b.x - a.x, + dy = b.y - a.y, + min = bounds.min, + max = bounds.max; + + if (code & 8) { // top + return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y); + } else if (code & 4) { // bottom + return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y); + } else if (code & 2) { // right + return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx); + } else if (code & 1) { // left + return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx); + } + }, + + _getBitCode: function (/*Point*/ p, bounds) { + var code = 0; + + if (p.x < bounds.min.x) { // left + code |= 1; + } else if (p.x > bounds.max.x) { // right + code |= 2; + } + if (p.y < bounds.min.y) { // bottom + code |= 4; + } else if (p.y > bounds.max.y) { // top + code |= 8; + } + + return code; + }, + + // square distance (to avoid unnecessary Math.sqrt calls) + _sqDist: function (p1, p2) { + var dx = p2.x - p1.x, + dy = p2.y - p1.y; + return dx * dx + dy * dy; + }, + + // return closest point on segment or distance to that point + _sqClosestPointOnSegment: function (p, p1, p2, sqDist) { + var x = p1.x, + y = p1.y, + dx = p2.x - x, + dy = p2.y - y, + dot = dx * dx + dy * dy, + t; + + if (dot > 0) { + t = ((p.x - x) * dx + (p.y - y) * dy) / dot; + + if (t > 1) { + x = p2.x; + y = p2.y; + } else if (t > 0) { + x += dx * t; + y += dy * t; + } + } + + dx = p.x - x; + dy = p.y - y; + + return sqDist ? dx * dx + dy * dy : new L.Point(x, y); + } +}; + + +/* + * L.Polyline is used to display polylines on a map. + */ + +L.Polyline = L.Path.extend({ + initialize: function (latlngs, options) { + L.Path.prototype.initialize.call(this, options); + + this._latlngs = this._convertLatLngs(latlngs); + }, + + options: { + // how much to simplify the polyline on each zoom level + // more = better performance and smoother look, less = more accurate + smoothFactor: 1.0, + noClip: false + }, + + projectLatlngs: function () { + this._originalPoints = []; + + for (var i = 0, len = this._latlngs.length; i < len; i++) { + this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]); + } + }, + + getPathString: function () { + for (var i = 0, len = this._parts.length, str = ''; i < len; i++) { + str += this._getPathPartStr(this._parts[i]); + } + return str; + }, + + getLatLngs: function () { + return this._latlngs; + }, + + setLatLngs: function (latlngs) { + this._latlngs = this._convertLatLngs(latlngs); + return this.redraw(); + }, + + addLatLng: function (latlng) { + this._latlngs.push(L.latLng(latlng)); + return this.redraw(); + }, + + spliceLatLngs: function () { // (Number index, Number howMany) + var removed = [].splice.apply(this._latlngs, arguments); + this._convertLatLngs(this._latlngs, true); + this.redraw(); + return removed; + }, + + closestLayerPoint: function (p) { + var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null; + + for (var j = 0, jLen = parts.length; j < jLen; j++) { + var points = parts[j]; + for (var i = 1, len = points.length; i < len; i++) { + p1 = points[i - 1]; + p2 = points[i]; + var sqDist = L.LineUtil._sqClosestPointOnSegment(p, p1, p2, true); + if (sqDist < minDistance) { + minDistance = sqDist; + minPoint = L.LineUtil._sqClosestPointOnSegment(p, p1, p2); + } + } + } + if (minPoint) { + minPoint.distance = Math.sqrt(minDistance); + } + return minPoint; + }, + + getBounds: function () { + return new L.LatLngBounds(this.getLatLngs()); + }, + + _convertLatLngs: function (latlngs, overwrite) { + var i, len, target = overwrite ? latlngs : []; + + for (i = 0, len = latlngs.length; i < len; i++) { + if (L.Util.isArray(latlngs[i]) && typeof latlngs[i][0] !== 'number') { + return; + } + target[i] = L.latLng(latlngs[i]); + } + return target; + }, + + _initEvents: function () { + L.Path.prototype._initEvents.call(this); + }, + + _getPathPartStr: function (points) { + var round = L.Path.VML; + + for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) { + p = points[j]; + if (round) { + p._round(); + } + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; + } + return str; + }, + + _clipPoints: function () { + var points = this._originalPoints, + len = points.length, + i, k, segment; + + if (this.options.noClip) { + this._parts = [points]; + return; + } + + this._parts = []; + + var parts = this._parts, + vp = this._map._pathViewport, + lu = L.LineUtil; + + for (i = 0, k = 0; i < len - 1; i++) { + segment = lu.clipSegment(points[i], points[i + 1], vp, i); + if (!segment) { + continue; + } + + parts[k] = parts[k] || []; + parts[k].push(segment[0]); + + // if segment goes out of screen, or it's the last one, it's the end of the line part + if ((segment[1] !== points[i + 1]) || (i === len - 2)) { + parts[k].push(segment[1]); + k++; + } + } + }, + + // simplify each clipped part of the polyline + _simplifyPoints: function () { + var parts = this._parts, + lu = L.LineUtil; + + for (var i = 0, len = parts.length; i < len; i++) { + parts[i] = lu.simplify(parts[i], this.options.smoothFactor); + } + }, + + _updatePath: function () { + if (!this._map) { return; } + + this._clipPoints(); + this._simplifyPoints(); + + L.Path.prototype._updatePath.call(this); + } +}); + +L.polyline = function (latlngs, options) { + return new L.Polyline(latlngs, options); +}; + + +/* + * L.PolyUtil contains utility functions for polygons (clipping, etc.). + */ + +/*jshint bitwise:false */ // allow bitwise operations here + +L.PolyUtil = {}; + +/* + * Sutherland-Hodgeman polygon clipping algorithm. + * Used to avoid rendering parts of a polygon that are not currently visible. + */ +L.PolyUtil.clipPolygon = function (points, bounds) { + var clippedPoints, + edges = [1, 4, 2, 8], + i, j, k, + a, b, + len, edge, p, + lu = L.LineUtil; + + for (i = 0, len = points.length; i < len; i++) { + points[i]._code = lu._getBitCode(points[i], bounds); + } + + // for each edge (left, bottom, right, top) + for (k = 0; k < 4; k++) { + edge = edges[k]; + clippedPoints = []; + + for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { + a = points[i]; + b = points[j]; + + // if a is inside the clip window + if (!(a._code & edge)) { + // if b is outside the clip window (a->b goes out of screen) + if (b._code & edge) { + p = lu._getEdgeIntersection(b, a, edge, bounds); + p._code = lu._getBitCode(p, bounds); + clippedPoints.push(p); + } + clippedPoints.push(a); + + // else if b is inside the clip window (a->b enters the screen) + } else if (!(b._code & edge)) { + p = lu._getEdgeIntersection(b, a, edge, bounds); + p._code = lu._getBitCode(p, bounds); + clippedPoints.push(p); + } + } + points = clippedPoints; + } + + return points; +}; + + +/* + * L.Polygon is used to display polygons on a map. + */ + +L.Polygon = L.Polyline.extend({ + options: { + fill: true + }, + + initialize: function (latlngs, options) { + var i, len, hole; + + L.Polyline.prototype.initialize.call(this, latlngs, options); + + if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) { + this._latlngs = this._convertLatLngs(latlngs[0]); + this._holes = latlngs.slice(1); + + for (i = 0, len = this._holes.length; i < len; i++) { + hole = this._holes[i] = this._convertLatLngs(this._holes[i]); + if (hole[0].equals(hole[hole.length - 1])) { + hole.pop(); + } + } + } + + // filter out last point if its equal to the first one + latlngs = this._latlngs; + + if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) { + latlngs.pop(); + } + }, + + projectLatlngs: function () { + L.Polyline.prototype.projectLatlngs.call(this); + + // project polygon holes points + // TODO move this logic to Polyline to get rid of duplication + this._holePoints = []; + + if (!this._holes) { return; } + + var i, j, len, len2; + + for (i = 0, len = this._holes.length; i < len; i++) { + this._holePoints[i] = []; + + for (j = 0, len2 = this._holes[i].length; j < len2; j++) { + this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]); + } + } + }, + + _clipPoints: function () { + var points = this._originalPoints, + newParts = []; + + this._parts = [points].concat(this._holePoints); + + if (this.options.noClip) { return; } + + for (var i = 0, len = this._parts.length; i < len; i++) { + var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport); + if (clipped.length) { + newParts.push(clipped); + } + } + + this._parts = newParts; + }, + + _getPathPartStr: function (points) { + var str = L.Polyline.prototype._getPathPartStr.call(this, points); + return str + (L.Browser.svg ? 'z' : 'x'); + } +}); + +L.polygon = function (latlngs, options) { + return new L.Polygon(latlngs, options); +}; + + +/* + * Contains L.MultiPolyline and L.MultiPolygon layers. + */ + +(function () { + function createMulti(Klass) { + + return L.FeatureGroup.extend({ + + initialize: function (latlngs, options) { + this._layers = {}; + this._options = options; + this.setLatLngs(latlngs); + }, + + setLatLngs: function (latlngs) { + var i = 0, + len = latlngs.length; + + this.eachLayer(function (layer) { + if (i < len) { + layer.setLatLngs(latlngs[i++]); + } else { + this.removeLayer(layer); + } + }, this); + + while (i < len) { + this.addLayer(new Klass(latlngs[i++], this._options)); + } + + return this; + } + }); + } + + L.MultiPolyline = createMulti(L.Polyline); + L.MultiPolygon = createMulti(L.Polygon); + + L.multiPolyline = function (latlngs, options) { + return new L.MultiPolyline(latlngs, options); + }; + + L.multiPolygon = function (latlngs, options) { + return new L.MultiPolygon(latlngs, options); + }; +}()); + + +/* + * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object. + */ + +L.Rectangle = L.Polygon.extend({ + initialize: function (latLngBounds, options) { + L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options); + }, + + setBounds: function (latLngBounds) { + this.setLatLngs(this._boundsToLatLngs(latLngBounds)); + }, + + _boundsToLatLngs: function (latLngBounds) { + latLngBounds = L.latLngBounds(latLngBounds); + return [ + latLngBounds.getSouthWest(), + latLngBounds.getNorthWest(), + latLngBounds.getNorthEast(), + latLngBounds.getSouthEast() + ]; + } +}); + +L.rectangle = function (latLngBounds, options) { + return new L.Rectangle(latLngBounds, options); +}; + + +/* + * L.Circle is a circle overlay (with a certain radius in meters). + */ + +L.Circle = L.Path.extend({ + initialize: function (latlng, radius, options) { + L.Path.prototype.initialize.call(this, options); + + this._latlng = L.latLng(latlng); + this._mRadius = radius; + }, + + options: { + fill: true + }, + + setLatLng: function (latlng) { + this._latlng = L.latLng(latlng); + return this.redraw(); + }, + + setRadius: function (radius) { + this._mRadius = radius; + return this.redraw(); + }, + + projectLatlngs: function () { + var lngRadius = this._getLngRadius(), + latlng = this._latlng, + pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]); + + this._point = this._map.latLngToLayerPoint(latlng); + this._radius = Math.max(this._point.x - pointLeft.x, 1); + }, + + getBounds: function () { + var lngRadius = this._getLngRadius(), + latRadius = (this._mRadius / 40075017) * 360, + latlng = this._latlng; + + return new L.LatLngBounds( + [latlng.lat - latRadius, latlng.lng - lngRadius], + [latlng.lat + latRadius, latlng.lng + lngRadius]); + }, + + getLatLng: function () { + return this._latlng; + }, + + getPathString: function () { + var p = this._point, + r = this._radius; + + if (this._checkIfEmpty()) { + return ''; + } + + if (L.Browser.svg) { + return 'M' + p.x + ',' + (p.y - r) + + 'A' + r + ',' + r + ',0,1,1,' + + (p.x - 0.1) + ',' + (p.y - r) + ' z'; + } else { + p._round(); + r = Math.round(r); + return 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r + ' 0,' + (65535 * 360); + } + }, + + getRadius: function () { + return this._mRadius; + }, + + // TODO Earth hardcoded, move into projection code! + + _getLatRadius: function () { + return (this._mRadius / 40075017) * 360; + }, + + _getLngRadius: function () { + return this._getLatRadius() / Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat); + }, + + _checkIfEmpty: function () { + if (!this._map) { + return false; + } + var vp = this._map._pathViewport, + r = this._radius, + p = this._point; + + return p.x - r > vp.max.x || p.y - r > vp.max.y || + p.x + r < vp.min.x || p.y + r < vp.min.y; + } +}); + +L.circle = function (latlng, radius, options) { + return new L.Circle(latlng, radius, options); +}; + + +/* + * L.CircleMarker is a circle overlay with a permanent pixel radius. + */ + +L.CircleMarker = L.Circle.extend({ + options: { + radius: 10, + weight: 2 + }, + + initialize: function (latlng, options) { + L.Circle.prototype.initialize.call(this, latlng, null, options); + this._radius = this.options.radius; + }, + + projectLatlngs: function () { + this._point = this._map.latLngToLayerPoint(this._latlng); + }, + + _updateStyle : function () { + L.Circle.prototype._updateStyle.call(this); + this.setRadius(this.options.radius); + }, + + setRadius: function (radius) { + this.options.radius = this._radius = radius; + return this.redraw(); + } +}); + +L.circleMarker = function (latlng, options) { + return new L.CircleMarker(latlng, options); +}; + + +/* + * Extends L.Polyline to be able to manually detect clicks on Canvas-rendered polylines. + */ + +L.Polyline.include(!L.Path.CANVAS ? {} : { + _containsPoint: function (p, closed) { + var i, j, k, len, len2, dist, part, + w = this.options.weight / 2; + + if (L.Browser.touch) { + w += 10; // polyline click tolerance on touch devices + } + + for (i = 0, len = this._parts.length; i < len; i++) { + part = this._parts[i]; + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { + if (!closed && (j === 0)) { + continue; + } + + dist = L.LineUtil.pointToSegmentDistance(p, part[k], part[j]); + + if (dist <= w) { + return true; + } + } + } + return false; + } +}); + + +/* + * Extends L.Polygon to be able to manually detect clicks on Canvas-rendered polygons. + */ + +L.Polygon.include(!L.Path.CANVAS ? {} : { + _containsPoint: function (p) { + var inside = false, + part, p1, p2, + i, j, k, + len, len2; + + // TODO optimization: check if within bounds first + + if (L.Polyline.prototype._containsPoint.call(this, p, true)) { + // click on polygon border + return true; + } + + // ray casting algorithm for detecting if point is in polygon + + for (i = 0, len = this._parts.length; i < len; i++) { + part = this._parts[i]; + + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { + p1 = part[j]; + p2 = part[k]; + + if (((p1.y > p.y) !== (p2.y > p.y)) && + (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { + inside = !inside; + } + } + } + + return inside; + } +}); + + +/* + * Extends L.Circle with Canvas-specific code. + */ + +L.Circle.include(!L.Path.CANVAS ? {} : { + _drawPath: function () { + var p = this._point; + this._ctx.beginPath(); + this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false); + }, + + _containsPoint: function (p) { + var center = this._point, + w2 = this.options.stroke ? this.options.weight / 2 : 0; + + return (p.distanceTo(center) <= this._radius + w2); + } +}); - if (this._moved) { - // ensure drag is not fired after dragend - L.Util.cancelAnimFrame(this._animRequest); - this.fire('dragend'); - } +/* + * CircleMarker canvas specific drawing parts. + */ - this._moving = false; +L.CircleMarker.include(!L.Path.CANVAS ? {} : { + _updateStyle: function () { + L.Path.prototype._updateStyle.call(this); } }); +/* + * L.GeoJSON turns any GeoJSON data into a Leaflet layer. + */ + +L.GeoJSON = L.FeatureGroup.extend({ + + initialize: function (geojson, options) { + L.setOptions(this, options); + + this._layers = {}; + + if (geojson) { + this.addData(geojson); + } + }, + + addData: function (geojson) { + var features = L.Util.isArray(geojson) ? geojson : geojson.features, + i, len; + + if (features) { + for (i = 0, len = features.length; i < len; i++) { + // Only add this if geometry or geometries are set and not null + if (features[i].geometries || features[i].geometry || features[i].features) { + this.addData(features[i]); + } + } + return this; + } + + var options = this.options; + + if (options.filter && !options.filter(geojson)) { return; } + + var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng); + layer.feature = L.GeoJSON.asFeature(geojson); + + layer.defaultOptions = layer.options; + this.resetStyle(layer); + + if (options.onEachFeature) { + options.onEachFeature(geojson, layer); + } + + return this.addLayer(layer); + }, + + resetStyle: function (layer) { + var style = this.options.style; + if (style) { + // reset any custom styles + L.Util.extend(layer.options, layer.defaultOptions); + + this._setLayerStyle(layer, style); + } + }, + + setStyle: function (style) { + this.eachLayer(function (layer) { + this._setLayerStyle(layer, style); + }, this); + }, + + _setLayerStyle: function (layer, style) { + if (typeof style === 'function') { + style = style(layer.feature); + } + if (layer.setStyle) { + layer.setStyle(style); + } + } +}); + +L.extend(L.GeoJSON, { + geometryToLayer: function (geojson, pointToLayer, coordsToLatLng) { + var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, + coords = geometry.coordinates, + layers = [], + latlng, latlngs, i, len, layer; + + coordsToLatLng = coordsToLatLng || this.coordsToLatLng; + + switch (geometry.type) { + case 'Point': + latlng = coordsToLatLng(coords); + return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); + + case 'MultiPoint': + for (i = 0, len = coords.length; i < len; i++) { + latlng = coordsToLatLng(coords[i]); + layer = pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng); + layers.push(layer); + } + return new L.FeatureGroup(layers); + + case 'LineString': + latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng); + return new L.Polyline(latlngs); + + case 'Polygon': + latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); + return new L.Polygon(latlngs); + + case 'MultiLineString': + latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng); + return new L.MultiPolyline(latlngs); + + case 'MultiPolygon': + latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng); + return new L.MultiPolygon(latlngs); + + case 'GeometryCollection': + for (i = 0, len = geometry.geometries.length; i < len; i++) { + + layer = this.geometryToLayer({ + geometry: geometry.geometries[i], + type: 'Feature', + properties: geojson.properties + }, pointToLayer, coordsToLatLng); + + layers.push(layer); + } + return new L.FeatureGroup(layers); + + default: + throw new Error('Invalid GeoJSON object.'); + } + }, + + coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng + return new L.LatLng(coords[1], coords[0]); + }, + + coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array + var latlng, i, len, + latlngs = []; + + for (i = 0, len = coords.length; i < len; i++) { + latlng = levelsDeep ? + this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) : + (coordsToLatLng || this.coordsToLatLng)(coords[i]); + + latlngs.push(latlng); + } + + return latlngs; + }, + + latLngToCoords: function (latLng) { + return [latLng.lng, latLng.lat]; + }, + + latLngsToCoords: function (latLngs) { + var coords = []; + + for (var i = 0, len = latLngs.length; i < len; i++) { + coords.push(L.GeoJSON.latLngToCoords(latLngs[i])); + } + + return coords; + }, + + getFeature: function (layer, newGeometry) { + return layer.feature ? L.extend({}, layer.feature, {geometry: newGeometry}) : L.GeoJSON.asFeature(newGeometry); + }, + + asFeature: function (geoJSON) { + if (geoJSON.type === 'Feature') { + return geoJSON; + } + + return { + type: 'Feature', + properties: {}, + geometry: geoJSON + }; + } +}); + +var PointToGeoJSON = { + toGeoJSON: function () { + return L.GeoJSON.getFeature(this, { + type: 'Point', + coordinates: L.GeoJSON.latLngToCoords(this.getLatLng()) + }); + } +}; + +L.Marker.include(PointToGeoJSON); +L.Circle.include(PointToGeoJSON); +L.CircleMarker.include(PointToGeoJSON); + +L.Polyline.include({ + toGeoJSON: function () { + return L.GeoJSON.getFeature(this, { + type: 'LineString', + coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs()) + }); + } +}); + +L.Polygon.include({ + toGeoJSON: function () { + var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())], + i, len, hole; + + coords[0].push(coords[0][0]); + + if (this._holes) { + for (i = 0, len = this._holes.length; i < len; i++) { + hole = L.GeoJSON.latLngsToCoords(this._holes[i]); + hole.push(hole[0]); + coords.push(hole); + } + } + + return L.GeoJSON.getFeature(this, { + type: 'Polygon', + coordinates: coords + }); + } +}); + +(function () { + function includeMulti(Klass, type) { + Klass.include({ + toGeoJSON: function () { + var coords = []; + + this.eachLayer(function (layer) { + coords.push(layer.toGeoJSON().geometry.coordinates); + }); + + return L.GeoJSON.getFeature(this, { + type: type, + coordinates: coords + }); + } + }); + } + + includeMulti(L.MultiPolyline, 'MultiLineString'); + includeMulti(L.MultiPolygon, 'MultiPolygon'); +}()); + +L.LayerGroup.include({ + toGeoJSON: function () { + var features = []; + + this.eachLayer(function (layer) { + if (layer.toGeoJSON) { + features.push(L.GeoJSON.asFeature(layer.toGeoJSON())); + } + }); + + return { + type: 'FeatureCollection', + features: features + }; + } +}); + +L.geoJson = function (geojson, options) { + return new L.GeoJSON(geojson, options); +}; + + +/* + * L.DomEvent contains functions for working with DOM events. + */ + +L.DomEvent = { + /* inspired by John Resig, Dean Edwards and YUI addEvent implementations */ + addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object]) + + var id = L.stamp(fn), + key = '_leaflet_' + type + id, + handler, originalHandler, newType; + + if (obj[key]) { return this; } + + handler = function (e) { + return fn.call(context || obj, e || L.DomEvent._getEvent()); + }; + + if (L.Browser.msTouch && type.indexOf('touch') === 0) { + return this.addMsTouchListener(obj, type, handler, id); + } + if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) { + this.addDoubleTapListener(obj, handler, id); + } + + if ('addEventListener' in obj) { + + if (type === 'mousewheel') { + obj.addEventListener('DOMMouseScroll', handler, false); + obj.addEventListener(type, handler, false); + + } else if ((type === 'mouseenter') || (type === 'mouseleave')) { + + originalHandler = handler; + newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout'); + + handler = function (e) { + if (!L.DomEvent._checkMouse(obj, e)) { return; } + return originalHandler(e); + }; + + obj.addEventListener(newType, handler, false); + + } else if (type === 'click' && L.Browser.android) { + originalHandler = handler; + handler = function (e) { + return L.DomEvent._filterClick(e, originalHandler); + }; + + obj.addEventListener(type, handler, false); + } else { + obj.addEventListener(type, handler, false); + } + + } else if ('attachEvent' in obj) { + obj.attachEvent('on' + type, handler); + } + + obj[key] = handler; + + return this; + }, + + removeListener: function (obj, type, fn) { // (HTMLElement, String, Function) + + var id = L.stamp(fn), + key = '_leaflet_' + type + id, + handler = obj[key]; + + if (!handler) { return this; } + + if (L.Browser.msTouch && type.indexOf('touch') === 0) { + this.removeMsTouchListener(obj, type, id); + } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) { + this.removeDoubleTapListener(obj, id); + + } else if ('removeEventListener' in obj) { + + if (type === 'mousewheel') { + obj.removeEventListener('DOMMouseScroll', handler, false); + obj.removeEventListener(type, handler, false); + + } else if ((type === 'mouseenter') || (type === 'mouseleave')) { + obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false); + } else { + obj.removeEventListener(type, handler, false); + } + } else if ('detachEvent' in obj) { + obj.detachEvent('on' + type, handler); + } + + obj[key] = null; + + return this; + }, + + stopPropagation: function (e) { + + if (e.stopPropagation) { + e.stopPropagation(); + } else { + e.cancelBubble = true; + } + return this; + }, + + disableClickPropagation: function (el) { + var stop = L.DomEvent.stopPropagation; + + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { + L.DomEvent.addListener(el, L.Draggable.START[i], stop); + } + + return L.DomEvent + .addListener(el, 'click', L.DomEvent._fakeStop) + .addListener(el, 'dblclick', stop); + }, + + preventDefault: function (e) { + + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + return this; + }, + + stop: function (e) { + return L.DomEvent.preventDefault(e).stopPropagation(e); + }, + + getMousePosition: function (e, container) { + + var body = document.body, + docEl = document.documentElement, + x = e.pageX ? e.pageX : e.clientX + body.scrollLeft + docEl.scrollLeft, + y = e.pageY ? e.pageY : e.clientY + body.scrollTop + docEl.scrollTop, + pos = new L.Point(x, y); + + return (container ? pos._subtract(L.DomUtil.getViewportOffset(container)) : pos); + }, + + getWheelDelta: function (e) { + + var delta = 0; + + if (e.wheelDelta) { + delta = e.wheelDelta / 120; + } + if (e.detail) { + delta = -e.detail / 3; + } + return delta; + }, + + _fakeStop: function stop(e) { + // fakes stopPropagation by setting a special event flag checked in Map mouse events handler + // jshint camelcase: false + e._leaflet_stop = true; + }, + + // check if element really left/entered the event target (for mouseenter/mouseleave) + _checkMouse: function (el, e) { + + var related = e.relatedTarget; + + if (!related) { return true; } + + try { + while (related && (related !== el)) { + related = related.parentNode; + } + } catch (err) { + return false; + } + return (related !== el); + }, + + _getEvent: function () { // evil magic for IE + /*jshint noarg:false */ + var e = window.event; + if (!e) { + var caller = arguments.callee.caller; + while (caller) { + e = caller['arguments'][0]; + if (e && window.Event === e.constructor) { + break; + } + caller = caller.caller; + } + } + return e; + }, + + // this is a horrible workaround for a bug in Android where a single touch triggers two click events + _filterClick: function (e, handler) { + var timeStamp = (e.timeStamp || e.originalEvent.timeStamp), + elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick); + + // are they closer together than 1000ms yet more than 100ms? + // Android typically triggers them ~300ms apart while multiple listeners + // on the same event should be triggered far faster; + // or check if click is simulated on the element, and if it is, reject any non-simulated events + + if ((elapsed && elapsed > 100 && elapsed < 1000) || (e.target._simulatedClick && !e._simulated)) { + L.DomEvent.stop(e); + return; + } + L.DomEvent._lastClick = timeStamp; + + return handler(e); + } +}; + +L.DomEvent.on = L.DomEvent.addListener; +L.DomEvent.off = L.DomEvent.removeListener; + + +/* + * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too. + */ + +L.Draggable = L.Class.extend({ + includes: L.Mixin.Events, + + statics: { + START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'], + END: { + mousedown: 'mouseup', + touchstart: 'touchend', + MSPointerDown: 'touchend' + }, + MOVE: { + mousedown: 'mousemove', + touchstart: 'touchmove', + MSPointerDown: 'touchmove' + } + }, + + initialize: function (element, dragStartTarget) { + this._element = element; + this._dragStartTarget = dragStartTarget || element; + }, + + enable: function () { + if (this._enabled) { return; } + + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { + L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); + } + + this._enabled = true; + }, + + disable: function () { + if (!this._enabled) { return; } + + for (var i = L.Draggable.START.length - 1; i >= 0; i--) { + L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this); + } + + this._enabled = false; + this._moved = false; + }, + + _onDown: function (e) { + if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } + + L.DomEvent + .stopPropagation(e); + + if (L.Draggable._disabled) { return; } + + L.DomUtil.disableImageDrag(); + L.DomUtil.disableTextSelection(); + + var first = e.touches ? e.touches[0] : e, + el = first.target; + + // if touching a link, highlight it + if (L.Browser.touch && el.tagName.toLowerCase() === 'a') { + L.DomUtil.addClass(el, 'leaflet-active'); + } + + this._moved = false; + + if (this._moving) { return; } + + this._startPoint = new L.Point(first.clientX, first.clientY); + this._startPos = this._newPos = L.DomUtil.getPosition(this._element); + + L.DomEvent + .on(document, L.Draggable.MOVE[e.type], this._onMove, this) + .on(document, L.Draggable.END[e.type], this._onUp, this); + }, + + _onMove: function (e) { + if (e.touches && e.touches.length > 1) { return; } + + var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), + newPoint = new L.Point(first.clientX, first.clientY), + offset = newPoint.subtract(this._startPoint); + + if (!offset.x && !offset.y) { return; } + + L.DomEvent.preventDefault(e); + + if (!this._moved) { + this.fire('dragstart'); + + this._moved = true; + this._startPos = L.DomUtil.getPosition(this._element).subtract(offset); + + if (!L.Browser.touch) { + L.DomUtil.addClass(document.body, 'leaflet-dragging'); + } + } + + this._newPos = this._startPos.add(offset); + this._moving = true; + + L.Util.cancelAnimFrame(this._animRequest); + this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget); + }, + + _updatePosition: function () { + this.fire('predrag'); + L.DomUtil.setPosition(this._element, this._newPos); + this.fire('drag'); + }, + + _onUp: function () { + if (!L.Browser.touch) { + L.DomUtil.removeClass(document.body, 'leaflet-dragging'); + } + + for (var i in L.Draggable.MOVE) { + L.DomEvent + .off(document, L.Draggable.MOVE[i], this._onMove) + .off(document, L.Draggable.END[i], this._onUp); + } + + L.DomUtil.enableImageDrag(); + L.DomUtil.enableTextSelection(); + + if (this._moved) { + // ensure drag is not fired after dragend + L.Util.cancelAnimFrame(this._animRequest); + + this.fire('dragend'); + } + + this._moving = false; + } +}); + + /* L.Handler is a base class for handler classes that are used internally to inject interaction features like dragging to classes like Map and Marker. @@ -21121,109 +21121,109 @@ L.Map.ScrollWheelZoom = L.Handler.extend({ L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom); -/* - * Extends the event handling code with double tap support for mobile browsers. - */ - -L.extend(L.DomEvent, { - - _touchstart: L.Browser.msTouch ? 'MSPointerDown' : 'touchstart', - _touchend: L.Browser.msTouch ? 'MSPointerUp' : 'touchend', - - // inspired by Zepto touch code by Thomas Fuchs - addDoubleTapListener: function (obj, handler, id) { - var last, - doubleTap = false, - delay = 250, - touch, - pre = '_leaflet_', - touchstart = this._touchstart, - touchend = this._touchend, - trackedTouches = []; - - function onTouchStart(e) { - var count; - - if (L.Browser.msTouch) { - trackedTouches.push(e.pointerId); - count = trackedTouches.length; - } else { - count = e.touches.length; - } - if (count > 1) { - return; - } - - var now = Date.now(), - delta = now - (last || now); - - touch = e.touches ? e.touches[0] : e; - doubleTap = (delta > 0 && delta <= delay); - last = now; - } - - function onTouchEnd(e) { - if (L.Browser.msTouch) { - var idx = trackedTouches.indexOf(e.pointerId); - if (idx === -1) { - return; - } - trackedTouches.splice(idx, 1); - } - - if (doubleTap) { - if (L.Browser.msTouch) { - // work around .type being readonly with MSPointer* events - var newTouch = { }, - prop; - - // jshint forin:false - for (var i in touch) { - prop = touch[i]; - if (typeof prop === 'function') { - newTouch[i] = prop.bind(touch); - } else { - newTouch[i] = prop; - } - } - touch = newTouch; - } - touch.type = 'dblclick'; - handler(touch); - last = null; - } - } - obj[pre + touchstart + id] = onTouchStart; - obj[pre + touchend + id] = onTouchEnd; - - // on msTouch we need to listen on the document, otherwise a drag starting on the map and moving off screen - // will not come through to us, so we will lose track of how many touches are ongoing - var endElement = L.Browser.msTouch ? document.documentElement : obj; - - obj.addEventListener(touchstart, onTouchStart, false); - endElement.addEventListener(touchend, onTouchEnd, false); - - if (L.Browser.msTouch) { - endElement.addEventListener('MSPointerCancel', onTouchEnd, false); - } - - return this; - }, - - removeDoubleTapListener: function (obj, id) { - var pre = '_leaflet_'; - - obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false); - (L.Browser.msTouch ? document.documentElement : obj).removeEventListener( - this._touchend, obj[pre + this._touchend + id], false); - - if (L.Browser.msTouch) { - document.documentElement.removeEventListener('MSPointerCancel', obj[pre + this._touchend + id], false); - } - - return this; - } -}); +/* + * Extends the event handling code with double tap support for mobile browsers. + */ + +L.extend(L.DomEvent, { + + _touchstart: L.Browser.msTouch ? 'MSPointerDown' : 'touchstart', + _touchend: L.Browser.msTouch ? 'MSPointerUp' : 'touchend', + + // inspired by Zepto touch code by Thomas Fuchs + addDoubleTapListener: function (obj, handler, id) { + var last, + doubleTap = false, + delay = 250, + touch, + pre = '_leaflet_', + touchstart = this._touchstart, + touchend = this._touchend, + trackedTouches = []; + + function onTouchStart(e) { + var count; + + if (L.Browser.msTouch) { + trackedTouches.push(e.pointerId); + count = trackedTouches.length; + } else { + count = e.touches.length; + } + if (count > 1) { + return; + } + + var now = Date.now(), + delta = now - (last || now); + + touch = e.touches ? e.touches[0] : e; + doubleTap = (delta > 0 && delta <= delay); + last = now; + } + + function onTouchEnd(e) { + if (L.Browser.msTouch) { + var idx = trackedTouches.indexOf(e.pointerId); + if (idx === -1) { + return; + } + trackedTouches.splice(idx, 1); + } + + if (doubleTap) { + if (L.Browser.msTouch) { + // work around .type being readonly with MSPointer* events + var newTouch = { }, + prop; + + // jshint forin:false + for (var i in touch) { + prop = touch[i]; + if (typeof prop === 'function') { + newTouch[i] = prop.bind(touch); + } else { + newTouch[i] = prop; + } + } + touch = newTouch; + } + touch.type = 'dblclick'; + handler(touch); + last = null; + } + } + obj[pre + touchstart + id] = onTouchStart; + obj[pre + touchend + id] = onTouchEnd; + + // on msTouch we need to listen on the document, otherwise a drag starting on the map and moving off screen + // will not come through to us, so we will lose track of how many touches are ongoing + var endElement = L.Browser.msTouch ? document.documentElement : obj; + + obj.addEventListener(touchstart, onTouchStart, false); + endElement.addEventListener(touchend, onTouchEnd, false); + + if (L.Browser.msTouch) { + endElement.addEventListener('MSPointerCancel', onTouchEnd, false); + } + + return this; + }, + + removeDoubleTapListener: function (obj, id) { + var pre = '_leaflet_'; + + obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false); + (L.Browser.msTouch ? document.documentElement : obj).removeEventListener( + this._touchend, obj[pre + this._touchend + id], false); + + if (L.Browser.msTouch) { + document.documentElement.removeEventListener('MSPointerCancel', obj[pre + this._touchend + id], false); + } + + return this; + } +}); /* @@ -21830,425 +21830,425 @@ L.Map.Keyboard = L.Handler.extend({ }, _addHooks: function () { - L.DomEvent.on(document, 'keydown', this._onKeyDown, this); - }, - - _removeHooks: function () { - L.DomEvent.off(document, 'keydown', this._onKeyDown, this); - }, - - _onKeyDown: function (e) { - var key = e.keyCode, - map = this._map; - - if (key in this._panKeys) { - - if (map._panAnim && map._panAnim._inProgress) { return; } - - map.panBy(this._panKeys[key]); - - if (map.options.maxBounds) { - map.panInsideBounds(map.options.maxBounds); - } - - } else if (key in this._zoomKeys) { - map.setZoom(map.getZoom() + this._zoomKeys[key]); - - } else { - return; - } - - L.DomEvent.stop(e); - } -}); - -L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard); - - -/* - * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. - */ - -L.Handler.MarkerDrag = L.Handler.extend({ - initialize: function (marker) { - this._marker = marker; - }, - - addHooks: function () { - var icon = this._marker._icon; - if (!this._draggable) { - this._draggable = new L.Draggable(icon, icon); - } - - this._draggable - .on('dragstart', this._onDragStart, this) - .on('drag', this._onDrag, this) - .on('dragend', this._onDragEnd, this); - this._draggable.enable(); - }, - - removeHooks: function () { - this._draggable - .off('dragstart', this._onDragStart, this) - .off('drag', this._onDrag, this) - .off('dragend', this._onDragEnd, this); - - this._draggable.disable(); - }, - - moved: function () { - return this._draggable && this._draggable._moved; - }, - - _onDragStart: function () { - this._marker - .closePopup() - .fire('movestart') - .fire('dragstart'); - }, - - _onDrag: function () { - var marker = this._marker, - shadow = marker._shadow, - iconPos = L.DomUtil.getPosition(marker._icon), - latlng = marker._map.layerPointToLatLng(iconPos); - - // update shadow position - if (shadow) { - L.DomUtil.setPosition(shadow, iconPos); - } - - marker._latlng = latlng; - - marker - .fire('move', {latlng: latlng}) - .fire('drag'); - }, - - _onDragEnd: function () { - this._marker - .fire('moveend') - .fire('dragend'); - } -}); - - -/* - * L.Control is a base class for implementing map controls. Handles positioning. - * All other controls extend from this class. - */ - -L.Control = L.Class.extend({ - options: { - position: 'topright' - }, - - initialize: function (options) { - L.setOptions(this, options); - }, - - getPosition: function () { - return this.options.position; - }, - - setPosition: function (position) { - var map = this._map; - - if (map) { - map.removeControl(this); - } - - this.options.position = position; - - if (map) { - map.addControl(this); - } - - return this; - }, - - getContainer: function () { - return this._container; - }, - - addTo: function (map) { - this._map = map; - - var container = this._container = this.onAdd(map), - pos = this.getPosition(), - corner = map._controlCorners[pos]; - - L.DomUtil.addClass(container, 'leaflet-control'); - - if (pos.indexOf('bottom') !== -1) { - corner.insertBefore(container, corner.firstChild); - } else { - corner.appendChild(container); - } - - return this; - }, - - removeFrom: function (map) { - var pos = this.getPosition(), - corner = map._controlCorners[pos]; - - corner.removeChild(this._container); - this._map = null; - - if (this.onRemove) { - this.onRemove(map); - } - - return this; - } -}); - -L.control = function (options) { - return new L.Control(options); -}; - - -// adds control-related methods to L.Map - -L.Map.include({ - addControl: function (control) { - control.addTo(this); - return this; - }, - - removeControl: function (control) { - control.removeFrom(this); - return this; - }, - - _initControlPos: function () { - var corners = this._controlCorners = {}, - l = 'leaflet-', - container = this._controlContainer = - L.DomUtil.create('div', l + 'control-container', this._container); - - function createCorner(vSide, hSide) { - var className = l + vSide + ' ' + l + hSide; - - corners[vSide + hSide] = L.DomUtil.create('div', className, container); - } - - createCorner('top', 'left'); - createCorner('top', 'right'); - createCorner('bottom', 'left'); - createCorner('bottom', 'right'); - }, - - _clearControlPos: function () { - this._container.removeChild(this._controlContainer); - } -}); - - -/* - * L.Control.Zoom is used for the default zoom buttons on the map. - */ - -L.Control.Zoom = L.Control.extend({ - options: { - position: 'topleft' - }, - - onAdd: function (map) { - var zoomName = 'leaflet-control-zoom', - container = L.DomUtil.create('div', zoomName + ' leaflet-bar'); - - this._map = map; - - this._zoomInButton = this._createButton( - '+', 'Zoom in', zoomName + '-in', container, this._zoomIn, this); - this._zoomOutButton = this._createButton( - '-', 'Zoom out', zoomName + '-out', container, this._zoomOut, this); - - map.on('zoomend zoomlevelschange', this._updateDisabled, this); - - return container; - }, - - onRemove: function (map) { - map.off('zoomend zoomlevelschange', this._updateDisabled, this); - }, - - _zoomIn: function (e) { - this._map.zoomIn(e.shiftKey ? 3 : 1); + L.DomEvent.on(document, 'keydown', this._onKeyDown, this); }, - _zoomOut: function (e) { - this._map.zoomOut(e.shiftKey ? 3 : 1); + _removeHooks: function () { + L.DomEvent.off(document, 'keydown', this._onKeyDown, this); }, - _createButton: function (html, title, className, container, fn, context) { - var link = L.DomUtil.create('a', className, container); - link.innerHTML = html; - link.href = '#'; - link.title = title; + _onKeyDown: function (e) { + var key = e.keyCode, + map = this._map; - var stop = L.DomEvent.stopPropagation; + if (key in this._panKeys) { - L.DomEvent - .on(link, 'click', stop) - .on(link, 'mousedown', stop) - .on(link, 'dblclick', stop) - .on(link, 'click', L.DomEvent.preventDefault) - .on(link, 'click', fn, context); + if (map._panAnim && map._panAnim._inProgress) { return; } - return link; - }, + map.panBy(this._panKeys[key]); - _updateDisabled: function () { - var map = this._map, - className = 'leaflet-disabled'; + if (map.options.maxBounds) { + map.panInsideBounds(map.options.maxBounds); + } - L.DomUtil.removeClass(this._zoomInButton, className); - L.DomUtil.removeClass(this._zoomOutButton, className); + } else if (key in this._zoomKeys) { + map.setZoom(map.getZoom() + this._zoomKeys[key]); - if (map._zoom === map.getMinZoom()) { - L.DomUtil.addClass(this._zoomOutButton, className); - } - if (map._zoom === map.getMaxZoom()) { - L.DomUtil.addClass(this._zoomInButton, className); + } else { + return; } - } -}); - -L.Map.mergeOptions({ - zoomControl: true -}); -L.Map.addInitHook(function () { - if (this.options.zoomControl) { - this.zoomControl = new L.Control.Zoom(); - this.addControl(this.zoomControl); + L.DomEvent.stop(e); } }); -L.control.zoom = function (options) { - return new L.Control.Zoom(options); -}; - +L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard); /* - * L.Control.Attribution is used for displaying attribution on the map (added by default). + * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. */ -L.Control.Attribution = L.Control.extend({ - options: { - position: 'bottomright', - prefix: 'Leaflet' - }, - - initialize: function (options) { - L.setOptions(this, options); - - this._attributions = {}; +L.Handler.MarkerDrag = L.Handler.extend({ + initialize: function (marker) { + this._marker = marker; }, - onAdd: function (map) { - this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); - L.DomEvent.disableClickPropagation(this._container); - - map - .on('layeradd', this._onLayerAdd, this) - .on('layerremove', this._onLayerRemove, this); - - this._update(); + addHooks: function () { + var icon = this._marker._icon; + if (!this._draggable) { + this._draggable = new L.Draggable(icon, icon); + } - return this._container; + this._draggable + .on('dragstart', this._onDragStart, this) + .on('drag', this._onDrag, this) + .on('dragend', this._onDragEnd, this); + this._draggable.enable(); }, - onRemove: function (map) { - map - .off('layeradd', this._onLayerAdd) - .off('layerremove', this._onLayerRemove); - - }, + removeHooks: function () { + this._draggable + .off('dragstart', this._onDragStart, this) + .off('drag', this._onDrag, this) + .off('dragend', this._onDragEnd, this); - setPrefix: function (prefix) { - this.options.prefix = prefix; - this._update(); - return this; + this._draggable.disable(); }, - addAttribution: function (text) { - if (!text) { return; } - - if (!this._attributions[text]) { - this._attributions[text] = 0; - } - this._attributions[text]++; - - this._update(); - - return this; + moved: function () { + return this._draggable && this._draggable._moved; }, - removeAttribution: function (text) { - if (!text) { return; } - - if (this._attributions[text]) { - this._attributions[text]--; - this._update(); - } - - return this; + _onDragStart: function () { + this._marker + .closePopup() + .fire('movestart') + .fire('dragstart'); }, - _update: function () { - if (!this._map) { return; } - - var attribs = []; - - for (var i in this._attributions) { - if (this._attributions[i]) { - attribs.push(i); - } - } - - var prefixAndAttribs = []; + _onDrag: function () { + var marker = this._marker, + shadow = marker._shadow, + iconPos = L.DomUtil.getPosition(marker._icon), + latlng = marker._map.layerPointToLatLng(iconPos); - if (this.options.prefix) { - prefixAndAttribs.push(this.options.prefix); - } - if (attribs.length) { - prefixAndAttribs.push(attribs.join(', ')); + // update shadow position + if (shadow) { + L.DomUtil.setPosition(shadow, iconPos); } - this._container.innerHTML = prefixAndAttribs.join(' | '); - }, + marker._latlng = latlng; - _onLayerAdd: function (e) { - if (e.layer.getAttribution) { - this.addAttribution(e.layer.getAttribution()); - } + marker + .fire('move', {latlng: latlng}) + .fire('drag'); }, - _onLayerRemove: function (e) { - if (e.layer.getAttribution) { - this.removeAttribution(e.layer.getAttribution()); - } + _onDragEnd: function () { + this._marker + .fire('moveend') + .fire('dragend'); } }); -L.Map.mergeOptions({ - attributionControl: true -}); - -L.Map.addInitHook(function () { - if (this.options.attributionControl) { - this.attributionControl = (new L.Control.Attribution()).addTo(this); - } -}); -L.control.attribution = function (options) { - return new L.Control.Attribution(options); -}; +/* + * L.Control is a base class for implementing map controls. Handles positioning. + * All other controls extend from this class. + */ + +L.Control = L.Class.extend({ + options: { + position: 'topright' + }, + + initialize: function (options) { + L.setOptions(this, options); + }, + + getPosition: function () { + return this.options.position; + }, + + setPosition: function (position) { + var map = this._map; + + if (map) { + map.removeControl(this); + } + + this.options.position = position; + + if (map) { + map.addControl(this); + } + + return this; + }, + + getContainer: function () { + return this._container; + }, + + addTo: function (map) { + this._map = map; + + var container = this._container = this.onAdd(map), + pos = this.getPosition(), + corner = map._controlCorners[pos]; + + L.DomUtil.addClass(container, 'leaflet-control'); + + if (pos.indexOf('bottom') !== -1) { + corner.insertBefore(container, corner.firstChild); + } else { + corner.appendChild(container); + } + + return this; + }, + + removeFrom: function (map) { + var pos = this.getPosition(), + corner = map._controlCorners[pos]; + + corner.removeChild(this._container); + this._map = null; + + if (this.onRemove) { + this.onRemove(map); + } + + return this; + } +}); + +L.control = function (options) { + return new L.Control(options); +}; + + +// adds control-related methods to L.Map + +L.Map.include({ + addControl: function (control) { + control.addTo(this); + return this; + }, + + removeControl: function (control) { + control.removeFrom(this); + return this; + }, + + _initControlPos: function () { + var corners = this._controlCorners = {}, + l = 'leaflet-', + container = this._controlContainer = + L.DomUtil.create('div', l + 'control-container', this._container); + + function createCorner(vSide, hSide) { + var className = l + vSide + ' ' + l + hSide; + + corners[vSide + hSide] = L.DomUtil.create('div', className, container); + } + + createCorner('top', 'left'); + createCorner('top', 'right'); + createCorner('bottom', 'left'); + createCorner('bottom', 'right'); + }, + + _clearControlPos: function () { + this._container.removeChild(this._controlContainer); + } +}); + + +/* + * L.Control.Zoom is used for the default zoom buttons on the map. + */ + +L.Control.Zoom = L.Control.extend({ + options: { + position: 'topleft' + }, + + onAdd: function (map) { + var zoomName = 'leaflet-control-zoom', + container = L.DomUtil.create('div', zoomName + ' leaflet-bar'); + + this._map = map; + + this._zoomInButton = this._createButton( + '+', 'Zoom in', zoomName + '-in', container, this._zoomIn, this); + this._zoomOutButton = this._createButton( + '-', 'Zoom out', zoomName + '-out', container, this._zoomOut, this); + + map.on('zoomend zoomlevelschange', this._updateDisabled, this); + + return container; + }, + + onRemove: function (map) { + map.off('zoomend zoomlevelschange', this._updateDisabled, this); + }, + + _zoomIn: function (e) { + this._map.zoomIn(e.shiftKey ? 3 : 1); + }, + + _zoomOut: function (e) { + this._map.zoomOut(e.shiftKey ? 3 : 1); + }, + + _createButton: function (html, title, className, container, fn, context) { + var link = L.DomUtil.create('a', className, container); + link.innerHTML = html; + link.href = '#'; + link.title = title; + + var stop = L.DomEvent.stopPropagation; + + L.DomEvent + .on(link, 'click', stop) + .on(link, 'mousedown', stop) + .on(link, 'dblclick', stop) + .on(link, 'click', L.DomEvent.preventDefault) + .on(link, 'click', fn, context); + + return link; + }, + + _updateDisabled: function () { + var map = this._map, + className = 'leaflet-disabled'; + + L.DomUtil.removeClass(this._zoomInButton, className); + L.DomUtil.removeClass(this._zoomOutButton, className); + + if (map._zoom === map.getMinZoom()) { + L.DomUtil.addClass(this._zoomOutButton, className); + } + if (map._zoom === map.getMaxZoom()) { + L.DomUtil.addClass(this._zoomInButton, className); + } + } +}); + +L.Map.mergeOptions({ + zoomControl: true +}); + +L.Map.addInitHook(function () { + if (this.options.zoomControl) { + this.zoomControl = new L.Control.Zoom(); + this.addControl(this.zoomControl); + } +}); + +L.control.zoom = function (options) { + return new L.Control.Zoom(options); +}; + + + +/* + * L.Control.Attribution is used for displaying attribution on the map (added by default). + */ + +L.Control.Attribution = L.Control.extend({ + options: { + position: 'bottomright', + prefix: 'Leaflet' + }, + + initialize: function (options) { + L.setOptions(this, options); + + this._attributions = {}; + }, + + onAdd: function (map) { + this._container = L.DomUtil.create('div', 'leaflet-control-attribution'); + L.DomEvent.disableClickPropagation(this._container); + + map + .on('layeradd', this._onLayerAdd, this) + .on('layerremove', this._onLayerRemove, this); + + this._update(); + + return this._container; + }, + + onRemove: function (map) { + map + .off('layeradd', this._onLayerAdd) + .off('layerremove', this._onLayerRemove); + + }, + + setPrefix: function (prefix) { + this.options.prefix = prefix; + this._update(); + return this; + }, + + addAttribution: function (text) { + if (!text) { return; } + + if (!this._attributions[text]) { + this._attributions[text] = 0; + } + this._attributions[text]++; + + this._update(); + + return this; + }, + + removeAttribution: function (text) { + if (!text) { return; } + + if (this._attributions[text]) { + this._attributions[text]--; + this._update(); + } + + return this; + }, + + _update: function () { + if (!this._map) { return; } + + var attribs = []; + + for (var i in this._attributions) { + if (this._attributions[i]) { + attribs.push(i); + } + } + + var prefixAndAttribs = []; + + if (this.options.prefix) { + prefixAndAttribs.push(this.options.prefix); + } + if (attribs.length) { + prefixAndAttribs.push(attribs.join(', ')); + } + + this._container.innerHTML = prefixAndAttribs.join(' | '); + }, + + _onLayerAdd: function (e) { + if (e.layer.getAttribution) { + this.addAttribution(e.layer.getAttribution()); + } + }, + + _onLayerRemove: function (e) { + if (e.layer.getAttribution) { + this.removeAttribution(e.layer.getAttribution()); + } + } +}); + +L.Map.mergeOptions({ + attributionControl: true +}); + +L.Map.addInitHook(function () { + if (this.options.attributionControl) { + this.attributionControl = (new L.Control.Attribution()).addTo(this); + } +}); + +L.control.attribution = function (options) { + return new L.Control.Attribution(options); +}; /* @@ -22365,251 +22365,251 @@ L.control.scale = function (options) { }; -/* - * L.Control.Layers is a control to allow users to switch between different layers on the map. - */ - -L.Control.Layers = L.Control.extend({ - options: { - collapsed: true, - position: 'topright', - autoZIndex: true - }, - - initialize: function (baseLayers, overlays, options) { - L.setOptions(this, options); - - this._layers = {}; - this._lastZIndex = 0; - this._handlingClick = false; - - for (var i in baseLayers) { - this._addLayer(baseLayers[i], i); - } - - for (i in overlays) { - this._addLayer(overlays[i], i, true); - } - }, - - onAdd: function (map) { - this._initLayout(); - this._update(); - - map - .on('layeradd', this._onLayerChange, this) - .on('layerremove', this._onLayerChange, this); - - return this._container; - }, - - onRemove: function (map) { - map - .off('layeradd', this._onLayerChange) - .off('layerremove', this._onLayerChange); - }, - - addBaseLayer: function (layer, name) { - this._addLayer(layer, name); - this._update(); - return this; - }, - - addOverlay: function (layer, name) { - this._addLayer(layer, name, true); - this._update(); - return this; - }, - - removeLayer: function (layer) { - var id = L.stamp(layer); - delete this._layers[id]; - this._update(); - return this; - }, - - _initLayout: function () { - var className = 'leaflet-control-layers', - container = this._container = L.DomUtil.create('div', className); - - //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released - container.setAttribute('aria-haspopup', true); - - if (!L.Browser.touch) { - L.DomEvent.disableClickPropagation(container); - L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation); - } else { - L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation); - } - - var form = this._form = L.DomUtil.create('form', className + '-list'); - - if (this.options.collapsed) { - if (!L.Browser.android) { - L.DomEvent - .on(container, 'mouseover', this._expand, this) - .on(container, 'mouseout', this._collapse, this); - } - var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container); - link.href = '#'; - link.title = 'Layers'; - - if (L.Browser.touch) { - L.DomEvent - .on(link, 'click', L.DomEvent.stop) - .on(link, 'click', this._expand, this); - } - else { - L.DomEvent.on(link, 'focus', this._expand, this); - } - - this._map.on('click', this._collapse, this); - // TODO keyboard accessibility - } else { - this._expand(); - } - - this._baseLayersList = L.DomUtil.create('div', className + '-base', form); - this._separator = L.DomUtil.create('div', className + '-separator', form); - this._overlaysList = L.DomUtil.create('div', className + '-overlays', form); - - container.appendChild(form); - }, - - _addLayer: function (layer, name, overlay) { - var id = L.stamp(layer); - - this._layers[id] = { - layer: layer, - name: name, - overlay: overlay - }; - - if (this.options.autoZIndex && layer.setZIndex) { - this._lastZIndex++; - layer.setZIndex(this._lastZIndex); - } - }, - - _update: function () { - if (!this._container) { - return; - } - - this._baseLayersList.innerHTML = ''; - this._overlaysList.innerHTML = ''; - - var baseLayersPresent = false, - overlaysPresent = false, - i, obj; - - for (i in this._layers) { - obj = this._layers[i]; - this._addItem(obj); - overlaysPresent = overlaysPresent || obj.overlay; - baseLayersPresent = baseLayersPresent || !obj.overlay; - } - - this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none'; - }, - - _onLayerChange: function (e) { - var obj = this._layers[L.stamp(e.layer)]; - - if (!obj) { return; } - - if (!this._handlingClick) { - this._update(); - } - - var type = obj.overlay ? - (e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') : - (e.type === 'layeradd' ? 'baselayerchange' : null); - - if (type) { - this._map.fire(type, obj); - } - }, - - // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe) - _createRadioElement: function (name, checked) { - - var radioHtml = 'b[sorter]) return 1 @@ -25206,7 +25205,7 @@ function sortThings(opts, sorter, sorted) { if (sorted === "descending") opts.data.reverse() makeTable(opts) var header - $(opts.tableDiv + " .tHeader").each(function(i, el){ + $(tableDiv + " .tHeader").each(function(i, el){ var contents = resolveDataTitle($(el).text()) if (contents === sorter) header = el }) @@ -25218,13 +25217,13 @@ function resolveDataTitle(string) { var adjusted = string.toLowerCase().replace(/\s/g, '').replace(/\W/g, '') return adjusted } + module.exports.initiateTableSorter = initiateTableSorter function initiateTableSorter(options) { $(document).on("click", ".tHeader", sendToSort) function sendToSort(event) { var tableDiv = "#" + $(event.target).closest("div").attr("id") - console.log("came from this table",tableDiv) var sorted = $(event.target).attr("data-sorted") if (sorted) { if (sorted === "descending") sorted = "ascending" @@ -25233,14 +25232,12 @@ function initiateTableSorter(options) { else { sorted = "ascending" } var sorter = resolveDataTitle(event.target.innerHTML) var sortInfo = {"sorter": sorter, "sorted": sorted, "tableDiv": tableDiv} - console.log(sortInfo) sortThings(options, sorter, sorted, tableDiv) } } module.exports.makeTable = makeTable function makeTable(opts, filteredList) { - // see if .tHeader exists initiateTableSorter(opts) if (filteredList) var data = filteredList @@ -25260,7 +25257,6 @@ function makeTable(opts, filteredList) { module.exports.setPagClicks = setPagClicks function setPagClicks(data, tableId, currentPage, pagination, totalPages) { - console.log(currentPage) $(".pagination-pre-" + tableId).addClass("no-pag") $(document).on("click", (".pagination-next-" + tableId), function() { @@ -25286,7 +25282,6 @@ function setPagClicks(data, tableId, currentPage, pagination, totalPages) { }) $(document).on("click", (".pagination-pre-" + tableId), function() { - console.log(this) if (currentPage > 1) $(this).removeClass("no-pag") if ($(this).hasClass("no-pag")) return @@ -25295,7 +25290,6 @@ function setPagClicks(data, tableId, currentPage, pagination, totalPages) { // } currentPage = currentPage - 1 - // console.log("current", currentPage) var nextPage = currentPage + 1 currentStart = (currentPage * pagination) - pagination currentEnd = currentPage * pagination diff --git a/template.hbs b/template.hbs index 96f24d1e..f3cdfced 100644 --- a/template.hbs +++ b/template.hbs @@ -6,10 +6,15 @@ such site, very sheetsee.js + + + + +
        {{{content}}} @@ -48,5 +53,6 @@

        Home Page

        + \ No newline at end of file From 85ec5a13cf76930bc003ddf44404ad57083ce9a6 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sat, 8 Feb 2014 16:13:02 -0800 Subject: [PATCH 035/157] chart comb through --- demos/demo-chart.html | 71 ++++++++++++++-------------- demos/demo-map.html | 7 +-- docs/sheetsee-charts.md | 86 +++++++++++++++++++++++----------- site/demos/demo-chart.html | 71 ++++++++++++++-------------- site/demos/demo-map.html | 7 +-- site/docs/sheetsee-charts.html | 43 +++++++++++++---- 6 files changed, 171 insertions(+), 114 deletions(-) diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 5e75da28..67501796 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -1,15 +1,15 @@ - Sheetsee Chart Demo - - - - - - - + Sheetsee Chart Demo + + + + + + + +

        Pennies by State

        -

        spreadsheet

        +

        spreadsheet

        View Source

        - +
      +

      Home

      -
      - - - - + function showInfo(data) { + var cali = Sheetsee.getOccurance(data, "state") + var colors = ['#ff00ff', '#acacac'] + var caliData = Sheetsee.makeColorArrayOfObject(cali, colors) + var lineOptions = { units: "units", + labels: "undefined", + m: [80, 100, 120, 100], + w: 800, h: 400, + div: "#pennies", + yaxis: "pennies", + hiColor: "#E4EB29" + } + Sheetsee.d3LineChart(caliData, lineOptions) + } + - + diff --git a/demos/demo-map.html b/demos/demo-map.html index a0fe3b51..4373aed6 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -23,12 +23,12 @@

      All Pennies Map

      spreadsheet

      View Source

      - +
    +

    Home

    - + - - - - - - + Sheetsee Chart Demo + + + + + + + +

    Pennies by State

    -

    spreadsheet

    +

    spreadsheet

    View Source

    - + -
    - - - - + function showInfo(data) { + var cali = Sheetsee.getOccurance(data, "state") + var colors = ['#ff00ff', '#acacac'] + var caliData = Sheetsee.makeColorArrayOfObject(cali, colors) + var lineOptions = { units: "units", + labels: "undefined", + m: [80, 100, 120, 100], + w: 800, h: 400, + div: "#pennies", + yaxis: "pennies", + hiColor: "#E4EB29" + } + Sheetsee.d3LineChart(caliData, lineOptions) + } + - + diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index a0fe3b51..4373aed6 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -23,12 +23,12 @@

    All Pennies Map

    spreadsheet

    View Source

    - + - + ``` -_View the [entire source](https://github.com/maxogden/sheetsee-d3bubble)_ +There are lots of charts to get excited about in the [D3 gallery](https://github.com/mbostock/d3/wiki/Gallery). +_View the [entire source](https://github.com/maxogden/sheetsee-d3bubble)_ diff --git a/docs/sheetsee-charts.md b/docs/sheetsee-charts.md index 0a1f7db6..a02ea045 100644 --- a/docs/sheetsee-charts.md +++ b/docs/sheetsee-charts.md @@ -2,7 +2,7 @@ _[View Demo](/demos/demo-chart.html)_ -Sheetsee.js provides three [d3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also use a custom d3.js chart with Sheetsee, read about that [here](custom-charts.md). +Sheetsee.js provides three [D3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also use a custom D3 chart with Sheetsee, read about that [here](custom-charts.md). ## Make a Chart @@ -10,7 +10,7 @@ Each chart requires your data be an _array of objects_, with objects containing Experiment with the charts to find the correct size your `
    ` will need to be to hold the chart with your data in it nicely. -You can also make your own d3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information [here](docs/custom-charts.md) on using your own chart. +You can also make your own D3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information [here](custom-charts.md) on using your own chart. ### Bar Chart diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 9e839ffe..f3f5fef9 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -18,7 +18,7 @@

    Custom Charts

    -

    It's easy to take a d3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

    +

    It's easy to take a d3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

    Sheetsee charts currently work by taking in some options, like so:

    var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
     
    @@ -61,7 +61,7 @@

    Custom Charts

    <script type="text/javascript">
       document.addEventListener('DOMContentLoaded', function() {
         var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } ) 
    +    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
       })
     
       function showInfo(data) {
    diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html
    index 71a0abdc..80f6f643 100644
    --- a/site/docs/sheetsee-charts.html
    +++ b/site/docs/sheetsee-charts.html
    @@ -23,7 +23,7 @@ 

    Sheetsee-charts

    Make a Chart

    Each chart requires your data be an array of objects, with objects containing label and units key/value pairs.

    Experiment with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    -

    You can also make your own d3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information here on using your own chart.

    +

    You can also make your own d3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information here on using your own chart.

    Bar Chart

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    <div id="barChart"></div>
    
    From 3e8fa5504c3e7a315aa87a35878b3a508c2c2260 Mon Sep 17 00:00:00 2001
    From: Jessica Lord 
    Date: Sat, 8 Feb 2014 16:40:35 -0800
    Subject: [PATCH 037/157] mappy
    
    ---
     demos/demo-chart.html          |  3 +--
     demos/demo-map.html            | 19 ++++++++-----------
     demos/demo-table.html          |  7 ++++---
     docs/sheetsee-maps.md          | 12 ++++++------
     site/demos/demo-chart.html     |  3 +--
     site/demos/demo-map.html       | 19 ++++++++-----------
     site/demos/demo-table.html     |  7 ++++---
     site/docs/custom-charts.html   |  7 ++++---
     site/docs/sheetsee-charts.html |  4 ++--
     9 files changed, 38 insertions(+), 43 deletions(-)
    
    diff --git a/demos/demo-chart.html b/demos/demo-chart.html
    index 67501796..bb5d0c3c 100644
    --- a/demos/demo-chart.html
    +++ b/demos/demo-chart.html
    @@ -6,7 +6,6 @@
         
         
         
    -    
         
       
     
    @@ -30,7 +29,7 @@
         

    Pennies by State

    spreadsheet

    -

    View Source

    +

    View Source // View Documentation

    Getting Started

    diff --git a/demos/demo-map.html b/demos/demo-map.html index 4373aed6..cd0d2315 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -1,14 +1,13 @@ - Sheetsee Maps Demo - - - - + Sheetsee Maps Demo - - + + + + + +

    About

    @@ -50,7 +48,7 @@

    Big Time Thanks

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/basics.html b/site/docs/basics.html index f1911b76..22a8a207 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Spreadsheets as Databases

    @@ -80,7 +78,7 @@

    Publishing Your Spreadsheet

    CSS

    Sheetsee.js comes with a bare minimum stylesheet, sss.csss, which contains elements you'll want to style when using the feature they correspond to.

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/building.html b/site/docs/building.html index 99d45478..2474aad4 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Just Right

    @@ -42,7 +40,7 @@

    Install sheetsee from NPM

    * otherwise, defaults to standardout on your console which you can | pbcopy

    So for instance, sheetsee -m -t --save will build you a sheetsee with the basic data functions, the map and tables sections built in and save it as a file named sheetsee.js.

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 5ed94ad4..03d57ce2 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Sheetsee v3

    @@ -36,7 +34,7 @@

    Charting Intake

    Thanks @maxogden for the help with this.

    Started doing this changelong pretty late in the game.

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 2a1a7819..89d963d4 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Custom Charts

    @@ -72,7 +70,7 @@

    Custom Charts

    There are lots of charts to get excited about in the D3 gallery.

    View the entire source

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index c4f26dc3..6c413aa6 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Fork-n-Go

    @@ -41,7 +39,7 @@

    Hack Spots Fork-n-Go

    Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName.

    forkcommit

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 62777dde..9d016ca1 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Sheetsee-charts

    @@ -113,7 +111,7 @@

    Pie Chart

    Sheetsee.d3PieChart(data, pieOptions)
     
    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index dc2669d3..74ef0765 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -2,68 +2,66 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Sheetsee-core

    -

    This is the core module for creating a sheetsee.js bundle. It contains the functions for building your custom file as well as the basic data manipulation functions, it's automatically built into bundles.

    +

    This is the core module in sheetsee and is included in all builds. It contains the functions for building your custom file as well as the basic data manipulation functions.

    Working With Your Data

    -

    Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

    +

    Tabletop.js will fetch the data from your spreadsheet and return it as an array of objects. Sheetsee.js has functions built in to help you filter or reorganize the data if you'd like.

    Sheetsee.getGroupCount(data, groupTerm)

    This takes in your data, an array of objects, and searches for a string, groupTerm, in each piece of your data (formerly the cells of your spreadsheet). It returns the number of times it found the groupTerm.

    -
    getGroupCount(gData, "cat")
    -// returns 2
    +
    getGroupCount(data, "cat")
    +// returns a number
     

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

    -
    getColumnTotal(gData, "cuddlability")
    -// returns 11
    +

    Given your data, an array of objects, and a string column header, this functions sums each cell in that column(so this collumn you mention best have numbers).

    +
    getColumnTotal(data, "cuddlability")
    +// returns number
     

    Sheetsee.getAveragefromColumn(data, column)

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(gData, "cuddlability")
    -// returns 1.8333333333333333
    +
    getColumnAverage(data, "cuddlability")
    +// returns number
     

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns {breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}
    +

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    +
    getMin(data, "cuddlability")
    +// returns array
     

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
    +

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    +
    getMin(data, "cuddlability")
    +// returns array
     

    Don't Forget JavaScript Math

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(gData, "2009")
    -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
    +
    var profit09 = Sheetsee.getColumnTotal(data, "2009")
    +var profit10 = Sheetsee.getColumnTotal(data, "2010")
     var difference = profit09 - profit10
     

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

    +

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with JavaScript math functions and knowing a little bit more about icanhaz.js.

    Sheetsee.getMatches(data, filter, category)

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(gData, "dog", "kind")
    +
    getMatches(data, "dog", "kind")
     

    Returns an array of objects matching the category's filter.

    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
     

    Sheetsee.getOccurance(data, category)

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(gData, "kind")
    +
    getOccurance(data, "kind")
     

    Returns an object with keys and values for each variation of the category and its occurance.

    {"dog": 3, "cat": 3}
    @@ -71,7 +69,7 @@ 

    Sheetsee.getOccurance(data, catego

    Sheetsee.makeColorArrayOfObject(data, colors)

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    This function takes in your data, as an object, and an array of hexidecimal color strings which you define.

    -
    var kinds = getOccurance(gData, "kind")
    +
    var kinds = getOccurance(data, "kind")
     var kindColors = ["#ff00ff", "#DCF13C"]
     
     var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors)
    @@ -81,17 +79,17 @@ 

    Sheetsee.makeColorArrayOfO

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)

    -

    If you're using gData, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    -
    var gData =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
    +

    If you're using data, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    +
    var data =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
     

    For istance, if from our original data above we want to chart the age of each cat, we'll use:

    -
    Sheetsee.addUnitsLabels(gData, "name", "cuddlability")
    +
    Sheetsee.addUnitsLabels(data, "name", "cuddlability")
     

    Which will return an array, ready for the d3 charts:

    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
     
    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index f1f0f390..c256ce18 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Sheetsee-maps

    @@ -31,18 +29,18 @@

    Your HTML Placeholder <div>Your <script> Functions

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    Sheetsee.createGeoJSON(data, optionsJSON)

    -

    This takes in your data and the parts of your data, optionsJSON, that you plan on including in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data (by default it will use all the row's information).

    +

    This takes in your data and the parts of your data, optionsJSON, that you plan on including in your map's popups. These will be column headers in your spreadsheet. If you're not going to have popups on your markers, don't worry about it then and just pass in your data (by default it will use all the row's information).

    var optionsJSON = ["name", "breed", "cuddlability"]
     var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
     
    -

    It will return an array in the special geoJSON format that map making things love.

    -
    [{
    +

    It will return an array in the special geoJSON format that map making things love.

    +
    [{
       "geometry": {"type": "Point", "coordinates": [long, lat]},
       "properties": {
         "marker-size": "small",
         "marker-color": lineItem.hexcolor
       },
    -  "opts": {the options you pass in},
    +  "opts": {},
     }}
     

    Sheetsee.loadMap(mapDiv)

    @@ -55,7 +53,7 @@

    Sheetsee.addTileLayer(map, tileLay

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    Sheetsee.addMarkerLayer(geoJSON, map)

    -

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

    +

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
     

    Example template:

    @@ -83,7 +81,7 @@

    Source from the Getting Started

    - \ No newline at end of file + diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 17195e60..91708368 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Sheetsee-tables

    @@ -105,7 +103,7 @@

    Sheetsee.initiateTableFilter

    View Demo

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/docs/tips.html b/site/docs/tips.html index 0c257d14..43bebd62 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    Tips

    @@ -58,7 +56,7 @@

    Query Strings

    IFTTT

    Ifttt.com offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets.

    - +

    Getting Started

    - \ No newline at end of file + diff --git a/site/index.html b/site/index.html index 7fba0e72..9f2d29e3 100644 --- a/site/index.html +++ b/site/index.html @@ -2,19 +2,17 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +

    sheetseeimg

    @@ -91,7 +89,7 @@

    Use

  • Sheetsee-charts
  • - +

    Getting Started

    - \ No newline at end of file + diff --git a/template.hbs b/template.hbs index f3cdfced..b1d8c29f 100644 --- a/template.hbs +++ b/template.hbs @@ -2,23 +2,21 @@ - - - - such site, very sheetsee.js - - - - - - - + Sheetsee.js + + + + + + + + - +
    {{{content}}} - +

    Getting Started

      @@ -55,4 +53,4 @@
    - \ No newline at end of file + From 492f2910db662e45236c1efbcf9482c6875499cb Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sat, 8 Feb 2014 17:39:01 -0800 Subject: [PATCH 039/157] more --- demos/demo-chart.html | 2 +- demos/demo-map.html | 2 +- demos/demo-table.html | 2 +- docs/about.md | 10 +++++----- docs/building.md | 16 ++++++++++------ docs/sheetsee-core.md | 14 +++++++------- site/demos/demo-chart.html | 2 +- site/demos/demo-map.html | 2 +- site/demos/demo-table.html | 2 +- site/docs/about.html | 12 ++++++------ site/docs/basics.html | 2 +- site/docs/building.html | 16 +++++++++------- site/docs/changelog.html | 2 +- site/docs/custom-charts.html | 2 +- site/docs/fork-n-go.html | 2 +- site/docs/sheetsee-charts.html | 2 +- site/docs/sheetsee-core.html | 22 +++++++++++----------- site/docs/sheetsee-maps.html | 2 +- site/docs/sheetsee-tables.html | 2 +- site/docs/tips.html | 2 +- site/index.html | 2 +- template.hbs | 2 +- 22 files changed, 64 insertions(+), 58 deletions(-) diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 517e9b3c..40bfa3d5 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -35,7 +35,7 @@

    Pennies by State

    Getting Started

    diff --git a/demos/demo-map.html b/demos/demo-map.html index f2f96e00..b5489c66 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -27,7 +27,7 @@

    All Pennies Map

    Getting Started

    diff --git a/demos/demo-table.html b/demos/demo-table.html index e6992c9e..53400923 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -35,7 +35,7 @@

    Pretty Pennies

    Getting Started

    diff --git a/docs/about.md b/docs/about.md index 583f4e82..55ff664a 100644 --- a/docs/about.md +++ b/docs/about.md @@ -2,19 +2,19 @@ Sheetsee.js began as a part of my [Code for America](http://www.codeforamerica.org) 2012 Fellowship project, [See Penny Work](http://www.seepennywork.in). The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet. -In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2. +In early 2013, after the CfA Fellowship, I recieved a grant from [Mozilla Open News](http://opennews.org/) to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2. -The present version makes the project modular, customizable and with more maping and table features. +The present version makes the project modular, customizable and with more maping and table features. ## Built on top of Tabletop.js -Sheetsee would not exist were it not for [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely JSON of your data. Every instance of Sheetsee begins with running tabletop.js. +Sheetsee would not exist were it not for [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js. ### Sheetsee.js + Mapbox.js + d3.js -Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of [Leaflet.js](http://leafletjs.com/) and [Mapbox.js](https://www.mapbox.com/mapbox.js/) and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic [d3.js](http://d3js.org) charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is [here](docs/custom-chart.md). +Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, **sheetsee-tables**, comes with sorting, filtering and pagination. **Sheetsee-maps** is built ontop of [Leaflet.js](http://leafletjs.com/) and [Mapbox.js](https://www.mapbox.com/mapbox.js/) and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, **Sheetee-charts** comes with three basic [d3.js](http://d3js.org) charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is [here](docs/custom-chart.md). ## Hacked on Openly - Sheetsee.js is open source software with a [BSD license](docs/license.md). -- Sheetsee.js is built and maintained by [jlord](http://www.github.com/jlord) ([twitter](http://www.twitter.com/jllord)) with support from [contributors](https://github.com/jlord/sheetsee.js/graphs/contributors). +- Sheetsee.js is a labor of love by [jlord](http://www.github.com/jlord) ([twitter](http://www.twitter.com/jllord)) with support from [contributors](https://github.com/jlord/sheetsee.js/graphs/contributors). ## Contact - File a [new issue](https://github.com/jlord/sheetsee.js/issues/new) for ideas and bug reports. diff --git a/docs/building.md b/docs/building.md index 1df3f586..77822a65 100644 --- a/docs/building.md +++ b/docs/building.md @@ -1,18 +1,22 @@ -# Just Right +# Right-sizing -You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at [github.com/jlord/sheetsee.js](https://github.com/jlord/sheetsee.js/blob/master/js/sheetsee.js). +You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at [github.com/jlord/sheetsee.js](https://github.com/jlord/sheetsee.js/blob/master/js/sheetsee.js). -All bundle comes with [mapbox.js]() and [handlebars.js]() (since both are available on NPM). Additionally you'll need to also include [tabletop.js](https://github.com/jsoma/tabletop) and [jquery](http://www.jquery.com) in your HTML head like so: +All bundle comes with [mapbox.js]() and [handlebars.js]() (since both are available on [NPM](http://www.npmjs.org)). Additionally you'll need to also include [tabletop.js](https://github.com/jsoma/tabletop) and [jQuery](http://www.jquery.com) in your HTML head like so: ```HTML ``` -**To build your sheetsee you'll need [Node.js](http://www.nodejs.org) and [NPM](http://www.npmjs.org) (the latter comes with the former in most installs) on your computer and a command line.** +**To build your Sheetsee you'll need [Node.js](http://www.nodejs.org) and [NPM](http://www.npmjs.org) (the latter comes with the former in most installs) on your computer and a command line.** + +#### Get Node/NPM + +Download Node.js from [nodejs.org/download](http://nodejs.org/download). For most users you can just download the Mac _.pkg_ or Windows _.msi_. Follow the install instructions, both include NPM. Once they're installed, proceed: ## Install `sheetsee` from NPM -The sheetsee module contains the basic sorting and organizing data functions and the script for building on the other modules. Install `sheetsee` globally and then run it within the folder of your soon-to-be sheetsee.js project. +The `sheetsee` (with no '.js') module is the tool for building custom Sheetsee.js builds. Install `sheetsee` globally and then run it within the folder of your soon-to-be sheetsee.js project. _Install globally_ @@ -35,4 +39,4 @@ Here are the options for the different modules. If you want save the generated f _* otherwise, defaults to standardout on your console which you can_ `| pbcopy` -So for instance, `sheetsee -m -t --save` will build you a sheetsee with the basic **data** functions, the **map** and **tables** sections built in and save it as a file named **sheetsee.js**. +So for instance, `sheetsee -m -t --save` will build you a Sheetsee.js with the basic **data** functions, the **map** and **tables** sections built in and save it as a file named **sheetsee.js**. Running `sheetsee -m -t | pbcopy` will save the output to your clipboard. diff --git a/docs/sheetsee-core.md b/docs/sheetsee-core.md index b6e51fc0..1d76b339 100644 --- a/docs/sheetsee-core.md +++ b/docs/sheetsee-core.md @@ -83,13 +83,13 @@ Returns an _array of objects_ matching the category's filter. Takes **data** as an _array of objects_ and a _string_ for **category** (a column header from your spreadsheet) you want tally how often an element occured. -```javascript +```JAVASCRIPT getOccurance(data, "kind") ``` Returns an object with keys and values for each variation of the category and its occurance. -```javascript +```JAVASCRIPT {"dog": 3, "cat": 3} ``` @@ -99,7 +99,7 @@ If you use `getOccurance()` and want to then chart that data with d3.js, you'll This function takes in your data, as an _object_, and an _array_ of hexidecimal color strings which you define. -```javascript +```JAVASCRIPT var kinds = getOccurance(data, "kind") var kindColors = ["#ff00ff", "#DCF13C"] @@ -108,7 +108,7 @@ var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors) It will return an array of objects formatted to go directly into a d3 chart with the appropriate _units_ and _label keys_, like so: -```javascript +```JAVASCRIPT [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}] ``` @@ -118,18 +118,18 @@ If you pass in an array of just one color it will repeat that color for all item If you're using data, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number). -```javascript +```JAVASCRIPT var data = [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}] ``` For istance, if from our original data above we want to chart the age of each cat, we'll use: -```javascript +```JAVASCRIPT Sheetsee.addUnitsLabels(data, "name", "cuddlability") ``` Which will return an array, ready for the d3 charts: -```javascript +```JAVASCRIPT [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}] ``` diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index 517e9b3c..40bfa3d5 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -35,7 +35,7 @@

    Pennies by State

    Getting Started

    diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index f2f96e00..b5489c66 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -27,7 +27,7 @@

    All Pennies Map

    Getting Started

    diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index e6992c9e..53400923 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -35,7 +35,7 @@

    Pretty Pennies

    Getting Started

    diff --git a/site/docs/about.html b/site/docs/about.html index 966ceae1..9ec7854f 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -17,16 +17,16 @@

    About

    Sheetsee.js began as a part of my Code for America 2012 Fellowship project, See Penny Work. The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet.

    -

    In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

    -

    The present version makes the project modular, customizable and with more maping and table features.

    +

    In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

    +

    The present version makes the project modular, customizable and with more maping and table features.

    Built on top of Tabletop.js

    -

    Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely JSON of your data. Every instance of Sheetsee begins with running tabletop.js.

    +

    Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js.

    Sheetsee.js + Mapbox.js + d3.js

    -

    Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

    +

    Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

    Hacked on Openly

    Contact

      @@ -52,7 +52,7 @@

      Big Time Thanks

      Getting Started

      diff --git a/site/docs/basics.html b/site/docs/basics.html index 22a8a207..fe13f357 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -82,7 +82,7 @@

      CSS

      Getting Started

      diff --git a/site/docs/building.html b/site/docs/building.html index 2474aad4..b248a178 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -15,15 +15,17 @@
      -

      Just Right

      -

      You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

      -

      All bundle comes with mapbox.js and handlebars.js (since both are available on NPM). Additionally you'll need to also include tabletop.js and jquery in your HTML head like so:

      +

      Right-sizing

      +

      You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

      +

      All bundle comes with mapbox.js and handlebars.js (since both are available on NPM). Additionally you'll need to also include tabletop.js and jQuery in your HTML head like so:

      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
       
      -

      To build your sheetsee you'll need Node.js and NPM (the latter comes with the former in most installs) on your computer and a command line.

      +

      To build your Sheetsee you'll need Node.js and NPM (the latter comes with the former in most installs) on your computer and a command line.

      +

      Get Node/NPM

      +

      Download Node.js from nodejs.org/download. For most users you can just download the Mac .pkg or Windows .msi. Follow the install instructions, both include NPM. Once they're installed, proceed:

      Install sheetsee from NPM

      -

      The sheetsee module contains the basic sorting and organizing data functions and the script for building on the other modules. Install sheetsee globally and then run it within the folder of your soon-to-be sheetsee.js project.

      +

      The sheetsee (with no '.js') module is the tool for building custom Sheetsee.js builds. Install sheetsee globally and then run it within the folder of your soon-to-be sheetsee.js project.

      Install globally

      npm install -g sheetsee
       
      @@ -38,13 +40,13 @@

      Install sheetsee from NPM

    • --save to write out the file*

    * otherwise, defaults to standardout on your console which you can | pbcopy

    -

    So for instance, sheetsee -m -t --save will build you a sheetsee with the basic data functions, the map and tables sections built in and save it as a file named sheetsee.js.

    +

    So for instance, sheetsee -m -t --save will build you a Sheetsee.js with the basic data functions, the map and tables sections built in and save it as a file named sheetsee.js. Running sheetsee -m -t | pbcopy will save the output to your clipboard.

    Getting Started

    diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 03d57ce2..b3e2210f 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -38,7 +38,7 @@

    Started doing th

    Getting Started

    diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 89d963d4..bedd2892 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -74,7 +74,7 @@

    Custom Charts

    Getting Started

    diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 6c413aa6..5040ea55 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -43,7 +43,7 @@

    Hack Spots Fork-n-Go

    Getting Started

    diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 9d016ca1..a9b20e92 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -115,7 +115,7 @@

    Pie Chart

    Getting Started

    diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 74ef0765..d02e2a23 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -46,7 +46,7 @@

    Sheetsee.getMax(data, column)

    Don't Forget JavaScript Math

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(data, "2009")
    +
    var profit09 = Sheetsee.getColumnTotal(data, "2009")
     var profit10 = Sheetsee.getColumnTotal(data, "2010")
     var difference = profit09 - profit10
     
    @@ -54,46 +54,46 @@

    What These Little Bits are Good For

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with JavaScript math functions and knowing a little bit more about icanhaz.js.

    Sheetsee.getMatches(data, filter, category)

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(data, "dog", "kind")
    +
    getMatches(data, "dog", "kind")
     

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    +
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
     

    Sheetsee.getOccurance(data, category)

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(data, "kind")
    +
    getOccurance(data, "kind")
     

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    +
    {"dog": 3, "cat": 3}
     

    Sheetsee.makeColorArrayOfObject(data, colors)

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    This function takes in your data, as an object, and an array of hexidecimal color strings which you define.

    -
    var kinds = getOccurance(data, "kind")
    +
    var kinds = getOccurance(data, "kind")
     var kindColors = ["#ff00ff", "#DCF13C"]
     
     var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors)
     

    It will return an array of objects formatted to go directly into a d3 chart with the appropriate units and label keys, like so:

    -
    [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    +
    [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}]
     

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)

    If you're using data, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    -
    var data =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
    +
    var data =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
     

    For istance, if from our original data above we want to chart the age of each cat, we'll use:

    -
    Sheetsee.addUnitsLabels(data, "name", "cuddlability")
    +
    Sheetsee.addUnitsLabels(data, "name", "cuddlability")
     

    Which will return an array, ready for the d3 charts:

    -
    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
    +
    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
     

    Getting Started

    diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index c256ce18..72bd73ee 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -85,7 +85,7 @@

    Source from the Getting Started

    diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 91708368..a1e3c792 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -107,7 +107,7 @@

    Sheetsee.initiateTableFilter

    Getting Started

    diff --git a/site/docs/tips.html b/site/docs/tips.html index 43bebd62..89bd0d6d 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -60,7 +60,7 @@

    IFTTT

    Getting Started

    diff --git a/site/index.html b/site/index.html index 9f2d29e3..87f344aa 100644 --- a/site/index.html +++ b/site/index.html @@ -93,7 +93,7 @@

    Use

    Getting Started

    diff --git a/template.hbs b/template.hbs index b1d8c29f..18c49bd7 100644 --- a/template.hbs +++ b/template.hbs @@ -20,7 +20,7 @@

    Getting Started

    From d4a0b5ce024540f3ad69e39709a42c159e0d3970 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sat, 8 Feb 2014 18:47:50 -0800 Subject: [PATCH 040/157] ready --- buildpage.js | 9 +- demos/demo-chart.html | 3 +- docs/basics.md | 47 ++-- docs/tips.md | 39 ++- readme.md | 514 +++---------------------------------- site/assets/style.css | 11 +- site/demos/demo-chart.html | 3 +- site/docs/basics.html | 46 ++-- site/docs/tips.html | 24 +- site/index.html | 6 +- 10 files changed, 158 insertions(+), 544 deletions(-) diff --git a/buildpage.js b/buildpage.js index 821afed3..4e171ff2 100644 --- a/buildpage.js +++ b/buildpage.js @@ -15,7 +15,7 @@ cpr('./demos', './site/demos', function(err, files) { }) }) -fs.readFile('new-readme.md', function(err, file) { +fs.readFile('readme.md', function(err, file) { if (err) return console.log(err) var name = "index" var content = file.toString() @@ -50,16 +50,16 @@ function applyTemplate(html, name) { var rawTemplate = fs.readFileSync(file).toString() var template = hbs.compile(rawTemplate) var page = template(content) - writeFile(page, name) + writeFile(page, name) } function writeFile(page, name) { if (name === "index") { - return fs.writeFileSync('./site/' + name + '.html' , page) + return fs.writeFileSync('./site/' + name + '.html' , page) } mkdirp('./site/docs', function (err) { if (err) return console.error(err) - fs.writeFileSync('./site/docs/' + name + '.html' , page) + fs.writeFileSync('./site/docs/' + name + '.html' , page) }) } @@ -71,4 +71,3 @@ function changeExtensions(html, name) { var newHtml = html.replace(/\.md/g, '.html') return newHtml } - diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 40bfa3d5..cc94c234 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -11,7 +11,6 @@ diff --git a/docs/basics.md b/docs/basics.md index 6de25c83..a073a3af 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -1,27 +1,39 @@ # Spreadsheets as Databases -Spreadsheets are a great _lightweight_ database. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database set ups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet! +Spreadsheets are a great _lightweight_ databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet! ## The Short & Sweet -1. Link to Sheetsee.js, [tabletop.js](https://github.com/jsoma/tabletop/) and [jquery](http://www.jquery.org) in your HTML head. +1. Link to Sheetsee.js, [tabletop.js](https://github.com/jsoma/tabletop/) and [jQuery](http://www.jquery.org) in your HTML head. 2. Create a place holder `
    ` in your HTML for any chart, map or table you want to have. 3. Create templates for tables in ` - - + +
    @@ -31,14 +43,13 @@ Ignoring some HTML things to conserve space, you get the point. This gives you a @@ -60,15 +71,13 @@ There shouldn't be any breaks or horizontal organization in the spreadsheet. But ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) -You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! +You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! ### Geocoding If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. -> image of lat and long column headers - ### Publishing Your Spreadsheet ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) @@ -77,7 +86,7 @@ You need to do this in order to generate a unique key for your spreadsheet, whic ![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) -You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. +You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. _Actually, you technically can use the whole URL, but it's so long..._ ### CSS diff --git a/docs/tips.md b/docs/tips.md index c1d2631c..e2f672ec 100644 --- a/docs/tips.md +++ b/docs/tips.md @@ -4,7 +4,7 @@ A few things to think about beyond charts, maps and tables. ## ICanHaz.js -You can use templates for more than just tables. Use them to create lists `ol`, `ul`; array of images... You'll need a placeholder `
    ` in your HTML, a ` ``` -_Tempalte_ +_Script_ ```JavaScript ``` -_non-table template_ +_non-table example output_ ![lib](http://jlord.s3.amazonaws.com/wp-content/uploads/lending-ss.png) @@ -64,6 +64,33 @@ With a some CSS and such, the resulting website has a table with the hack spots When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM! -# IFTTT +## IFTTT -[Ifttt.com](http://www.ifttt.com) offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets. \ No newline at end of file +[Ifttt.com](http://www.ifttt.com) offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets. + +## Row Numbers + +When Tabletop.js returns your spreadsheet data, it adds a key/value of `rownumber`. This is great to use when you need to uniquely match or find a row in your data. + +## Images + +Your spreadsheet can contain URLs to images which you can use to display the images on the page you build. Your template would look something like this: + +```HTML + +``` + +## Data as Classes + +You can use your data as classes to style with CSS. For instance, if you had data about recipes and a column called 'Taste' that contained either 'savory' or 'sweet'. In a table of the recipes you could do something like: + +```HTML +

    +``` + +Then in your CSS: + +```CSS +td .savory {} +td .sweet {} +``` diff --git a/readme.md b/readme.md index 40151151..3173752e 100644 --- a/readme.md +++ b/readme.md @@ -1,502 +1,62 @@ -_**Attention!** Hi! Sheetsee will be updated *soon*. Fun! I'm currently working on adding in some features (pagination on tables and polygons in maps) and breaking the tables, maps and charts components of Sheetsee into individual modules allowing for custom builds with just the components you plan on using (or all if you don't care). Changes currently in progress on the [`modules` branch](https://github.com/jlord/sheetsee.js/tree/modules). Sheetsee modules (still being debugged) are in my [repositories](https://github.com/search?q=%40jlord+sheetsee+module&type=Repositories&ref=searchresults)._ -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/sheetsee-03.png) +![sheetseeimg](https://raw.github.com/jlord/sheetsee-cache/master/img/sheetsee-03.png) # Sheetsee.js -Sheetsee.js is a client-side JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page. -Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with. +**Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. -To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see [JavaScript for Cats](http://www.jsforcats.com), [Eloquent JavaScript](http://eloquentjavascript.net/) or [Mozilla's Developer Network](https://developer.mozilla.org/en-US/docs/JavaScript). +Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](/docs/basics.md). -### Dependencies +## Modules -Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, [Tabletop.js](http://builtbybalance.com/Tabletop/) gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with [IChanHas.js](http://icanhazjs.com/)(built on [mustache.js](http://mustache.github.io/)), maps with [Mapbox.js](http://mapbox.com/mapbox.js/example/v1.0.0/), and charts with [d3.js](http://d3js.org/). And [jQuery](http://jquery.com/) of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below. +Each of **sheetsee.js**'s features are divided into modules. Use just the parts you need; see docs on [building](/docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). -### Building -```bash -[sudo] npm install -g browserify uglify-js -npm install -make -``` +| Module | Contains | Docs | +| ------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------- | +| **sheetsee-core** | **Included in any build**. Gets you started and has the working-with-your-data functions. | [Doc](/docs/sheetsee-core.md) | +| **sheetsee-tables** | Contains everything you'll need to create a table including sortable columns, pagination and search.| [Doc](/docs/sheetsee-tables.md) | +| **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js. | [Doc](/docs/sheetsee-maps.md) | +| **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](/docs/sheetsee-charts.md) | -### CSS -Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design. +## Making Things -### Client-side or Server-side +What can you make with **Sheetsee.js**? Lost of things, here are some examples: -Sheetsee.js comes in two flavors, client-side (this repo) and server-side ([sheetsee-cache](http://www.github.com/jlord/sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal. +- [Hack-Spots](http://jlord.github.io/hack-spots) +- [Combine with IFTTT](http://jlord.us/instagram/) -The server-side version is built with [Node.js](http://www.nodejs.org) and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah! +**List your sheetsee project here: file an [issue or pull request](http://www.github.com/jlord/sheetsee.js).** -## The Short & Sweet +## Demos -1. Link to Sheetsee.js and dependencies in your HTML header. -2. Create a place holder `
    ` in your HTML for any chart, map or table you want to have. -3. Create templates for tables in ` - - - - - - -
    - - - +More resources on using Sheetsee.js: -## Awesome Possibilities +#### Getting Started -1. Small newsrooms with data for stories but small dev teams. -2. Friends or groups collaborating on data for a website/project. -3. Using [iftt.com](http://www.ifttt.com) to auto populate spreadsheets which are hooked to a website with Sheetsee.js. +- [About Sheetsee.js](docs/about.md) +- [Building Sheetsee](docs/building.md) +- [Basics](docs/basics.md) -## Examples -1. [Hack Spots](http://jlord.github.io/hack-spots) -2. [James Sconfitto](https://twitter.com/jugglingnutcase) make a [map of his relationship](https://github.com/jugglingnutcase/katiejamie) with his wife <3 +#### Ideas -## Getting Started +- [Fork-n-Go](docs/fork-n-go.md) +- [Tips!](docs/tips.md) +- [Custom charts](docs/custom-charts.md) -This bit is the same for both client-side and server-side versions. +#### Use -### Your Data - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) - -Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/nonos.png) - -There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting. - - [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] - -#### Hexcolor - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) - -You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! - -#### Geocoding - -If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) - that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. - -> image of lat and long column headers - -#### Publishing Your Spreadsheet - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) - -You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click _File_ > _Publish to the Web_. Then in the next window click _Start Publishing_; it will then turn into a _Stop Publishing_ button. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) - -You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. - -### Your Website - -Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet. - -For now, create empty `div` placeholders for the map, chart and tables you plan on including. - -## Hooking Up Your Data - -Here the paths diverge: - -### Client-side Hookup - -For client-siders, all you need to do is include the dependencies and sheetsee in your HTML `` and then in a script tag at the bottom of your page, right before the `` tag, you'll include this: - - - -The **URL** variable is the key from your spreadsheet's longer URL, explained above. `Tabletop.init()` takes that URL and execute's Tabletop, when it's done generating the table it executes the callback `showInfo` function. It's inside of this function that you'll then use your spreadsheet data, **gData**, to do all the Sheetsee.js goodness with. - -### Server-side Hookup - -The server-side version is in the repo [sheetsee-cache](http://www.github.com/jllord/sheetsee-cache). It uses [Node.js](http://www.nodejs.org) to go to Google, get the spreadsheet data (with a Node.js version of [Tabletop.js](http://npmjs.org/tabletop), thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data. - -When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled. - - - -#### Running Locally - -You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay! - -Once you [clone the repo](http://www.github.com/jllord/sheetsee-cache), navigate there in Terminal, install the node modules and launch the server. - - cd sheetsee-cache - npm install - node server.js - -This will launch a local server you can visit and develop locally with in your browser. - -## Working With Your Data - -Tabletop.js will return all of your data and it will be passed into your site as an _array of objects_ called **gData**. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like. - -### Sheetsee.getKeyword(data, keyword) - -This takes in your data, an _array of objects_, and searches for a _string_, **keyword**, in each piece of your **data** (formerly the cells of your spreadsheet). It returns an array of each element containing a **keyword** match. Similarly, using `getKeywordCount(data, "keyword)` will return the just the number of times the **keyword** occured. - - getKeyword(gData, "cat") - // returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}] - -### Sheetsee.getColumnTotal(data, column) - -Given your **data**, an _array of objects_ and a _string_ **column** header, this functions sums each cell in that column, so they best be numbers. - - getColumnTotal(gData, "cuddlability") - // returns 11 - -### Sheetsee.getAveragefromColumn(data, column) - -A really simple function that builds on `getColumnTotal()` by returning the average number in a **column** of numbers. - - getColumnAverage(gData, "cuddlability") - // returns 1.8333333333333333 - -### Sheetsee.getMin(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the lowest number value in the **column** you specify from your **data**. - - getMin(gData, "cuddlability") - // returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}] - -### Sheetsee.getMax(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the highest number value in the **column** you specify from your **data**. - - getMax(gData, "cuddlability") - // returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...} - -### Don't Forget JavaScript Math - -Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that [here on MDN](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math). - - var profit09 = Sheetsee.getColumnTotal(gData, "2009") - var profit10 = Sheetsee.getColumnTotal(gData, "2010") - var difference = profit09 - profit10 - -#### What These Little Bits are Good For - -You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about [icanhas.js](http://icanhazjs.com/). View source on this page to see how I created "Most Cuddlable". - -### Sheetsee.getMatches(data, filter, category) - -Takes **data** as an _array of objects_, a _string_ you'd like to **filter** and a _string_ of the **category** you want it to look in (a column header from your spreadsheet). - - getMatches(gData, "dog", "kind") - -Returns an _array of objects_ matching the category's filter. - - [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ] - - -### Sheetsee.getOccurance(data, category) - -Takes **data** as an _array of objects_ and a _string_ for **category** (a column header from your spreadsheet) you want tally how often an element occured. - - getOccurance(gData, "kind") - -Returns an object with keys and values for each variation of the category and its occurance. - - {"dog": 3, "cat": 3} - -### Sheetsee.makeColorArrayOfObject(data, colors) - -If you use `getOccurance()` and want to then chart that data with d3.js, you'll need to make it into an _array_ (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset). - -This function takes in your data, as an _object_, and an _array_ of hexidecimal color strings which you define. - - var kinds = getOccurance(gData, "kind") - var kindColors = ["#ff00ff", "#DCF13C"] - - var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors) - -It will return an array of objects formatted to go directly into a d3 chart with the appropriate _units_ and _label keys_, like so: - - [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}] - -If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements. - -## Make a Map - -Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [[Leaflet.js](http://leafletjs.com/)](http://leafletjs.com/) plugin, to make maps. - -Create an empty `
    ` in your HTML, with an id. - -
    - -Next you'll need to create geoJSON out of your data so that it can be mapped. - -### Sheetsee.createGeoJSON(data, optionsJSON) - -This takes in your **data** and the parts of your data, **optionsJSON**, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data. - - var optionsJSON = ["name", "breed", "cuddlability"] - var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON) - -It will return an _array_ in the special geoJSON format that map making things love. - - [{ - "geometry": {"type": "Point", "coordinates": [long, lat]}, - "properties": { - "marker-size": "small", - "marker-color": lineItem.hexcolor - }, - "opts": {the options you pass in}, - }} - - -### Sheetsee.loadMap(mapDiv) - -To create a simple map, with no data, you simply call `.loadMap() and pass in a _string_ of the **mapDiv** (with no #) from your HTML. - - var map = Sheetsee.loadMap("map") - -### Sheetsee.addTileLayer(map, tileLayer) - -To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your **map** and the source of the **tileLayer**. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See [Mapbox's Documentation](http://mapbox.com/mapbox.js/api/v1.0.2/#L.mapbox.tileLayer) for more information. - - Sheetsee.addTileLayer(map, 'examples.map-20v6611k') - -You can add tiles from awesome mapmakers like [Stamen](examples.map-20v6611k) or create your own in Mapbox's [Tilemill](http://www.mapbox.com/tilemill) or [online](https://tiles.mapbox.com/newmap#3.00/0.00/0.00). - -### Sheetsee.addMarkerLayer(geoJSON, map) - -To add makers to your map, use this function and pass in your **geoJSON** so that it can get the coordinates and your **map** so that it places the markers there. - - var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map) - -### Sheetsee.addPopups(map, markerLayer) - -To customize the marker popup content in your map you'll need to use this entire function on your website. - - function addPopups(map, markerLayer) { - markerLayer.on('click', function(e) { - var feature = e.layer.feature - var popupContent = '

    ' + feature.opts.name + '

    ' + - '

    ' + feature.opts.breed + '

    ' - e.layer.bindPopup(popupContent,{closeButton: false,}) - }) - } - -You will edit the **popupContent** variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use `feature.opts` and then one of the column headers you passed into `createGeoJSON().` - -## Make a Table - -Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for filtering and table headers can be used to sort the data in that column. For each of these you'll need a `
    ` in your html, a ` - -#### Your ` - -To create another table, simply repeat the steps. - -
    - - - - Learn more about the things you can do with [mustache.js](http://mustache.github.io/). - - -### Sheetsee.makeTable(data, targetDiv) - -You'll call this to make a table out of a **data** and tell it what **targetDiv** in the html to render it in (this should also be the same id as your script template id). - - Sheetsee.makeTable(gData, "#siteTable") - -## Table Filter/Search - -If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html: - - - Clear - no matches - -### Sheetsee.initiateTableFilter(data, filterDiv, tableDiv) - -You will then call this function to make that input live: - - Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable") - -## Make a Chart - -Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an _array of objects_, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting. - -You'll have to experiement with the charts to find the correct size your `
    ` will need to be to hold the chart with your data in it nicely. - -You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee. - -### Bar Chart - -To create a bar chart you'll need to add a placeholder `
    ` in your HTML with an id. - -
    - -In your CSS, give it dimensions. - - #barChart {height: 400px; max-width: 600px; background: #F8CDCD;} - -In a ` - - - - - - - - -
    -

    Pennies by State

    -

    spreadsheet

    -
    -

    View Source // View Documentation

    - - -
    - - - - - diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html deleted file mode 100644 index b5489c66..00000000 --- a/site/demos/demo-map.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Sheetsee Maps Demo - - - - - - - - - -
    -

    All Pennies Map

    -

    spreadsheet

    -

    -

    View Source // View Documentation

    - - - - - - diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html deleted file mode 100644 index 53400923..00000000 --- a/site/demos/demo-table.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - Sheetsee Table Demo - - - - - - - - -
    -

    All Pennies

    -

    spreadsheet

    - -

    -

    California Pennies

    - -
    -

    Pretty Pennies

    -
    -

    View Source // View Documentation

    - - -
    - - - - - - - - - - - diff --git a/site/demos/demo.html b/site/demos/demo.html deleted file mode 100644 index fdaed1f3..00000000 --- a/site/demos/demo.html +++ /dev/null @@ -1,505 +0,0 @@ - - - Yo, yo, yo! - - - - - - - - - - - - - - - -
    -

    sheetsee

    -

    Sheetsee.js

    -

    Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page.

    -

    Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with.

    -

    To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see JavaScript for Cats, Eloquent JavaScript or Mozilla's Developer Network.

    - -

    Dependencies

    -

    Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, Tabletop.js gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with IChanHas.js (built on mustache.js), maps with Mapbox.js, and charts with d3.js. And jQuery of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below.

    - -

    CSS

    -

    Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design.

    - -

    Client-side or Server-side

    -

    Sheetsee.js comes in two flavors, client-side (this repo) and server-side (sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal.

    -

    The server-side version is built with Node.js and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah!

    - -
    -

    The Short & Sweet

    -
      -
    1. Link to Sheetsee.js and dependencies in your HTML header.
    2. -
    3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
    4. -
    5. Create templates for tables in <script> tags.
    6. -
    7. Create a script tag that waits for the document to load and then executes any of the map, chart or tables you've specified in it.
    8. -
    9. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information everytime they load the page.
    10. -
    -
    - -

    Bare Minimum Setup

    -

    Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

    -
    <html>
    -    <head>
    -        <script type="text/javascript" src="http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.js"></script>
    -        <script type="text/javascript" src="js/ICanHaz.js"></script>
    -        <script type="text/javascript" src="js/jquery.js"></script>
    -        <script type="text/javascript" src="js/tabletop.js"></script>
    -        <script type="text/javascript" src="js/d3.js"></script>
    -        <script type="text/javascript" src="js/sheetsee.js"></script>
    -        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.css' rel='stylesheet' />
    -    </head>
    -    <style> #map {height: 600px; width: 600px;} </style>
    -    <body>
    -    <div id="map"></div>
    -    <script type="text/javascript">
    -      document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -      })
    -      function showInfo(data) {
    -        gData = data
    -        optionsJSON = ["something", "something"]
    -        var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -        var map = Sheetsee.loadMap("map")
    -        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
    -        // customize the popup content
    -        addPopups(map, markerLayer)
    -        function addPopups(map, markerLayer) {
    -          markerLayer.on('click', function(e) {
    -            var feature = e.layer.feature
    -            var popupContent = '<h3>' + feature.opts.something + '</h3>'
    -            e.layer.bindPopup(popupContent,{closeButton: false})
    -          })
    -        }
    -      }
    -    </script>
    -    </body>
    -</html>
    - -

    Awesome Possibilities

    -
      -
    1. Small newsrooms with data for stories but small dev teams.
    2. -
    3. Friends or groups collaborating on data for a website/project.
    4. -
    5. Using iftt.com to auto populate spreadsheets which are hooked to a website with Sheetsee.js.
    6. -
    - -

    Examples

    -
      -
    1. Hack Spots
    2. -
    3. James Sconfitto make a map of his relationship with his wife <3
    4. -
    - -

    Getting Started

    -

    This bit is the same for both client-side and server-side versions.

    -

    Your Data

    -

    sheetsee

    -

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

    -

    sheetsee

    -

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    -
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    - -

    Hexcolor

    -

    sheetsee

    -

    You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    - -

    Geocoding

    -

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin - that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    - sheetsee -

    Publishing Your Spreadsheet

    -

    sheetsee

    -

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    -

    sheetsee

    -

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet.

    -

    Your Website

    -

    Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet.

    -

    For now, create empty div placeholders for the map, chart and tables you plan on including.

    -

    Hooking Up Your Data

    -

    Here the paths diverge:

    -

    Client-side Hookup

    -

    For client-siders, all you need to do is include the depences and sheetsee in your HTML <head> and then in a script tag at the bottom of your page, right before the </body> tag, you'll include this:

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -    })
    -    function showInfo(data) {
    -        gData = data
    -        //
    -        //everything you do with sheetsee goes here
    -        //
    -    }
    -</script>
    -

    The URL variable is the key from your spreadsheet's longer URL, explained above. Tabletop.init() takes that URL and execute's Tabletop, when it's done generating the table it executes the callback showInfo function. It's inside of this function that you'll then use your spreadsheet data, gData, to do all the Sheetsee.js goodness with.

    -

    Server-side Hookup

    -

    The server-side version is in the repo sheetsee-cache. It uses Node.js to go to Google, get the spreadsheet data (with a Node.js version of Tabletop.js, thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data.

    -

    When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled.

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        // table/templating things the rest can be in their own script tags if you'd like
    -    })
    -</script>
    -

    Running Locally

    -

    You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay!

    -

    Once you clone the repo, navigate there in Terminal, install the node modules and launch the server.

    -
    cd sheetsee-cache
    -npm install
    -node server.js
    -

    This will launch a local server you can visit and develop locally with in your browser.

    -

    Working With Your Data

    -

    Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

    -

    Play Along!

    -

    This page is using sheetsee. If you (are in Chrome and) right click on the page and select Inspect Element it will bring up the Web Inspector. Select the Console tab. Now you can interact with the data and functions from Sheetsee. Give the functions below a try - gData is the variable with the data (from this spreadsheet). - sheetsee -

    Sheetsee.getKeyword(data, keyword)

    -

    This takes in your data, an array of objects, and searches for a string, keyword, in each piece of your data (formerly the cells of your spreadsheet). It returns an array of each row that contained a keyword match. Similarly, using `getKeywordCount(data, keyword)` will return just the number of times the keyword occured.

    -
    getKeyword(gData, "cat")
    -// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}]
    -

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

    -
    getColumnTotal(gData, "cuddlability")
    -// returns 11
    -

    Sheetsee.getAveragefromColumn(data, column)

    -

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(gData, "cuddlability")
    -// returns 1.8333333333333333
    -

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}]
    - -

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMax(gData, "cuddlability")
    -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
    - -
    - - -

    Don't Forget JavaScript Math

    -

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(gData, "2009")
    -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
    -var difference = profit09 - profit10
    -

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

    - -

    Sheetsee.getMatches(data, filter, category)

    -

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(gData, "dog", "kind")
    -

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    - -

    Sheetsee.getOccurance(data, category)

    -

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(gData, "kind")
    -

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    - -

    Sheetsee.makeColorArrayOfObject(data, colors)

    -

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    -

    This function takes in your data, as an object, an array of hexidecimal color strings which you define and the category you used in getOccurance().

    -
    var kinds = getOccurance(gData, "kind")
    -var kindColors = ["#ff00ff", "#DCF13C"]
    -var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors, "kind")
    -

    It will return an array of objects with units as the title of the occurance amount like so:

    -
    [{"kind": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"kind": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    -

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    - -

    Make a Map

    -
    -

    Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps.

    -

    Create an empty <div> in your HTML, with an id.

    -
    <div id="map"></div>
    -

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    - -

    Sheetsee.createGeoJSON(data, optionsJSON)

    -

    This takes in your data and the parts of your data, optionsJSON, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data.

    -
    var optionsJSON = ["name", "breed", "cuddlability"]
    -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -

    It will return an array in the special geoJSON format that map making things love.

    -
    [{
    -  "geometry": {"type": "Point", "coordinates": [long, lat]},
    -  "properties": {
    -    "marker-size": "small",
    -    "marker-color": lineItem.hexcolor
    -  },
    -  "opts": {the options you pass in},
    -}}
    - -

    Sheetsee.loadMap(mapDiv)

    -

    To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

    -
    var map = Sheetsee.loadMap("map")
    - -

    Sheetsee.addTileLayer(map, tileLayer)

    -

    To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

    -
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    - -

    Sheetsee.addMarkerLayer(geoJSON, map)

    -

    To add makers to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there.

    -
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map)
    - -

    Sheetsee.addPopups(map, markerLayer)

    -

    To customize the marker popup content in your map use this function and pass in your map and markerLayer.

    -
     Sheetsee.addPopups(map, markerLayer)
    -

    To customize the marker popup content in your map you'll need to use this entire function on your website.

    -
    function addPopups(map, markerLayer) {
    -  markerLayer.on('click', function(e) {
    -    var feature = e.layer.feature
    -    var popupContent = '<h2>' + feature.opts.name + '</h2>' +
    -                        '<h3>' + feature.opts.breed + '</h3>'
    -    e.layer.bindPopup(popupContent,{closeButton: false,})
    -  })
    -}
    -

    You will edit the popupContent variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use feature.opts and then one of the column headers you passed into createGeoJSON().

    - -

    Make a Table

    - -
    -

    Example - Local Pet Friends

    - - Clear - no matches -
    -
    - - -

    Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for searches and table headers can be used to sort the data in that column. For each of these you'll need a <div> in your html, a <script> template and a <script> that calls table functions.

    -

    Your HTML Placeholder <div>

    -

    This is as simple as an empty <div> with an id. This id should match the script tempate id in the next section.

    -
     <div id="siteTable"></div>
    -

    Your <script> Template

    -

    Your template is the mockup of what you'd like your table to look like and what content it should show. Most of this is up to you but if you want users to be able to click on headers and sort that column you must make a table row with table headers with the class tHeader.

    -

    The variables inside the {{}} must match the column headers in your spreadsheet. Lowercase (?) and remember spaces are ommited, so "Place Name" will become "placename".

    -
    <script id="siteTable" type="text/html">
    -    <table>
    -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    -      {{#rows}}
    -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    -      {{/rows}}
    -  </table>
    -</script>
    -

    Your <script> Execution

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        Sheetsee.makeTable(gData, "#siteTable")
    -        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
    -    })
    -</script>
    -

    To create another table, simply repeat the steps with the corresponding data and divs.

    -
    <div id="secondTable"></div>
    -<script id="secondTable"> // your table template here </script>
    -<script>
    -  Sheetsee.makeTable(otherData, "#secondTable")
    -  Sheetsee.initiateTableFilter(otherData, "#secondFilter", "#secondTable")
    -</script>
    -
    -

    Learn more about the things you can do with mustache.js.

    - -

    Sheetsee.makeTable(data, targetDiv)

    -

    You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id).

    -
    Sheetsee.makeTable(gData, "#siteTable")
    - -

    Table Filter/Search

    -

    If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html:

    -
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    -<span class="clear button">Clear</span>
    -<span class="noMatches">no matches</span>
    - -

    Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

    -

    You will then call this function to make that input live:

    -
    Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
    - -

    Make a Chart

    -

    Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting.

    -

    You'll have to experiement with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    -

    You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee.

    - -

    Bar Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    -
    <div id="barChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • xaxis is optional text label for your x axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3BarChart() function with your data and options.

    -
    Sheetsee.d3BarChart(data, barOptions)
    - -

    Line Chart

    - -
    -
    -
    - -

    To create a line chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="lineChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • yaxis is optional text label for your y axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3LineChart() function with your data and options.

    -
    Sheetsee.d3LineChart(data, lineOptions)
    - -

    Pie Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="pieChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options. You must include labels and units, this tells it what you're charting. Because for the pie chart we're using data we got from getOccurance() and makeColorArrayofObject(), our units are already called units. If we were using original data, we might have units as "cuddleability" or something else.

    -
    var pieOptions = {labels: "kind", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3PieChart() function with your data and options.

    -
    Sheetsee.d3PieChart(data, pieOptions)
    - -

    Don't forget, right click this page, select View Source and scroll to the bottom and see exactly how these charts were set up!

    - - -

    Big Time Thanks

    -

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georga.

    -

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    -

    Thanks to Max Ogden for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making Tabletop.js for Node.js.

    -

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    -

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    - -

    Licensed under BSD. East Bay represent!

    - - - - - - - - - diff --git a/site/demos/template.html b/site/demos/template.html deleted file mode 100644 index 28067525..00000000 --- a/site/demos/template.html +++ /dev/null @@ -1,94 +0,0 @@ - - - Sheetsee Maps Demo - - - - - - -
    -

    Here it is:

    -
    
    -
    -	
    -		Yo, yo, yo!
    -    
    -    
    -    
    -	  	
    -    
    -		 
    -	
    -
    -  
    -    
    -	
    -  
    -
    -  
    -
    -  
    -
    -
    - - - -
    - - - - - - - - - - - - - diff --git a/site/docs/about.html b/site/docs/about.html deleted file mode 100644 index 9ec7854f..00000000 --- a/site/docs/about.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    About

    -

    Sheetsee.js began as a part of my Code for America 2012 Fellowship project, See Penny Work. The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet.

    -

    In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

    -

    The present version makes the project modular, customizable and with more maping and table features.

    -

    Built on top of Tabletop.js

    -

    Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js.

    -

    Sheetsee.js + Mapbox.js + d3.js

    -

    Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

    -

    Hacked on Openly

    - -

    Contact

    - -

    Big Time Thanks

    -

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georgia.

    -

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    -

    Thanks to Max Ogden for emotional support, teaching me JavaScript and answering lots of questions.

    -

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    -

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    - - - -
    - - - diff --git a/site/docs/basics.html b/site/docs/basics.html deleted file mode 100644 index 1d619142..00000000 --- a/site/docs/basics.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Spreadsheets as Databases

    -

    Spreadsheets are a great lightweight databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet!

    -

    The Short & Sweet

    -
      -
    1. Link to Sheetsee.js, tabletop.js and jQuery in your HTML head.
    2. -
    3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
    4. -
    5. Create templates for tables in <script> tags.
    6. -
    7. Inside of a <script> tag initialize Tabletop.js. It waits for the document to load and then initializes tabletop and calls back a function when it has returned with the spreadsheet data.
      document.addEventListener('DOMContentLoaded', function() {
      - var gData
      - var URL = "YOURSPREADSHEETSKEYHERE"
      - Tabletop.init( { key: URL, callback: callback, simpleSheet: true } )
      -})
      -
      -
    8. -
    9. Define the function that Tabletop.js calls when it returns with the data. This function will contain all the Sheetsee.js functions that you use for the maps, charts and tables you desire. Style it up with some CSS.
      function callback(data) {
      - // All the sheetsee things you want to do!
      -}
      -
      -
    10. -
    11. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information every time they load the page.
    12. -
    -

    Bare Minimum Setup

    -

    Ignoring some HTML things to conserve space, you get the point. This is a basic setup.

    -
    <html>
    -  <head>
    -    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    -    <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
    -    <script type="text/javascript" src='js/sheetsee.js'></script>
    -    <link rel="stylesheet" type="text/css" href="css/sss.css">
    -  </head>
    -  <body>
    -  <div id="placeholder"></div>
    -
    -  <script id="placeholder" type="text/html">
    -    // template if you so desire!
    -  </script>
    -
    -  <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        var URL = "YOURSPREADSHEETSKEYHERE"
    -        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } )
    -    })
    -    function myData(data) {
    -        All the sheetsee things you want to do!
    -    }
    -  </script>
    -  </body>
    -</html>
    -
    -

    Your Data

    -

    sheetsee

    -

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

    -

    sheetsee

    -

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    -
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    -

    Hexcolor

    -

    sheetsee

    -

    You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    -

    Geocoding

    -

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin - that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    -

    Publishing Your Spreadsheet

    -

    sheetsee

    -

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    -

    sheetsee

    -

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. Actually, you technically can use the whole URL, but it's so long...

    -

    CSS

    -

    Sheetsee.js comes with a bare minimum stylesheet, sss.csss, which contains elements you'll want to style when using the feature they correspond to.

    - - - -
    - - - diff --git a/site/docs/building.html b/site/docs/building.html deleted file mode 100644 index b248a178..00000000 --- a/site/docs/building.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Right-sizing

    -

    You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

    -

    All bundle comes with mapbox.js and handlebars.js (since both are available on NPM). Additionally you'll need to also include tabletop.js and jQuery in your HTML head like so:

    -
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    -<script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
    -
    -

    To build your Sheetsee you'll need Node.js and NPM (the latter comes with the former in most installs) on your computer and a command line.

    -

    Get Node/NPM

    -

    Download Node.js from nodejs.org/download. For most users you can just download the Mac .pkg or Windows .msi. Follow the install instructions, both include NPM. Once they're installed, proceed:

    -

    Install sheetsee from NPM

    -

    The sheetsee (with no '.js') module is the tool for building custom Sheetsee.js builds. Install sheetsee globally and then run it within the folder of your soon-to-be sheetsee.js project.

    -

    Install globally

    -
    npm install -g sheetsee
    -
    -

    Run from within a project folder

    -
    sheetsee [options]
    -
    -

    Here are the options for the different modules. If you want save the generated file as sheetsee.js then add the --save option.

    -
      -
    • -m or -maps for maps
    • -
    • -t or -tables for tables
    • -
    • -c or -charts for charts
    • -
    • --save to write out the file*
    • -
    -

    * otherwise, defaults to standardout on your console which you can | pbcopy

    -

    So for instance, sheetsee -m -t --save will build you a Sheetsee.js with the basic data functions, the map and tables sections built in and save it as a file named sheetsee.js. Running sheetsee -m -t | pbcopy will save the output to your clipboard.

    - - - -
    - - - diff --git a/site/docs/changelog.html b/site/docs/changelog.html deleted file mode 100644 index b3e2210f..00000000 --- a/site/docs/changelog.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Sheetsee v3

    -

    August 13, 2013

    -

    Charting Intake

    -

    D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart.

    -

    Previously Sheetsee required you pass your data through a function, addUnitsAndLabels() which took in your data and the things you wanted to chart, reformatted your data for you so that you could pass it into one of the d3 charts. This is one more step than actually needs to happen.

    -

    Now Sheetsee just asks for what you want your labels and units to be in the options you give it when calling the chart function. It then sorts the data correctly on the inside of the chart function. Yay, easier!

    -
    var options = {
    -  labels: "name",
    -  units: "cuddleability",
    -  m: [60, 60, 30, 150],
    -  w: 600, h: 400,
    -  div: "#barChart",
    -  xaxis: "no. of pennies",
    -  hiColor: "#FF317D"
    -}
    -
    -

    Thanks @maxogden for the help with this.

    -

    Started doing this changelong pretty late in the game.

    - - - -
    - - - diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html deleted file mode 100644 index bedd2892..00000000 --- a/site/docs/custom-charts.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Custom Charts

    -

    It's easy to take a D3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

    -

    Sheetsee charts currently work by taking in some options, like so:

    -
    var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    -
    -

    The labels represent the actual thing you're charting and units are how many of those things. Margin, width and height are m, w, h and the <div> to build your chart in is div. Finally, you can supply a highlight color if you want.

    -

    So, your chart could take the same options, but map them into your D3 code with the correct variables. An example from maxogden/sheetsee-d3bubble:

    -

    Append the d3.js code with a map of your sheetsee options

    -
    Sheetsee.d3BubbleChart = function(data, options) {
    -    var tree = {name: "data", children: []}
    -    var groups = {}
    -
    -    // data needs to look like this:
    -    // var data = { name: "wahtever", children: [
    -    //   { name: "group1", children: [
    -    //     { name: 'bob', size: 3},
    -    //     { name: 'judy', size: 5}
    -    //   ]},
    -    //   { name: "group2", children: [
    -    //     { name: 'jim', size: 10},
    -    //     { name: 'bill', size: 5}
    -    //   ]}
    -    // ]}
    -
    -    data.map(function(r) {
    -        var groupName = r[options.group]
    -        groups[groupName] = true
    -    })
    -
    -    Object.keys(groups).map(function(groupName) {
    -        var groupMembers = []
    -        data.map(function(r) {
    -            if (r[options.group] !== groupName) return
    -            groupMembers.push({name: r[options.name], size: r[options.size]})
    -        })
    -        tree.children.push({name: groupName, children: groupMembers})
    -    })
    -
    -  // the rest of the code
    -
    -

    In your HTML call it like so

    -
    <script type="text/javascript">
    -  document.addEventListener('DOMContentLoaded', function() {
    -    var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -  })
    -
    -  function showInfo(data) {
    -    Sheetsee.d3BubbleChart(data, { name: 'name', size: 'cuddlability', group: 'kind', div: '#stuff'})
    -  }
    -</script>
    -
    -

    There are lots of charts to get excited about in the D3 gallery.

    -

    View the entire source

    - - - -
    - - - diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html deleted file mode 100644 index 5040ea55..00000000 --- a/site/docs/fork-n-go.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Fork-n-Go

    -

    A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

    -

    To awesome things that make this possible: Forking and GitHub Pages.

    -

    On GitHub, a fork is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button.

    -

    GitHub Pages is the hosting service that GitHub provides free to all users, organizations and repositories. This means everyone of these entities or project can have it's own website at a predictable domain:

    -
      -
    • organizations: orgname.github.io
    • -
    • users: username.github.io
    • -
    • repositories: username.github.io/repositoryname
    • -
    -

    To have a website for a repository all you need is a branch named gh-pages. GitHub will then look in that branch for web files and serve them up at the address.

    -

    What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily.

    -

    A Fork-n-Go example from my blog post on the topic:

    -

    Hack Spots Fork-n-Go

    -

    I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do:

    -
      -
    • Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing.
    • -
    • Fork the original repository.
    • -
    • Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). -Commit your change.
    • -
    -

    Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName.

    -

    forkcommit

    - - - -
    - - - diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html deleted file mode 100644 index a9b20e92..00000000 --- a/site/docs/sheetsee-charts.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Sheetsee-charts

    -

    View Demo

    -

    Sheetsee.js provides three D3.js chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also use a custom D3 chart with Sheetsee, read about that here.

    -

    Make a Chart

    -

    Each chart requires your data be an array of objects, with objects containing label and units key/value pairs.

    -

    Experiment with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    -

    You can also make your own D3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information here on using your own chart.

    -

    Bar Chart

    -

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    -
    <div id="barChart"></div>
    -
    -

    In your CSS, give it dimensions.

    -
    #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -
    -

    You'll also have these CSS elements to style however you'd like:

    -
    .labels text {text-align: right;}
    -.bar .labels text {fill: #333;}
    -.bar rect {fill: #e6e6e6;}
    -.axis {shape-rendering: crispEdges;}
    -.x.axis line {stroke: #fff; fill: none;}
    -.x.axis path {fill: none;}
    -.x.axis text {fill: #333;}
    -.xLabel {font-family: sans-serif; font-size: 9px;}
    -
    -

    In a <script> tag set up your options.

    -
    var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
    -
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • xaxis is optional text label for your x axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3BarChart() function with your data and options.

    -
    Sheetsee.d3BarChart(data, barOptions)
    -
    -

    Line Chart

    -

    To create a line chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="lineChart"></div>
    -
    -

    In your CSS, give it dimensions.

    -
    #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -
    -

    And these chart elements to style:

    -
    .axis {shape-rendering: crispEdges;}
    -.x.axis .minor, .y.axis .minor {stroke-opacity: .5;}
    -.x.axis {stroke-opacity: 1;}
    -.y.axis line, .y.axis path {fill: none; stroke: #acacac; stroke-width: 1;}
    -.bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);}
    -path.chartLine {stroke: #333; stroke-width: 3; fill: none;}
    -div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;}
    -circle {fill: #e6e6e6;}
    -
    -

    In a <script> tag set up your options.

    -
    var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
    -
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • yaxis is optional text label for your y axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3LineChart() function with your data and options.

    -
    Sheetsee.d3LineChart(data, lineOptions)
    -
    -

    Pie Chart

    -

    To create a bar chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="pieChart"></div>
    -
    -

    In your CSS, give it dimensions.

    -
    #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -
    -

    Style chart elements:

    -
    .arc path { stroke: #fff;}
    -
    -

    In a <script> tag set up your options.

    -
    var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    -
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3PieChart() function with your data and options.

    -
    Sheetsee.d3PieChart(data, pieOptions)
    -
    - - - -
    - - - diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html deleted file mode 100644 index d02e2a23..00000000 --- a/site/docs/sheetsee-core.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Sheetsee-core

    -

    This is the core module in sheetsee and is included in all builds. It contains the functions for building your custom file as well as the basic data manipulation functions.

    -

    Working With Your Data

    -

    Tabletop.js will fetch the data from your spreadsheet and return it as an array of objects. Sheetsee.js has functions built in to help you filter or reorganize the data if you'd like.

    -

    Sheetsee.getGroupCount(data, groupTerm)

    -

    This takes in your data, an array of objects, and searches for a string, groupTerm, in each piece of your data (formerly the cells of your spreadsheet). It returns the number of times it found the groupTerm.

    -
    getGroupCount(data, "cat")
    -// returns a number
    -
    -

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects, and a string column header, this functions sums each cell in that column(so this collumn you mention best have numbers).

    -
    getColumnTotal(data, "cuddlability")
    -// returns number
    -
    -

    Sheetsee.getAveragefromColumn(data, column)

    -

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(data, "cuddlability")
    -// returns number
    -
    -

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(data, "cuddlability")
    -// returns array
    -
    -

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMin(data, "cuddlability")
    -// returns array
    -
    -

    Don't Forget JavaScript Math

    -

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(data, "2009")
    -var profit10 = Sheetsee.getColumnTotal(data, "2010")
    -var difference = profit09 - profit10
    -
    -

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with JavaScript math functions and knowing a little bit more about icanhaz.js.

    -

    Sheetsee.getMatches(data, filter, category)

    -

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(data, "dog", "kind")
    -
    -

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    -
    -

    Sheetsee.getOccurance(data, category)

    -

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(data, "kind")
    -
    -

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    -
    -

    Sheetsee.makeColorArrayOfObject(data, colors)

    -

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    -

    This function takes in your data, as an object, and an array of hexidecimal color strings which you define.

    -
    var kinds = getOccurance(data, "kind")
    -var kindColors = ["#ff00ff", "#DCF13C"]
    -
    -var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors)
    -
    -

    It will return an array of objects formatted to go directly into a d3 chart with the appropriate units and label keys, like so:

    -
    [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    -
    -

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    -

    Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)

    -

    If you're using data, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    -
    var data =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
    -
    -

    For istance, if from our original data above we want to chart the age of each cat, we'll use:

    -
    Sheetsee.addUnitsLabels(data, "name", "cuddlability")
    -
    -

    Which will return an array, ready for the d3 charts:

    -
    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
    -
    - - - -
    - - - diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html deleted file mode 100644 index 72bd73ee..00000000 --- a/site/docs/sheetsee-maps.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Sheetsee-maps

    -

    View Demo

    -

    Sheetsee.js uses Mapbox.js and Leaflet.js to make maps of your points, polygons, lines or multipolygons (all coordinate based). Details on what that actually looks like here.

    -

    You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags. You can also customize your popup content.

    -

    Your HTML Placeholder <div>

    -

    Create an empty <div> in your HTML, with an id (name). Add CSS to give it dimensions

    -
    <div id="map"></div>
    -
    -

    CSS

    -
    #map {width: 500px; height: 500px;}
    -
    -

    Your <script> Functions

    -

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    -

    Sheetsee.createGeoJSON(data, optionsJSON)

    -

    This takes in your data and the parts of your data, optionsJSON, that you plan on including in your map's popups. These will be column headers in your spreadsheet. If you're not going to have popups on your markers, don't worry about it then and just pass in your data (by default it will use all the row's information).

    -
    var optionsJSON = ["name", "breed", "cuddlability"]
    -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -
    -

    It will return an array in the special geoJSON format that map making things love.

    -
    [{
    -  "geometry": {"type": "Point", "coordinates": [long, lat]},
    -  "properties": {
    -    "marker-size": "small",
    -    "marker-color": lineItem.hexcolor
    -  },
    -  "opts": {},
    -}}
    -
    -

    Sheetsee.loadMap(mapDiv)

    -

    To create a simple map, with no data, you simply call .loadMap() and pass in a string of the mapDiv (with no '#') from your HTML.

    -
    var map = Sheetsee.loadMap("map")
    -
    -

    Sheetsee.addTileLayer(map, tileLayer)

    -

    To add a tile layer (aka a custom map scheme/design/background) you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

    -
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -
    -

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    -

    Sheetsee.addMarkerLayer(geoJSON, map)

    -

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

    -
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
    -
    -

    Example template:

    -
    var popupTemplate = "<h4>Hello {{name}}</h4>"
    -
    -

    Source from the map demo:

    -
    <script type="text/javascript">
    -  document.addEventListener('DOMContentLoaded', function() {
    -    var gData
    -    var URL = "0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc"
    -    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -  })
    -
    -  function showInfo(data) {
    -    gData = data
    -    var optionsJSON = ["placename", "photo-url"]
    -    var template = "<ul><li><a href='{{photo-url}}' target='_blank'>"
    -                 + "<img src='{{photo-url}}'></a></li>"
    -                 + "<li><h4>{{placename}}</h4></li></ul>"
    -    var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -    var map = Sheetsee.loadMap("map")
    -    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, template)
    -  }
    -</script>
    -
    - - - -
    - - - diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html deleted file mode 100644 index a1e3c792..00000000 --- a/site/docs/sheetsee-tables.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Sheetsee-tables

    -

    View Demo

    -

    With this module you can create tables of your data that are sortable, searchable and paginate-able.

    -

    You'll need a placeholder <div> in your html, a <script> mustache template and a <script> that initiates the table.

    -

    Your HTML Placeholder <div>

    -

    This is as simple as an empty <div> with an id. This id should match the script template id in the next section.

    -
    <div id="siteTable"></div>
    -
    -

    Your <script> Template

    -

    Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you!

    -

    Sorting

    -

    If you want users to be able to click on headers and sort that column, your template must include table headers with the class tHeader.

    -

    Example

    -

    The variables inside the {{}} must match the column headers in your spreadsheet. They should be lowercase and remember spaces are omitted, so "Place Name" will become "placename".

    -
    <script id="siteTable" type="text/html">
    -    <table>
    -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    -      {{#rows}}
    -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    -      {{/rows}}
    -  </table>
    -</script>
    -
    -

    Your <script> Execution

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -      var tableOptions = {
    -                          "data": gData, 
    -                          "pagination": 10, 
    -                          "tableDiv": "#fullTable", 
    -                          "filterDiv": "#fullTableFilter"
    -                          }
    -      Sheetsee.makeTable(tableOptions)
    -      Sheetsee.initiateTableFilter(tableOptions)
    -    })
    -</script>
    -
    -

    To create another table, simply repeat the steps except for initiateTableFilter()

    -
    <div id="secondTable"></div>
    -<script id="secondTable"> // your table template here </script>
    -<script>Sheetsee.makeTable(otherData, "#secondTable", 10)</script>
    -
    -

    Learn more about the things you can do with ICanHaz.js.

    -

    Sheetsee.makeTable(tableOptions)

    -

    You pass in an object containing:

    -
      -
    • data your data array
    • -
    • pagination how many rows displayed at one time, defaults to all
    • -
    • tableDiv the
      placeholder in your HTML
    • -
    • filterDiv the <div> containing your <input> filter if using search
    • -
    -
    var tableOptions = {
    -                    "data": gData, 
    -                    "pagination": 10, 
    -                    "tableDiv": "#fullTable", 
    -                    "filterDiv": "#fullTableFilter"
    -                    }
    -Sheetsee.makeTable(tableOptions)
    -
    -

    Pagination

    -

    If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for naviagtion, which you can style in your CSS:

    -

    HTML

    -
    <div id='Pagination' currentPage class='table-pagination'>
    -  Showing page {{currentPage}} of {{totalPages}}
    -  <a class='pagination-pre'>Previous</a><a class='pagination-next'>Next</a>
    -</div>
    -
    -

    CSS

    -
    <style>
    -  #Pagination {background: #eee;}
    -  .pagination-next, .pagination-pre {cursor: hand;}
    -  .no-pag {color: #acacac;}
    -</style>
    -
    - -

    If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want, placeholder text:

    -
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    -
    -

    Sheetsee.initiateTableFilter(tableOptions)

    -

    You will then call this function with your tableOptions to make that input live and connected to your table:

    -
    Sheetsee.initiateTableFilter(tableOptions)
    -
    -

    It will connect that input to your data as well as inject this HTML for a button, which you can style yourself in your CSS:

    -
    <span class="clear button">Clear</span>
    -<span class="noMatches">no matches</span>
    -
    -

    View Demo

    - - - -
    - - - diff --git a/site/docs/sheetsee.html b/site/docs/sheetsee.html deleted file mode 100644 index 9523dd3d..00000000 --- a/site/docs/sheetsee.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - such site, very sheetsee.js - - - - - -
    -

    sheetsee

    -

    This is the core module to create a sheetsee.js library. It contains the functions for building your custom file as well as the basic data manipulation functions.

    -

    Working With Your Data

    -

    Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

    -

    Sheetsee.getGroupCount(data, groupTerm)

    -

    This takes in your data, an array of objects, and searches for a string, groupTerm, in each piece of your data (formerly the cells of your spreadsheet). It returns the number of times it found the groupTerm.

    -
    getGroupCount(gData, "cat")
    -// returns 2
    -
    -

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

    -
    getColumnTotal(gData, "cuddlability")
    -// returns 11
    -
    -

    Sheetsee.getAveragefromColumn(data, column)

    -

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(gData, "cuddlability")
    -// returns 1.8333333333333333
    -
    -

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns {breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}
    -
    -

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
    -
    -

    Don't Forget JavaScript Math

    -

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(gData, "2009")
    -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
    -var difference = profit09 - profit10
    -
    -

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

    -

    Sheetsee.getMatches(data, filter, category)

    -

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(gData, "dog", "kind")
    -
    -

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    -
    -

    Sheetsee.getOccurance(data, category)

    -

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(gData, "kind")
    -
    -

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    -
    -

    Sheetsee.makeColorArrayOfObject(data, colors)

    -

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    -

    This function takes in your data, as an object, and an array of hexidecimal color strings which you define.

    -
    var kinds = getOccurance(gData, "kind")
    -var kindColors = ["#ff00ff", "#DCF13C"]
    -
    -var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors)
    -
    -

    It will return an array of objects formatted to go directly into a d3 chart with the appropriate units and label keys, like so:

    -
    [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    -
    -

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    -

    Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)

    -

    If you're using gData, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    -
    var gData =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
    -
    -

    For istance, if from our original data above we want to chart the age of each cat, we'll use:

    -
    Sheetsee.addUnitsLabels(gData, "name", "cuddlability")
    -
    -

    Which will return an array, ready for the d3 charts:

    -
    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
    -
    - -
    - - \ No newline at end of file diff --git a/site/docs/template.html b/site/docs/template.html deleted file mode 100644 index 143e75f3..00000000 --- a/site/docs/template.html +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - such site, very sheetsee.js - - - - - -
    -

    Basic Template

    -
    <html>
    -    <head>
    -        <title>Yo, yo, yo!</title>
    -    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    -    <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
    -    <script type="text/javascript" src='../js/sheetsee.js'></script>
    -      <meta charset='utf-8'>    
    -    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    -        <link rel="stylesheet" type="text/css" href="css/sss.css"> 
    -    </head>
    -
    -  <body>
    -    <!-- Your HTML Here -->
    -
    -  <script id="" type="text/html">
    -    // template if you so desire!
    -  </script>
    -
    -  <script type="text/javascript">
    -  //  document.addEventListener('DOMContentLoaded', function() {
    -  //      var gData
    -  //      var URL = "YOURSPREADSHEETSKEYHERE"
    -  //        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } ) 
    -  //    }) 
    -  // function myData(data) {
    -     // All the sheetsee things you want to do!
    -  // }
    -  </script>
    -
    -  </body>
    -</html>
    -
    - - - -
    - - \ No newline at end of file diff --git a/site/docs/tips.html b/site/docs/tips.html deleted file mode 100644 index fc09d877..00000000 --- a/site/docs/tips.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -
    -

    Tips

    -

    A few things to think about beyond charts, maps and tables.

    -

    ICanHaz.js

    -

    You can use templates for more than just tables. Use them to create lists ol, ul; array of images... You'll need a placeholder <div> in your HTML, a <script> for your template and a script to call ICanHaz from your Tabletop.js callback. For a live example, see the bottom photo grid of the sheetsee-table demo.

    -

    HTML

    -
    <div id="divID"></div>
    -
    -

    Template

    -
    <script id="divID" type="text/html">
    -  {{#rows}}
    -    <div><img class="photo" src="{{some-variable}}"></div>
    -  {{/rows}}
    -</script>
    -
    -

    Script

    -
    <script type="text/html">
    -  // your other Sheetsee.js, Tabletop code above
    -  var html = Sheetsee.ich.divID({'rows': data})
    -  $('#divID').html(html)
    -</script>
    -
    -

    non-table example output

    -

    lib

    -

    Query Strings

    -

    If your spreadsheet contains address information, using templates (Sheetsee.js uses a form of Mustache), you can embed those elements into a query string (aka a search URL) like Google Maps URL or Yelp. If you search for a location in Google Maps, you'll notice it creates a URL for that search.

    -

    So, if you have information in your spreadsheet that would go inside a query string, make a template for inserting them into a link on your page.

    -

    The basic elements are: a spreadsheet with address info + HTML template to create the query string.

    -

    The Sheetsee Hack-Spots is an does such a thing. Here is the spreadsheet, with address information

    -

    img

    -

    In the HTML template for the table on the Hack-Spots page, the button’s links look like this:

    -
    <a class="button" href="https://maps.google.com/maps?q={{address}},{{city}},{{state}}" target="_blank">View in Google Maps</a>
    -<a class="button" href="http://www.yelp.com/search?find_desc={{name}}&find_loc={{city}},{{state}}" target="_blank">Find on Yelp</a>
    -
    -

    Here is the exact line of code on GitHub.

    -

    We’re inserting the address, city, and state details from the spreadsheet into the structure of a query string for Google maps and Yelp. You can figure out the query string of a service by just using it (type in an address in Google Maps) and looking at the resulting URL.

    -

    With a some CSS and such, the resulting website has a table with the hack spots and a button for viewing in Google Maps or Yelp:

    -

    img

    -

    When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM!

    -

    IFTTT

    -

    Ifttt.com offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets.

    -

    Row Numbers

    -

    When Tabletop.js returns your spreadsheet data, it adds a key/value of rownumber. This is great to use when you need to uniquely match or find a row in your data.

    -

    Images

    -

    Your spreadsheet can contain URLs to images which you can use to display the images on the page you build. Your template would look something like this:

    -
    <img src='{{imgurl}}'/>
    -
    -

    Data as Classes

    -

    You can use your data as classes to style with CSS. For instance, if you had data about recipes and a column called 'Taste' that contained either 'savory' or 'sweet'. In a table of the recipes you could do something like:

    -
    <tr><td class="{{taste}}"></tr>
    -
    -

    Then in your CSS:

    -
    td .savory {}
    -td .sweet {}
    -
    - - - -
    - - - diff --git a/site/img/fbi_spinner.gif b/site/img/fbi_spinner.gif deleted file mode 100644 index 872ede51dae7ff71785364dddf4ec960d90268b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1899 zcmY+Dc~DdL8is%8B!LKl1PB3QM1kaBAR#~`gjFD{2^@AXIjquP1%x1Lk$X)~A~^v{ zUFqO-w2Gp28+33)K}A5NDxzGgxLdFLsN=pX_u!S8_P_7HXWsXF-nfKVc~Bt>u)rG( ztX#P=EiFy0R=;`k=Iz_J2M!!SQS|oh+xz$L@9OF*FE7u|&d$ilsH>}c{P^+Bn>TxU zdbV%hzI*rXr%#_=x^(H(sZ$LN4Wpx@LZR^9y?fo=-GzmP)z#G_BO@C&Y&d=T^p-7K zZr!?d<;s=&_wPS^_^`FL_4DV?2!h1M#^&bce)#a=?%lhCgM*!&o$ubgTfcrij^ig! zo;-5oNMB#y#fuj`JUrUl+xP9;cjwNXiHV7^v9TRHb{sr-@X3=W+qP|Ev)KP*dK3%wQVR(4>*|TR~zI-`z=FIu?=hv)R zbN%}Dt5>h`c)XoEcl!JLQz(?Ova%H`R=j`zesXg1#fulmk00;t?KPXtFJHd=`0-;~ zTidZ?$9C=7b@=e%fq{Xcp`kr{_VoAn@7=ri)vH%qw{E?0{`&Q6y z@8e5>003_9sZ<)61S0Y#pTq*dazu~e7=ni~l!j*9#Y%-q<}1BI(_65JEFqSffdz{_ znqBx9%UPQr;5278=EX-5Us$UXf)sigm*T>*qhd@oWJB@6*US>r<;}CpRy3=E4AMDe zc9y@C`V|#BhA#xNCBNi^2A236X#C*;W z+XSnAiejRIIzBR=tQ23uhj;MIZHY(L=b07MKC zC%!zp9+&whQxjZ4v7M(a?jlZ*QN3`loIK;a2GoovYiV?klXy`{2|ePhF>J}7KodNJ z`{$4Ugt7pggywyPW(tf1@Q`_f{F$IYxY(TJ>k1Y|cQ`LH@(Vx>M3lF_8PNIG5V{aLu*(Nxixe|6hHWoUK(3&ai7LDr7RlLh3v6>OYAIq` zp>kc7Go&>SNlZgS@?`?q_a}{tI%iLdvw*vpn8wk7XsTOlU`yh(dKxVy4#iEhFq$X? zrMjw2Qd(j-EtI1$i7ovilPLSgY13r#p>zO|%`!=HzCII>c48)bQcM>U z#oB!U+voF!LeG9-$u{fcnHk&>q|1$jDu`(PI-FMAAtaOQ54R9CY@@Y~h~e1T z!l9PYGC4D`%E7TxjTdFGd>Kv<7v|R>4$d|RuNF>)mKc`SDPU4|+vueRWD^Xcl(3I+ zIvX@K5IVX2DOZd15FXCPnoLvc#PMJ;VrpW_S66Tvf1s?!q*MD;)-_7_9Lc{uRFWKa zc!&neOT!#JGbOxojtEOC{|Tyyw?M#5%s#>8S4>r1gb9RbQvU3-Xlc_NUu5v_!jffv z6IM-bBv*pqCY%F7Gm{CT61IjDe{K&7Y$pUi)KY)e0wg*h-$V9Ym@Rv;E(kcTQ$cy$ z)bz-CM5$FhN@}ewb1=!Hoxlt=n)5xI*a)PqxCZ;?)Bpeg diff --git a/site/img/hexcolors.png b/site/img/hexcolors.png deleted file mode 100644 index 83c98d93c525de9a4f1c0ef47d34107585834b0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118186 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 BqLlyu diff --git a/site/img/key.png b/site/img/key.png deleted file mode 100644 index 94ef13b1e366324312f2ac11e6fc3cd781dc486d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40026 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 P1Nc~4*qK+J^}hQ*^4P7F diff --git a/site/img/latlong.png b/site/img/latlong.png deleted file mode 100644 index 343e393e2c13d5815128eedeb7fc30065277a150..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46644 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 V_G_`>X`lf=QWCN+^2BsL{x9{wQjY)t diff --git a/site/img/nonos.png b/site/img/nonos.png deleted file mode 100644 index 15ab0a7f0fe93378d5e2a914609dbe6edf725a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49990 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%0A&=<(KV!+rLY9H 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 DT`Cx% diff --git a/site/img/publish.png b/site/img/publish.png deleted file mode 100644 index c0ff710177b05b647761447640a8f9291360c045..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50108 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 B>`wpy diff --git a/site/img/sheetsee-03.png b/site/img/sheetsee-03.png deleted file mode 100644 index a9a4154d6b9127d6d32d4d5cb29edacc36ed15fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76716 zcma&Nbyyrh*C#r-y9T!a!QI^n7Tn!kgL{HI1a~L6ySu|caCdhZoICHg-|n-!_x^F` z>8|cBIaOWf)RABHMEp>cMnNP%1ONaivN94X007i6006lT4+{W5K=G9OfeR3vWVBrY z06fh9oDi0|bKqKtO4j1yKYmy_x;eU9IXaQaii?vuxj0%_+nECZo~zlamTIaexPqX~ zdoj82z&~=1Dmd_DDq>NA*a_5hjlSg{g-h!jL%b{e%RAP*W~G+}D82l&AVFro=KoCgGEKc)LX0CfM5<3Qvk z0LZY+!zBP#{D8_CjYvs=77GB|LT->3u*?Wxk=3-20o1ktdZ*Em>H+Y`02bx&kZ%BJ zAAr#)C8a0ecRB!D>Q+kc>Gc9_RJ@Wwy6}w7aGIJ-B(&4Ac=Xs@#*oGt zB24{W>0j7_IMBB5CINuF1RU_&-o1NHqgGE(bHz5J8Zw^tz7WHT%O@O?URn0r6|ICeKetg@?%EA8r^7lb8 zUE^_0zYoiP!(PpIyJvraH_*d&_bycsn|_cq^wW0#^)^n=U9o1=sUJziU_g9Z$n?_KFxNw7+#@-wm1Q`HbM|S35;d>rcjS^ zH0WAxy}KX);I_lD?;kBZRG`(bof(hME8%zPysv;j3)w_x0Khxg zwlalW0;deCN~9W@x(xBHpbI2#n4VO70{muB#w4OLTJlx)+CXKC{+1A7H{$U`a9}U^h-XGX!-zVHBztu&|HW6_ydQ#n`RT;PW{^bDufa3tx zJdI6My)Z*%qby$ygELM?tSY}*rA9fd42$Du2Jh4_Tv@r|s)FQs0xLW#kaf+mTRX-^ zGKpg9tmfRriS%*mG1R>WGD;}UuaR&|+Ao>-aQK#AJn(DMltv zIY?bMwc_he*OB&4+z};M{x_djoc%kyW`oMz9}8i)y)@^iEH_1jBiho`JO9W{?5l6P z-v~=MUH;wlL8JybK5+ZGe%cSv~jIFw$d<#Zba=EysiZhCbcy%6~^zpK65zmz^mBWuAn zAXCAvAy4BA3~@R;3J^1otlcP!>ko*C7aJ!Vr|$etXafoqE=a{lp+#E{>+MnP*$>+f z7gEDglT*tnoGM&qs3^3Rd@JFX=a(Ounw%<_T1@B66l7guJIXxDT*};PG1BqWVQ4OE zZZ(&!-`6S8zHIJv2+`ryF4j`l(QlBd%C7pl*iqF{ic#98n50;dvuHU`d(%AD{I}&x z?ZGnaT6MF1v!Ai037%!kQ1!rNQdg2+yI;(^ARJ2A3Tg$h4za&$qYE~l2H$4Jbk?P? z-_U)^3A3fv4EoG6`(88F#J54~Y}L$pX-hoIHrHQw;ZYHC!4piWLQI*2!yBVr``_Ij zob`9S=N_^%8#4PZ%GPQwxh}0Q!`5>rIdZ?{XtTS{4vdO#D<1%bk#dt+Y_}@?mBf{T zESrufnN67!G^>_sTZ%o(LB>~jLXSc&xqCu;0^FNyo7#qx+`TQMEfY!ujyZ-QTjBwf zpJt!lpFluq;8zGssE8oZAYI7UCvRW!o>*bNHS@>%l?&16yf#rB(YWBM;Df#@a;wqv z_$qSHQQCCEv^8qT5C7xESvccE$mGIR>wiRTHOoL*Ez?8OWRZNF*$#&^o2$Zurw<=|$xli9Ng@^!KPN=%4% z7Aq%LNNTn`wLG+NpQtnsss9*qh-zUbNroGh+}O}7*DE;QD?rVgR5uwb!Z{wn+001~c_C_i~hd9~NCQnYuz7=fCDdWWM#ZC+~o zw?I56sHPIPNPi}cIzrn0k$vUCh{A=U9+Ne^OX(!xwSNLa*aDHD@U6N>`&910&6Bzl zTM{$dh-KVnNM)*Kyy}|hwku5v0T)jHpRubu?YCt2RkL}w>w z`}s3HuN$ouH2WNxPH)+uIbOA+yY0+LenuVfck)l`-L|^j)~_94X|`%+)bJVFpSqn2 zd?d{)jdWynWK_55*|uGJcQyG~fKCW=xTiPnyS#32KNlBrcm+4Q?z|mAL!gH(+zo#h zn)m66juj7@%c@SLPQ!bV3(*zvjj#n_-H-L$3!(AF0=pB!r9U^Fb$ZWdYhWmWA9u1 ze%gEXrDkoof0(3u%#)qf;9lePqR(U9gZQd&3r%U?mn?wx)9ShIL3OtDHR(%I(kC=j z+TEKeJL4MI-y}1YQBeQ@yuShffxiHN=TGqU1OWKS0sx#E0RVhyU_aC`(Qrr#0714S zDAn(t&l!kVyU9{g4Mp9ciCj;Tu)SZ2_6h_8kAG;CCcbJQhJ+aeg$qk`;t{ka)fK}<(md$ zng~~t(BWT=tHnz}Laqkug&f<5V7VaIOspU%9xKc{pW=m%wqjR+lI~!0W}t!!=o0n% z_2^{o0b$G338+?)8fLe$bPKG!)Xkj=5MkWN-mYoEZwAIsNe;9`n-v}H2_mi1&w?28 zG)KEPEr}?PFE5GHB9@MKbNPQ-(XnB@W7TAVSC3%=oli80jz=_+d%-=caD5n-`GPb4L(tKz(f?&U(gOGTs?-RCt_3 z$R2p14+Sk&gKTTD#-qW=Z+Jb_};w|0yI$a1wg2?@k2Z(zF$bLb6`b`1TY{wqS< zaVpvHV|%ErDC+r5lGulXD>CQOVQ|m6vn@avV0084R`-#7Z^^~A(TxF^{irb9%jvi* zx%6Z0MN)sJF^OQ_R6-kS#{P`oIpwSXw)yb~_mSnScHjZ7Px@xaHlEP|d7qA3kbvno z5K;Hbp{<8V&mMP6m*FI51^$eOpkMjTsWd6~$`buyKy=&)(j%~0LV0ayWG@*lJN0FE z5A&N*{K9x!MF;K1>!p4NS>y>q#N^zB3a^u|OS)}7JK$-*7ow~@a`Di@H{g+Bv8Ba_ zqdOp4e<@gy)1 zw43jLGl(-$P#^^;FpF z{5X@Jt-XwPZqE?Y*UvW9tNeIRnlS>T9ZWW^%LA>jBP1@Vg%v^1zOl}A-hNX>eX^+Q9VT3*>x!AD^XyJzW|*d?rl_GgBT&!=ISBJ- z8Yt~sSJJAgSRYOrL$RtSo5t?$i@dWi!~2s<7U2cq<`XG9*)3bcAv^bIq&Y%K`GOxOVTZ4qiw_RnBm#AwT`@+i&0R8Af2QtqSJNB{eu8H zJP&&U|G$kG$}lw3i`6E4RssS7 zL@rSpjQe~mGg;!87_wHj(eWLRO&?I)|7I1zCJEs`((zv+0?#+b`XUUr`JbQvG2#CX z!6v+!dE~%FXbVPc@kbqdQO3U@ovJUH9M-0o3z6`%@jvpib*hTpRE+0eX8x&M6st6S z^l@3+bN;1RIp&~+3W*JZWYk5HHz|e=5=lxS>MBEFB;RdaqEc{q{Af*mB3f&6^=0mU z>z>mDJ$aqeY{%tp-MKW!RSlJ1Zy3qi&CYJ}t zJEl<$L%CUVz!J{dmHBpe`pTv$%Rv%C`+IR#^To8CZIcbG$cC8hLldI@VjFtncnO|P zg{5s{GGUN#zOuVylV5n=8kVmZ+?$koYifc)vMTEJCiU?nHrjS7;&mnBJq$s?tQmyG07c!Ai8Y;pZ?hg@auWX|y;f>+n-QmhxD`%BTxo zkp;#8t#Oe8B{&-t z?#;W8gu-wD-urv7hmeT-SqndG4KH*SfUB~#eONPXvxE2gdSK#fu_brgCxVUl@!)UZ z|D@Pzh22hiPDB(Tkhz`R7K71+Lqq0ULVKZ!J7a8 zAZNK7YQ)>;X1jc0`DU5xJm8EG@hYXsvzsSSJ{t?_Y={?>YQ87)T4)238r7F*_qu!H9e}0z@i{J3Y18n~_gy0;pV$1f^*WoS$&Ehwd+~U)!H0Qr6)+k4rDb(hL`Ba?{qe2v zV7A46BQlOjA9Cidty3}zSDiAdzAAaMTK&0wQY9Q>+vrw*epWkFRC=_=Hq?0gFi-b!KGR^T{_o#!Q*Tq` z!bGTW_@S)ks(4(16??G)+#DRedpF=CuWv7?f_!VG-o!pG1$BD^2SXpKw{`G1<$Y(f z)gfKu;|Ay8iv9}#?Vr*SZ@N51f{d1fP8PX3v)gd5)T>eKUgPaaWEJEw*id0WNwY7~ z&+{|kMp++jssGci92pr=_!K@nJ7eUxOvXRfM$|`#W_a-W$p{~ODHKfBTcdjTV6(JT zS=OMXi*Wg%%uPayiMY8nHNGrFwS7Yl5w|H5fa~hJ5aJOFYyk?b1mzi|YY6Fv%;&cO z_`ZDkOd+^ad=odI_NZjckCTnAj(HptTcXdbQ0yq9-yi5EM_`85Vwhl1dmOP?L}rRz zSV8mtzW5(PeHmav-Bg<0>Y0K;J%owZd8vIKZzo8ai9z;;#@DNi+#wzvAs`bs7q#IL zW!{Eb7^3d41L~pQ5T?B8Xsc}9zf&J`mL5!F1B}Gxy4zmD@tg4OJp~LfX)qBc&a%?d z%HZ#pbTF;3w5C`-Kx~ZkV3_gfIdOUKM$4dd;-Fm1HlQy6?+UsgEgoNf9J%?0+KB~S zvR=Lc1M%u^7Q8|*0|gaKdGNyzZ|kioWdYur5>9H-c>|zgKh1qA+4{Jn8^0Id6sHQ& zMgQFC`bX9QhGlrko$UV@ld%j*FsC^$YhmuS7&I_P_M9iqh;l~+vemVjmAnj6I2hCC z<3iuO)|vw^AH3yEa*h~l8aDR@^b><7z>)#A>gA23mH$Jg;hcmf1XTX7#=+})9Pb&H zg}x>zI~|kGvE|TzIr+yCSq3wTikb3i$vtfOu7~lq)y=WdVswMvh`3Z zEG%pen*K9U1>tPq?{L%*MUV16$jw8=K3NE)m6CEe8qdhcu*xy0;A;sTXtG@*hlk9_ zOr6`E6a$_vRE)oX;Jwp1czM<5M&b~>lOvA2d>>Cr@!L3q3Hu0PczN)tj@?tYu9(MT zVq*T|Utka+CNIQ95vG4n|6kt4fB6|;m&6V8zmt{kpK$-}Z8%|>lZ^Cq5GHcj%dTSU z^85~M=8~+b`ZeNZiUB>SgFfV4ns=c1W%kR%zxf+AB8j0J{rjvopy_o8B8|5PMP$FM z7ca!jV#;DtcTtT>5sbCWF_QhN*;SlfKbOLs{idORZu*to?fKoggM03k(2P*e6cb@A z+7?ZM%m+^P210PVGqh+t5FwbX5DQvViUvM7S`i)ki=f!I^7_{K>H<2XE8`DOD(3R~ zNzi<~-bt$ex<=18*Kuq!b1Ug^vcj-Lkg<C-VQ^YHI1i`Aq&)57u z3G4sIAg>F!hvI?XRw#Y=0?~+++XKZS*Vs)^>b+Y&)LeQ2^W%G1O0;6MT@xpu8uQB~ zEKLJDlg{%>|9xwGHFo!>P8t*DTnp0HLBTBo;IK{0felcV`JjJEA&Amjdt78X<5Lxu zgae)B-H<&Ea+fv78mIC?3`kKNhzBC)D=_wr#Of4D(LI3wHkGKA5>txV^z!Uom6mQVBiQc1}o`4?2deQqtv$ zcVtH^LZ_a@yDz10bOyjUMU6J*^c%2&bs}w-sM?1KA2hgeZL3Yyh|}eG69z<787raQjrMqI5s0*SkD^XUe_tqTa{y$e;)n=p77E&^knDmDk%c#z-gTXb zEoYp@JunLgT&Eo9m5IU*6B#&C&GK*f7!?IHf*05B@(e3Ox@C~wQFKOpQ+2qY7$=wq zj3!uFvL@b5dMvl`?Pi)>yMFB>mK&MfUyB)hlfH_wMGkaXY;L#BrP9C7Dt=*os1TaL&_m#y%<+Wl5RVGq~kyU}}y# zUxr$dXIiayAjnXAh44=9c3z}1oIN76L#kj}z6jI`o_?%~qt2hzC^cNsz&69FG1cZe z`G2gjtEG<~?e_$`!pnmRFi1rX#sC10LPUBMY(rSwxAv4&TdzYP%Kv+)`!#P$iH5DkZrIof?I3(2nz_r-)U!{J|l<119{O@tB6 z=vO_*k-pY5!I6le>JoEyre>ekIfZW#Kf)D$9!u?STsNM)k8*>gdhNA)z!lvw|=!+47EB{v_7AHfWQ?y zDN9S5)wR{KGsWM>1pX(;x~W15P^P5F^r-7i-v;V=Kv!rGi?4JA8D+uwYugQoNJn{2 z(+iYy;9q`rLd4`GgH;2QXtf>sgT53twjQc@3&eMG$Z1e+i(jlJ1*Le@{rwn=8(}=F zAk;Gq49gbqNUV{%4Kp{=Z=JW?SIad41+tH4nvOq}^psXk zi#Dga8TKv|GD8b4B%ai~NiX>mBp4x^jwLwma>z-r@Qt)9GTfz#2>ed>$MD+!ApZ&@ z@dTheJg^YNcs}Ka<^7}Td@CSD*@8`_K?AHs! zwu8;bFDbZyzy%vgLqpP+*H_@CvCm{W6E~i~%z#ak$z8{l)H?*>p?xG3PwYVVtxL^d zJ;ONiP3zrAgy|_#(uD!&w#%o>AXhB`IB)@1-}f3}(Xe7mDZ!2#1#^eTaQ$7Q0;l-f z(aq((t7*9wCp$k?Gain%cJ;4u02nR z`V$-j;b!}Fti_D{;mxNU4}{_+lV){{gm?}2pM98;aU^Ns z6%dXP4MwJwHLbm;fIVU?RH!lYVllh#jh)+EFYmu?jxdlV0(B~wq+=?-z2Bo#dg<@- zwEtt9uJZ?z$%Ux!iDH^%u{z&lHG^?~pENzPCb`jj>ZGQjj&_JEyc#|2dz>_=p^7CA zpsJgsDR}Z}4^HT0awgKZ`EsNsJOq57u}mLUw)VqaGgtL$;dphJVNqTZG}>_gK_s}k zdz|0f54FZ7kB=!JXaZh|FWgqPvl=N7yCa)xna zYXG8D7VyA@_muF|Peb1?+c1Sv@`c)O+0oQbT#&DWPu$;^TmEFoHTZlz+j}$NarmEW zGj3WK$rm--_-qeYD?o^!S8*`-UL@)c1I=&M_MnF@9*!)B$F_)6MzW)5&WD`%Q?pPWuiN*Q??xM zriaAv{gl~98d?BANdF(5djPrSC~$UmyW#Zg?7g1on~jYP;;X%#m6eF5rsj{h19UW} zXv-DWyXgJSOCHw}!e76BB@PF!*BzSRE@^5zS#e2Ap-~-*vb*tR&x}t^JxsV1(em^2 zpSLKN&XWrY3YPnz|NToqiyf(aqN%RsWC5@Bls$y8;5>4X^u?E#-kW4VLEnRdN01{F zM0>Lw{jYQH;Mxw=!`HEIVGIx1|MZ_VK{V2HAkk1~A$6?7;g>iUx6+Y>B|`U^-CCwQ zu_h(C4lA?N_cWM0I!3d5Bl1i#cI`@Bo+$Gbj2k15y509z(2mvys~TyQl!85qO;3%a zf_;pf{aQPYv~4V3x6in)Ml(!x^MpxLV3M=LkyoPE=(#$tV{+P`WjR0Or8gcULb$TC zgE8=mvZR7@2vAg1RGjv&jnCI~ zW3A^)cA{p4rH2A~LZk|VqzXk{Tz<@+!-I@RP?v8lN(Cb2d zGMycc@beb-l9o|YR5Zxc;AC9IMLfFyPJmh=R8%mLH$wBm|0}G?4tKy04HC-_=Y0S@pdXF&~4ALpCT3Ce9E%VcXxflVR1}_$0HIdrCs^#baS2g6Un{-4fA-on% z>{c2ef~d%JF+*jk#~48GtnBIhN$F$RnJY)2cVGWpvuVMJ4S(0^Hc%Ej!ACo-qztIV@(Zvd}#H`%J;A0fw^MMH9gPeo!|12*RTxhCxN~Exh(kL}a z(`@y7m(7|8SLA>F!CUPc2p^L(hCRd^0MSd3V?mHDA(ePyS$|Djf30o2%Z!Be!K|I; ztLxPHzFGT4bZ6(0S$Ogz4hdsvOir#43(Z2iiWcw`WVZ(DGS2lpV4s_>e{%F5K!ZNG zlU%X%;t3W~y7B+uup-?zM3ggIt3F3>6_Yp6&uXOrpRSQ z)WOK__s7Nla8G*z?kiZ`SB_{x_@)k! z3Muolglc7zcoG9F0a{mHy%+&lZ)m_0?*Y=sO}K8M58S8R@=UX58;CzJ#1n*@7ZnhH z=*r#^Vsd`I;fUm(-~G+I@Dt4yhMpxU3HgCX@z#|$lL_G#5`kAf*7cRPTTY_^N~FO~ z7bS4MvxtLltn&!z|KzgyBA1WBL|->y)WgN z@30VRo`kUuLT{Hq2slr{G=Pe|nXnfg=0peM<>xYc<%YFeBEcKO=yEEZ%sgZs`UhyE z(A*FkZs6Y~l4m)%P)llb($C|MHQoUGuPVyP$8naX*N*>crlm+1eh2eANB=QaYyc6U z`1|jMTZ8rx$I`tSt`+qqE|UWxnG*lM;E&DahdjI+y*mj@H~YY3vPhi%%b zABU1)j3VYp%K%5yuN4wCxh2SBjreLne(pA@`GsO(($n7W0I$CZ%4v$5f4FJoJqUIz zi)8@}okSdb5v1%8Z*1cqEj8ah5AxiwaQtQegu-8K7v}+GeV<7JZE!3;Y0FZorH_Yb z0NXB4hG$JTf9AoXv%6iK17>V!%7HvTXOfEj^erxXLS#Ikl=#6zQF8o&LL9S#a$SRT zB-bH8tH=#$xaXYhPLNHNVAOCV6`n~`(c}@bY(UB0%xbmPbE5_(`E$}idiz&PF`H}H zY0?%AJLmvoyfv*fU5e(f`J+9XYYz^EL&)U%4DDo3T4@?M*V3I=I{0NROnqN4s}wB$ zW1<9u=R&4&QKH(gISvHbW_Z~GFkpV!**hqSt-N}^fEls;;YpG4&k*^=_Zy_yJXPh_~!!^$_-=!rTbOh-&k9fwBN(q&bFG$$<5t3Hd@xTjBK) z6;F*{3S40(S%z_yC7+Q?*Pxr*`QsJ4$Bv!!@(lUiwz)~jE7mRKYAf+V%eIx=yT!}& zNw+I!Ie_8~ZXU1!#xMBw%mw_xSn4{nb_ckn7^y%{JLY5-Pcn${$uQ(yIx+5D*u059 zAIP4A3P}3ZFC=jeTPUBH{+gVxF-S~kD53Oj8Myy@m`uzRojiQ^hpk6Owv-YxL28)} zT^DNadR}ePH3MCKC}w&a8ZxE_Z2wIBS?R^dmc;zr4Nt>|Y@?7TR7Q$|*g(Gv2Lprj zUeke~Z6y+v zW(b0`&>!ZHC(b8BKR+(5VMdTX)N4*0oUnT~34y6lyRGnGLI;!d0OSmw$Uv|%&vON- zs42F3X4loJ{kw4=-w^GtyLEk;fo~M}$L9?@m z9aguu#(tk3R%MU)pW7(vJMyH9=cR^TS=_iWIl(lWW};nu4Ny67>Mlj-@7{(N#3uwb zN$LEjbT`MKqXDlM&&ipXeV6?FcA}UlIr2j^mNz8$y5Y`Yt3w6J!cyvjv0(6PD<|D! z{0>;)TCOR7BiVkN<8wa+QK?j$7YILzbJ#n;AI8qY`4!xeY z6LA>uD=N&@KrZL8I8;rpry~E%)xGS1eSGJ~@`!c0oAuO(;oExuIZEyO-if&>!{JSk zrvI<}qJbHv_UmMG1Dor}IrmKFRhHnsP@9h8=T)JVmfr4Jk0VsA2D&6XpP(ZJfuP^Z zIm(@S7eQ`V@58F!Ve_CjY1}#|-t_!PqEF7fmsJ^)^qTm@5y10$w7kOWZua=Z;t`UA z>6>cOy>EKoUhv%{E0~?g1dbDMq%xmnRWThli=W>!GPlCu3^(vu4PMh9ThG>cGbIX> zjx%m}+iYIXoe!=(3O<3jF;ZBXRrtWDhl@66W}2*h1zLjava<%}=qX1Uc%2y*wX;KR zr>8}2@Th}-O_Yj>Xs_!5O^*dI{1{`by7$;P)Z*@u`MZYMkstQ&(E7~n!=!TI{w~E1+tLXZ&f(&U zqf;))hIO-2n$OJVGGnv)l*&23xv|m2=zvw=AI-C3Y9z{5oe|y0g^HV-c24w z!o^!5OM#ixy>&kw+iSgzvOozzeiJi4J+0{G=9bq~45Q2C*caNe*)MmtXna?q0JWRZ znDgG@euD|WzzeF)Jl)k!i?hb|)e)hx-UqdTgSTFC_;Y|w!K($1^uf?GY zW*{ok=|Ej`r^2uUg4bKnjgPpzyu8*bLU^WT!;=yqQn6q%Jei*M^JeI2?rSR8%0=MO zao6na$(hJu19Ok@C_pM$eU_%ZRP&OG*rHNVIDm)kiTe1?DS7r9c z<)&7anZBfiYAFxC>@~Es+!mbhP?Sb3u!^d7zeiWA6i=BJ@#v%ubMT( zmQ77s&K;Irza1G2V@U^FCoxso}+@H*2GlM5`R?F-@0FT!4@-*|}Zn$6jJzIde2kn6_?d0grd2_L3Iy}u{Z zvpT9#}vzUT=F?=U-y``xL@g0ci`RqlH}O3rk;!w(`>gXUpRu; zLM1v5i4Yur&4xAA`F!U*l&mRLwc>gx0(rg4L%)btur%zI(@uyCt8Ok?SaCE}2*##O zg8}5QE<8lar4V`L49eJrit~$$xJi4_k56+5rA6{o3YnL20S<#rVGQMNwM#vVpu}I} z^Tf9$^8n@KqrG<8xqs$kwABHtP0Ki=;pad3&F_ssl#{5|Y7OQ4W=iQWcC>m#kz=b`O zdX1E8s^gMt+q!WF3jgsaSE<=|EHJQfqgAv_?JE5!?B}?O1$`cFnYh-J*Tau}FN`X{ z$Fk^_c#1sFw?Ot)Z039I0pfXz*atSbh2X%JOgg1MJY6oLLlQ|$#IFe4%lJ^}#Y2$0z_fn1+-|eW?`tbTN zOJE|s%&|Mt=#qDJ%!ciu;1Og8Y{jsZm=L??rygod4*WV@F&Al*`D=V=Z5-93+C(S~ zAxGeGRhOXQ{^l72#M!EtVM6LOJ~&|f=TxhC?ikA~NYry!2OwiU&NqmK9bEu$;nmiT z&PzRQ;wwl{n)PS>{=?P2ZI4)?d@WioTUsK}WL}3r;?ro1hzZk63#mIT;{@ed!duIA z^xoGE9nyM{Wz>^Gc{7)s>zFymFZnElccI+^>XNOKjpQN}X$P`|{IS;bpEPEltmuegsO z;O8(?(cGt{HY-;+f`up0)15EnSO0vBM@SqwKW3Qxu3?;kQctR$W_hWqjvFDEu-Ka$ zPt#lGG<ynE);Z&UnNv80lBsDkI-6`~pw53O0A3<@Xr~022$+(=)~aHS=N{y9KoAIKg}6 zLZs`_G>SG?CL{IppqzV$;EuTk;a5Ix2gb&|T#W-X;TQr0VaBN}*W`LBW|qu^++1O^ zbor9BeJtiL$f3Ve(_{4PF9*QNmj~PPy=P*2XNYw%n$MqWLw0fY0{7bDS^KT~jbYr4 zX?X+kg=z+xvWv`k1E1cX{gOe-n%$9FY@EPvW>b*ohlkOqjg?)vtkCzy&)$!+`Nqa( zD!WhL?_7HiOqGmv#`X~?N)s6)-L*|$n?Jg5=8HdSU!{i*@l>)fuhssd1XLam>KoHH>Pa5{HTRYfQnvrqxm+|5%7#uoyJa6!iJA5P z_lGK$>dJ+CJ5P2DlMTo04`+=30zbTW!&laA$#3qu3bP5p(nDn%15UHz6u}h#gPFuP zvhW=hx(e})LH;K_DwLKh7$z^;gHiy`*t)j+GFvzz_DC0bKi{<^Wh7?7p=>{qMS%YB7yB<3x7KQB_riuqK>~IRyhtGaX0vthUg%8$0pk&A8wVA4XKf*_oA&j_!ws#^NWL z{Z{w8@qA5oUXVDX1ui^?cV{}6JpmY;<1kamVqv9zrUmYgB^4^FYG|a?zTbUIfCp3y zn?;m8D-2+dWG`{p&9V&;??ni0Z+a{B_?-UxhH>|FhKv!XVFQ+UY|d;5yRzfxGKFN~ z$UTQ@wVt=zTYV<^8;zpAATyL?5JK;r*cdduO71DCIzlM)T}oTL>L#~)lt zyREjd>HoIQ!FJmj0W12W7K1X<>fWqi{v>a~hTWimmKt3BuHTA2Cob=kuHjqktNdSu z2Y+myLlj)9V(K#1352MXhMe24A!fc88b zF--vuZ=%^qipa=FNHwDyCI42R1v-3WSb9!HTlp3lXp0KnI;UunNFq7b$e7DDxS zegv>|*JG9{=JZEk<%Ye7UY?u;8RY&lwYN`u3^~F7x#{I5f_t+sffD(!(?Tk^Dpoj> zSv-+qJnwV$pELj9SQ)uN%jx+b)pYgWUv$ol5Br*~7dnf{w4e*lwc0KV!tdX|*P72; zq)l1KXLF$x7n?tAzgI0AG@xXDwu8T5xgXg8->(T(_C?GniTn#ct^+-_*sn>^nDH1+ z#=X_LOr`NUG+s-UO*rg}bHObRRPYcB9S_#Q!}UAt_duid5z*GtI%ZWM_<)z9yQ+(iC@0d)adWo!Ktn}%nh2qI z%trc@=<4Y35z*r7wlR%StWP1~{-J*+HpTFX_0ZhR1?Y{yqH%t?x86TEFdwX&11qFw ztCa9`i-5BdF!Wx$*}`2Y6*F0;nE(d;Y)CStvkDog;^*`Q@)>|3rg1#fs#4$s>( zv82muJ1c_Y3|0f(+dDjEPI_KoJLX_7#9H%|iKzl-v2@mi*UvMydZ z!2(jO@>h*+;h5>&1rGxQSj~fhfuWoi6&@ZAsV^ZRfqhItL4oM@|35PUXmO*n)vfWd z+a%-zzB7Hj(OT#|(C=Jq(LXbe*O?z`jKE4a(BiO)pq-U`0mZ*waTlI@b-^z?#AvjM zw0C>_r_X^0PNNFKNd4Z1-g{9J*RQktLWf(u=MW`=xKE}0RWm3%e?)}>lpr@QO+TO* zP*^vZgJ2*&15iD`@X%PbQwBa+pXQZLx&9f_^j7hRP~#sQ|w(6*l1$l#`GVAYBCN2c#Z%uPHUu2ox#gT_6g1b7GB$ zqYu&(Qar#6U>8-FMZSCgm>ma#ZS&1z4vM}=_px}T5DSW#8c;dh4s_C8B%*8k z$Eelt-W+fukt|PWEh8R>1vZk0>3>AW%un}GRUZUXrt|uOD{aW-XUp^^J5#I9TF}1a zi?AWKqi{~+D^C)m{TGWbrnFq`KHx**7FJ?UTP0Dtpv^{MhvQtfyQH_*<|Km0ktjQ|b%3_t9?`n>Hz3T-Z^XrUgEyAPVK4c9)QW8Hr6U2p08vU8=k z+1`2N?vkit-wN%f%he&4IXhSr*)T9qYw;kC`f>Xz5y!vQpdrs11W{Z8w7ai`{4vTs zJVs$;o_KL4c;`TYULO)Tn)_yPm6#1zSccFR!&z`mBTiS}YPJxexwOUfr_$^5#QdGx z>~u~2-jH+ZowE7%=#^+g)+0E`DvwBJX|M1#RAz!s(<{7A`V!>WKyKx~7s)fcyCw3UCrK!_##%Mx zc$k)(-hiwHwLK)T>@@{0@*jpMcSra^LXPo=6k=bjb$ipf51Zr$)kCL#! zkECg0sGj@_@OFg8iopalJ%hk@0*r3jRAWND97c2NCN5+NawuIA~FK>Njvq@>m z6>?}T3qvFTigz2e3NCs=j%-2*NHy7hM@9%8o0pGUBeN#8=`O33QFZRZ&8fSBl~eb<;PXT z?;5nST@&U4xX6>8{fYqEC*j<5P_Jd_eCK8;;1owzl6GRfc)fWs}@? zu9m!gO(*A#iEM@0==zv z<{VM+s;AcWAvg`Uof_BD7YhlD59jJ6IcZbuD|=8iUqnV+Lq!KmW09lh&QVk)3+rgR z?H(IjO^)g!FEs7wu!p=Zag9RpA#9LV{q63^il%GfsPhrYM7a1if_mw!h+2?r`z4`u zdU~45b*nGn1io;AqO;G8*(>P;ww^19Z+0PF7M67%U8 zqL+suGq`Ml=HFMw`J$Wwd(3|3G)(WS<~s&f2g~~2%df~GJC3HjrvtPOZWj!Q<)fdU zvGnNuYuHVeLq;v=G`~Yoe3_SqZ`aklZNo+CtJfa5@yH&aQ95@<9|G%insxUMk=ztH z@3j~KtwH-Zj+}Sz(E1^${z#>QTJOKt!Pkeq$>olcea+NZvGGCie*$I~Kr1iS9m%!? z6(HZB7wl?gDnSu`UhHUL4skk{2dTIFk7630$@sk|^8F>BYqHxxZ?UqmZl7D6KG-&p zY5?y@&TDup@A$k%;@o_uubUd#xrd|6FAHa&w+Q&NLRJ^vQ@eN z9yR`xya+*8@jXo`nz*EBXR^pJej^|n9TgB=>T8ID3zZO>MEvN}8`+Myd^vr2eU*o2 z_syadTaqX&Wta|00E*3k$xqG+nq7}r5ddJDfI*OAiu$EdVj z`VH1YE9eK5B#k%i8C7#~KqRqGvE{E$pYSDI)4&*^1Dhi-~Q>QY{4;c6sQ9%M> zN7h>Bz#_v%QH)`Y4}o4gRI%n5H^Sf--+O+;-`bEY2;*cy2QXPlbFk{dQ8gbnp9Ugn zXatJBPxc{DINpC5w?IXZ2#8sNIeF$>V)aFx+>U5fQ=}a|7e}(hF2uCIZ?pCZ1HU-Q6f)N{PaQM02YH`|@}W1M zTQN%^M5!zAA<&w`@GcVK5|zu2j^XzCU$2vqDEKVPJfKJ3oN_K`n|3K_=P%aYTS+bR9-${+Ax2cbh)zHwj zDB_VF=)7!)6T+0o!RCW(U>dUPKauh5C3Zf5XmO;rmGSOWU)MFte*200g9D_CCampDo= zeD-AC|Jvn~m)rmW+dVb1xw)#`9l6c5AG~V$MIuxH)a%KW)MW?|G}IA|?%3{He;EXU z%ah#W7Y&`xg?GwwO5Bk=rCBKI3AA_$0Fk<-@0yLRe=jY@5NjUD=~`ku~Zi6uWgtOfAl!k9)~h`I>3p3F6Q^}234&-0M$dwvb=q*oBX z*N9NQBmMYAyL0yh-X|@DB$iD>v0GMBB+%BWqW)mv2_{1szLmjKh1V&GQ?|dsesm3Y zG5m0DtLX5pO8eoamMCC59p5Ca=C2e!*G-mc*H7x_4)^hSQNbLbj)*4nTyIF}SYHyq z0KRAG*%+A5xsrXxi{81B$hxDEvoB|uV>oNc5Ysju`S^&}(0=c@1Aa?cY^r8+)_y(a zHqdotS1yCGnGZ*=Gm`6gFM3C3k{d~nbh zV{u~}F83F^-Jr${K2>{JZz|RXV+Mq?sT9U6b zhnr5;tTCzzjk#D!4WWqr=>Tu5(CwcyR=trGo95->>U-Y`TEF@T0J41Er#k$$Qq|?1 z>UaSsA(!eam($;5c{+AmUrtv;8k*7jj5(Qrv5tW|Naf{3i#87)!4%gg8LPWEIIloA zuY5^H(T7VIUi{#_2^oWjDKxe#nh*z$d8e&J|03&xKWNv*y%nYf1Y)fDWmz z+N)%yatfnuQ;i1pI_GVR(#56xhZi;S<5O2<4{dZ>Jg*m(7?d1-;JYhc&^B0hxZT)e z{V_+0$KJ{I!PFb)tU}kql#|aNKm5LxW)Q}lsB^_MPOVMWNX6@kILO6ZxV}u#pX=}S zKb0N1=>x@12{_4NzQeo0va_AxHi8R9#~~S9#%D?7&hQ9oz<7!(wMM0;mHacV={#uL zn&^~h7vqSFRuW$Zdx%ck%&3Dn^H<(a@ zQLi7oJ34p8LhbRa1qRD_vTDenD%W;$&DMG_7}V_)BCbw4WBiz_%p@xsq~E--Q*rjb zAo-c5mWQnU$th3B(rU(0UR!Hdb&sB#w~y1nSM)R35~pP2fl9sr0B z-A0AWfGyBC%++9>kvo-Q^RDykxsXbfYW|v<3c}p%r^+RyYq0NUIr7J6IxRW0W z)FEe$7^>S+Qhm|}>3RM#LJ>INFrA5sI#b$_hACM!)rnhh5Ti~G9X>gkKDbYzT9Hxe z!-2OwAH}8k120|%JQ-Y(4R9>KC*FOtzt>eQoo4C=#)RIfP-NZVQ21+fr?BSv77N|k z*-OlYuC`VJ7K^ZpL?hi`Shp=u_ak*RS9H6t{*Ee{{u zyq|n3me8WaH~ybRT**6u{j z;D16+D6xLCF(*fNwr7L9>%0?Brn{dA{4vui@xuM())-Rx;pBb%%41~p=&PoNW-+(^ zuhU(*>0s4eM4#8wgXv#<-ilZ8X(~JQBN01(#BbFw2t%dAK1%R-W20}I58EKNH?mrs zy#-*b;m@~gF7xp4n62)22N1hmQuVXpo3fPN^)CHoKmzIcohI+qU$4Go!H;4Uj`RXl2a4^afWR^Sovs%+#%HZI?ZsU4 zIDZ8f5Wlm3_#-?V#r0`jwML9R3JwwuSX*PBs&yyS-X3K;-zEJ>Uw`86b@o}2d3n{R zGmkR1q2ex7mV((g%$n-_A4Cg2UR_;UIm@L6Zo69j4u ziPQ&y6!1ZKfFb109YRfGGqkq$-tzMDZRowXA3t6aA6%}t_P!=2mN@aG#4MR&5Ptl) zLnRo7yPuktR#$(^=0MEv(s5WYgA|v7+rxMoH6R6UCMqU&L;afL&L@x0mt#93+s@>8 zav|yxLqnO^DcA_6prj-YIQOx#vZ87r=7v|2z-uEpgFAU4|3wP)Q3=s|fwinHt4G2P za@py^R*DLXO&h)V%!CbB-u4NV)Yqq@R8OVj1j25AcXw|-SWX0x&~f2AjSMM$T8|$y z#yT2HyK_w2M9T5l`cjL2|IQEEs`_bJ6DyJz8Y>{T5psMP zxE~N8o2{#-gh2)j3=OR!FnJ>zbsp}XZeI$UpsMK9;A8D&j3;pM(lNI?y{@2aqh#dU`t{TBn^U_3kTcGz zIoyBDiFd->a_k zG$qc#xS0uIK^84F`MS4KC0L~gX_=XqDg7&lEU3PTqfxtH@!8SgGQ9yfv2PCpuc-`Noo4#RFt&Vc(bB zq^w?6mJ%{KIlcW94~HV^AAW0TI#K?i<2DPTmoU4TUi!UJbVa7uw63S~={CnCBWe2qf?*}jIefpgGgRKJCw$US$ z;{zX_9KWlpr=+)?qE>f}pFVwPV89|LC-=mBCq4vUKX0uPtO$FWG`i2|T~S;dyTR`5 z0UUP1$qVY8UfVBc9s;d1PVO`6B=IRo zKKF8Vb^%VQg#tFEE62vi@k>BPPp{2-lU~&%uRjfb-D2e4&FA<4I#Yv`0U_-#L&jPz9olhb)25$k$HK7}xz|9GO5s?;W!>r=6o|9uD?#=NS_~uOZA`oC(GnS zyYV%pM`^4^GYI&1UBTG z6CaEV%At(p)Pylliv#A?m|Lw^#k+p}cyeZ(*I&%aHUy^SbKB?h+>sBh5zU1M-`uZD zU{3$!QvE|EadkDTdGx*F%XI5#Nn#6;)OTEFqo(eUFW4<39r^|vKL=()^aG382BSU> z)q0jQ23U*jTmP3#9U0izSpOt+RyXJWsk>R-aI~+J2<#w%qB)2wYcBp|6_oq2>c4A z^tgCPLQWJ~r4*Btb0L^6Ox!bzkR0fOfWmI&B;FanZq8#-%-*+9kn5;2vM%Js%@f<$ z!eu@7=*!M+kGgq!p4W|KK3Ed1qgF3O7|4x%-eO9ju8{BDhm`q6 zZfviGT*sSj7$q@6pXEL-?_0~205_fDx~``se=!p=pPaQZ^Bj|F7v<_(xr}U`HELGE z`JYNsnc{G|Y222b`o1*W&ayDSVUP=^Jz{5+AMhgW6&j*CJWsN=1i9hsL1q(6< zSf?1e7m9U*x_HdsovngG>#mItw6nv5h4&}QTa2jm>lY7)hPe+vnHkK{(wt(rz}`^r z*ewY^8`Wk@k2FsfKQz5!t7_s+0eg!tDRWm-cFUAL)sHz%qO6ufrM{ib@uPfDtbe?N ztoem%d-36rSBz~l%Y9DmPag^!s0~ly>u!OEa~cTKkP?*A>&gm}?9I#aVs~VIbzc3pFmcs#@XGZ`$0ZlG6lN?!&LVGkDy=gi<4v*lZU{jYQBdLXuG0N zo_JZ6o>2SRV@Jp2j^y%u*iKFU5GJtl6SwQwBJ2|Dg@ZqX3{dFo03+{*Qs?!Y1JIFJ z9~#rm?l$fkclH!)nu$2cf?~kHecd>IT@buA!(LS%ygm2u>C>mb%evZMPArPwE$Q)*feJ_o z-J9`rs~bpC2yx9Y$R265k&ynTP&)@OEWq_m-n2)KJBLBM!g@d_s>GIij;&Br$kuvQ zP3@9C^br`Wetdj<$$(#Icf$(~>rDZ9i)FqS`fvyoPG!BGoOp*m)@nb8~J^ zVg2)s&?-~jE6`hO`tkd3kOgv=%wAhnSV*~p08)$ z-AF+RKi{5xP%dGAE<^7{ZM?$O`8mRQiAU1$3QN&OUZ!1vGw{LKqV=4AtN-6lOvg4- zKrZM*#X@~}DcC|S2p=>trBmGU!RBz$IicHMP7VZ=n5kRVZC)dRQh3%jFFiAv@Ty;>P2t#(}Pl{v8Irw$`3*qxtbQ) z=IoVudH$TSq5X#}s+Kb|t|?JK3h2Sj-+SoO=4Z%uvo}eq_ln-SGpZ{it488}^aU%A zoPh24q%JAoJWXz(c&D{X$}du4ZT?4xR9wHOM*_icpSU~VckjnfzP`vZGsw;suEo9L z!x{0&?>+aUrF>D}rXDD#6AkChU|T0leZSK`TNIJD=v=d&UmBSmy1PmdRjKP41-Q;ps+ z{-U#*ZHmtKpzu%7)zoyM^- zpp?oG!g(eQT!jl>s{%OVWaQ*)@cWNxgj3 zOGrqBwAj@HAPH-0#FudU2z4O?gQ1AM0eT=%I)u-+HC}5CDNE_`hzvYl+U~k%1*M6s z^fQnW4jJA|}cVYoA8Hs>0tU0cz|LLIGNgtZUgGxCy-0WR4Rw7q zpn0{7Sa~T8k=`*9Vmv(?5l}4h64iuXph3e!mWMuS#8(aOiG0K zX@B2WfRMGlI-$f|!hIWP-05kAC!)Bu6`Z$5T65$k!!@nfC>vn*Q7^s&<{IVywz!49 zA1Bx5`Rt}GMZ;KYp5ZN-2BQL|jcin*n?x5>E_%M6rBt0SthDLpPyI-e7@!(oyExj{f7#JJu5$mu01>5cMVuQ{7quyTO<^>L2J-zQ0 z6(yymOl_zX)J`7;xIP)#S!|H~t-`|fE(N*5>j%;3TyDAXpHG&nt1E%n@a|op%P_R# zV10aGcvx6nU2y!~T?5X+>PLEd&Qm`vU%0wb8{68-3J*^jf9bny1dWrhuCEN*oci|d z*DqZ_iLQ@L0WxvD-sazi!Cbqr44aGn7G|LHHTXNiU{=TexPR7`TqLL7THUME;qBz{ z*L{D#&*?I~b-m}G1hX$Gf_diPId$h>ml8@0_-X-+S4ZLFv`%w6Iy(KlrPG(JKY6ct zBc?y!b)xSXFJ=i>Ck=t@J?0M9iTDQ6cV1Z+?Vn||Cga6MB>>JkQrxChc3YiQ7lO<&RSrzNnR2NCCJQVXDHug6o^6kidlt7n(TII361q@Yd!=?6EyFN6p*D zI{K0$2|zAJukDI zqBW^{Pe$Itv$*!>#{>zkk3NzmwLb$1UeR@p&t;`raWtZ$10O%8A2gz@msgh)C0CZ2 zq+WFOviv-DW1;khv8*ckI^q($shA|i3KHLm+HLbgLj-c72V3e392%Ef z(X^6dN^!?0SowWK%k;Oyc?ksYJZQS&#oA9xAT#zpGqXPlcKVS?sx?0OFc^E(V|!QQ zD6an*9?Q;6wr$uk@f*F*;Jzw4>eL65Qp|hz``vpdT2~k6)SNT}^I&evS zt&*Gjs}&J%=yU`JptChu8jv$PIiH1Qb+X1*Wmg0K5MdeGh5wzS0voxvj~Q{rA{!&n zTQzr?W3*VaP?)pDP{NtOsn0iMBD4mteGve4=v>ROxOx4q!;+4AYeR1z&(x9Ps+0Z9 z8efE|&Ev;!&Fg8@l)X^(B=~V7`hxJg!R%7gq}0!#6Va05O>xjV{&-TIL;nb|#JwZv z{b!UV&$@-2k0lUin}YZjp_h2vdf)L{Edj}wCstKi8*@2`QegEDxJaK;Q@`pywnU*m zamvUGWIK&Ib@5oJOlS3F`wpx`qrcSDl#Y0P`t&If1akT;oF>fW)&n309^6bV&vV&J zTNi%I-OY;|oE5gu9tE)(hK3$v+c-IviAW7VYY&`EfP?Jo45P1@W2QCGfmdY3ihMGs zr>0D7Y<_YT0nX*aH@2vYB~JmIG|l_$QuY~2^dNI*8`+rl`t`Z8^AvQ=JM&w&ir(=l z7>fNz>CDmTvgh22GopSw5JY$v62Qe}oq5-(X$nq3;dTD1&yw>HrlaG0o45(FiObCu zq=e$m&bRD*7_;R=MWv(wQ;;w>X9WZg-%Cq@tXr}dqTa-GS>Md8#;M}?61U-`GLVCg z?~h*I4e9^&>-n#bqQ9X^F_twhrZzUeUo&#{4-MTC5y^%^J%QR4pcciUm)Z66E_$D} z-RDx$VF|D(UMJwTo^KVUDc^q$4^J_b{$D_$|AiE!oI{q6B@F#AvEj1TDEijW-#`F#6 zi!6leg4#5&P{pdPkp6_55LCtVezio-&Y$_mCkp`tWI(YO0st3Ner^VvFi|j+amarG z;Qzg@{}mPf|MHMZny~K+8O#XKU_$`Ee6&aQpK=H90)N7OlT;(hryfeJGG!|fg?eiT z%ub$Af?qX62T4h4*lv1W(~+iPnukimw{77$z^4yOTmLx-`x?J$Ju8h0UbOSlrGUqx za=ug$L7G3{P842#xF34uJUqYQQbPpOxGRlN(>S3hC{${6%h3J;6!vD_h&lnej)>B^ zt}lB9;~P}M7sWGQ-N=AEp3&sRg}49B$KHtYLAt9%l~DOeRmh!JMLCm5Y>GdHHo-<; z_-BgZroxj{P+=e?nlLy8+!pq7Hg|MYO+%oeF@t;O<`>qPX%d0~%63mXGZ?Cpw+}z} z=iH+Dm!`Pm3R*#i3&=LJC|TsO{-(@)LHk|XvjqmlISCQ3`Us6+46QW%kw!a>jC^VM zU7T`d5)n3?W1+(q9i9$H_61u)5Y#?2wk|H^#@@N zZ`J`sz+8vj z@_^?rm0+~S%Gw_}P~&hed7latJVJw6%7PT*FhbOl0Ya#X!F!_Z(bydfe7ug9E4w8f z1v)0RO15e2#D-0Wsi^!4TIA>0@jPCG?=yq44qp&30_{myLj#ugQ_i1Dnobw$=+qbH zmE0I4H>wK)H>qHQeEB2*+LUVLdxv|AlNPXF_XxnJbUj$Sc|1t%lKRD zh|%@mXf|6g3PB2u$mqLn+gaC53iZ@Tuc#@)2H3kAVX$mldqk=0s^om)ex_tfkYKuo zWamLf;IUc&6{0Ax1|Ocb@PjhK0yHT=k{23)l!8<5J(VJxA^Ji=u|z>zE3&O#Nfvgb zOM$6sNDmXpc~TXTQn~I(CL%+hR=VrJwCasPm=CWf&IhRqIi7IY<_al9ZJSb`)(xU8 z0<%E5|ASP0r0UHS>6g)0FA|m!J-Kx7Eai!=A1k7(H(+uRDwcAObYbxTJe8Lc@ThrH z31*qpzGx|*D z3$C&e9Ovg##tC0GPbz{k7{aiXw*kuY#zrW{eI>JDa3?(89yP^-_hQx!NUXRzA~6p+ zwI<@pFYR(=xN)gmS*70~xa3$0*GMFCvA?P*%|r7m!~DY5X}1z&A0=(auJdU!@>M*B zln;_qf*>xHeo>htzN{eB7Vw%g2PtQ?v(H0C%!Wn>Z-Yw?--bwV)|o6JzAsC2ihF9l zQPJY+>!_!S7MD&()PA+QsQd@0L55>FEk-)LM8Hp5aWI&?kRL}*3}gvxA=X6H^uZX; zw$5_bVxQd4$aymqv+YEHC~v|tl^8OBm=2{P1O@z5s|0}I__}~$&fX1wj;^|TlOHdcfM$G(4 z0J2Yga|w@K0o!j;@xKi?LwyOywCMS2zt($OX{W&BPum=D6?y|Ha3Re=r-PFsg)pk) zOPKcuzXXdJ$BDN*R;|Akbmx$HJe!}CE3hcWz?xUjT8j!;d>V`7I``Az1vvWQtIF16 z?_^)jYpf%j!*b&OV$kp2pwe{Z56gvOWPjLTeCx^EOAzyh3Zg6rf&LyKChU)`P}S?B zbwrO(l;7A1s6PIL#yoZeTMQ6XJ$b3(H`0a7!P*R8V{6uDe~2k~JJf3hti zBZ?G66=8}k+NH+-KJD{s_wbI2i|UJ_Wl*fx^u>~LzfRr(rtu-aP7239Ebz;7Q3-1O zQCm-b_}Y<2-46;UIn>6ZGyJ?kFM$dI;>F|Kr9TIJP()V(a0c~&-r=UNPX?9!1%A5A z*6Xr9v>1;X%Bl-NS?!aWHGH|ByrWnjM!{%PXwlIE#9ats`QSYd#j`e;`jyk!W9UN! zeAO;qe%0i;sOBI7Vz|bo$nuOSVpYAqIc5LK>hKPH?lr~gE!`G4Qpc6?#g{2gze*8& z)zqmdu*M4Nnmflz)4H_^DW;9X7bIIm|L0{6^xp3)%@cxP!O<_?au~iiIY|xO0;{*Q zgWF$$htYXh*7jv}Lk+XCAc{~_Tc7{Uz?y6lslMo<;K1O)>Z`9|y_r}$Kw0~Mi*Tj& zM@%D!B74a`a$QYdc9!K}*W}yIEm&P^eaiTVxrZ%4*;G$3_nXj(rv2T<4rSgDddw&Z zwH|p1Hrf8k#43Haop3U1W&aZvML}COfVKZ?FY{(XQu#+|G^OZ_-QQ^$hs2G?s9&)Q z*!;1BKBz%XodmXUQFuL2E)YVKxfol-cBBELTM!!e!xnN6xG6k~F$o*8Y`;ay1d9%@ z`cpjNV=GZb&;x6MH=$~O>$k$k9t9fGQX$`rC$`q5j0-JdpZu-=NugvR*U(fz3}VcF ztZN^%$b6lX#Su#F>%HDb{zxt5mPUbYrarw<>2(RCz;xuyHsZB|eW3r&)HVanoH>r{ zTTk%=(Yw5?`Pc5xbo;Ie6t&&nV3%vpXv1C9^w~FA=Cnx&CG@7fW^Riz-h<%#Y$+Oi zJ@4r-7h(5Dx@s0^K0c^w<@06jvW|qFg@ESR{|EWa@h4nS4H14}Rzs(;byiU!`t1u2 zKnf3TPflJ4iBcgdwopHzPTBCHV7VVZC|wVA$V`k<_-cdFI#^(8jm{l`vvrR|Z-Mn8 z%D99D?tf!XC`s$zjH7*MQeIKR6JeAwK#Fcf{Z}Wo@fVe3*IEL54RGY<2i^y*`MT7R zJ8BC;oKdI)9P$Z0QHE*Y8laXy71et3Rd9wab)yuV4B1ruN58v7i)I@y(^@n;ED0qL?3zS`eqePi=&zYU23!}AW?1=HS5?F)DBVe9r>l!bArJ5!M%Ji|eF`r%t3 z=eY==C-zx4Mm4tc0cyC3t81i4sL7nC1AC>O#u<#u^}KbLM8=|x1!Y9`_4~Aon@f#p zzRKV652;-5H3Tbk+kb_izg1AN`q8RVA$e9;J*SH)q`V1#&sX^2KOY@fk-&iGqLg=( z0{R_2W>cr7Vv+xqf-ikjX!!YzD&1^LK(l0Q3OPclKC^3P6N!H9I-aT@!G;=ZDCSe{ z5}l^#fM=~Y6DrzZId3m`+5OXd8TO+)ooG>jG7MYeDaU10$^Nve=WP-LhK`JJggvB{ zm({;^H8*f;SI@{24nFdNx)3?-3Y9OKJiz4oi`QsizzboBQ8o(QY(T(wp`sC{DK#lf z2{&%uC}0~uP0bzo0Hf7#Mi)8rRN_@~@$y$}-^%}kz0V@gK}Y-CF*+fh*9{q(Ga^^oA!Zr)x~>IJzP1JH@#rz`Z`&{czd{{=9wa9t?e8bgB8CVmQ5*lD+D!qQ$eaM zE6r)7Xxv*)cQA@-M95D4a0(r3J1>_{I$YK`DxfAa$5*>ag+r0^NDg-%=Oe!@;j{QI zppDkI2wvk56l$9XC+|!aa{}Ig*}@JeDs#_>`q{4Zpw%g3eJ+~dN8h+URPHTydI74n zAw?s!_|CfRoa^snE^o0jJ?IDQ8f^-V!XkediUFhAQe`>N%Uf~g<1N-YKHT1=h}rRi zT2I;)M*%?acxDlS_L%lS!cG{BE<$)X-Z#hb^9BC?DS?$@R@deeSzlH%sI`6-e!cffioMG0hA{Hml!Hca#`jI(dwhDWtNXPMpWE z(WEynoe3NEsQ`qIr>eY&kuQ3S)rT6o8$7P{Qub9I8SU81V)2Z!(|+`9&WG$(?wsI(}5sKTGNpPw z$^6oWnspkmqrE{O`Z5r9*fr0Wz}hH7yhSFBbK2x%53U;3YwjFqz^N!@=Dik+A-V+ z3-x}QDzQnYNV_r7FgPC_K+8)JLk>kgjJIP8<4wngpexgZ0Ul|-p@@0uoo1Ivb-oJs zem#dm+9^WnIy`-A7#Lzys(DJ|A;5>E?{$5!d<^|^;bKu+7Nv@Tw<*Co1id)Lmq)FsT%)$2@1{<`>!-rv5i*MQt?_v}0Ilh1~dGO0&; zISw3(!=zQMy^LYcua1*QR*P36|56Oxxs8R0>*@LGjNfKD@6jp7xxwn0e9JRn(Srrj zZDC<;>Mc9=y6%Ej84(?+H$;phHVi+Kuzf#U_s%64p|ZY)B8)?f1>Z0vf5o-iTp;ju zq;~b0M67xLJl@WFqCs@E$~fgIt#j^b{{4h4R;kcFh(!^WOV_}PkuQ&#WtwEL0HTa+ zu{MnEXZ29o^rvgopR6-oj21sV6Dp-j?oqnwO-p#Nw2z`cWyBaqKEXb5k(;az$@4U~ z4^@p_@4*!*s=SDeUfO*g5}6r&)x}EL#fsiVnyD*8x1l~Yy+Zx#$$*MwQU_dhGH8b8$j{` ziLVYqEW=5&_aM7q@lt`wxbzc36ps_m%8+UbjeM~d3cYVizgeL;Jxh$vYuXpAH8$WK zgh(?Pxv*Z2IeIC>%v`~CqbDURJ^I5&iIc%yIVsilANJrBfO4h{5J|n1J72cancPoD zvK@jP=v8CXK95tq3x+^0m!NIPAy<*crEKK@)31ZuN(!sj=7h$Mb~mfMzfXHQelCcH zFyEi=TYmT0o7M}!$R43W=7?y1b_N3Nh6&jiIFf53iH2qx*&WV!>Olhb3h{puIF6EOpr9Ej+0D@D! ze7obn22a%d_%i(_cmG~mlsX_AdW}av#F8V={Z8ogI0j{;A2Bko_WQ`c_L#0-{@GIh zGE)a!QTRN>%+3f zKYHjD_AT_pXhIcYFK)fD7?-9+^koD=urg~(8H{^VFcp!TM_?RADDN7z;u^sNNQj=O!u$t=8M!lD|WH$DFb z7s1wGD3Q>2XF@`rRa554oL_7JzCmIavFvCY_j0Q0^e8KnaX}{K=;4M@0d}ZQRMq#U z1nQKb3n4KBq$zUg-|ZZd-Gzhpg~l070jm*1ycF^+Yz6d0Bh>n*)gu;7?8V;%3q{)2 zLK+K>B5M1u`2`WTdP=t6Wu<>W`V=_`dz34^;d0$cT9TdJ64%2BZ0gFB+lt=^{q=h^Cid~S>UX!| z)=d1!leSU;L^j+l;Ki0VN3&EXyFPn>FK?DgQv4Az-)a_FFVAt zOY&tM7dZzni*`okeLleaCUR~V?2gzf+bPM^bM&()9#K&(ouHJ~lLNo*y;|!Dqcsed;I9*6lS*`8d z&V}boS2WcMT*duiDos&yUx>nlu8%-I+*|ENCqwK}s(=VyW5Vx+m-|bKB-q9knO;A5 zWtbVXhBrR#vMmVC2{kkvmbW0COpk+u@RPD>MK&bFrmK3To{MgxvvDJV5$)5w_9JVc zHiA}S+6FX#b}~hYd2BU9Ri7Xsa&=N?4`aXw_Z#wKeIpGf)?7u_!(LV~2kUNLb(?Fp z%ln~_9B@xt>^|TjC-OJ|^+i6ybHc;HY8DLkFxlRqTi z0Kcx;?sW512Jdkk^fnhDkVkA7UIY7eqsp2C9p*S5leO%JMQ`7Qs>HDD;_>+#_}AGR zPSqi?AC9R1-evZW9L|Zb2+HibGb(oH&Or_kH_d*|<4)Uf#TKs}hoeO%3^;G}#PA+C zgctzs`0;UzMb+MNjAhuty$fvp&I2FNqDYO5vAm(8mcT68GLa^s$ga)&gXJzK|Km?y zvoD-oKV*H%8oebUmWXiuJR^UauXP8dPv)H~Zhlt8NdGQaqvY=W;aPxvUm=T(nEj0WVihsPecL+0nFA3*vC z{N@A=Ga+o;_~ZUPTR8t$ongZX^f`UbV*O{nZ}zyG9_6`x)dj`IA&a*!uniQfbjEx; zMGOW0w5Lmd!~45iAMbOFzf2Ff|D`!yb6YU~8)8!7N;9pSl%?vTufn+6rM$WfdL7;` zp`5Dc)Noc0QCg&|5(Vaaan4FwhdZ_7hL zY5}2~p1O--asyZgGo&yCh52qBA#nem^WY4qqJ?_KG206`ltkQ&+G!+ump7ig%ne(9 zEJ^B-$~E(AUcU}!@ea@Ph|*2App-Z~ z$o?*_!&N`+mkwBGdywsUNK0mi{??)S&qHpEap=|fC48@oCDNB|(!BD-LZtfOy(&dy z(tXr>4+#9&x(fCGHpir5dk%+(hu84acIaWm&SF&?IR_}KNM_^|+1s8*;TBYO_9iXt zcMmkqI%?O)cZsBkgC!mQ)0~}3&vjEn#oca}eWg7(@It0UskIfewW`5#xc?D|wXmfn z2RNAzIUEo<-nWH32LJ#zVYAKvPAPac$RZf&C$a$9vHdlbepg*1Zy-(NLt0wbHl#VN zB^Z&T#isJE<#3J(QJ_ez)Tu0Ut2G3F=35b+N9l;Jliu&j6dQ@%<+c9e%;nsBfz5&ySlnT-zqM(wBlp{n`9z{S!Q9w$h86nL`Q4lFX zC8R`3q`?I-7%knou?>)r8av8CdD}bo~6{N`>3S3m1sLeAbUKq+XscuG!)<;N&hR z)$CpNA9JS?^4k_!u3Tp;Ld`!>*~XYrZEqzzrw%fEt8@vDsN^tKU-TyUa^|1!XfP|D zfQ0!m2AP?842Js3D3PB@SM9$X8^coB+POM?e`2iP-jXi;>-AK0gX}$77DsGznPj!8 zOlM~&&Tl~qw-%<}(}%kUSivBqO6L5#+Du^$0{$Jn)kk<3RZ3v*n~``OSt-;iyaECP zGLBa){Ve-wcEUeP5$qdM1LLyAJ`;y@$3P=Yn2G!}`PrR`y3D7p&C6F07v#y!5_S#t z`bTSJ?Me$N<;q9(%&5sW3B}j@KHMqY%Cm=wA9Rx#F`$HLr&glKd}FRR#cer;dZkhe zB#7BxymV=Dp}5w%{xws)w2R$~sSs`43fg8@CxP|rC%*@NK zn814=1CbE0&T82bC90^HK*swdlm~2xf&?NxPhAD=cu9*eL9Z_b1(BlBDi70LfkKwG z&+}qaTOSZav#Wi$Zy_`>&Dh5@__%C&OFMM>3?#=c?$f6?-Ls-{5)KWP9O61>&!2w- zvJF}Lmn*SO$@?kF4q{Yb8;ZgfE5xx-q#$gmT#-Xe_eFXtB2&t-KTa_`2)jn!J4pEz zy4M)aF$zmZD{pO2Q7M5RAjc=NTe$mTZYl#t2)5knR7GOL+*waKVrB^0Uy1Br^;XHs z&W=q=V!{M73N~&*7O5}_Sf}=2MqxTk!D#u2Ww&aQvYQxe39V?^5^dFu-s)p~2Gr)h z(fpv^_#L1%Z?QR$Q+&RL`UnVK{pT)Y)YVn~5`@%_qQywx0RhyIhM$-R$m{d00>5AL z)jYrL=4}<5G+Q4ho&qzZ+V3_s{Iz?uX;OK5ZPN=zx1)LT6w83i;PMUhnsaTg(;)%E z@snviLFiGUR(SWUc4gU<+ldNTVrTOiyNfkh&zifwI!v9ObF~=y@mn1>S=zExtGf2> zF3m@Wfc50UhehZ^-@V*S<0ZD3Ft+|*3E0_D3R*Dmk(y0`6`f{VIAL?vj~7;I_k*Q6 zltzzpPIK8yk>J;Y6OAUqv;?!i_BkleYzv>5FPWPwq0A?8YytJlMqN&_eM~nUzddBl zzsR+CX7GpM=yLDzlk~gyncv(nVv2h!S@>!j>3`-mli&E{U>hg|eEZMWYiH0Q?^)Lu z^f#v^fm1W~=BKGrTO_N&57j0O8m>o(yx^C#TmQOn7NEnkan~&l z|M3VCF8G<#bY&%3L5thQt?9G-zI|Qu)?Mer3bJOn{ z#Ky(F0?B??;r6$(NS~!b%wp`mma7UOCaQ5}kY=499{UoYi_y^BPY2_{P({DM2rn zozqXuKZ^+p3WD?JvR3T_@C)rquKHoDzOGsl#JM(gVBnF85PP@E!PV2#)BC&M^Sw8x z6R5Y>+GUj2H~N)V8P&gJW!;o8c)?&SMR%Lr((l|XL=gg3GR9j zfo230G;rMBkqK;-C`LDbAI$e59_|6LMUftMAgv4mArZGZbTK5d+x#8zRUEU-N;i^V z-K$8joxb~s@ZE?$+;aE_n^=zRzCZYWm7e_k{8b-O_Cdg^x4Pp8_+ZP94)^rSp1&#Q z#^YXD@LW}t2Xw%p7CcW8oyEnK@9tk{j3w-)85B`+dMvXG3!`3vY&CE%Z@Z1-n+94x z7;d+Uzp%F6^4{y9)FuxXWPC4+>o9-ct#2pvshAp)rY}ej`MQqc>I_uflT?CAMi)B;MJUOiuv#Bi=HtC(O z6bZl5)Q^(Bx7`KGU~09erw1cULWMw_YExa5I&ckanORw{BcxG51cI+a41_A~snmv8 zd(TQL7_S~(yp`*+&+O{-u$kQR#$#gl5;1G1B|uXc8NC(+uKT*)tz?Nwzl5hF02r_FFmJyKI8UxO8+t3Y52v z2S+Z;3n-3AUOBOx?DYWF&?puAl>*ena5Ra_C<`88j3fpM*_^Euv+?*-AP z3`7k$=Sus1Xg_&h$g%rgR5xUm=nB^f`$}PK@+Dp-Ch@7qJfeSYRAaZgg%UZsMz?uT zmA7|-sMa79X9dfXhGY5rY(`X`@*Y&GISlp8P-1^6T@vh%8NExT<#VQy3$Lx~HcC=n+R8+*yD8^{G(6#)Eo`@lyuD zLRv<~#(4$bBa{0^26)OVLH{mGgC|fE=)L*8Zv|h9YNU%0zwb+0&dT?<`Zab~yJS0% z)?U;`K1k5J)IeJABG&Lfwl(1I$0?{(p}%w9s9&{n)C(L5qfRefvz);X%vKBh^uO zN8V~Vsoi#XV2P&lb4vb!=nKtcXycEKp~4pz<`;fIbL7#1E6l1z%t zgcY+hGDNIB28RZl3yMHCX5v7()A%)j;U?{qZ&!W%^y$36j2HMivaylTdr))Hq|@5g z_Ri2m^yO`Eif}kw;(%Ph{&wOZI7K+%ZbPZ-Z@}z^dlBvFaVAZarPfrw-5f8NMt}EEW0YtP{q& zst>)y^m<-8?8^Gy0iXRN&bhKTr>#GGqw%PVIpUth zfNGzcnArwH?`eY7JBrOF+p`oFPgO5Ri^atNd5)vSh zKPDe~jk8?|CvCjWNMoNto@ggHDESAg1Xb!>>IqBbOphrjC_r5V#nsjx+1c4m1w|nJ zIdR}aYO0PbPvoBue{=cps3B)uVO#G*%$@}8v$AU;9Pi{RK-HjdaoexvO%1NAS!LhH zH9zN(|A36TQ6=(;V>d5^d+Q6QTdZ4X2W3W-E5pxysJhhWU3>Y>rpO0__A{?F{6~n% zTrx3_b}Ag9AP(6*v0HYgFj3XiAE1XU3#ypm?Ft`%S?lSXO^qQ>Z(rPAO@N8-z`}mc zAhu9Ch8p=vD{v<*e^cvO(L$(s1=p>o(kF4U1h3!6*v!((?5yuh7!T#7TzB|s)@EkjxJ6y!qkqWPJw|^0_+*GPP6{RTWO&p2#=YB&G8}WH zZC~Ee#PK!o=dj!|SwfT!CTO3F^$E&#IM{#gaV^iJ9(kFCTW@i1_+ajl_jkvsqg);Z zVTE0#>~j%cx{4)wKHM@f5d`K$c=AKgCat`3sK|u>gYR)>W<$fuD`Fl}rqzj$^9`B? z6{0*1f7qThE!Mrv5+<__lb}^GOMd57?r&L4?fiJ`>ZZj%f&5B7k#|O-t3?BEK8U_y z5}YPbR$dO0r44W&do#7b4g(e0Em>)x0zeKhZzm4O+jI#4N@AWT*sEh!$xws{XWzxp zjF&b(e1SzHKX4DyhH}>jdpB-t9yhc*6pESje`e$6bQoW|hLzm5dE6~X1#qZkMER=3 z!0Ea0F2oY+dHRT;lh_*xyNWWJ57O`as@&JSpTM4PtZERMAYmB65(T!;(bc_eul}5A zGo6bkjZvD}3XUt+t%A7QrD_svh~X!iHP}CTjr@RSh+>ka?$tOg9yA$aoZI?1%7$xc zOe!x28MlX|lwOgrp5FLmSl}3gD{pchOL=(eU{@`?Cx6%hvy+|lz^tZ9qQ7$Rv@BFt zx;5I@gqh+`$s6dY+FE5g$p1uUQ97bwgX<_kd$~7-L!SDLG>;8k2Qw_}@ow9$ZUhbx4yq9ca zzi*sU)cMNmyJK{#T#4&0X27Fo=@g>BCFyF|-qAI`P#v9r9suZfAAla6aOCiZw^m98 z4HMFXCE)DykqsCsKY`JlTGO>$itn8@oe8DZD=t@dt9Cow|8zVVU8Z>G=EifV@8DGx zfR?FdPQfu}CB>kDh+jy5kj?9aK0XOBlhNo*SaKKSL?0ZC#{60CB+{vC4bgjo$a`GB0qayz9!)7WmO4I^OZE_>~ZFpx;9q^J!G2x;dwS)l?GclYyJb zkmrg>PKienvbqIH?gQGvX)ZLuRF=(=;mL7HvAh5am6ux@4F8N3wS3qOxT$$#<<1r% z?0&SPT&GGTH+lalQc`3XXOe1Q_7F*~7t8gkA_#ahYG7}tPIAtLOAVGVC6-E|p(PpL zigVqtnh&1beJxbw83|-+AsY3p_+DX@uL+FN!;R~XW0)0!47q76wY_xp1LN@12k66q zSKVJV|J-9ufBpZ|`!sMD!)IX^$6l!C$rhnup}+P>cf0QO(h`8@%)W>?CRlf4C9 z@!(g27Sxg66$Xs!6v}*-vc!ZP-3qRGyhBU9c6%BCvwynZ8k!g;8D7qp5Qm71ZANzS z3zk=Eq%dc`u$i`K11u3~ne2XCn^O4_(reMs@L?XN zlHf#RCpHiknsX>Bhuw95eVyV&>0@lML3+XpfIgh%lY|O=zLqQ%k{)SqumBuaXV3Po zWuBDUt`hKdW~uw6f6p{u;4=z}U`dnsmVIls>+~EGy8a$V@i4z)(?;X+Ca^CDKYeLJ z3`XCzh9c_pKP=dmvyMrk{Nr1p=ZD_=)giGAfjopDt$ZLlSA z=ET9lo}LpQd;w8_W#u#D%tue2ER?}5zKmW;RELLZizPj)Y~+hG{)`x9P>h5wu1~)N zHok*edQ4UXU+fPX%|UOzX2zUh*iuTTq&=%F1$%`ckRo%gx-aVa!S-UdJ5;l7t?a1 z#HHdj5G^x5P8O=jS44v=duM-%pUqL4&VFTtPc&%A*LT?N9Jvi_H;+4?X;gQBeNcvS zam9VyoL(^e;r-y=yivKe&b@i?{N#BF?dK1Nkr6dkR=?X&V>!Lj1iw92(_*iuflgS* z5cL_wl`7Y$@ir@;WHysAYhK(*i!uHddCw}QR;BdQu4%|f=eJmoUJHoSMzl0UR0PX( zV9?%k{qpgR2~lxKm~#1SqYkf}FAKI~R7}icdUh7zBj}7{!^c*Aa9sq}vHjPb58$}m zu5v^!dA`0epQO_4aQXasT;U6Eg(zA6v${{-pIY{0cV$lGvlz>}Xfdt}(En-|0($z> zYYB>3eezDDsvrZQEeGG@lbDra0g#dtmP+b>m!2f^!`zAuNz z>Jf@rJwFdFtD{3%_u2qeI2;Zf8kr_Tg}|FRp9vBj6Lf$F`!e9(KwV5qN}`A%adB&p zC;?^QCIO{`KuJLhuLR(fHeZ7Dum7)=cojuSgS&YX@hTWcRx^$8yg)e}{*#JJ8VUcz zPAM{|69NJ+CX4aBhg?#$yKAYRx$F98O%m)!1Q04=q|>a`e#i@9M{w_|H#-)$Lefb# zoi)L4d{3?VqJ1+j^-Q_ENfI+HR&;vzJA8ZrINZNWXhcAi3;Il9~BW3MDA5sV8%coDbfEVn~8a2Og%J4$uFdCml9)?-hgwJ908h#iN z<<2-Zl$yORJu;>v@dBV-LVxwfh-52Yy(&Z!+pwN15E|}3k zqK`7Cz1QrmF|oHsQ=Y}i6R#AXi$L-}R7i6EZm~Xop@W=fA6Q>J%Wq z0BwupoTFUi0@J9=!uIVVzW%GkwfxIE0*UyVRzHZNWzRbL1-(6IIU zNt7@Kr5=BAc6x3;eK{> zoCBS{BaVcR(NPE#0Vm8=dHDxMmG;+*r)EFg$xb8j&`J}LY&$X zdo2@H#TEX_FlDzHS)Vmvu(Ec2S%0pHb*hrexPKw9w()TAm!*bgTTuIc=tn2B zP_dO>^I7BcSI$(alPnG92fLe`r%!`g;Qm}a8^E6tB6LHZhvkavBpsKOk;<2&Bdn*; z4TWcr$Gu<(p$#xZ;nz5q^GQA|s0_)}y-R%z&ki5PHdjR@d%j!e+ak^yCpB}(ACNeQ zM@D|m^=2krgPUU(rty!tZ2Sagl03$dM=8qXhBejS2mLJo(bhQw8HnbGn)A5~ z4O^rcJG=cp72(M|6BXt6t-7>S!)y^~rB>OcMg*1E@{qu(atIg zIX$7#g={#-Ii(g3d7)G{?$lsrVC>Dx^Wkm`dZ{HwxLC%Ma<@an*8D1v?D$!R2d0S+ z+p|8pAa~T%M|QXduE@&^tb44DcnV#^35Ms$s#N&@%A^Ah=8)weamoq&_Pd0U;3E~k zE@+?m(0uq_?y|Pnt;5e|HGazaxw=bR-WNEZZ_W>La!Ffk&dURF#laRFM1ChH|al!g@wVd_pmd6!wV^;0QKH@wWia`>{7Sz{zzdf>f2Hb4QWtYP#xG5(*Gi!vSEG=oKjbPF}=?M<&|I< zoZzQ!O5#TkXcRa#H|r-#)T;Yz0u7-j5fg){s?}A=VVCo|mR>Btc>B%(E!z~q3||Al zeF}uEx$^?l0U|V(>{T21z3ID}opb6K-OAp<1Bu}4K_5jDi)&*R?pWDI49|*k9v}SO zFX3-Rg^@g-*E8>LRW2w*K4j>6UlwWssQP?aU@ZdLUYFz*9@;Uhh_G&t+DhMtk8Wdc%aQC&bfNI@Hswcgm~|K7;O4 zj>rSHXWJjrS7!Eiw*4+9=Co?dRA0Y!i=G_^6J}Ri3G#gyaW1I^DW@2zFsrD@_Ne?k z2tR#{FX}t~=!7BQ+@=D+*0fd;4|tS>nRW@lxs z{hHEq8T*~PKBviE`l9tzPG@452BUBX_tAk&=I!ZC7~Zrv;fbklteL4NujuV)V({Lw zIOp+l$JU1r4+5+^)1t-#&$e1Qey_uiGDKN;+vOf^ns;|~ea+Og@!_1iv&<--g4rB4 zX$b?7;YyDMK#u@Gr zRt}K2hhy(&tgDg0Yn-NdUO`v11P8XS^3^P2>(rUCz!TTGYV0N)b@m3sKNw% zFW4Myw*Yh)oe6l4LB>zP@D5bX42w`++7K>V@&rB5gkV%IJ#~z7ZbOnF4xMCZ2nd2o zu*+3)K5ZZW$wP}&SHbt8$(n4CkDw3kDYh_W^8WgYw~9buJrfwr+JR;C3~DMS#yfgQ zmIaQxb?VvdICi&vYE>4n%>X(MO>65MgDe`=QuJywzohpRD?UX%@WWd3Lb2QteAwIV z&~K)8i_f|Ga5r@JnlPc7@)m&lr~qREF_T^GR|8pn_4Zlm-PR^!Np4fWle4LT0ma>B z0n?|c77=?+&-VM%H|%QsFV>TFD#Ho1F-33&mF~X2$B_ccWi5~* z(9Y0M!ZcVY(4gQ_cEQ*EsQ1CE}A{6@Ze+bS;)gI_xP(5Ucp^?c7LU4Y%hVvOEwyFFGqZU&IY(AN>Fexuq+~wUWB|zE zi_)fbk-YuzhZKNZCNJ<|)}5r|7W4kd{dxC;`$k6Z>^=hz#88n`W`U!imDR#AIvP&S zd%bOs{ut(K5v^iN%NO0+LphpnI;B2&^av=GM%KU>e#LmOD`hny2cYv}#d52CJzZ_#2-;{NS1OAe7 zA8|hc-TnC!$82v=ET3}^28V~`tlD1u%h7VKtgY=*Ast1zpDSBiduj5d2v~NpH)q#( zew_OE(=`X4CzX|zjZRX&K0F7+Ey^87UjqJio_YQS;46%WB9byc{rQ+}vaCq@@BZA_ z*w|nTo`JzZKo`^4m#v*wQ1BImvap>Gck}b|!f!=zfe4^dp$p}*jW>WplAc~a2`KT3 z3Q>@}0_F@%t|8J%5Lg0|hGieE+T$M>8Qt~qQGWb*ke~7!NF(sV>(dejJ$-$5WqDq7 zrHmR?PzE?U2B0{PoHYxW5eoea7!8F-d~I!wNBL!AXk0=<3rInuWJLi(K;*=V17HjS z_Umrz5MXPIc*`OOM47R^cJJEPtcy#6f=}bKqbM{myry7>11i}&pW|ZFilRVb?0@Dj z#r&kycQ>dfqOQ4YTDrB&DqkCGgIBkH z!7PG}lQPcVTvwj;I`v{{8JA?Zq~=D#Ib4elx%;OJ;HN*ozNbl5?l@xjN!~hn_tK}@U{n2UqXfPh z@CWqP?j?Bm)*JiOdHyhT&09IwFjXFTmou4RF>{Dhf2Jt5sFFF6Erk_FH$V-uLl!(> zJJI7bLVOo=3zUm`nDY^-8105B=K&mw4bO%rCtqb*&iVwGoP0|?jiFkKXKiMDeQnz( z%`*xlS5cf;j?WNKG9e^rbxexCLM_hhJKMWw79;w>CDAT8}{~?Acx&hp3DjhP5zMFWF%aUpb8xZFQ^G zVY$aIVzDzr{tz4_XTg}ZgyoxIM9UT}Vg=#Dj5~Q^x9HrzS1L2eSO}2eyk>fTM`)X6 zTOg7C=GZ=r!^MhQ6LzX3=m_qUcAT`MzHTZyb5Jd$go?1(kv=o6sz%-6ypB`%hT8j& zlY(MRa9Wu`WUPvooNRfg+UIfWJwc-KnLzn&FTG@f>bH=>S*JYx%?sLbXr7 z+T}5Gq)7wf-daF0%Sh>X?PJ<(e69SCJ*3%$ZZui>#3Iqhrm(5h=$NDvxjX>>Cb|my z+MoquZAN28?G_yG8M6mR1{!!|oW(LHcVe8e2gZfuk%s|zY;^?LmpNF(!M1w_KV{?7 zlC`u`hU%<=I;}f1EdL5QNfIcnoKQ7iU56ctQ-wTP-IF2ez8di)48lmCWY7^@@FgKR zK5u5!^}v@vDpLc|d@YV%WnkGRow)Tah8{t!u=y&Uz^r9Vtw`I_vt#N+i&XT9<@S#9 z{6w!ZST}`WEHZ0yi{8BPY;O-Kvz8{;y_f20`c~c*mX2k}rIDc%s(3f7M2!?je(CIv zr-gVI_i~d>S1+6Hu@F-{yGu_yk>*!C)oU|#_KpVY97wpj0KQPjl`n-=uFj`z2N%&p zCrEH)YVy>Q12Ne-rV1y+6%0$c)CTY(8yT#uY{_yg)3?U+0wNM0%B?zj42GS|AddJyyz3 ztnjI)T47h~d!zD4L-kx?SK6@$`@R8c0{#Wu-^V_`f%xs!=KDlpgZ;4w1yp3NSDPZe z%eCdfVZlptD6fj+CA!{WvnWrckfiygJ8|G+0NU z7%V7|zkbboJPDKJ;C<-k5>`Kqge|I}RG0Yc$r$)jKzs6+6ZPWOsw?qgIrj66cn}$@<1!&{Z5_emD6*us(Hr8SJl1+3d?K zM;7$>=g#0nL2Vs|ly5Ow{yn$YaNI#w{K z(PP^~{^i9v=y(w1rdnU?mAP%Tqb{L@t`(RFN>m<`jQUXZraFRdiDXEq7!Ry{3yJ$$ z*zaPq6yt6|7!#~E$Y*vXy>VVRkGn%%Rp!i*I)YSl7WUw7s5;iyd&==LX|f?3mHDuP zO?qSh6)Pk!_1`i6BSR#=a&jQrp@;V!aU#ENR}q94=!u9Kntor~Ju>w&lw9sm?THJ4 zh@|!wq4k5GR1?A{yB-N;PVFV|yCjT#23ZMu6Kq(u)O2=uSMw56T3s8wFB3&}DejtN z3)nj4a%x$1iX*sH&~NLovkKGm3vDX8Ocyu>*&aXPV!~*#+0SOWheSElAU(3VE1k`! zJC+J*@bq!Wu|@2$HMS6EuiY_6N&kI+d`S8-4oh-5Mt7xh<` zATh?kj*e6HFaQw@IZ-GGA~Jus?dsV|j%}DY zVpbg^>>6gRI8~$(u*oMR$BqmerShyt%Xn)ra>6CJpN{D~Q>rxCcy2B<`3AX;v=<_0->oj50lZ_&4v=VH!1K z%yZE5uCRHty40VY=AC5Cz=4?^aw9sdG9{f%g~dArghK>sJP2yz;r_4$a+M*TKB3qZ z){E7<#M6SFCPHz&9EA&|ftBx=S&XNmZ`iKQOW-D^;rSzMxg1!&hE&;NxYm&pDaB-< zZfC~3SiW;lmDVdxrp{dIA@|IYz?Ppw>_B zdq|O?oL-F>E)?0>c*#`s7)!ID?xC-ES}`@UMP)c&3e7AcxT9|FUX?Dt-v5BZeT5W5 zRW*s%?LG99Lo*-K-`S~LqwsN3Ot`aYLlwsaaPm`FLUJHe$)l<}|89hvH;0NJZ?37w zU_}FJJ!AiZ)wczKVXOTjzY8}VaIiLDMN;<6zYhxZ`1AO`C;#`_|2_Gm*#7sXAw%jC zMwgQ-;zXA(#h!lxx)f8=T}EB@G>Xcb`x|wN!ei!YCLGl>)_uXJlLy!v=4MMb{w~YO z-zgd>Rf3*xMkSOghL%91NK-}i#>5*hf|0Ch`((&2NS-hpD=f9(%cvOrCWAF`>bae~|pt0`w|W)vS^Z9GFbg z3xPadhz+Ug9z6e58etgs$;$p3lt5!>~%X^Faqb(`kt;+yuN6KdSv zEK1ZPtaJU^W1lu&t)-gU3emox4SnK+@w^^OUM~-Rs#sG)y~uuVeQPSYpf-GwvL=+< z@}*W^rgPx-7I76iVaI{tcOhk{@sFIEBfV+In_pbfBPta~`H#`Ls4r(Z*-YqOe-aAo zhG`iEL4r;!H+m>icIopn1G~RI8hl zP@+PPIA!Wr*QWn&_Hzd*!H@w+YGaTxrV6u(Ia=)xAMwM;61h>T4arlwxS`XEFb)4} zC7Pdqz?5BrhMR*iZsYs=49h804~nJh1t0w17#PGhdlsbY!H!@cB2i?2B*V%HSw1gM zvUaeZ;pR<8Dgsd#H$$sSAMb7f5u*_MXcFPS`jOO(z;=<_YjR$z+Jo;qt=P_IiELHLQ5RP^Bu-|ofz zzh8G2g`PM`%)83sp6)9$P8FTuz|kH>gKrQtJ-i}&CTdKc*311BbtEHxd1h9I?r>3X zSd8eNI`iLPU;-2Ll_VGOYubu26KsSo#xbV-2jXLvrRm#Qx<&+O9C@<&$O zG#t&eovG{bA5Im_p*oG?K8s;Lw*|k9!C3!0s;oRcEfZUjGV{MI%YuiiTTEX;GGW(t<(5@9 z-njbdhv4Nb{)-1Ae96_hLy5{?cDTRdz`4nsCH-oQ2^K z+uFj5lB*JT9p2I%h9eiAR;Omha8=yNZ9)R&+)%Eilr`RqgDw&=mVx z9H`1v1A+U;15sde8pC$|Y?g0NxKeP=K?f4onlD;iruGC!B+=xe&>*sDqOd-{FV zQOrSv(wAJ@MY!%%MqDU1UyWnCiDADBs0ixqW{5PKgpFk&jaO2&RB(x|<=<&;l@y*V zQdVPlI?~!g7gXz8w~9CIX?8aBQ769vje@*}l!$?*#_5}5HATl=orS%rk;oeP*SXbD z^f9j;IF7YC{nDoAiGOXI*t91MEDfoWiy_h~%jaaC)g0gU)qptHr=nGby>71;ZObpu z1z&J^B(8QOPMt6zogHt_(dghJPK3}Qk!mKAJ=p7iH9=p?OWd6XNu0$>Dx7_JY{86J zWSF+h=Q8ZC7!=|{Dkc@2SxMwZ)UMU6O#F08Uvs{X>?sPXiNZy^<_6N5Pp zJATX_yI}DsE~bBWOI^j|fB=|^A`~OUeb`^Sq_G9_}Q>DnzTbg zAuKhDex`buRL*4)+?`PcPX0vNYPysVSiXkCF&Vl5rj$1j4YRKw_5z?+=N|zXO)&^# z@e@#->0}=$DDKx}Du&`PgqEwgEdxQ>vRCLoAOLuX``Z_bfKYtG8292IKwWqPnhR1CT z>=_O6N#$3aV_q)ePE}kZzN-F3w}WF`!iX`p9QCZETD=CenJS)nE0F7iX+(?Eo$?5l z|3vNhFAf~jXlVZq)3hH(x}er$Am1h795y7K?GDhEEhc3D0FWgtQmkt7I76ROsz?EJ zSFkiVrs*3PIey}%JvxHchBkBC&Uu@P7=z;YVP)^UI=1yCVd2r~ziS<($)eQ3+%{Y= zNBJ8K>8K$`SAd4YP0hfSC2q1^TcqxV`c!H^U$8!5RfV zLx6w{zo8$r3cca2P{Qiuyxm?sE|XPJoqw~sG!dl{AwF=54~x=N&fL!m={F_T@B|1DTtD4wAi zxR7Lmj_ilC;35vIJcX3V(;rZ5_mk={3>M?1g`iCvaJp+8GIZt3u-$O@-!tdya|)U3 z=MliDQfTrie#rW5Rs2(qzjJX_?vyv(2=xdJ3Nc=LG`hFLhSE;i?3dP-&=_(;96*Cc z!Di!Kh2nTO6km*9=eR!&ZMVT_V;V4@Fsm3-%p;P@QcK(P=6}k3s-r3O*m5mqc;9bk zV-(+g6amSv663BDQqR(a(O{?W>BS_g zvuAhB!Q!6WVN#cEWyU?3+TskHd83_cLS@S0$5wq@B^sOQccFy0Czrp*;aNkQ{0zi6 z=ZV^xl6PzH9dwZjk{x)lC!$A2gq8S|`W^NJF>V-c)BAcJE_D`{Rv3v~r030Hn0ilc z);J6c4tuSLCV-WtC-36FXZ>u_!YLVn+t}9)N-H7UsH4|d{c1S3w6XH_^DAmD;>)rm zRWyOWwM_(H2%j}_GSm6IRLpswv{YUUTnz{A3EWxT3;|P1VbrEyoC8O-S#`4Tk}IiHO?YI8 z`Lm%QU8e@73uA~vFFH?b33P+=R$VCKP~q>v>wPFgThoF*J>^OS2K>_c*wU0EE^Svc z2o_|BYM7}LoR(z+LWtMP*5AQ9hT00liho1(SK$5c}J0OmC*kLeh&=Keb8SyQPI`7G+M<=J~V0- zsBl&G4)nJ3OP;AMLca!Q9^uoAqJu!h~^%tWnk-r0Wm`XY<~H%b$bs3 zH5FBcD^RMQ!*<9m`LqpAMt&$!#t zt2I4@L7nbts##m)*4MVT8*mNJ^@sl zf>6*uyGk5h7vU}7o}D&pwn!~ES3JxfA9awTK>#G;9K=Tgfc^vCXI1+C zHxtmZl%kYX^Xa`3eNV1fD5}oNW5mYb{EK@H*KtWTM@?;;WyZrDHO$+!9)3}u6*6>v zk+Ux1Oe{2k4(sbC)t1!-{9XT@H;+dVki3EG#B~q9qF~Hb9PD|n?XYLE2u1{RfFi$! zppcS}h|+M6Gbc>hi>q)D^>c2G!I>_wL3Zlz=yYzdl|IifKx%|~i;K1C=HeN zv)9%o;&C2o>(P7X<&aWe+{uR@m*s75b?%H?cc@zP&j?k}Gk1-~wDBMQGYxMk-6-aM zaM1JVk-Gb7xC~yaQ=OFkd+N#CuHDe>S4ktiT#L5M);*0KWw;gLtyi@K)_or99Q3RW zb=Bn7SM}kUSsU-!nN(E%^}oA?k8z`x(A<%__i(*K@aZVH75Pg)2ABswxWI;on+)*l z{`4&PpSm9=Fw>Z$AYYlcSd13t7N%>%PbNDAQoR#{IfJq19`Kd^z$jUgdG(Ndx=rTr zbT*9DYDV|`N3%5tK6UTdUu%~-a5o~abA`&3d|k}B_7JXpM}FW$x?)JY3?X|unca4~ zdwrnx@Z4sxdfl41bH+@babD%-y*8QM)6CstVam0sm=uDp`ApG4VuhQTwG$yM3G(TF zWy^JI;VbbKEsmY_a^x4iJB$xq2Om6A_onwKK8X5%nEDE^DBG=T1qGEB=`s*dIwYh- z1Vl=tq#LBWVJPYDF6oez?ydn8keZ=OYUmu|zemqG|HtL)HD2#9^UOT=-h1s@s}CT~72?UezY3`1QErck1Gp`9C{ac2@E_cp>EA6K-xX3XJRl>B}%(xyL~|K8EQ9skZgFo&yTv!o%218bcmcO~?!gz0-t`&E+JI|L_*{eZr#qAzcXw+DYlhH4 z)VjTr+wM4wUV4kpRRq4*5@L=e@Ftn5*vLqAin$spY>8>K!x{SADOK#p5e4>O2ll$X z6<&>QonbPmkg)$qL{i+2vLm&TGOqaJz!>SsqVIGqU$`sy<_VKd*pICQx+??9@|F&s zeYPIOg$h}B4d}E=2^;P3hgNFK7$Bn5KSBDf3LtwQ$b~O?_76D92@!!_)+uZm)SdeZ zbM@wnEcsKLOuMN<4!+%X=&8<+8Vhlup-9-vzaXbltL2@V5Ozk!KykRyTDWf@^z0EM z>vD@UWaBQh*=q$H>4~~3@m5foHnUp7bnM;HH8&^hN+YdIh_PBPTM;K#WK@#s@ zG0_7H*qnEce(sb$*fDmhbK?Chsow5BrxTN7=jHXYM9%>hrur=nK*XA6;PBjk#2Ve* zG2)Ih#T2HKWRKO%<)tOOdYnglxAB!1|7%^7yZ*WIC;wcN=6e!<;lM?_PmskjhFOn0 zzf|XSjEprtdX8ZgN;r1f?fCGU9aWjkOcd6g2C;%%ZMjVy-gKvvfo8UcP?^$(}yeNZZ?#Ci`J)Ezsg--T96ls-9FCgI&@@SoQpn48QdW(}1) zz80=CEA(7VbKBY>#_9FHs7)V+AHMkulMT@C9DBiDH2t|me=%!#>)1-jj{sWdHlA_o z`lrmuvDq%g*_GhWaC`*QME)Xfb1m%azLm``pJWc@GBr+nZE?UH&%ji;?n*(P<(8^$%~)1`GJ-@_3nCzwp%IP-rU z9J?j9m&@M!2PGUXeKxRk?z~l;cOt7gA(x&F!P7Z|N~@=T=T8Hjk*%goc$#QA4xGA; z&^zI?ONR3ur`eO%1>EM{jba9Z1@wgxi<;hB2i`a6rI-V5S8mU~M3ofl{i?@QaQyRG z&#t8xD$lliiOa=yc^mqXl#`!^G9cdSW^mMv#i+fXp9AT&2!)qM^0m%>&GqEV=)t>@ zsmvR|+1a{2U1xz~sqfaFPiNPWL^fDh-tWZ3*%k1mG8z66lJcK0hfJ93*gID}Im3a@ zSTQ)9zNjVy!AF>npWap~N#(mzhihG2ZJZ;!6y{C@ z?oqB-$bpa}+t%GiLYBaYPTW7!9h-4uwsvjF`K_v@8+(1z>YdX~^Zl=Eb`Q#*$#6B@ zJe5KSB)IgNcSgX7KVIi|np|H}Jq{;R+oC=pMLf6@;JVJy#{K4%b>Hg@dPvBW&pB5U z@-lew=3nwMI^?-8gFV<=DN$xTq2*iPf?$DKi{pS2gSrj<^F~+nrt}>@@7ARgpITfQ zR?PHvP3{tH^6dn_I>Dn>3=C&vKc=}qEc?a^o_+`wJQgMHHw^jgymk$}x*~oDxqQgU zsP0L~y^=Dv-aEidd(dgj)Ur=&v?CZhjTxSO;XNqHq`5Mj@auT)*mFtiy<6+hycda= z$|OV-hb{BsdQkG!gvp8HzoT({l`!A2hgsmVsceK8PncQ1UK+kg=Mw?FlGud%8jaN2 z^w{v*sXlHrE^=mQ*SM6SZu1QrcjI;I%p^f$BD-}zbyJnN@S+WSHLzQ2C)Eq`XjC<8n4ZEzcF4TNsAv^tS$cLyIOI zj+Le#y@B@T`n>U9Wa_!s6AK)bRDO=n6nP!L!tLKarfwV)vwdY>{rYe^cQ&H z)E5)TE<5k}+c#)0r#|PWJF5A*5ZT@ANv%<~knIn+JWw}*?wzy0Rqa~4e6#whm(6bd z;Q%hV=#KC%`k;-(MG0TYJO(!AX4B0unh>Te7(6*+);nCQJVHpZi<0X;`8NVYs2whY z#YvyBDN&~1qkKNzeC9BUm(ya9A4mV7ckK6 zB~Nr3cZ8nrJaW>jETP;<(K^QLZ-WlBOFmb<9v_0vnBnI(9vSy*4|j&wf=-pnRjtWw zMC570%;mP$LeHy~5<^{{S05q$x>FT_bYnoi2vvSR&$L_xcx3AM@+{=(rnaZ8jJCg9 z_Pp!u(>N|zX>OZ-8>`K3mKDx&wzrv=>T6LILZ~mXY^C2h{Z9KfxAc)s;9i1I{1 z!S$rqUXD%wfy{Rtz}J#{sx7`Td{yXq)i0fLJlm5dDd;AnJu~V10Div&g0=GF{?e6~ zzSqs|`)Ph@0xHc8P?B^H{HhZQara;5C8=oK6Thy=fVd}q7jyvSqM^br^bmMypco0| z2lErB#3xvtr!n_uhuf(5#x@h$@ZQXgr1K1Z+pNJVbX&C<+61Z(sIk))k=c7j@*X#a z&>1&25Wj;6paq$8KKzRAw-8L*vxUTGck1w+I%*~!3z1IYITd(R4OdnR@LUl)N(ru# zP>WAL(GMEF#$}|}<~P!Rjmbo#EGq<}SNWd~(ZqUv0uWWx*UIL4_v+X0A>f4kRR_UC zwD99m75J%+Kl7%RTXI7JO)pfL7i?&P+a!sUd*DQMyoqEnoR||WK%Sx}5sw#p-EVW& zaU`LEVK;^FV|%1atbLFJUneVPIZ6ydzGmL z!TZ5!ccdxXQv_Iv-W}*EPHQzIj>*TN@ENJ zSIaWR^fo%Uw-P<0xMNzyo)Q$-7rw~+5MyeI`_3Hg7;F8`nudqQLa{}M_by)Anbx^N ztyR?fX`9aG@ zdis5WU5+kh1<06RovUa+X9Tn-L#(VSxw_0ng&{-d*A(l>Eji>#xNel!Mozi+J1Nt> zz)m@}z130i{BLiOlB>$UD-A1Z=RA1o$AsooR|XDbagtlN;iP;oc^1WV+S{ z>OYQ+OTRj*DDErmfA{5 zOjH{#t2F&mfrEwt4N@0q;Ck~-wU=I@I4jHBfFmetq`EzX#rk$z;3gL_H5{k)EL=s^b@$*s--t8#PF-G%{Gf11!=w4SMqx1K-h zUkz!uPl({~ZMJGn(GAJPgZGW{v$jEp2Ln5kKIDEeG0{B>T*RgjlK$PP#9@9XU;5=* z?Nuhe>}oLoqcS7vBvs^8p*xa`6cJA42R-p`QxcG8Uuf}W*L!D#~HA)?3VDr~!F7D?5+I!1_((i=je zg>~C(;OhuK`^K^Tek^!Wws%=)?eloc8Sh|56A`EH#48>)cp=8~@2TA52Ki5Y-#@67 zcCO^;h6kQV^<0xpu;8Qo0|8F~g^;imqWP;T5;qs2ji+}ubfhjZ%f@!8JPDbvWJ9xX zt-m6c{gDK6Os<<<9N_7Fl0D(WOBAvO09wgA?vWZHMkA8=A930xv_OUIvF#$R?uHD{ zr35pE>rBsIOLw~6&?=t@7UsEPXV7q_ZYcvX1e&(Jb7g-07Tx4TZ+s(17Jn0hr2V^6 zyY-2F#)$URPC9lwq!37kzXIngJyhkHwOV{?y+puMcd8iCsHF zl^;Ig3`(*T=d3nH0BoOqOz!FsC$6H8i#ITKlC^47zywzzsi`jD_bjxyKWVo~3y=x#(9@G{T zwLH-bTgiK&J4iOO`9-FN1)cagCo<-F_dvpsIue?<#EDzpKY4GgjZy;x$et+M)f)!f`$0@gQIsdj5gmmASie7mW3bq8_@;A`^I z=Lg!)8E0qN5x34@`VlrgCiyln=33inpul{RWPGr;RffI?=Nz%UX+FKpw$r%Fd-!9l z{-mgwAG-n%?j)?D3Awx5bj6*Z;Y`rVzimzJdBiS+JW@c^t!Qiqu+Sw1F4s!O^AqQ{ z2!$QW@%zaMU6Xnt5%mFMvV4A?0>@6bTCO)4Sz5O_N}DciW%+@qt%`E=hg=l5Gv7_B z9pA=R!urLAtuLmgXbZll^Xrl5xGS;3>0RgRse|ho9yLoYrOg+nh{kp5Vg7Z>0izL& z%x_ITPelDAi3U1sC`(%oUgE;7JXv^81xo7=iik##C+b!+7Dmj|+Ivb2{zx z9<6zBF-&Cb8kiMM?_*o;wiUV|)5A^zOjICh+KP~o1}!y;B; z$ty391RHUYfL1nUtE?H<3ot_lOMR$YyVxQX)I z=EHou8nUm?4TLTi(0jsZD4SP0l{&9`5ZE^S&frS?3y|1^qWQp=-S*7dL7>i?Q)>EAIf zgd~Anw!SsZxM5Uo$M`HU%f(*B6fbDY%<1$p4>6CY>u<;3^hW3NMDWZXQvb>2^pM5F z7>%05_%h+l&AgZ-yE-04$f-BT3}}lig+ua2=6ftn?A_p1vspLA719p#xCEn9sBPvIeltWA-|84!OS zEw?nz;n#$%^Ye=}Q#CSeyS?*kXdl70R8*i-r_1B61LV!SL8uiQ8nG;8uxv|uW4cFD zgQ3*<{Eg5etJ6GATj&NS#8x?=Q}^<=Fb!nyHvgrqdY)Vc?i&Wut}k|s!OOe|jXUX0 zO#*od!z(^f=n>Einc((57Q|7e1LmJj|E|ie2#YYLTC1=fMWv%I0!~8TEBWUR1{EK&F1vh9N;U*Fv zW-jLn^E1SOQ4O-T8kBjQ7`39Gtbga3U#K@u*M;rWsPDV=QaU_Rx2!o2zJcsiPonI2 zS58puW!%yb&z#Q5_H@(nS_+eTO(-x&`PVz@wpxuOW49?&QXw9n*>pHy(n%dj#%W>< zj96Z+g2%M10yk*tfYWU~)qz;zX7PQV2Txd3ws@3uZXI&Cv2J68hXcf!L?yKk$DdAH z4u`nsQz=Rt!-c6m(Ev3)SqL$U!JrJ7IORtG&eHJy6!Q)tACc;G!uReeLAuA{-O|Q2a>p46CI~bSWCgCBwOlp~Z?&9Xm@#!Oq&MC? zXhV5`Z(<=+wqrxQTSuI{o2RYo)hb$x<(fIeK zw?#B{K4j`n`X6`M64zfOmPIUBp0iikvQ-^gf09&dxnh;NwiU9&P5C1mTB{&zgkXzo z@Dz+C*h(4P3?t)@fBtH4+9N{n7I4V|)nPc>jW^fA=gnZXnplN(^_vvSZJmRaey(?F zybGDWkdstTw@pbc$j)z~o2$iMn#0W$tIHK9Y7bzgmup)@Hy#6p`5bO@8pFI>OiY7% zfHZxn*s66gs+T6at}gL~Lf+mG^wXTj!EJ6l*t=+4$F3gu&b`vBb#>`EgBYTbxU{q( zsj`+1l6m(b3nzHHzT9Ql3x#|(=RF;v^KAu$#{z_2r>xq=uBL`NtRHyd4 z?#HvW@SC5$=FLOg*krF`SzE9CQLbP)TsVDQ`;tDzs^adg^>j~aEJnttQr81wnyw0?v!VDw^!`4^?*q}8a_6L z%gTQ5*#XR|Zkg3-|13tXas-0BZ9V==;_&##F7FkTv+jICy&h0FEB`oN5XH@Mmn5p4 zb-~Otsobf7?f0)|>_ZPnIQ3TEi-(f7n_0E=r|dR$0>%c1j*!27J37qcTs)2Th*qY& z#WdpyODc!4E^KvxEL{O$&(WESX>WGmz9?Z6e_S`C`iIk*_0PLMcV%fzKm7@a-C4l< z>da$RDQ>;R%QNtlh$ zzd5T7<#@bKn#_wisl;YIs$<-E<3peGgI+6pH|UK+t51E--Ci38CWg%N%*ZCVfD*Y1 zL#W+QRzMm!F%kT)mrrHb<)8~4{JqjPs`BbR5r4iL5uJ?<< zpT~Wc4O_2*^jFx?u5`}xx4OEz@rJ7P7L#(sQKePhXoE&o*3n<}7dUlnIt(E24y!*` z&p|C|6t*!4IIshco=RdmLW9akC(^C4=S=VEY>NNeLIl~{wDnSWd!0@+bH{z~P5iV! zE9o9-O7zoyqWN#c=G{AP%1$pq+vP-mq+dO|;hvU)m)9cTL;Avdhim13Pny8%^$xTs zXR{<=%j`0av3)#f@7(yL%_PK@&sBulZTQ7X)~aqt^6dY9p+V)R^%>pfx)as`U$a0$ zaZzQV9NA|K(l_JmpJU6vNR!2$nV$?s5IAwI{r}%lg0fG&OkFr9a0tcCQ6_64Bu)KE z-|^TpIOjE(H@dCKk!Gk0z?BXu1{Mj+$`;_KNGWU0tE_z3YtuK}-_GT55e#PCPCxJ= zNLFANJO?R03&VBesaq*Q~vi$5uUH3qqv2==@yg+M9&~_IAa5di0q!$d;^^N$P$$LE2m}^a{ zTP}@2+!7gEY`aWUjskkN_Wc?l%==%s*39W)mA0;d9DG+$%Xwc6gi?C2mm!rQ7EOvB9g`x(MtZq%-zxdh@r$M9 z2%)6{;Y)Au+6Pz%{l}0=lS2~<@GJE60g5lhKo!SdH!>#1cYgP#e;14)y*CP;!B97% zcZR$ZM0e+|mW=6qkS*Q+;o(^GIx5UG|0EY~#_qg|pcX>3Ns4!`qA9tUhZ~wSD;o|06I6Mc7 z{D7PzCHuyjRz(ZK*RB(}Ra)<_A0ZGdOlfmRPT-nXRaF%rW$+Dim~4NBIP^V+5DEJ^T%$7rV)qf}-SgIi8$uD?KK^exlj}3DQJB zCunn!^&DsgB?`E3bV`JRWXgWC0$?#fVRblrv>|Y{U8P~Y=$Gob=+|^S%r9{CCmU?O z$EaJ?`{}T~7oavCFOY}3-CUVhti}T(LhE6db(_=XQ`?cN)5DZb+-Jlgi@dlz^Y(@(rd}KHo!mjY4OlJ;ii@{K?^pw6ln-?07sX|D01)wQ;(6+{dYmk#H}29=;_BNk z)>HOAiF&`+r67kA7_b>qQi-C#J@iz!8uG;xcys}#hk6&J8<)NoJ&lrT(u+I^52 z73LXI1XDa)_RyxMr;9H=03ki?L*8&vUdpu!32NOplJ{?r^EY(}e+uWd`t`HZK~_5u z_Xxt?Dc>yl|I&Sr$-5D&fC_)A%IbsYc*4-sN)E?q6M6uK+{l}B51)>5M&n{1!M0Oq zj7OSyk!!tVC9C0JkO$aP4#itn+73<6E5=DJPeIR?Ygflv6Z&{XCHapZ-#o_uY=h?l z*iukN)(SVG7$9Np*gZYGI-S=)cL&5<-is%o0vxiLD^)>-ImqS70c+GH1yTS^#MzbK ze5@T4OG=n1d)v8WKs}S+vX;uK^_ZBCZ#w7G3vQS>C!%hPg?rXs0f=GPx4m=y+`&#t zCT-)MK^*=v*!pb-u{fqmvrz@`lHhi{r{@b7Wg=fK&=1$u6}!tbYl}4^bcpS?)54EB z))JQ|wUj4Y+IHK&Bmk8I2S}?VF|aA$15E~=c~{1Wn;omB(~O()^Vq`e#?v`eB0qgW z(z@V|~f{g(xioVEGW0>}(PhK7!lgt|9zfGr6rSN6^Fmac&UlN5H4Y8Hyhn$sbOrP5>4{Wb@ z6IuZ+<6W;j-mwS&Ppbay(2wPJO9F!y#M=p zf&(*N_qSCIeX4>@|V*$K$0j$5{K zU%4KA`4Ai;nfvKt;jc>~*&rXZ4)|ec=rWuj!N6g@>7T4b*;G)cv@Yv?; zoh4~rblwrJjZ|fq649i^5vK8-6B|h{@e;{rl?7-41qN{ucNpo3B+m40uv%Y+9;9HG z4PtU}(#5K+UYS{lS@_-z%37a$89`>TW=^(z7)Vacj0_%&>AeDL3+4CMPtDex#D4v- zf@R&6A7(IF{OLo=?)G~pm=8mtGFk&(mZVLTbF+V;BoaG#!Nbm;_;l?LW8M3Pd*rwg zOe1<3m2Xc{6xyx@6_G+=q*DWC)M$4(X)$Lr^-Z@dldK0-q0NyPb{`fi>2$AF zv-irMYJfw6vX|dMwG5W~7G1qRu)ps<6@mnw1@en07vW-G(i_bIX(V@bdQ4cFfYyIbJVjLI20mB+8Al_p&d=LSt`e}f zbZ4Q%ctKn^PBlw&KWpBQlop+Z&e^f3UyK2U50sUR#^W3vPfOpUBTLA7C6s6&%{HBT z3r7A^G;fS?hL<~$)_^z7G-LUyos3ADU1$jQ>Pccw*@)IMHsbrbZTLoxM~d1=fBA-e zk>-ERuID!PSXU(z_~cwNP;9t_kw3K)6{Au^yl!$bEy~5;)-?F-E<^*EKtYYP+<9M5 z2@?=Mw*mT4j#5of*CU(ED|)WPq}?KrJ)@|qDk&p_17slcD=RR z1pQ+xFd+KWPpg`Re}z2Fx0-J$!hH#FYjkvUsF?}`0_mwP%&Gg@(a{lVs?Z9#0z_+> zfQ}S$b+I8hEmiE<3RziQ(}Oj5|L3)s$tXk&FIwaqIU4`>d8h|GFa#???_lLfI2j<5sS-5Oz6sNNUoVwsGs|f~qyz6#LAdwsj8H&rWmC zE8Gme2=*SEJednxCbq$@8I;_6&&r!XL#Z}mv`EV?;jw|bO&})i_9>&S89Y^afPL_L(a{Dt&_oVl`s{T5b$7tifKp#>3`@y0f; zE-aYC%sRV#e%tcOeOiWolw7r5DBQ5^BM`0`IS8u&WUev26+Mzq>8J zCS(Lc&ZQAVh(vL1&s{Up?|ukKlX)nac2EWPekPIK0rR|sdgA#6X7ox|5m==(X2#;2 z`rNcIZ}V#1-3GR?`mzMdvdBp{K-EJ8K_4I_juKzUkX8N?&sYZ%ts)u0UQOb7b7W zM%55kg?Sj-U~7Xrsk~awwFr6RxGL%-3tf7!%Qsr@p~5tr#bxSX%EvM2B@SCydp@lZ z1?*#VfKsaj&%xBC$!l>>rmHtMZo^YZOKbXk`T5hzgWXynULc}XiglnYsuOlBE9zyu z^%fdDlES2rwOdjAT3|4&vGW#ydL_#H@#|VK_|u4 zcr~!F(fxwB7hB8X-U0I5Wm`?T&t$b88m#)&f&DY;Q;=Xf#UJ=S_@*(@nuLWkG}0U| zOFF#ZR@knRbX-JAc6cv(KO%7%i5lK%EYRl6_9>KQewJYS7-rAgoZ}ZVb~y#+fH;wB z-LHR_*6Ei^G9;a>ABbHg*Ml@O+ZQ~UhW_d3iLaYQ3mdsTdG!R6l$+pXS&Z+uMS zs&}`+ZA>6K$RD7Lr2jr#8U1TR@5j zc-3$240BT%bu-Co#ts4ybyoi3&6GXYuTRIfWTN|NhlYkg!dvjV;GKX7?Zf^$ z$8NofP%{PEhfj!yN*rGSrrVJ2K=Eu>;gf@9(uiL6SCXkmdAs-QJ%p0q_@DMAd+oF} zMzP%l6Cdbl;)e{+&r`82=H}u`;Bk)veO$#ytn~btlRci?WI9P( z#yB=VE&$a~sS#Uqior@$wd2u)!q*HLBMDJE56;j*JOP>c<4DyVz!3cu|DJ(HBX0O6h>p6g0|~OfO{7rGTnQ zl^Koin1AwTjI@TGfjdjMaE|%4NC@3+yID)lKv=m+X?uD%2CE9c!S`-y>v*1XxaMzN z2&ZtybIF*g-wSd#Q|GPBkmitRM@@6m|~CJ|?lb)RUyflyTiDM6B#TBv8%3ZtF?= z!f9U58Cq7@k=NLyk~iD0>xx{C9-u@N;5G`bVcd~9%j{W7fsm zPFkU}cAQlwePI>qmZ6kmS&SKBFEB4a@og{tSsJX?*fR8ChD;G*Mg=zl`v?DO*EHu) z#O$04J6%9@nyJbtDxx*Jwe!`hScbOz#V?iD=gma2vKooKrv%yof`ikF8qe0zM)dw8F{t5^?awQaf+olfs+53XhcF~ec*dnfS2bbn8LLpC44PP zY$PYlv53W}hF?@yP@N6liILaUk6Yw7=*U0DWquLhdqJ-GU?b`g<NU7wBees9sKsn?LfSP=*)&YR*6} zTtuO0dEUdcqH`g#{lpLBm#l`8m27*3FZM&+Snfs==gG;t!F=o?RfBetuOFa_vXvrt zd_+vQHqR_)oTM|@HGh{v60gyfq>2(%U&qko-9*Y;s4KQGEQkMwjwV6VczCkIf1e7w zk93G(CAI26deVF;6l9PP^0*L2pu!14;#;G2#D*nvE8X@?CKEdOCyWH;wV#O`6Ruj3 zOoXNntt|_OE(1HOvt??aJP__9L6{HbfJF^68|g!}D=31UqNbmxK(g&nGqJ+sdn>)` zldGU)rne3Bs53Ir>dYjrD{@;QU)pfAOA=rMmr;X@)2)#+o8=?{6I=0Wi@t>?03Y;3 zP>l2uJmcK_Y{B6|=#NV_u&3L}iJ*ihnhww@kn-w0?l<^EBS3K|X49D^plh>``u2or z3l9CmKk{;^vb+9_3+n89pB$HU60=Y`ahAhgK&N3VR-1ovt=Khy(?4lj(;VMPd2Ygh z%-XYlsKQtJz#Z|)QW!aG)ETScD;SKUrC#I6SyL8PzOiR38i|*Jmdq=QiUJqtFU^f0 z--lA58~}uG4a9k(D?__dhT|+=-{GIm1|&5ubkwW_8-64`7Hl}R#!Z}C!N#hHl0P-J zzc3bgbS$Auzx{P;Pf2TsIc;yArg*YC@RqcK`zuY^W&=kK(3F;+cfKJ^$rzT@L-&K6 ziFvnwKit8oiB0o$LrjNvq7S|u|B{Ou2Ap(TO zyutoP8I;3I!E*arBPt{zJ1^Z^EcYE=LNBljB$HAb7$UOQ@=q)H&9!cyvS1PZdDjTs z8D8>b^ODB(6?m@czSG5$FN*XeV{uPhG}1q|Vy@+D3fObM?syo`NHVkit9RiW0V4Si z*3&)t@104VP@>c9TCFcaZi)SjQnUB}OuTwli?N%7E)UyTl;iujU^l5GTu|0dCMq*b zW^@qXO^1vp4ehJ>9Q~u5E3FV@Jm#Nq5j5Kh!RpQcr=H@P^z}7Zy+`+?8f^mw`FA8j zW}w!&QbLP|>yQB)$?3vRj69>~L40P{405kOewl`I7epZg@=hz<>^}pT8-&06uJKz< zyW@0_mJN$A*AH)*s)uO+wLTra(r%#mgfTDfPO;MBiGF&0SewAF!PmQ%a2I1TjQzak z*W#dS0Qv>_kDSN4ohG6()WtsvgR5q!wRp3GIRAWY_G9lB;=Ib zZ41k40ZBuaQ{g%A1&d{j-TTuRNMedqfv%M$0=jivp7WhszS_j3p$|m8X~<*tlzcmd ziTU9zZEL{AN2ts+RlygFF~BR}{SrXk|6=SYUD6!$lrLN# zn1~e|KK2`MJcGr(r{yTq+$Y_C2Xe1RVd9ds50hM)xW5JW=+SbCq`r6cr0;mLMw;Ww z=H<_PR{CqPp`M$S*?|z8#OOAKU(9yXMy0*hJ^Ny@Mg}*;G z3#qQ{b;+Y%>DqdamZ2eViwb_6*A1iYE)}Asw7qd`p3G+5L7o?wS`-fcs0B><`!`Bh zf1k(7lq{$qgqp?7Ws})a;)q_!KHV7bCo2AW)K&c>wsw1FHCwvJZ}Eu6qG&l%|JO1J zPFtE{Y3oRjF>f**s)oYNg?`4pv^?a0YnRK&sCkxjVYcU1nB%08X*G6%Y;x0YteG=q zeXra!jfdS`X&-m4=$z(r>>B6H@9lYXO%^(yV>8Gl0z*X%fcPGT!0YpH=hpXm@sPr~ zayb4GrBK^SpEunkwBp<!M3&G{r&Z*ZG7C4jT4X7A;seFGPt z%7C|C#*lJzW|(?FOzhdV?5vzI`jau;L+htIuxdlc=!z`G{E54=d~9u2RZ1XZti`5( zaWbv8`}ti?ev30jxw@sh@9}4ze0cQ`D}~{~$aC%prKvkIqX=p%iavHK|GS@Pt4C2a z4RdE)gzLNqQ_45&QZ%!jwIOb>^S=d_UN(Ebq$geXHb)pXisJLTu&Dnu8@NEW|3?D*{UM@qIjn-WRGN0y0ZG4}6a1d3oHcoI(9iKeNZtPIS`fZ3-` zHyO|ctBED$1tobS`=CFUOZ9UE6`Rs}j;{qVgHrc86=SA<8t>^KVmYjM!_WGVt9~CLk91Tq+)**q$D7peVyxs(E~T z3?O8#RKh0(g&27Y&~*7$S{k05Ob#9$rEholR#ar&9;`fSe-^#=ExdhV`o8QR!mN4< zbQ6UK;Z!Sg#*lsU6uC{x4wGy8tmB8>@?!FD#V0NAKLTh$HHERh@KKgdWQzy#lZHmg zW+qT`11!pNJ=KgnJUq)YQ$5z@skS$HL-cul{4Hw- z^-ZCE1gS5uc&*B+D!U-x_=RDMePOr z2O3EdGS{@9@ZC?RlJAZ5YMu!i{l-l>Ita?fTKcx_UzAidAI5^aFvPYTIIIc3s^@UJ|9F4%!=FcG(W!*lgm){2!kS`05{jtfS<#%SLOqb5? zAML^--aXC2qmI%V-uJmc)U(e~X%2!kv(8W}c$yiX!>#v(Cl6a3Q$c|HM|vwxnXw|9 zm|{EXo{z5JRsW~9!3$~|+0ufD@bAEE=23+WG^S`tk>-AG(oLy@(?y&n-pX)o5^+gh z@fn#CBR3d1H~1)E1zO-&;{Ydt>TNqoOdgz-W7G_V6IS3vH}wDaFw(||nfrd#FSnCT zMf!6cocvKsr;#54M=$Bohldo4f^#1f=b z(gcV8GmJ5)#FJH@6a#38E6e-q8mtHnj4xXzzE&;R^!Ls+u?WApD2bqCx! z*yU6HcB=>3sq&*8&#zMIi#!P@aX+h0Vt-i*zLwDdB?<+pr<92_`c)-&#Dv_s#k>;r zFAX+$P_aOZd|09IQPlgdU$}}kGeMGG@tJ9P1{LNHoV)e+LrvvCdY&Fg7}5K;jQz`P z#3Z^dOufU~`}&a_PT6v?F|O8i=F(8BjSOl|O$;K-AnLhxPasOD@MIw~~qR8Ep0N zoTE|`$S!Bk5MpEOBQHUXf;;|!>n=|C3%=$@&!55f85ik*uHaWcDPWorV}g-2z3NG&AUic;~uY3 zSd{}k52nG-ZeZ80I3uY;v#C_OUd5A*c&LI2R z+}uh$x#BXqMmj~JygY`s=3eL))#sdQ>5p-f703ml4lE=nVa7?*aaL*qyth2_2$W}fIg2&HX>k@v zw*lVf<-?%J_q1%-qQL3>eL1Qs3yO?+Iayg;Fb@Dq?fCcbaRWez%+g^1zmFSm-;bkM z6UY~U$y?BEJc4Ym_Ojz+>%nS-oPh^NwU&%-g-8wMZ$}Bsr0+E&_@zhyb=`&)msnLn-mU>pWB? z1|Oq4gro}GZqQ$tntBh`GJ2|uTUvycXMWgkd;;2&AgC%SDWQZD6cj|2l;ZvdRc>xB z9o6{%U2pt{+wno?c?G1QhoHC_+{E!4HZx3yk@=>XBlALpRVJqN<^k`=PT)qbV_X;KQfF zNB+8ha)|yNZq>nC_oi?!@sIZnLo&)-3tG(g6^PXj1u#H&61yehX!`{6Yspv(+Mzb$ z0%gMnQgoyO&iFBOGK#snGU)s5uUWjpD(jNJ)P#!&1-`%N`q7#9J{MVGXtp+SR(|KZ6f(>7nJ*t09j9+*9<_vPJv8<~^bm?9(ZB2Znjq zeuKbYS0_2ol*lkq9CU{|x&BXgXevf~*l?Ej%{aGf(^49CLk-Ee+u(^M0~jCM+%%16 z(Hyuu$6{b))ZZ921(TUTi!3#j5{RXs2KTxG2|{Uv!)=y(IP|*iVc=0q&jXR5moI67 zSAoM(D)eC3g^q_O0JxZoqm524)X0fDFF3V^@H!i8GLA$aA2jeRFf^g4q~yYAulNhz zq-(5?6l-aZQDE}PgT+|hzCE_X?lfXk=Tg!ig-#>_JaTSthYLp>(2MbVPy1~%^WpxT zUthSEXNV%YId`4Ko^^o|zNvzg6c!NUT%M_}P?Dm3D-iXQ)~5OV@L?YZRfnKPmTW1# zWnTXYhTE4byIz}u!b074pSz06%Ad5fWWn?x7=Z-C;b25@aBr~_$eMC_AmhPcG*6%7 zxx3KC>F)0LywQy9Z8oU{mfR9^T##*17*JqfENZ8yU21!a(5_xHS$2A5wjV0YX8fId zRgCaj)=8oRudBmWu$k#Dq%B@ExO-}>)rcm7cKt@Y`o*IMi>FA=LuZS3L=Q0b&2Wyi z7@AdxiUhn(=JJ;34l`&?1-|ha~pZosZJ&JAd)Ff(@;6T4IujeEQUUUxnF+*%wj1e-R!`mq%MSKaq z(y%`S<^Ut?zF8z+Xe)_Uw5fz-W~0tF>da1&EC&bYYMY2u&Z9hKx1E;A)CR-L*%A@W ziI;S4po5~K4o=%3Kuix6m~iug>05N#{TaOppV*_b@>o(Ej>#GHlEs-k-u#Pu&2)cu zskEb)51;QO@AA?Ce82E>Wrn7w{YFM7b53v zRdp_%6(aIVHD-Pqh34+6gRfC&J9L6cU-tY)3Q_Oi=vALSnfaADy;ilVv>+-zGCz7W zx4zEMY%ar8MDgGuReN{L${CkCZcDwTi{2@xv`GfTVU{YwztXtnm}W;T>zr*9B z0ELwD!47R{z9*C{CMs$Yfkm5EKH3SjBm^%lGp5K80Uv{LHUpX+MjoNrp9>%>4`_A> z>v|0KM5#OD*-sVOT4Wz!UQ*Q=%K;E3K# z_Chx<3c^oI_ii08N!ME*KJ>*&f7qXRKNTka{+sApP1lPl zq-lY^svewUmvG#(Vg91Kd9^^bQ5QZ>Olm)0v0Q(sF0$fwI!;$tR|aHltlVzaNwevo zDuykJ5+!L~8@?G;g=AP6mO|>;zYsnrB;*RBlzsmmUtAoUeqz!6U2|&x*Pl4Kbil!f zV_o`-nMu=Ik?lPPQKYhf>dv{?Do^2krtKN}AeajR)mp|Y|0KyCA~>!<8y*gz$LqY; z&e73PNGa!etSW_#aKdOfJ4>%EGZKx+K?>>a&c{k(*<9}D2XIx7R2Tv| zZg7@qVzH7Slz~Xw?O`Ccta!-6Cv8^9o3|njz8Aos&;p&5>U2l475&+`%|<@$g*Z?h zL&N$wd6yh}12)|)l%3>0f4E7mi9v?X0pVeF54NvO43sOw)K5rF4XdnF0ac+?eS@0+ zE6(`#qN~MgJ~>r123JmgUB{*v<4ibmp^c0Z{6Xf}{cG+yK70|?D0%ZFG0V}rNEAQx zEZwj)6&rIOio4skwnqg+vs@aZfneA;*){GUgbGj*jm7%7|1X zteQvKMYpYhsvR!iEA+INSI>wCoZM2&SHCoH-cg;3^hqKCS5<`_LFG1=ggjM<$ zwBZ~{AYi`QGZY8v`Rd3>a6kUNx>&{SiKu5rN25JgG7AtDO>3@^7vs8-C({z~#Gdom z@GY$`CfxVl0Lq%_aX` zYu)3UI=@rXLw@h^qkYOc3epKvOZJH>Ic`gx5$ML zP&u2R_nyRyp+a#2Rs>13^|zPU8~PFGn7R?T?9ShWFNO+Ky~L*EjFPKQqdyYK&rMtF<;>}sM2i-Y2(cN1%17!vT^5rs z9R{o@);TmIFSj1gWNk)`!rY)gX1UN@e*Gg4=!GWF^S)qEyQM{NW5qll^;wnl9OzSy zI{eG_A$}5WULA>OjoLGX9u|wLPhl@Li4|cmI2E?RpoNQps4Y}^S@cx-_kB^8dqb-| z=9x5U4u2bo8bGGfSe{L#w$j3umJv7~7S3Ekt1Nz!sdj?WC3SCImTmds$ZY*-C z2K~B;QTtbm%Rlt-)H!gX;4FEYo*oj&8sG|>*#slk<*vuK$H$StU^W47DX@{ej;I31 zWRQK&$k+&2rt4<8l;a8p?my8I{Rmsrr+P|aQqm*x5wEA0Kxht^x2d<6v>w!^I7nZa zU-7{Zu~50u z56qtuP?x~XQKq&*v47d|;4@VWkV&aoSu`*ei6|-_hChb*GVQX;K7)nzva`B0Y+kSM zur|Oe8vYp2_sdLTcL<`HKgV1$*HmWwDM7iJW!fRd3H$(Y`iGN7iCJ(QGgfF`+fbWO zR`y&~=;1JCWNhrTNyRpFmjw?Jb_y1-j=m*pa4>)eBSQXba20b!=h}R?cvg61WWKL^ zo@tl{Ui74x)#o-bes}85uSJXfGas*?D@aj-8mmbwbd-RB6@jb@K8(#C_w~_}AoxRO zVQOYt^*5#~6*R0#InaV66&F=k{I-9YW4$P*S~Fm(K*j{L-l#xG>r{ps0Cub@XW4M1 zDRw^+PHNHp)FHBk_~zFc)h5Mt|?~j_8`ei_aD3Jr;VsP60^YUPzt%8ztwfq$BtGGXt(I zBv)PtPbVz}7A7qMmO4i&ox-EDd%7z+A8~t8)PFwDRlaJqZ?!)S&Tsb~D*|Kzo zcKPaV1Bd*71qnFs_~Er){6$^%GoN*Qz`(3^R_Wqcy50MP+;`znRzeMTA&}$fp(lVN zJ;3NWq0<}m=jk*aU1W{~NP4*DR=4V4ccGi|8DJFn_?QPMnx+tgjhmMSlC{MIkOt5M z^b|s&IE0fHPVJla0ad0Ft->e{WGLa@2e86HBMCngo#=_y5>+)a0!tZt`M@=R8eQ`8 zOKZMYmKTy!Q*EkMU0$ag*isz+03_k`1RJMK({JxL=Mq?STChT@>onV%?>#MD&w z2fzQ8UDI*f=WJ{4Ws!YLZNtD(=FSK5IaZoba`R*Wh9sr%-}~NthwfKyQuB18E{=ID zIa#I^Z`H8+g0IzYu;3DZ1I!P$iW@z5>K`9pe_?T2{c2Kxjcm8%7X`6fAn6_NC|3rm z50A&6JbOuaUqVq@3_|+)bDy=SK6mchcp?hzDhkrHK4NL#b@)2+s0xWqe$>7==Ywc< z5Nhko?f?~JGT`jXA}oV zF1ZE*Go$|~-sp4nZ*^`iTQ2iUkZ z(ehSWH0tk4f;93GYh?R^9Qp(Sv7fz%soNAKe{1~Br=0HZ2T0IBhf+pF0~I1@yFLgwq(m=#n``ZFYC7h<;C!w!hI)*@U_;v%xw7R3P53gOi4dT>uT5dZFZ zQk`v&`~A1y!Q=}AV1~Q~taUhRfSJ7aV2g56wZH;Y1|KhYFcDs}z8+d9j?W?^BEVQG zg5ogKk8(@e8lcN#PW)_?TwrMuiNvT;O7!0?8Mp21fak5AU7UKf)hv0T!8JbQ1a~p} zg@Z$)RXbUq55;i^69zl9LrIYF){GIxb`dkL(0{Jf&8;69Yk2$^bogd#BL0_e{`uK| zdy+aED++IGh6=or{P{tpRJO$Ksy|itZ9eIRQ5B62!PazU+VObrl^D1SM}@w1oO3+X zTz&Uy(o)WOET^UP&%w<)&Zd>$-JB1G+GxKw@beF`1gG;1@vL&UhGU`13uJPn!%7jR@WT9>FP*>AbeXnBj*S`Ud;7Tn3 diff --git a/site/img/spreadsheettodata.png b/site/img/spreadsheettodata.png deleted file mode 100644 index d787d9f2cbb8a575c0f29751d1668ab1ccf24120..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79410 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⪙P{yu!sByulR~7t;A(Ag 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 SF4+zM@K{+}sZ0SJ`u_l!Lg9`8 diff --git a/site/img/webconsole.png b/site/img/webconsole.png deleted file mode 100644 index 610ad9bef6febbed85eddbcf5146c9ae14d5206b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35675 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 E0H&Thi~s-t diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 8cd23927..00000000 --- a/site/index.html +++ /dev/null @@ -1,133 +0,0 @@ - - - - - Sheetsee.js - - - - - - - - - - - -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    ModuleContainsDocs
    sheetsee-coreIncluded in any build. Gets you started and has the working-with-your-data functions.Doc
    sheetsee-tablesContains everything you'll need to create a table including sortable columns, pagination and search.Doc
    sheetsee-mapsFor making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js.Doc
    sheetsee-chartsIncludes 3 basic d3 charts: bar, line and pie. You can also use your own.Doc
    -
    -

    Making Things

    -

    What can you make with Sheetsee.js? Lost of things, here are some examples:

    - -

    List your sheetsee project here: file an issue or pull request.

    -

    Demos

    -

    Demos pages for the documentation.

    - -
    -
    -

    Documentation

    -

    More resources on using Sheetsee.js:

    -

    Getting Started

    - -

    Ideas

    - -

    Use

    - -
    - - - - - - - diff --git a/site/js/highlight.pack.js b/site/js/highlight.pack.js deleted file mode 100644 index aea9187b..00000000 --- a/site/js/highlight.pack.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
    ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js deleted file mode 100644 index 72f45e90..00000000 --- a/site/js/sheetsee.js +++ /dev/null @@ -1,25349 +0,0 @@ -;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var baseCreateCallback = require('lodash._basecreatecallback'), - keys = require('lodash.keys'), - objectTypes = require('lodash._objecttypes'); - -/** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources will overwrite property assignments of previous - * sources. If a callback is provided it will be executed to produce the - * assigned values. The callback is bound to `thisArg` and invoked with two - * arguments; (objectValue, sourceValue). - * - * @static - * @memberOf _ - * @type Function - * @alias extend - * @category Objects - * @param {Object} object The destination object. - * @param {...Object} [source] The source objects. - * @param {Function} [callback] The function to customize assigning values. - * @param {*} [thisArg] The `this` binding of `callback`. - * @returns {Object} Returns the destination object. - * @example - * - * _.assign({ 'name': 'moe' }, { 'age': 40 }); - * // => { 'name': 'moe', 'age': 40 } - * - * var defaults = _.partialRight(_.assign, function(a, b) { - * return typeof a == 'undefined' ? b : a; - * }); - * - * var food = { 'name': 'apple' }; - * defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } - */ -var assign = function(object, source, guard) { - var index, iterable = object, result = iterable; - if (!iterable) return result; - var args = arguments, - argsIndex = 0, - argsLength = typeof guard == 'number' ? 2 : args.length; - if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { - var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); - } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { - callback = args[--argsLength]; - } - while (++argsIndex < argsLength) { - iterable = args[argsIndex]; - if (iterable && objectTypes[typeof iterable]) { - var ownIndex = -1, - ownProps = objectTypes[typeof iterable] && keys(iterable), - length = ownProps ? ownProps.length : 0; - - while (++ownIndex < length) { - index = ownProps[ownIndex]; - result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; - } - } - } - return result -}; - -module.exports = assign; - -},{"lodash._basecreatecallback":3,"lodash._objecttypes":22,"lodash.keys":23}],3:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var bind = require('lodash.bind'), - identity = require('lodash.identity'), - setBindData = require('lodash._setbinddata'), - support = require('lodash.support'); - -/** Used to detected named functions */ -var reFuncName = /^function[ \n\r\t]+\w/; - -/** Used to detect functions containing a `this` reference */ -var reThis = /\bthis\b/; - -/** Native method shortcuts */ -var fnToString = Function.prototype.toString; - -/** - * The base implementation of `_.createCallback` without support for creating - * "_.pluck" or "_.where" style callbacks. - * - * @private - * @param {*} [func=identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of the created callback. - * @param {number} [argCount] The number of arguments the callback accepts. - * @returns {Function} Returns a callback function. - */ -function baseCreateCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { - return func; - } - var bindData = func.__bindData__ || (support.funcNames && !func.name); - if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; - } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); - } - } - // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { - return func; - } - switch (argCount) { - case 1: return function(value) { - return func.call(thisArg, value); - }; - case 2: return function(a, b) { - return func.call(thisArg, a, b); - }; - case 3: return function(value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - } - return bind(func, thisArg); -} - -module.exports = baseCreateCallback; - -},{"lodash._setbinddata":4,"lodash.bind":12,"lodash.identity":19,"lodash.support":20}],4:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var getObject = require('lodash._getobject'), - noop = require('lodash._noop'), - reNative = require('lodash._renative'), - releaseObject = require('lodash._releaseobject'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -var defineProperty = (function() { - try { - var o = {}, - func = reNative.test(func = Object.defineProperty) && func, - result = func(o, o, o) && func; - } catch(e) { } - return result; -}()); - -/** - * Sets `this` binding data on a given function. - * - * @private - * @param {Function} func The function to set data on. - * @param {*} value The value to set. - */ -var setBindData = !defineProperty ? noop : function(func, value) { - var descriptor = getObject(); - descriptor.value = value; - defineProperty(func, '__bindData__', descriptor); - releaseObject(descriptor); -}; - -module.exports = setBindData; - -},{"lodash._getobject":5,"lodash._noop":7,"lodash._releaseobject":8,"lodash._renative":11}],5:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectPool = require('lodash._objectpool'); - -/** - * Gets an object from the object pool or creates a new one if the pool is empty. - * - * @private - * @returns {Object} The object from the pool. - */ -function getObject() { - return objectPool.pop() || { - 'array': null, - 'cache': null, - 'configurable': false, - 'criteria': null, - 'enumerable': false, - 'false': false, - 'index': 0, - 'leading': false, - 'maxWait': 0, - 'null': false, - 'number': null, - 'object': null, - 'push': null, - 'string': null, - 'trailing': false, - 'true': false, - 'undefined': false, - 'value': null, - 'writable': false - }; -} - -module.exports = getObject; - -},{"lodash._objectpool":6}],6:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used to pool arrays and objects used internally */ -var objectPool = []; - -module.exports = objectPool; - -},{}],7:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * A no-operation function. - * - * @private - */ -function noop() { - // no operation performed -} - -module.exports = noop; - -},{}],8:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var maxPoolSize = require('lodash._maxpoolsize'), - objectPool = require('lodash._objectpool'); - -/** - * Releases the given object back to the object pool. - * - * @private - * @param {Object} [object] The object to release. - */ -function releaseObject(object) { - var cache = object.cache; - if (cache) { - releaseObject(cache); - } - object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; - if (objectPool.length < maxPoolSize) { - objectPool.push(object); - } -} - -module.exports = releaseObject; - -},{"lodash._maxpoolsize":9,"lodash._objectpool":10}],9:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used as the max size of the `arrayPool` and `objectPool` */ -var maxPoolSize = 40; - -module.exports = maxPoolSize; - -},{}],10:[function(require,module,exports){ -module.exports=require(6) -},{}],11:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Used to detect if a method is native */ -var reNative = RegExp('^' + - String(objectProto.valueOf) - .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - .replace(/valueOf|for [^\]]+/g, '.+?') + '$' -); - -module.exports = reNative; - -},{}],12:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var createBound = require('lodash._createbound'), - reNative = require('lodash._renative'); - -/** - * Used for `Array` method references. - * - * Normally `Array.prototype` would suffice, however, using an array literal - * avoids issues in Narwhal. - */ -var arrayRef = []; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeSlice = arrayRef.slice; - -/** - * Creates a function that, when called, invokes `func` with the `this` - * binding of `thisArg` and prepends any additional `bind` arguments to those - * provided to the bound function. - * - * @static - * @memberOf _ - * @category Functions - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {...*} [arg] Arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var func = function(greeting) { - * return greeting + ' ' + this.name; - * }; - * - * func = _.bind(func, { 'name': 'moe' }, 'hi'); - * func(); - * // => 'hi moe' - */ -function bind(func, thisArg) { - return arguments.length > 2 - ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg) - : createBound(func, 1, null, null, thisArg); -} - -module.exports = bind; - -},{"lodash._createbound":13,"lodash._renative":18}],13:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var createObject = require('lodash._createobject'), - isFunction = require('lodash.isfunction'), - isObject = require('lodash.isobject'), - reNative = require('lodash._renative'), - setBindData = require('lodash._setbinddata'), - support = require('lodash.support'); - -/** - * Used for `Array` method references. - * - * Normally `Array.prototype` would suffice, however, using an array literal - * avoids issues in Narwhal. - */ -var arrayRef = []; - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var push = arrayRef.push, - toString = objectProto.toString, - unshift = arrayRef.unshift; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, - nativeSlice = arrayRef.slice; - -/** - * Creates a function that, when called, either curries or invokes `func` - * with an optional `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of method flags to compose. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` - * 8 - `_.curry` (bound) - * 16 - `_.partial` - * 32 - `_.partialRight` - * @param {Array} [partialArgs] An array of arguments to prepend to those - * provided to the new function. - * @param {Array} [partialRightArgs] An array of arguments to append to those - * provided to the new function. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new bound function. - */ -function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { - var isBind = bitmask & 1, - isBindKey = bitmask & 2, - isCurry = bitmask & 4, - isCurryBound = bitmask & 8, - isPartial = bitmask & 16, - isPartialRight = bitmask & 32, - key = func; - - if (!isBindKey && !isFunction(func)) { - throw new TypeError; - } - if (isPartial && !partialArgs.length) { - bitmask &= ~16; - isPartial = partialArgs = false; - } - if (isPartialRight && !partialRightArgs.length) { - bitmask &= ~32; - isPartialRight = partialRightArgs = false; - } - var bindData = func && func.__bindData__; - if (bindData) { - if (isBind && !(bindData[1] & 1)) { - bindData[4] = thisArg; - } - if (!isBind && bindData[1] & 1) { - bitmask |= 8; - } - if (isCurry && !(bindData[1] & 4)) { - bindData[5] = arity; - } - if (isPartial) { - push.apply(bindData[2] || (bindData[2] = []), partialArgs); - } - if (isPartialRight) { - push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); - } - bindData[1] |= bitmask; - return createBound.apply(null, bindData); - } - // use `Function#bind` if it exists and is fast - // (in V8 `Function#bind` is slower except when partially applied) - if (isBind && !(isBindKey || isCurry || isPartialRight) && - (support.fastBind || (nativeBind && isPartial))) { - if (isPartial) { - var args = [thisArg]; - push.apply(args, partialArgs); - } - var bound = isPartial - ? nativeBind.apply(func, args) - : nativeBind.call(func, thisArg); - } - else { - bound = function() { - // `Function#bind` spec - // http://es5.github.io/#x15.3.4.5 - var args = arguments, - thisBinding = isBind ? thisArg : this; - - if (isCurry || isPartial || isPartialRight) { - args = nativeSlice.call(args); - if (isPartial) { - unshift.apply(args, partialArgs); - } - if (isPartialRight) { - push.apply(args, partialRightArgs); - } - if (isCurry && args.length < arity) { - bitmask |= 16 & ~32; - return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity); - } - } - if (isBindKey) { - func = thisBinding[key]; - } - if (this instanceof bound) { - // ensure `new bound` is an instance of `func` - thisBinding = createObject(func.prototype); - - // mimic the constructor's `return` behavior - // http://es5.github.io/#x13.2.2 - var result = func.apply(thisBinding, args); - return isObject(result) ? result : thisBinding; - } - return func.apply(thisBinding, args); - }; - } - setBindData(bound, nativeSlice.call(arguments)); - return bound; -} - -module.exports = createBound; - -},{"lodash._createobject":14,"lodash._renative":18,"lodash._setbinddata":4,"lodash.isfunction":16,"lodash.isobject":17,"lodash.support":20}],14:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var isObject = require('lodash.isobject'), - noop = require('lodash._noop'), - reNative = require('lodash._renative'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate; - -/** - * Creates a new object with the specified `prototype`. - * - * @private - * @param {Object} prototype The prototype object. - * @returns {Object} Returns the new object. - */ -function createObject(prototype) { - return isObject(prototype) ? nativeCreate(prototype) : {}; -} - -module.exports = createObject; - -},{"lodash._noop":15,"lodash._renative":18,"lodash.isobject":17}],15:[function(require,module,exports){ -module.exports=require(7) -},{}],16:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * Checks if `value` is a function. - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - */ -function isFunction(value) { - return typeof value == 'function'; -} - -module.exports = isFunction; - -},{}],17:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectTypes = require('lodash._objecttypes'); - -/** - * Checks if `value` is the language type of Object. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Objects - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if the `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ -function isObject(value) { - // check if the value is the ECMAScript language type of Object - // http://es5.github.io/#x8 - // and avoid a V8 bug - // http://code.google.com/p/v8/issues/detail?id=2291 - return !!(value && objectTypes[typeof value]); -} - -module.exports = isObject; - -},{"lodash._objecttypes":22}],18:[function(require,module,exports){ -module.exports=require(11) -},{}],19:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** - * This method returns the first argument provided to it. - * - * @static - * @memberOf _ - * @category Utilities - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var moe = { 'name': 'moe' }; - * moe === _.identity(moe); - * // => true - */ -function identity(value) { - return value; -} - -module.exports = identity; - -},{}],20:[function(require,module,exports){ -var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var reNative = require('lodash._renative'); - -/** Used to detect functions containing a `this` reference */ -var reThis = /\bthis\b/; - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var toString = objectProto.toString; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind; - -/** Detect various environments */ -var isIeOpera = reNative.test(global.attachEvent), - isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); - -/** - * An object used to flag environments features. - * - * @static - * @memberOf _ - * @type Object - */ -var support = {}; - -/** - * Detect if `Function#bind` exists and is inferred to be fast (all but V8). - * - * @memberOf _.support - * @type boolean - */ -support.fastBind = nativeBind && !isV8; - -/** - * Detect if functions can be decompiled by `Function#toString` - * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). - * - * @memberOf _.support - * @type boolean - */ -support.funcDecomp = !reNative.test(global.WinRTError) && reThis.test(function() { return this; }); - -/** - * Detect if `Function#name` is supported (all but IE). - * - * @memberOf _.support - * @type boolean - */ -support.funcNames = typeof Function.name == 'string'; - -module.exports = support; - -},{"lodash._renative":21}],21:[function(require,module,exports){ -module.exports=require(11) -},{}],22:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ - -/** Used to determine if values are of the language type Object */ -var objectTypes = { - 'boolean': false, - 'function': true, - 'object': true, - 'number': false, - 'string': false, - 'undefined': false -}; - -module.exports = objectTypes; - -},{}],23:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var isObject = require('lodash.isobject'), - reNative = require('lodash._renative'), - shimKeys = require('lodash._shimkeys'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/* Native method shortcuts for methods with the same name as other `lodash` methods */ -var nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys; - -/** - * Creates an array composed of the own enumerable property names of an object. - * - * @static - * @memberOf _ - * @category Objects - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - * @example - * - * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); - * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) - */ -var keys = !nativeKeys ? shimKeys : function(object) { - if (!isObject(object)) { - return []; - } - return nativeKeys(object); -}; - -module.exports = keys; - -},{"lodash._renative":24,"lodash._shimkeys":25,"lodash.isobject":26}],24:[function(require,module,exports){ -module.exports=require(11) -},{}],25:[function(require,module,exports){ -/** - * Lo-Dash 2.1.0 (Custom Build) - * Build: `lodash modularize modern exports="npm" -o ./npm` - * Copyright 2012-2013 The Dojo Foundation - * Based on Underscore.js 1.5.2 - * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -var objectTypes = require('lodash._objecttypes'); - -/** Used for native method references */ -var objectProto = Object.prototype; - -/** Native method shortcuts */ -var hasOwnProperty = objectProto.hasOwnProperty; - -/** - * A fallback implementation of `Object.keys` which produces an array of the - * given object's own enumerable property names. - * - * @private - * @type Function - * @param {Object} object The object to inspect. - * @returns {Array} Returns an array of property names. - */ -var shimKeys = function(object) { - var index, iterable = object, result = []; - if (!iterable) return result; - if (!(objectTypes[typeof object])) return result; - for (index in iterable) { - if (hasOwnProperty.call(iterable, index)) { - result.push(index); - } - } - return result -}; - -module.exports = shimKeys; - -},{"lodash._objecttypes":22}],26:[function(require,module,exports){ -module.exports=require(17) -},{"lodash._objecttypes":22}],27:[function(require,module,exports){ -var d3 = require('d3') - -module.exports.d3 = d3 - -// Bar Chart -// Adapted mostly from http://bl.ocks.org/mbostock/3885705 -// options = {units: "string", labels: "string", m: [60, 150, 30, 150], w: 800, h: 300, div: "#dogBar", xaxis: "cuddlability", hiColor: "#EE0097"} - -module.exports.d3BarChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - // m = [t0, r1, b2, l3] - var m = options.m, - w = options.w - m[1] - m[3], - h = options.h - (m[0] + m[2]) - var format = d3.format(",.0f") - - var x = d3.scale.linear().range([0, w]), - y = d3.scale.ordinal().rangeRoundBands([0, h], .1) - - var xAxis = d3.svg.axis().scale(x).orient("top").tickSize(-h).tickFormat(d3.format("1s")), - yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0) - - var svg = d3.select(options.div).append("svg") - .attr("width", w + m[1] + m[3]) - .attr("height", h + m[0] + m[2]) - .append("g") - .attr("transform", "translate(" + m[3] + "," + m[0] + ")") - - x.domain([0, d3.max(data, function(d) { return d.units })]) // 0 to max of units - y.domain(data.map(function(d) { return d.labels })) // makes array of labels - - var mouseOver = function() { - var rect = d3.select(this) - var indexValue = rect.attr("index_value") - - var barSelector = "." + "rect-" + indexValue - var selectedBar = d3.selectAll(barSelector) - selectedBar.style("fill", options.hiColor) - - var valueSelector = "." + "value-" + indexValue - var selectedValue = d3.selectAll(valueSelector) - selectedValue.style("fill", options.hiColor) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.style("fill", options.hiColor) - } - - var mouseOut = function() { - var rect = d3.select(this) - var indexValue = rect.attr("index_value") - - var barSelector = "." + "rect-" + indexValue - var selectedBar = d3.selectAll(barSelector) - selectedBar.style("fill", function(d) { return d.hexcolor}) - - var valueSelector = "." + "value-" + indexValue - var selectedValue = d3.selectAll(valueSelector) - selectedValue.style("fill", "#333333") - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.style("fill", "#333") - } - - var bar = svg.selectAll("g.bar") - .data(data) - .enter().append("g") - .attr("class", "bar") - .attr("transform", function(d) { return "translate(0," + y(d.labels) + ")" }) - - bar.append("text") - .attr("x", function(d) { return x(d.units) }) - .attr("y", y.rangeBand() / 2) - .attr("dx", 12) - .attr("dy", ".35em") - .attr("text-anchor", "end") - .attr("index_value", function(d, i) { return "index-" + i }) - .text(function(d) { return format(d.units) }) - .attr("class", function(d, i) { return "value-" + "index-" + i }) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - - bar.append("text") - .attr("x", -5) - .attr("y", y.rangeBand() / 2) - .attr("dx", 0) - .attr("dy", ".35em") - .attr("text-anchor", "end") - .attr("index_value", function(d, i) { return "index-" + i }) - .text(function(d) { return d.labels }) - .attr("class", function(d, i) { return "value-" + "index-" + i }) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - - bar.append("rect") - .attr("width", function(d) { return x(d.units)}) - .attr("height", y.rangeBand()) - .attr("index_value", function(d, i) { return "index-" + i }) - .style("fill", function(d) { return d.hexcolor}) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) - .attr("class", function(d, i) { return "rect-" + "index-" + i }) - - svg.append("g") - .attr("class", "x axis") - .call(xAxis) - .append("text") - // .attr("transform", "rotate(-90)") - .attr("y", -20) - .attr("x", m[1]) - .attr("class", "xLabel") - .style("text-anchor", "end") - .text(function() { - if (options.xaxis) return options.xaxis - return - }) -} - -// Pie Chart -// pieOptions = {units: "string", labels: "string", m: [80, 80, 80, 80], w: 800, h: 400, div: "#dogPie", hiColor: "#E4EB29"} -module.exports.d3PieChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - - var width = options.w, - height = options.h, - radius = Math.min(width, height) / 2.3 - - var arc = d3.svg.arc() - .outerRadius(radius - 10) - .innerRadius(0) - - var arcOver = d3.svg.arc() - .outerRadius(radius + .1) - - var pie = d3.layout.pie() - .sort(null) - .value(function(d) { return d.units }) - - var svg = d3.select(options.div).append("svg") - .attr("width", width) - .attr("height", height) - .append("g") - .attr("transform", "translate(" + width / 3 + "," + height / 2 + ")") - - var data = data - - data.forEach(function(d) { - d.units = +d.units - }) - function mouseOver(d) { - d3.select(this).select("path").transition() - .duration(500) - .attr("d", arcOver) - var slice = d3.select(this) - var indexValue = slice.attr("index_value") - - var pathSelector = "." + "path-" + indexValue - var selectedPath = d3.selectAll(pathSelector) - selectedPath.style("fill", options.hiColor) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.transition() - .duration(150) - .style("font-size", "12px").style("font-weight", "bold").style("fill", options.hiColor) - selectedText.attr("class", function(d, i) { return "labels-" + indexValue + " bigg" }) - } - function mouseOut(d) { - d3.select(this).select("path").transition() - .duration(150) - .attr("d", arc) - var slice = d3.select(this) - var indexValue = slice.attr("index_value") - - var pathSelector = "." + "path-" + indexValue - var selectedPath = d3.selectAll(pathSelector) - selectedPath.style("fill", function(d) { return d.data.hexcolor }) - - var textSelector = "." + "labels-" + indexValue - var selectedText = d3.selectAll(textSelector) - selectedText.transition() - .duration(200) - .style("font-size", "10px").style("font-weight", "normal").style("fill", function(d) { return d.hexcolor }) - } - - var g = svg.selectAll(".arc") - .data(pie(data)) - .enter().append("g") - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "slice-" + "index-" + i + " slice arc" }) - .on("mouseover", mouseOver) - .on("mouseout", mouseOut) - - var path = g.append("path") - .attr("d", arc) - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "path-" + "index-" + i }) - .style("fill", function(d) { return d.data.hexcolor}) - .attr("fill", function(d) { return d.data.hexcolor}) - - svg.selectAll("g.labels") - .data(data) - .enter().append("g") // Append legend elements - .append("text") - .attr("text-anchor", "start") - .attr("x", width / 2.5) - .attr("y", function(d, i) { return (height / 2) - i*(data.length * 20)}) - .attr("dx", 0) - .attr("dy", "-140px") // Controls padding to place text above bars - .text(function(d) { return d.labels + ", " + d.units}) - .style("fill", function(d) { return d.hexcolor }) - .attr("index_value", function(d, i) { return "index-" + i }) - .attr("class", function(d, i) { return "labels-" + "index-" + i + " aLabel "}) - .on('mouseover', mouseOver) - .on("mouseout", mouseOut) -} - -// Line Chart -// Adapted from http://bl.ocks.org/1166403 and -// http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html -/// options = {units: "string", labels: "string", m: [80, 100, 120, 100], w: 800, h: 400, div: "#dogLine", yaxis: "cuddlability", hiColor: "#E4EB29"} -module.exports.d3LineChart = function(data, options) { - // format data into units and labels - var data = data.map(function(r) { - var labels = options.labels - var units = options.units - return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} - }) - - var m = options.m - var w = options.w - m[1] - m[3] - var h = options.h - m[0] - m[2] - var data = data - - var x = d3.scale.ordinal().rangeRoundBands([0, w], 1) - x.domain(data.map(function(d) { return d.labels })) - var y = d3.scale.linear().range([0, h]) - y.domain([d3.max(data, function(d) { return d.units }) + 2, 0]) - - var line = d3.svg.line() - .x(function(d, i) { return x(i) }) - .y(function(d) { return y(d) }) - - var graph = d3.select(options.div).append("svg:svg") - .attr("width", w + m[1] + m[3]) - .attr("height", h + m[0] + m[2]) - .append("svg:g") - .attr("transform", "translate(" + m[3] + "," + m[0] + ")") - - var div = d3.select(options.div).append("div") - .attr("class", "tooltip") - .style("opacity", 0) - - // create yAxis - var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(true) - // Add the x-axis. - graph.append("svg:g") - .attr("class", "x axis") - .attr("transform", "translate(0," + h + ")") - .call(xAxis) - .selectAll("text") - .style("text-anchor", "end") - .attr("dy", "-.5em") - .attr('dx', "-1em") - .attr("transform", "rotate(-80)") - .call(xAxis) - - // create left yAxis - var yAxisLeft = d3.svg.axis().scale(y).ticks(4).tickSize(-w).tickSubdivide(true).orient("left") - // Add the y-axis to the left - graph.append("svg:g") - .attr("class", "y axis") - .attr("dx", "25") - .attr("transform", "translate(0,0)") - .call(yAxisLeft) - .append("text") - .attr("transform", "rotate(-90)") - .attr("y", -40) - .attr("dy", 0) - .style("text-anchor", "end") - .text(function() { - if (options.yaxis) return options.yaxis - return - }) - -var lineData = data.map(function(d) { return d.units }) - graph.append("svg:path") - .attr("d", line(lineData)) - .attr("class", "chartLine") - .attr("index_value", function(d, i) { return i }) - // .attr("stroke", options.hiColor).attr("fill", "none") - - graph.selectAll("dot") - .data(data) - .enter().append("circle") - .attr("r", 3.5) - .attr("fill", options.hiColor) - .attr("cx", function(d) { return x(d.labels); }) - .attr("cy", function(d) { return y(d.units); }) - .on("mouseover", function(d) { - div.transition().duration(200).style("opacity", .9) - div .html(d.labels + ", " + d.units) - .style("left", (d3.event.pageX) + "px") - .style("top", (d3.event.pageY - 28) + "px") - }) - .on("mouseout", function(d) { - div.transition().duration(500).style("opacity", 0) - }) -} - - -},{"d3":29}],28:[function(require,module,exports){ -d3 = function() { - var d3 = { - version: "3.2.8" - }; - if (!Date.now) Date.now = function() { - return +new Date(); - }; - var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; - try { - d3_document.createElement("div").style.setProperty("opacity", 0, ""); - } catch (error) { - var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; - d3_element_prototype.setAttribute = function(name, value) { - d3_element_setAttribute.call(this, name, value + ""); - }; - d3_element_prototype.setAttributeNS = function(space, local, value) { - d3_element_setAttributeNS.call(this, space, local, value + ""); - }; - d3_style_prototype.setProperty = function(name, value, priority) { - d3_style_setProperty.call(this, name, value + "", priority); - }; - } - d3.ascending = function(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; - }; - d3.descending = function(a, b) { - return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; - }; - d3.min = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && a > b) a = b; - } else { - while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; - } - return a; - }; - d3.max = function(array, f) { - var i = -1, n = array.length, a, b; - if (arguments.length === 1) { - while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; - while (++i < n) if ((b = array[i]) != null && b > a) a = b; - } else { - while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; - } - return a; - }; - d3.extent = function(array, f) { - var i = -1, n = array.length, a, b, c; - if (arguments.length === 1) { - while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; - while (++i < n) if ((b = array[i]) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } else { - while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; - while (++i < n) if ((b = f.call(array, array[i], i)) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - return [ a, c ]; - }; - d3.sum = function(array, f) { - var s = 0, n = array.length, a, i = -1; - if (arguments.length === 1) { - while (++i < n) if (!isNaN(a = +array[i])) s += a; - } else { - while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; - } - return s; - }; - function d3_number(x) { - return x != null && !isNaN(x); - } - d3.mean = function(array, f) { - var n = array.length, a, m = 0, i = -1, j = 0; - if (arguments.length === 1) { - while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; - } else { - while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; - } - return j ? m : undefined; - }; - d3.quantile = function(values, p) { - var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; - return e ? v + e * (values[h] - v) : v; - }; - d3.median = function(array, f) { - if (arguments.length > 1) array = array.map(f); - array = array.filter(d3_number); - return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; - }; - d3.bisector = function(f) { - return { - left: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; - } - return lo; - }, - right: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; - } - return lo; - } - }; - }; - var d3_bisector = d3.bisector(function(d) { - return d; - }); - d3.bisectLeft = d3_bisector.left; - d3.bisect = d3.bisectRight = d3_bisector.right; - d3.shuffle = function(array) { - var m = array.length, t, i; - while (m) { - i = Math.random() * m-- | 0; - t = array[m], array[m] = array[i], array[i] = t; - } - return array; - }; - d3.permute = function(array, indexes) { - var i = indexes.length, permutes = new Array(i); - while (i--) permutes[i] = array[indexes[i]]; - return permutes; - }; - d3.zip = function() { - if (!(n = arguments.length)) return []; - for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { - for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { - zip[j] = arguments[j][i]; - } - } - return zips; - }; - function d3_zipLength(d) { - return d.length; - } - d3.transpose = function(matrix) { - return d3.zip.apply(d3, matrix); - }; - d3.keys = function(map) { - var keys = []; - for (var key in map) keys.push(key); - return keys; - }; - d3.values = function(map) { - var values = []; - for (var key in map) values.push(map[key]); - return values; - }; - d3.entries = function(map) { - var entries = []; - for (var key in map) entries.push({ - key: key, - value: map[key] - }); - return entries; - }; - d3.merge = function(arrays) { - return Array.prototype.concat.apply([], arrays); - }; - d3.range = function(start, stop, step) { - if (arguments.length < 3) { - step = 1; - if (arguments.length < 2) { - stop = start; - start = 0; - } - } - if ((stop - start) / step === Infinity) throw new Error("infinite range"); - var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; - start *= k, stop *= k, step *= k; - if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); - return range; - }; - function d3_range_integerScale(x) { - var k = 1; - while (x * k % 1) k *= 10; - return k; - } - function d3_class(ctor, properties) { - try { - for (var key in properties) { - Object.defineProperty(ctor.prototype, key, { - value: properties[key], - enumerable: false - }); - } - } catch (e) { - ctor.prototype = properties; - } - } - d3.map = function(object) { - var map = new d3_Map(); - if (object instanceof d3_Map) object.forEach(function(key, value) { - map.set(key, value); - }); else for (var key in object) map.set(key, object[key]); - return map; - }; - function d3_Map() {} - d3_class(d3_Map, { - has: function(key) { - return d3_map_prefix + key in this; - }, - get: function(key) { - return this[d3_map_prefix + key]; - }, - set: function(key, value) { - return this[d3_map_prefix + key] = value; - }, - remove: function(key) { - key = d3_map_prefix + key; - return key in this && delete this[key]; - }, - keys: function() { - var keys = []; - this.forEach(function(key) { - keys.push(key); - }); - return keys; - }, - values: function() { - var values = []; - this.forEach(function(key, value) { - values.push(value); - }); - return values; - }, - entries: function() { - var entries = []; - this.forEach(function(key, value) { - entries.push({ - key: key, - value: value - }); - }); - return entries; - }, - forEach: function(f) { - for (var key in this) { - if (key.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, key.substring(1), this[key]); - } - } - } - }); - var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); - d3.nest = function() { - var nest = {}, keys = [], sortKeys = [], sortValues, rollup; - function map(mapType, array, depth) { - if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; - var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; - while (++i < n) { - if (values = valuesByKey.get(keyValue = key(object = array[i]))) { - values.push(object); - } else { - valuesByKey.set(keyValue, [ object ]); - } - } - if (mapType) { - object = mapType(); - setter = function(keyValue, values) { - object.set(keyValue, map(mapType, values, depth)); - }; - } else { - object = {}; - setter = function(keyValue, values) { - object[keyValue] = map(mapType, values, depth); - }; - } - valuesByKey.forEach(setter); - return object; - } - function entries(map, depth) { - if (depth >= keys.length) return map; - var array = [], sortKey = sortKeys[depth++]; - map.forEach(function(key, keyMap) { - array.push({ - key: key, - values: entries(keyMap, depth) - }); - }); - return sortKey ? array.sort(function(a, b) { - return sortKey(a.key, b.key); - }) : array; - } - nest.map = function(array, mapType) { - return map(mapType, array, 0); - }; - nest.entries = function(array) { - return entries(map(d3.map, array, 0), 0); - }; - nest.key = function(d) { - keys.push(d); - return nest; - }; - nest.sortKeys = function(order) { - sortKeys[keys.length - 1] = order; - return nest; - }; - nest.sortValues = function(order) { - sortValues = order; - return nest; - }; - nest.rollup = function(f) { - rollup = f; - return nest; - }; - return nest; - }; - d3.set = function(array) { - var set = new d3_Set(); - if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); - return set; - }; - function d3_Set() {} - d3_class(d3_Set, { - has: function(value) { - return d3_map_prefix + value in this; - }, - add: function(value) { - this[d3_map_prefix + value] = true; - return value; - }, - remove: function(value) { - value = d3_map_prefix + value; - return value in this && delete this[value]; - }, - values: function() { - var values = []; - this.forEach(function(value) { - values.push(value); - }); - return values; - }, - forEach: function(f) { - for (var value in this) { - if (value.charCodeAt(0) === d3_map_prefixCode) { - f.call(this, value.substring(1)); - } - } - } - }); - d3.behavior = {}; - d3.rebind = function(target, source) { - var i = 1, n = arguments.length, method; - while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); - return target; - }; - function d3_rebind(target, source, method) { - return function() { - var value = method.apply(source, arguments); - return value === source ? target : value; - }; - } - function d3_vendorSymbol(object, name) { - if (name in object) return name; - name = name.charAt(0).toUpperCase() + name.substring(1); - for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { - var prefixName = d3_vendorPrefixes[i] + name; - if (prefixName in object) return prefixName; - } - } - var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; - var d3_array = d3_arraySlice; - function d3_arrayCopy(pseudoarray) { - var i = pseudoarray.length, array = new Array(i); - while (i--) array[i] = pseudoarray[i]; - return array; - } - function d3_arraySlice(pseudoarray) { - return Array.prototype.slice.call(pseudoarray); - } - try { - d3_array(d3_documentElement.childNodes)[0].nodeType; - } catch (e) { - d3_array = d3_arrayCopy; - } - function d3_noop() {} - d3.dispatch = function() { - var dispatch = new d3_dispatch(), i = -1, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - return dispatch; - }; - function d3_dispatch() {} - d3_dispatch.prototype.on = function(type, listener) { - var i = type.indexOf("."), name = ""; - if (i >= 0) { - name = type.substring(i + 1); - type = type.substring(0, i); - } - if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); - if (arguments.length === 2) { - if (listener == null) for (type in this) { - if (this.hasOwnProperty(type)) this[type].on(name, null); - } - return this; - } - }; - function d3_dispatch_event(dispatch) { - var listeners = [], listenerByName = new d3_Map(); - function event() { - var z = listeners, i = -1, n = z.length, l; - while (++i < n) if (l = z[i].on) l.apply(this, arguments); - return dispatch; - } - event.on = function(name, listener) { - var l = listenerByName.get(name), i; - if (arguments.length < 2) return l && l.on; - if (l) { - l.on = null; - listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); - listenerByName.remove(name); - } - if (listener) listeners.push(listenerByName.set(name, { - on: listener - })); - return dispatch; - }; - return event; - } - d3.event = null; - function d3_eventPreventDefault() { - d3.event.preventDefault(); - } - function d3_eventSource() { - var e = d3.event, s; - while (s = e.sourceEvent) e = s; - return e; - } - function d3_eventDispatch(target) { - var dispatch = new d3_dispatch(), i = 0, n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - dispatch.of = function(thiz, argumentz) { - return function(e1) { - try { - var e0 = e1.sourceEvent = d3.event; - e1.target = target; - d3.event = e1; - dispatch[e1.type].apply(thiz, argumentz); - } finally { - d3.event = e0; - } - }; - }; - return dispatch; - } - d3.requote = function(s) { - return s.replace(d3_requote_re, "\\$&"); - }; - var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; - var d3_subclass = {}.__proto__ ? function(object, prototype) { - object.__proto__ = prototype; - } : function(object, prototype) { - for (var property in prototype) object[property] = prototype[property]; - }; - function d3_selection(groups) { - d3_subclass(groups, d3_selectionPrototype); - return groups; - } - var d3_select = function(s, n) { - return n.querySelector(s); - }, d3_selectAll = function(s, n) { - return n.querySelectorAll(s); - }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { - return d3_selectMatcher.call(n, s); - }; - if (typeof Sizzle === "function") { - d3_select = function(s, n) { - return Sizzle(s, n)[0] || null; - }; - d3_selectAll = function(s, n) { - return Sizzle.uniqueSort(Sizzle(s, n)); - }; - d3_selectMatches = Sizzle.matchesSelector; - } - d3.selection = function() { - return d3_selectionRoot; - }; - var d3_selectionPrototype = d3.selection.prototype = []; - d3_selectionPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, group, node; - selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(subnode = selector.call(node, node.__data__, i, j)); - if (subnode && "__data__" in node) subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_selector(selector) { - return typeof selector === "function" ? selector : function() { - return d3_select(selector, this); - }; - } - d3_selectionPrototype.selectAll = function(selector) { - var subgroups = [], subgroup, node; - selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); - subgroup.parentNode = node; - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_selectorAll(selector) { - return typeof selector === "function" ? selector : function() { - return d3_selectAll(selector, this); - }; - } - var d3_nsPrefix = { - svg: "http://www.w3.org/2000/svg", - xhtml: "http://www.w3.org/1999/xhtml", - xlink: "http://www.w3.org/1999/xlink", - xml: "http://www.w3.org/XML/1998/namespace", - xmlns: "http://www.w3.org/2000/xmlns/" - }; - d3.ns = { - prefix: d3_nsPrefix, - qualify: function(name) { - var i = name.indexOf(":"), prefix = name; - if (i >= 0) { - prefix = name.substring(0, i); - name = name.substring(i + 1); - } - return d3_nsPrefix.hasOwnProperty(prefix) ? { - space: d3_nsPrefix[prefix], - local: name - } : name; - } - }; - d3_selectionPrototype.attr = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(); - name = d3.ns.qualify(name); - return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); - } - for (value in name) this.each(d3_selection_attr(value, name[value])); - return this; - } - return this.each(d3_selection_attr(name, value)); - }; - function d3_selection_attr(name, value) { - name = d3.ns.qualify(name); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - function attrConstant() { - this.setAttribute(name, value); - } - function attrConstantNS() { - this.setAttributeNS(name.space, name.local, value); - } - function attrFunction() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); - } - function attrFunctionNS() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); - } - return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; - } - function d3_collapse(s) { - return s.trim().replace(/\s+/g, " "); - } - d3_selectionPrototype.classed = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") { - var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; - if (value = node.classList) { - while (++i < n) if (!value.contains(name[i])) return false; - } else { - value = node.getAttribute("class"); - while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; - } - return true; - } - for (value in name) this.each(d3_selection_classed(value, name[value])); - return this; - } - return this.each(d3_selection_classed(name, value)); - }; - function d3_selection_classedRe(name) { - return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); - } - function d3_selection_classed(name, value) { - name = name.trim().split(/\s+/).map(d3_selection_classedName); - var n = name.length; - function classedConstant() { - var i = -1; - while (++i < n) name[i](this, value); - } - function classedFunction() { - var i = -1, x = value.apply(this, arguments); - while (++i < n) name[i](this, x); - } - return typeof value === "function" ? classedFunction : classedConstant; - } - function d3_selection_classedName(name) { - var re = d3_selection_classedRe(name); - return function(node, value) { - if (c = node.classList) return value ? c.add(name) : c.remove(name); - var c = node.getAttribute("class") || ""; - if (value) { - re.lastIndex = 0; - if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); - } else { - node.setAttribute("class", d3_collapse(c.replace(re, " "))); - } - }; - } - d3_selectionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); - return this; - } - if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); - priority = ""; - } - return this.each(d3_selection_style(name, value, priority)); - }; - function d3_selection_style(name, value, priority) { - function styleNull() { - this.style.removeProperty(name); - } - function styleConstant() { - this.style.setProperty(name, value, priority); - } - function styleFunction() { - var x = value.apply(this, arguments); - if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); - } - return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; - } - d3_selectionPrototype.property = function(name, value) { - if (arguments.length < 2) { - if (typeof name === "string") return this.node()[name]; - for (value in name) this.each(d3_selection_property(value, name[value])); - return this; - } - return this.each(d3_selection_property(name, value)); - }; - function d3_selection_property(name, value) { - function propertyNull() { - delete this[name]; - } - function propertyConstant() { - this[name] = value; - } - function propertyFunction() { - var x = value.apply(this, arguments); - if (x == null) delete this[name]; else this[name] = x; - } - return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; - } - d3_selectionPrototype.text = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.textContent = v == null ? "" : v; - } : value == null ? function() { - this.textContent = ""; - } : function() { - this.textContent = value; - }) : this.node().textContent; - }; - d3_selectionPrototype.html = function(value) { - return arguments.length ? this.each(typeof value === "function" ? function() { - var v = value.apply(this, arguments); - this.innerHTML = v == null ? "" : v; - } : value == null ? function() { - this.innerHTML = ""; - } : function() { - this.innerHTML = value; - }) : this.node().innerHTML; - }; - d3_selectionPrototype.append = function(name) { - name = d3_selection_creator(name); - return this.select(function() { - return this.appendChild(name.apply(this, arguments)); - }); - }; - function d3_selection_creator(name) { - return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { - return d3_document.createElementNS(name.space, name.local); - } : function() { - return d3_document.createElementNS(this.namespaceURI, name); - }; - } - d3_selectionPrototype.insert = function(name, before) { - name = d3_selection_creator(name); - before = d3_selection_selector(before); - return this.select(function() { - return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); - }); - }; - d3_selectionPrototype.remove = function() { - return this.each(function() { - var parent = this.parentNode; - if (parent) parent.removeChild(this); - }); - }; - d3_selectionPrototype.data = function(value, key) { - var i = -1, n = this.length, group, node; - if (!arguments.length) { - value = new Array(n = (group = this[0]).length); - while (++i < n) { - if (node = group[i]) { - value[i] = node.__data__; - } - } - return value; - } - function bind(group, groupData) { - var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; - if (key) { - var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; - for (i = -1; ++i < n; ) { - keyValue = key.call(node = group[i], node.__data__, i); - if (nodeByKeyValue.has(keyValue)) { - exitNodes[i] = node; - } else { - nodeByKeyValue.set(keyValue, node); - } - keyValues.push(keyValue); - } - for (i = -1; ++i < m; ) { - keyValue = key.call(groupData, nodeData = groupData[i], i); - if (node = nodeByKeyValue.get(keyValue)) { - updateNodes[i] = node; - node.__data__ = nodeData; - } else if (!dataByKeyValue.has(keyValue)) { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - dataByKeyValue.set(keyValue, nodeData); - nodeByKeyValue.remove(keyValue); - } - for (i = -1; ++i < n; ) { - if (nodeByKeyValue.has(keyValues[i])) { - exitNodes[i] = group[i]; - } - } - } else { - for (i = -1; ++i < n0; ) { - node = group[i]; - nodeData = groupData[i]; - if (node) { - node.__data__ = nodeData; - updateNodes[i] = node; - } else { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - } - for (;i < m; ++i) { - enterNodes[i] = d3_selection_dataNode(groupData[i]); - } - for (;i < n; ++i) { - exitNodes[i] = group[i]; - } - } - enterNodes.update = updateNodes; - enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; - enter.push(enterNodes); - update.push(updateNodes); - exit.push(exitNodes); - } - var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); - if (typeof value === "function") { - while (++i < n) { - bind(group = this[i], value.call(group, group.parentNode.__data__, i)); - } - } else { - while (++i < n) { - bind(group = this[i], value); - } - } - update.enter = function() { - return enter; - }; - update.exit = function() { - return exit; - }; - return update; - }; - function d3_selection_dataNode(data) { - return { - __data__: data - }; - } - d3_selectionPrototype.datum = function(value) { - return arguments.length ? this.property("__data__", value) : this.property("__data__"); - }; - d3_selectionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); - } - } - } - return d3_selection(subgroups); - }; - function d3_selection_filter(selector) { - return function() { - return d3_selectMatches(this, selector); - }; - } - d3_selectionPrototype.order = function() { - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { - if (node = group[i]) { - if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); - next = node; - } - } - } - return this; - }; - d3_selectionPrototype.sort = function(comparator) { - comparator = d3_selection_sortComparator.apply(this, arguments); - for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); - return this.order(); - }; - function d3_selection_sortComparator(comparator) { - if (!arguments.length) comparator = d3.ascending; - return function(a, b) { - return a && b ? comparator(a.__data__, b.__data__) : !a - !b; - }; - } - d3_selectionPrototype.each = function(callback) { - return d3_selection_each(this, function(node, i, j) { - callback.call(node, node.__data__, i, j); - }); - }; - function d3_selection_each(groups, callback) { - for (var j = 0, m = groups.length; j < m; j++) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { - if (node = group[i]) callback(node, i, j); - } - } - return groups; - } - d3_selectionPrototype.call = function(callback) { - var args = d3_array(arguments); - callback.apply(args[0] = this, args); - return this; - }; - d3_selectionPrototype.empty = function() { - return !this.node(); - }; - d3_selectionPrototype.node = function() { - for (var j = 0, m = this.length; j < m; j++) { - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - var node = group[i]; - if (node) return node; - } - } - return null; - }; - d3_selectionPrototype.size = function() { - var n = 0; - this.each(function() { - ++n; - }); - return n; - }; - function d3_selection_enter(selection) { - d3_subclass(selection, d3_selection_enterPrototype); - return selection; - } - var d3_selection_enterPrototype = []; - d3.selection.enter = d3_selection_enter; - d3.selection.enter.prototype = d3_selection_enterPrototype; - d3_selection_enterPrototype.append = d3_selectionPrototype.append; - d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; - d3_selection_enterPrototype.node = d3_selectionPrototype.node; - d3_selection_enterPrototype.call = d3_selectionPrototype.call; - d3_selection_enterPrototype.size = d3_selectionPrototype.size; - d3_selection_enterPrototype.select = function(selector) { - var subgroups = [], subgroup, subnode, upgroup, group, node; - for (var j = -1, m = this.length; ++j < m; ) { - upgroup = (group = this[j]).update; - subgroups.push(subgroup = []); - subgroup.parentNode = group.parentNode; - for (var i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); - subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - return d3_selection(subgroups); - }; - d3_selection_enterPrototype.insert = function(name, before) { - if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); - return d3_selectionPrototype.insert.call(this, name, before); - }; - function d3_selection_enterInsertBefore(enter) { - var i0, j0; - return function(d, i, j) { - var group = enter[j].update, n = group.length, node; - if (j != j0) j0 = j, i0 = 0; - if (i >= i0) i0 = i + 1; - while (!(node = group[i0]) && ++i0 < n) ; - return node; - }; - } - d3_selectionPrototype.transition = function() { - var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { - time: Date.now(), - ease: d3_ease_cubicInOut, - delay: 0, - duration: 250 - }; - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) d3_transitionNode(node, i, id, transition); - subgroup.push(node); - } - } - return d3_transition(subgroups, id); - }; - d3.select = function(node) { - var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; - group.parentNode = d3_documentElement; - return d3_selection([ group ]); - }; - d3.selectAll = function(nodes) { - var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); - group.parentNode = d3_documentElement; - return d3_selection([ group ]); - }; - var d3_selectionRoot = d3.select(d3_documentElement); - d3_selectionPrototype.on = function(type, listener, capture) { - var n = arguments.length; - if (n < 3) { - if (typeof type !== "string") { - if (n < 2) listener = false; - for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); - return this; - } - if (n < 2) return (n = this.node()["__on" + type]) && n._; - capture = false; - } - return this.each(d3_selection_on(type, listener, capture)); - }; - function d3_selection_on(type, listener, capture) { - var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; - if (i > 0) type = type.substring(0, i); - var filter = d3_selection_onFilters.get(type); - if (filter) type = filter, wrap = d3_selection_onFilter; - function onRemove() { - var l = this[name]; - if (l) { - this.removeEventListener(type, l, l.$); - delete this[name]; - } - } - function onAdd() { - var l = wrap(listener, d3_array(arguments)); - onRemove.call(this); - this.addEventListener(type, this[name] = l, l.$ = capture); - l._ = listener; - } - function removeAll() { - var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; - for (var name in this) { - if (match = name.match(re)) { - var l = this[name]; - this.removeEventListener(match[1], l, l.$); - delete this[name]; - } - } - } - return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; - } - var d3_selection_onFilters = d3.map({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }); - d3_selection_onFilters.forEach(function(k) { - if ("on" + k in d3_document) d3_selection_onFilters.remove(k); - }); - function d3_selection_onListener(listener, argumentz) { - return function(e) { - var o = d3.event; - d3.event = e; - argumentz[0] = this.__data__; - try { - listener.apply(this, argumentz); - } finally { - d3.event = o; - } - }; - } - function d3_selection_onFilter(listener, argumentz) { - var l = d3_selection_onListener(listener, argumentz); - return function(e) { - var target = this, related = e.relatedTarget; - if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { - l.call(target, e); - } - }; - } - var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; - function d3_event_dragSuppress() { - var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; - style[d3_event_dragSelect] = "none"; - return function(suppressClick) { - w.on(name, null); - style[d3_event_dragSelect] = select; - if (suppressClick) { - function off() { - w.on(click, null); - } - w.on(click, function() { - d3_eventPreventDefault(); - off(); - }, true); - setTimeout(off, 0); - } - }; - } - d3.mouse = function(container) { - return d3_mousePoint(container, d3_eventSource()); - }; - var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; - function d3_mousePoint(container, e) { - var svg = container.ownerSVGElement || container; - if (svg.createSVGPoint) { - var point = svg.createSVGPoint(); - if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { - svg = d3.select("body").append("svg").style({ - position: "absolute", - top: 0, - left: 0, - margin: 0, - padding: 0, - border: "none" - }, "important"); - var ctm = svg[0][0].getScreenCTM(); - d3_mouse_bug44083 = !(ctm.f || ctm.e); - svg.remove(); - } - if (d3_mouse_bug44083) { - point.x = e.pageX; - point.y = e.pageY; - } else { - point.x = e.clientX; - point.y = e.clientY; - } - point = point.matrixTransform(container.getScreenCTM().inverse()); - return [ point.x, point.y ]; - } - var rect = container.getBoundingClientRect(); - return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; - } - d3.touches = function(container, touches) { - if (arguments.length < 2) touches = d3_eventSource().touches; - return touches ? d3_array(touches).map(function(touch) { - var point = d3_mousePoint(container, touch); - point.identifier = touch.identifier; - return point; - }) : []; - }; - d3.behavior.drag = function() { - var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); - function drag() { - this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); - } - function touchid() { - return d3.event.changedTouches[0].identifier; - } - function touchposition(parent, id) { - return d3.touches(parent).filter(function(p) { - return p.identifier === id; - })[0]; - } - function dragstart(id, position, move, end) { - return function() { - var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); - if (origin) { - offset = origin.apply(target, arguments); - offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; - } else { - offset = [ 0, 0 ]; - } - event_({ - type: "dragstart" - }); - function moved() { - if (!parent) return ended(); - var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; - dragged |= dx | dy; - origin_ = p; - event_({ - type: "drag", - x: p[0] + offset[0], - y: p[1] + offset[1], - dx: dx, - dy: dy - }); - } - function ended() { - w.on(move + "." + drag, null).on(end + "." + drag, null); - dragRestore(dragged && d3.event.target === eventTarget); - event_({ - type: "dragend" - }); - } - }; - } - drag.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return drag; - }; - return d3.rebind(drag, event, "on"); - }; - d3.behavior.zoom = function() { - var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1; - function zoom() { - this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); - } - zoom.translate = function(x) { - if (!arguments.length) return translate; - translate = x.map(Number); - rescale(); - return zoom; - }; - zoom.scale = function(x) { - if (!arguments.length) return scale; - scale = +x; - rescale(); - return zoom; - }; - zoom.scaleExtent = function(x) { - if (!arguments.length) return scaleExtent; - scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); - return zoom; - }; - zoom.x = function(z) { - if (!arguments.length) return x1; - x1 = z; - x0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - zoom.y = function(z) { - if (!arguments.length) return y1; - y1 = z; - y0 = z.copy(); - translate = [ 0, 0 ]; - scale = 1; - return zoom; - }; - function location(p) { - return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; - } - function point(l) { - return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; - } - function scaleTo(s) { - scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); - } - function translateTo(p, l) { - l = point(l); - translate[0] += p[0] - l[0]; - translate[1] += p[1] - l[1]; - } - function rescale() { - if (x1) x1.domain(x0.range().map(function(x) { - return (x - translate[0]) / scale; - }).map(x0.invert)); - if (y1) y1.domain(y0.range().map(function(y) { - return (y - translate[1]) / scale; - }).map(y0.invert)); - } - function dispatch(event) { - rescale(); - event({ - type: "zoom", - scale: scale, - translate: translate - }); - } - function mousedowned() { - var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); - function moved() { - dragged = 1; - translateTo(d3.mouse(target), l); - dispatch(event_); - } - function ended() { - w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); - dragRestore(dragged && d3.event.target === eventTarget); - } - } - function touchstarted() { - var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); - started(); - function relocate() { - var touches = d3.touches(target); - scale0 = scale; - locations0 = {}; - touches.forEach(function(t) { - locations0[t.identifier] = location(t); - }); - return touches; - } - function started() { - var now = Date.now(), touches = relocate(); - if (touches.length === 1) { - if (now - touchtime < 500) { - var p = touches[0], l = locations0[p.identifier]; - scaleTo(scale * 2); - translateTo(p, l); - d3_eventPreventDefault(); - dispatch(event_); - } - touchtime = now; - } else if (touches.length > 1) { - var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; - distance0 = dx * dx + dy * dy; - } - } - function moved() { - var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier]; - if (p1 = touches[1]) { - var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale; - if (scale1 == null) { - var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; - scale1 = distance0 && Math.sqrt(distance1 / distance0); - } - p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; - l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; - scaleTo(scale1 * scale0); - } - touchtime = null; - translateTo(p0, l0); - dispatch(event_); - } - function ended() { - if (d3.event.touches.length) { - relocate(); - } else { - w.on(touchmove, null).on(touchend, null); - t.on(mousedown, mousedowned).on(touchstart, touchstarted); - dragRestore(); - } - } - } - function mousewheeled() { - d3_eventPreventDefault(); - if (!translate0) translate0 = location(d3.mouse(this)); - scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); - translateTo(d3.mouse(this), translate0); - dispatch(event.of(this, arguments)); - } - function mousewheelreset() { - translate0 = null; - } - function dblclicked() { - var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; - scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); - translateTo(p, l); - dispatch(event.of(this, arguments)); - } - return d3.rebind(zoom, event, "on"); - }; - var d3_behavior_zoomInfinity = [ 0, Infinity ]; - var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { - return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); - }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { - return d3.event.wheelDelta; - }, "mousewheel") : (d3_behavior_zoomDelta = function() { - return -d3.event.detail; - }, "MozMousePixelScroll"); - function d3_Color() {} - d3_Color.prototype.toString = function() { - return this.rgb() + ""; - }; - d3.hsl = function(h, s, l) { - return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); - }; - function d3_hsl(h, s, l) { - return new d3_Hsl(h, s, l); - } - function d3_Hsl(h, s, l) { - this.h = h; - this.s = s; - this.l = l; - } - var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); - d3_hslPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, this.l / k); - }; - d3_hslPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_hsl(this.h, this.s, k * this.l); - }; - d3_hslPrototype.rgb = function() { - return d3_hsl_rgb(this.h, this.s, this.l); - }; - function d3_hsl_rgb(h, s, l) { - var m1, m2; - h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; - s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; - l = l < 0 ? 0 : l > 1 ? 1 : l; - m2 = l <= .5 ? l * (1 + s) : l + s - l * s; - m1 = 2 * l - m2; - function v(h) { - if (h > 360) h -= 360; else if (h < 0) h += 360; - if (h < 60) return m1 + (m2 - m1) * h / 60; - if (h < 180) return m2; - if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; - return m1; - } - function vv(h) { - return Math.round(v(h) * 255); - } - return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); - } - var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; - function d3_sgn(x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; - } - function d3_acos(x) { - return x > 1 ? 0 : x < -1 ? π : Math.acos(x); - } - function d3_asin(x) { - return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); - } - function d3_sinh(x) { - return (Math.exp(x) - Math.exp(-x)) / 2; - } - function d3_cosh(x) { - return (Math.exp(x) + Math.exp(-x)) / 2; - } - function d3_haversin(x) { - return (x = Math.sin(x / 2)) * x; - } - d3.hcl = function(h, c, l) { - return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); - }; - function d3_hcl(h, c, l) { - return new d3_Hcl(h, c, l); - } - function d3_Hcl(h, c, l) { - this.h = h; - this.c = c; - this.l = l; - } - var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); - d3_hclPrototype.brighter = function(k) { - return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.darker = function(k) { - return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); - }; - d3_hclPrototype.rgb = function() { - return d3_hcl_lab(this.h, this.c, this.l).rgb(); - }; - function d3_hcl_lab(h, c, l) { - if (isNaN(h)) h = 0; - if (isNaN(c)) c = 0; - return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); - } - d3.lab = function(l, a, b) { - return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); - }; - function d3_lab(l, a, b) { - return new d3_Lab(l, a, b); - } - function d3_Lab(l, a, b) { - this.l = l; - this.a = a; - this.b = b; - } - var d3_lab_K = 18; - var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; - var d3_labPrototype = d3_Lab.prototype = new d3_Color(); - d3_labPrototype.brighter = function(k) { - return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.darker = function(k) { - return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); - }; - d3_labPrototype.rgb = function() { - return d3_lab_rgb(this.l, this.a, this.b); - }; - function d3_lab_rgb(l, a, b) { - var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; - x = d3_lab_xyz(x) * d3_lab_X; - y = d3_lab_xyz(y) * d3_lab_Y; - z = d3_lab_xyz(z) * d3_lab_Z; - return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); - } - function d3_lab_hcl(l, a, b) { - return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); - } - function d3_lab_xyz(x) { - return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; - } - function d3_xyz_lab(x) { - return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; - } - function d3_xyz_rgb(r) { - return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); - } - d3.rgb = function(r, g, b) { - return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); - }; - function d3_rgbNumber(value) { - return d3_rgb(value >> 16, value >> 8 & 255, value & 255); - } - function d3_rgbString(value) { - return d3_rgbNumber(value) + ""; - } - function d3_rgb(r, g, b) { - return new d3_Rgb(r, g, b); - } - function d3_Rgb(r, g, b) { - this.r = r; - this.g = g; - this.b = b; - } - var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); - d3_rgbPrototype.brighter = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - var r = this.r, g = this.g, b = this.b, i = 30; - if (!r && !g && !b) return d3_rgb(i, i, i); - if (r && r < i) r = i; - if (g && g < i) g = i; - if (b && b < i) b = i; - return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); - }; - d3_rgbPrototype.darker = function(k) { - k = Math.pow(.7, arguments.length ? k : 1); - return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); - }; - d3_rgbPrototype.hsl = function() { - return d3_rgb_hsl(this.r, this.g, this.b); - }; - d3_rgbPrototype.toString = function() { - return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); - }; - function d3_rgb_hex(v) { - return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); - } - function d3_rgb_parse(format, rgb, hsl) { - var r = 0, g = 0, b = 0, m1, m2, name; - m1 = /([a-z]+)\((.*)\)/i.exec(format); - if (m1) { - m2 = m1[2].split(","); - switch (m1[1]) { - case "hsl": - { - return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); - } - - case "rgb": - { - return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); - } - } - } - if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); - if (format != null && format.charAt(0) === "#") { - if (format.length === 4) { - r = format.charAt(1); - r += r; - g = format.charAt(2); - g += g; - b = format.charAt(3); - b += b; - } else if (format.length === 7) { - r = format.substring(1, 3); - g = format.substring(3, 5); - b = format.substring(5, 7); - } - r = parseInt(r, 16); - g = parseInt(g, 16); - b = parseInt(b, 16); - } - return rgb(r, g, b); - } - function d3_rgb_hsl(r, g, b) { - var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; - if (d) { - s = l < .5 ? d / (max + min) : d / (2 - max - min); - if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; - h *= 60; - } else { - h = NaN; - s = l > 0 && l < 1 ? 0 : h; - } - return d3_hsl(h, s, l); - } - function d3_rgb_lab(r, g, b) { - r = d3_rgb_xyz(r); - g = d3_rgb_xyz(g); - b = d3_rgb_xyz(b); - var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); - return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); - } - function d3_rgb_xyz(r) { - return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); - } - function d3_rgb_parseNumber(c) { - var f = parseFloat(c); - return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; - } - var d3_rgb_names = d3.map({ - aliceblue: 15792383, - antiquewhite: 16444375, - aqua: 65535, - aquamarine: 8388564, - azure: 15794175, - beige: 16119260, - bisque: 16770244, - black: 0, - blanchedalmond: 16772045, - blue: 255, - blueviolet: 9055202, - brown: 10824234, - burlywood: 14596231, - cadetblue: 6266528, - chartreuse: 8388352, - chocolate: 13789470, - coral: 16744272, - cornflowerblue: 6591981, - cornsilk: 16775388, - crimson: 14423100, - cyan: 65535, - darkblue: 139, - darkcyan: 35723, - darkgoldenrod: 12092939, - darkgray: 11119017, - darkgreen: 25600, - darkgrey: 11119017, - darkkhaki: 12433259, - darkmagenta: 9109643, - darkolivegreen: 5597999, - darkorange: 16747520, - darkorchid: 10040012, - darkred: 9109504, - darksalmon: 15308410, - darkseagreen: 9419919, - darkslateblue: 4734347, - darkslategray: 3100495, - darkslategrey: 3100495, - darkturquoise: 52945, - darkviolet: 9699539, - deeppink: 16716947, - deepskyblue: 49151, - dimgray: 6908265, - dimgrey: 6908265, - dodgerblue: 2003199, - firebrick: 11674146, - floralwhite: 16775920, - forestgreen: 2263842, - fuchsia: 16711935, - gainsboro: 14474460, - ghostwhite: 16316671, - gold: 16766720, - goldenrod: 14329120, - gray: 8421504, - green: 32768, - greenyellow: 11403055, - grey: 8421504, - honeydew: 15794160, - hotpink: 16738740, - indianred: 13458524, - indigo: 4915330, - ivory: 16777200, - khaki: 15787660, - lavender: 15132410, - lavenderblush: 16773365, - lawngreen: 8190976, - lemonchiffon: 16775885, - lightblue: 11393254, - lightcoral: 15761536, - lightcyan: 14745599, - lightgoldenrodyellow: 16448210, - lightgray: 13882323, - lightgreen: 9498256, - lightgrey: 13882323, - lightpink: 16758465, - lightsalmon: 16752762, - lightseagreen: 2142890, - lightskyblue: 8900346, - lightslategray: 7833753, - lightslategrey: 7833753, - lightsteelblue: 11584734, - lightyellow: 16777184, - lime: 65280, - limegreen: 3329330, - linen: 16445670, - magenta: 16711935, - maroon: 8388608, - mediumaquamarine: 6737322, - mediumblue: 205, - mediumorchid: 12211667, - mediumpurple: 9662683, - mediumseagreen: 3978097, - mediumslateblue: 8087790, - mediumspringgreen: 64154, - mediumturquoise: 4772300, - mediumvioletred: 13047173, - midnightblue: 1644912, - mintcream: 16121850, - mistyrose: 16770273, - moccasin: 16770229, - navajowhite: 16768685, - navy: 128, - oldlace: 16643558, - olive: 8421376, - olivedrab: 7048739, - orange: 16753920, - orangered: 16729344, - orchid: 14315734, - palegoldenrod: 15657130, - palegreen: 10025880, - paleturquoise: 11529966, - palevioletred: 14381203, - papayawhip: 16773077, - peachpuff: 16767673, - peru: 13468991, - pink: 16761035, - plum: 14524637, - powderblue: 11591910, - purple: 8388736, - red: 16711680, - rosybrown: 12357519, - royalblue: 4286945, - saddlebrown: 9127187, - salmon: 16416882, - sandybrown: 16032864, - seagreen: 3050327, - seashell: 16774638, - sienna: 10506797, - silver: 12632256, - skyblue: 8900331, - slateblue: 6970061, - slategray: 7372944, - slategrey: 7372944, - snow: 16775930, - springgreen: 65407, - steelblue: 4620980, - tan: 13808780, - teal: 32896, - thistle: 14204888, - tomato: 16737095, - turquoise: 4251856, - violet: 15631086, - wheat: 16113331, - white: 16777215, - whitesmoke: 16119285, - yellow: 16776960, - yellowgreen: 10145074 - }); - d3_rgb_names.forEach(function(key, value) { - d3_rgb_names.set(key, d3_rgbNumber(value)); - }); - function d3_functor(v) { - return typeof v === "function" ? v : function() { - return v; - }; - } - d3.functor = d3_functor; - function d3_identity(d) { - return d; - } - d3.xhr = d3_xhrType(d3_identity); - function d3_xhrType(response) { - return function(url, mimeType, callback) { - if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, - mimeType = null; - return d3_xhr(url, mimeType, response, callback); - }; - } - function d3_xhr(url, mimeType, response, callback) { - var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; - if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); - "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { - request.readyState > 3 && respond(); - }; - function respond() { - var status = request.status, result; - if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { - try { - result = response.call(xhr, request); - } catch (e) { - dispatch.error.call(xhr, e); - return; - } - dispatch.load.call(xhr, result); - } else { - dispatch.error.call(xhr, request); - } - } - request.onprogress = function(event) { - var o = d3.event; - d3.event = event; - try { - dispatch.progress.call(xhr, request); - } finally { - d3.event = o; - } - }; - xhr.header = function(name, value) { - name = (name + "").toLowerCase(); - if (arguments.length < 2) return headers[name]; - if (value == null) delete headers[name]; else headers[name] = value + ""; - return xhr; - }; - xhr.mimeType = function(value) { - if (!arguments.length) return mimeType; - mimeType = value == null ? null : value + ""; - return xhr; - }; - xhr.responseType = function(value) { - if (!arguments.length) return responseType; - responseType = value; - return xhr; - }; - xhr.response = function(value) { - response = value; - return xhr; - }; - [ "get", "post" ].forEach(function(method) { - xhr[method] = function() { - return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); - }; - }); - xhr.send = function(method, data, callback) { - if (arguments.length === 2 && typeof data === "function") callback = data, data = null; - request.open(method, url, true); - if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; - if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); - if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); - if (responseType != null) request.responseType = responseType; - if (callback != null) xhr.on("error", callback).on("load", function(request) { - callback(null, request); - }); - request.send(data == null ? null : data); - return xhr; - }; - xhr.abort = function() { - request.abort(); - return xhr; - }; - d3.rebind(xhr, dispatch, "on"); - return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); - } - function d3_xhr_fixCallback(callback) { - return callback.length === 1 ? function(error, request) { - callback(error == null ? request : null); - } : callback; - } - d3.dsv = function(delimiter, mimeType) { - var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); - function dsv(url, row, callback) { - if (arguments.length < 3) callback = row, row = null; - var xhr = d3.xhr(url, mimeType, callback); - xhr.row = function(_) { - return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; - }; - return xhr.row(row); - } - function response(request) { - return dsv.parse(request.responseText); - } - function typedResponse(f) { - return function(request) { - return dsv.parse(request.responseText, f); - }; - } - dsv.parse = function(text, f) { - var o; - return dsv.parseRows(text, function(row, i) { - if (o) return o(row, i - 1); - var a = new Function("d", "return {" + row.map(function(name, i) { - return JSON.stringify(name) + ": d[" + i + "]"; - }).join(",") + "}"); - o = f ? function(row, i) { - return f(a(row), i); - } : a; - }); - }; - dsv.parseRows = function(text, f) { - var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; - function token() { - if (I >= N) return EOF; - if (eol) return eol = false, EOL; - var j = I; - if (text.charCodeAt(j) === 34) { - var i = j; - while (i++ < N) { - if (text.charCodeAt(i) === 34) { - if (text.charCodeAt(i + 1) !== 34) break; - ++i; - } - } - I = i + 2; - var c = text.charCodeAt(i + 1); - if (c === 13) { - eol = true; - if (text.charCodeAt(i + 2) === 10) ++I; - } else if (c === 10) { - eol = true; - } - return text.substring(j + 1, i).replace(/""/g, '"'); - } - while (I < N) { - var c = text.charCodeAt(I++), k = 1; - if (c === 10) eol = true; else if (c === 13) { - eol = true; - if (text.charCodeAt(I) === 10) ++I, ++k; - } else if (c !== delimiterCode) continue; - return text.substring(j, I - k); - } - return text.substring(j); - } - while ((t = token()) !== EOF) { - var a = []; - while (t !== EOL && t !== EOF) { - a.push(t); - t = token(); - } - if (f && !(a = f(a, n++))) continue; - rows.push(a); - } - return rows; - }; - dsv.format = function(rows) { - if (Array.isArray(rows[0])) return dsv.formatRows(rows); - var fieldSet = new d3_Set(), fields = []; - rows.forEach(function(row) { - for (var field in row) { - if (!fieldSet.has(field)) { - fields.push(fieldSet.add(field)); - } - } - }); - return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { - return fields.map(function(field) { - return formatValue(row[field]); - }).join(delimiter); - })).join("\n"); - }; - dsv.formatRows = function(rows) { - return rows.map(formatRow).join("\n"); - }; - function formatRow(row) { - return row.map(formatValue).join(delimiter); - } - function formatValue(text) { - return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; - } - return dsv; - }; - d3.csv = d3.dsv(",", "text/csv"); - d3.tsv = d3.dsv(" ", "text/tab-separated-values"); - var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { - setTimeout(callback, 17); - }; - d3.timer = function(callback, delay, then) { - var n = arguments.length; - if (n < 2) delay = 0; - if (n < 3) then = Date.now(); - var time = then + delay, timer = { - callback: callback, - time: time, - next: null - }; - if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; - d3_timer_queueTail = timer; - if (!d3_timer_interval) { - d3_timer_timeout = clearTimeout(d3_timer_timeout); - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - }; - function d3_timer_step() { - var now = d3_timer_mark(), delay = d3_timer_sweep() - now; - if (delay > 24) { - if (isFinite(delay)) { - clearTimeout(d3_timer_timeout); - d3_timer_timeout = setTimeout(d3_timer_step, delay); - } - d3_timer_interval = 0; - } else { - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } - } - d3.timer.flush = function() { - d3_timer_mark(); - d3_timer_sweep(); - }; - function d3_timer_replace(callback, delay, then) { - var n = arguments.length; - if (n < 2) delay = 0; - if (n < 3) then = Date.now(); - d3_timer_active.callback = callback; - d3_timer_active.time = then + delay; - } - function d3_timer_mark() { - var now = Date.now(); - d3_timer_active = d3_timer_queueHead; - while (d3_timer_active) { - if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); - d3_timer_active = d3_timer_active.next; - } - return now; - } - function d3_timer_sweep() { - var t0, t1 = d3_timer_queueHead, time = Infinity; - while (t1) { - if (t1.flush) { - t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; - } else { - if (t1.time < time) time = t1.time; - t1 = (t0 = t1).next; - } - } - d3_timer_queueTail = t0; - return time; - } - var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; - var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); - d3.formatPrefix = function(value, precision) { - var i = 0; - if (value) { - if (value < 0) value *= -1; - if (precision) value = d3.round(value, d3_format_precision(value, precision)); - i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); - i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); - } - return d3_formatPrefixes[8 + i / 3]; - }; - function d3_formatPrefix(d, i) { - var k = Math.pow(10, Math.abs(8 - i) * 3); - return { - scale: i > 8 ? function(d) { - return d / k; - } : function(d) { - return d * k; - }, - symbol: d - }; - } - d3.round = function(x, n) { - return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); - }; - d3.format = function(specifier) { - var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; - if (precision) precision = +precision.substring(1); - if (zfill || fill === "0" && align === "=") { - zfill = fill = "0"; - align = "="; - if (comma) width -= Math.floor((width - 1) / 4); - } - switch (type) { - case "n": - comma = true; - type = "g"; - break; - - case "%": - scale = 100; - suffix = "%"; - type = "f"; - break; - - case "p": - scale = 100; - suffix = "%"; - type = "r"; - break; - - case "b": - case "o": - case "x": - case "X": - if (symbol === "#") symbol = "0" + type.toLowerCase(); - - case "c": - case "d": - integer = true; - precision = 0; - break; - - case "s": - scale = -1; - type = "r"; - break; - } - if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; - if (type == "r" && !precision) type = "g"; - if (precision != null) { - if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); - } - type = d3_format_types.get(type) || d3_format_typeDefault; - var zcomma = zfill && comma; - return function(value) { - if (integer && value % 1) return ""; - var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; - if (scale < 0) { - var prefix = d3.formatPrefix(value, precision); - value = prefix.scale(value); - suffix = prefix.symbol; - } else { - value *= scale; - } - value = type(value, precision); - var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); - if (!zfill && comma) before = d3_format_group(before); - var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; - if (zcomma) before = d3_format_group(padding + before); - negative += symbol; - value = before + after; - return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; - }; - }; - var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; - var d3_format_types = d3.map({ - b: function(x) { - return x.toString(2); - }, - c: function(x) { - return String.fromCharCode(x); - }, - o: function(x) { - return x.toString(8); - }, - x: function(x) { - return x.toString(16); - }, - X: function(x) { - return x.toString(16).toUpperCase(); - }, - g: function(x, p) { - return x.toPrecision(p); - }, - e: function(x, p) { - return x.toExponential(p); - }, - f: function(x, p) { - return x.toFixed(p); - }, - r: function(x, p) { - return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); - } - }); - function d3_format_precision(x, p) { - return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); - } - function d3_format_typeDefault(x) { - return x + ""; - } - var d3_format_group = d3_identity; - if (d3_format_grouping) { - var d3_format_groupingLength = d3_format_grouping.length; - d3_format_group = function(value) { - var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; - while (i > 0 && g > 0) { - t.push(value.substring(i -= g, i + g)); - g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; - } - return t.reverse().join(d3_format_thousandsSeparator); - }; - } - d3.geo = {}; - function d3_adder() {} - d3_adder.prototype = { - s: 0, - t: 0, - add: function(y) { - d3_adderSum(y, this.t, d3_adderTemp); - d3_adderSum(d3_adderTemp.s, this.s, this); - if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; - }, - reset: function() { - this.s = this.t = 0; - }, - valueOf: function() { - return this.s; - } - }; - var d3_adderTemp = new d3_adder(); - function d3_adderSum(a, b, o) { - var x = o.s = a + b, bv = x - a, av = x - bv; - o.t = a - av + (b - bv); - } - d3.geo.stream = function(object, listener) { - if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { - d3_geo_streamObjectType[object.type](object, listener); - } else { - d3_geo_streamGeometry(object, listener); - } - }; - function d3_geo_streamGeometry(geometry, listener) { - if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { - d3_geo_streamGeometryType[geometry.type](geometry, listener); - } - } - var d3_geo_streamObjectType = { - Feature: function(feature, listener) { - d3_geo_streamGeometry(feature.geometry, listener); - }, - FeatureCollection: function(object, listener) { - var features = object.features, i = -1, n = features.length; - while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); - } - }; - var d3_geo_streamGeometryType = { - Sphere: function(object, listener) { - listener.sphere(); - }, - Point: function(object, listener) { - var coordinate = object.coordinates; - listener.point(coordinate[0], coordinate[1]); - }, - MultiPoint: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); - }, - LineString: function(object, listener) { - d3_geo_streamLine(object.coordinates, listener, 0); - }, - MultiLineString: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); - }, - Polygon: function(object, listener) { - d3_geo_streamPolygon(object.coordinates, listener); - }, - MultiPolygon: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); - }, - GeometryCollection: function(object, listener) { - var geometries = object.geometries, i = -1, n = geometries.length; - while (++i < n) d3_geo_streamGeometry(geometries[i], listener); - } - }; - function d3_geo_streamLine(coordinates, listener, closed) { - var i = -1, n = coordinates.length - closed, coordinate; - listener.lineStart(); - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); - listener.lineEnd(); - } - function d3_geo_streamPolygon(coordinates, listener) { - var i = -1, n = coordinates.length; - listener.polygonStart(); - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); - listener.polygonEnd(); - } - d3.geo.area = function(object) { - d3_geo_areaSum = 0; - d3.geo.stream(object, d3_geo_area); - return d3_geo_areaSum; - }; - var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); - var d3_geo_area = { - sphere: function() { - d3_geo_areaSum += 4 * π; - }, - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: function() { - d3_geo_areaRingSum.reset(); - d3_geo_area.lineStart = d3_geo_areaRingStart; - }, - polygonEnd: function() { - var area = 2 * d3_geo_areaRingSum; - d3_geo_areaSum += area < 0 ? 4 * π + area : area; - d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; - } - }; - function d3_geo_areaRingStart() { - var λ00, φ00, λ0, cosφ0, sinφ0; - d3_geo_area.point = function(λ, φ) { - d3_geo_area.point = nextPoint; - λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), - sinφ0 = Math.sin(φ); - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - φ = φ * d3_radians / 2 + π / 4; - var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); - d3_geo_areaRingSum.add(Math.atan2(v, u)); - λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; - } - d3_geo_area.lineEnd = function() { - nextPoint(λ00, φ00); - }; - } - function d3_geo_cartesian(spherical) { - var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); - return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; - } - function d3_geo_cartesianDot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; - } - function d3_geo_cartesianCross(a, b) { - return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; - } - function d3_geo_cartesianAdd(a, b) { - a[0] += b[0]; - a[1] += b[1]; - a[2] += b[2]; - } - function d3_geo_cartesianScale(vector, k) { - return [ vector[0] * k, vector[1] * k, vector[2] * k ]; - } - function d3_geo_cartesianNormalize(d) { - var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); - d[0] /= l; - d[1] /= l; - d[2] /= l; - } - function d3_geo_spherical(cartesian) { - return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; - } - function d3_geo_sphericalEqual(a, b) { - return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; - } - d3.geo.bounds = function() { - var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; - var bound = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - bound.point = ringPoint; - bound.lineStart = ringStart; - bound.lineEnd = ringEnd; - dλSum = 0; - d3_geo_area.polygonStart(); - }, - polygonEnd: function() { - d3_geo_area.polygonEnd(); - bound.point = point; - bound.lineStart = lineStart; - bound.lineEnd = lineEnd; - if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; - range[0] = λ0, range[1] = λ1; - } - }; - function point(λ, φ) { - ranges.push(range = [ λ0 = λ, λ1 = λ ]); - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - function linePoint(λ, φ) { - var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); - if (p0) { - var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); - d3_geo_cartesianNormalize(inflection); - inflection = d3_geo_spherical(inflection); - var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; - if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = inflection[1] * d3_degrees; - if (φi > φ1) φ1 = φi; - } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = -inflection[1] * d3_degrees; - if (φi < φ0) φ0 = φi; - } else { - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - if (antimeridian) { - if (λ < λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } else { - if (λ1 >= λ0) { - if (λ < λ0) λ0 = λ; - if (λ > λ1) λ1 = λ; - } else { - if (λ > λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } - } - } else { - point(λ, φ); - } - p0 = p, λ_ = λ; - } - function lineStart() { - bound.point = linePoint; - } - function lineEnd() { - range[0] = λ0, range[1] = λ1; - bound.point = point; - p0 = null; - } - function ringPoint(λ, φ) { - if (p0) { - var dλ = λ - λ_; - dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; - } else λ__ = λ, φ__ = φ; - d3_geo_area.point(λ, φ); - linePoint(λ, φ); - } - function ringStart() { - d3_geo_area.lineStart(); - } - function ringEnd() { - ringPoint(λ__, φ__); - d3_geo_area.lineEnd(); - if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); - range[0] = λ0, range[1] = λ1; - p0 = null; - } - function angle(λ0, λ1) { - return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; - } - function compareRanges(a, b) { - return a[0] - b[0]; - } - function withinRange(x, range) { - return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; - } - return function(feature) { - φ1 = λ1 = -(λ0 = φ0 = Infinity); - ranges = []; - d3.geo.stream(feature, bound); - var n = ranges.length; - if (n) { - ranges.sort(compareRanges); - for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { - b = ranges[i]; - if (withinRange(b[0], a) || withinRange(b[1], a)) { - if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; - if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; - } else { - merged.push(a = b); - } - } - var best = -Infinity, dλ; - for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { - b = merged[i]; - if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; - } - } - ranges = range = null; - return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; - }; - }(); - d3.geo.centroid = function(object) { - d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, d3_geo_centroid); - var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; - if (m < ε2) { - x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; - if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; - m = x * x + y * y + z * z; - if (m < ε2) return [ NaN, NaN ]; - } - return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; - }; - var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; - var d3_geo_centroid = { - sphere: d3_noop, - point: d3_geo_centroidPoint, - lineStart: d3_geo_centroidLineStart, - lineEnd: d3_geo_centroidLineEnd, - polygonStart: function() { - d3_geo_centroid.lineStart = d3_geo_centroidRingStart; - }, - polygonEnd: function() { - d3_geo_centroid.lineStart = d3_geo_centroidLineStart; - } - }; - function d3_geo_centroidPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); - } - function d3_geo_centroidPointXYZ(x, y, z) { - ++d3_geo_centroidW0; - d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; - d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; - d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; - } - function d3_geo_centroidLineStart() { - var x0, y0, z0; - d3_geo_centroid.point = function(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroid.point = nextPoint; - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } - } - function d3_geo_centroidLineEnd() { - d3_geo_centroid.point = d3_geo_centroidPoint; - } - function d3_geo_centroidRingStart() { - var λ00, φ00, x0, y0, z0; - d3_geo_centroid.point = function(λ, φ) { - λ00 = λ, φ00 = φ; - d3_geo_centroid.point = nextPoint; - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - d3_geo_centroid.lineEnd = function() { - nextPoint(λ00, φ00); - d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; - d3_geo_centroid.point = d3_geo_centroidPoint; - }; - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); - d3_geo_centroidX2 += v * cx; - d3_geo_centroidY2 += v * cy; - d3_geo_centroidZ2 += v * cz; - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } - } - function d3_true() { - return true; - } - function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { - var subject = [], clip = []; - segments.forEach(function(segment) { - if ((n = segment.length - 1) <= 0) return; - var n, p0 = segment[0], p1 = segment[n]; - if (d3_geo_sphericalEqual(p0, p1)) { - listener.lineStart(); - for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); - listener.lineEnd(); - return; - } - var a = { - point: p0, - points: segment, - other: null, - visited: false, - entry: true, - subject: true - }, b = { - point: p0, - points: [ p0 ], - other: a, - visited: false, - entry: false, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - a = { - point: p1, - points: [ p1 ], - other: null, - visited: false, - entry: false, - subject: true - }; - b = { - point: p1, - points: [ p1 ], - other: a, - visited: false, - entry: true, - subject: false - }; - a.other = b; - subject.push(a); - clip.push(b); - }); - clip.sort(compare); - d3_geo_clipPolygonLinkCircular(subject); - d3_geo_clipPolygonLinkCircular(clip); - if (!subject.length) return; - if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { - clip[i].entry = e = !e; - } - var start = subject[0], current, points, point; - while (1) { - current = start; - while (current.visited) if ((current = current.next) === start) return; - points = current.points; - listener.lineStart(); - do { - current.visited = current.other.visited = true; - if (current.entry) { - if (current.subject) { - for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.next.point, 1, listener); - } - current = current.next; - } else { - if (current.subject) { - points = current.prev.points; - for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.point, current.prev.point, -1, listener); - } - current = current.prev; - } - current = current.other; - points = current.points; - } while (!current.visited); - listener.lineEnd(); - } - } - function d3_geo_clipPolygonLinkCircular(array) { - if (!(n = array.length)) return; - var n, i = 0, a = array[0], b; - while (++i < n) { - a.next = b = array[i]; - b.prev = a; - a = b; - } - a.next = b = array[0]; - b.prev = a; - } - function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { - return function(listener) { - var line = clipLine(listener); - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - clip.point = pointRing; - clip.lineStart = ringStart; - clip.lineEnd = ringEnd; - segments = []; - polygon = []; - listener.polygonStart(); - }, - polygonEnd: function() { - clip.point = point; - clip.lineStart = lineStart; - clip.lineEnd = lineEnd; - segments = d3.merge(segments); - if (segments.length) { - d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); - } else if (polygonContains(polygon)) { - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - } - listener.polygonEnd(); - segments = polygon = null; - }, - sphere: function() { - listener.polygonStart(); - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - listener.polygonEnd(); - } - }; - function point(λ, φ) { - if (pointVisible(λ, φ)) listener.point(λ, φ); - } - function pointLine(λ, φ) { - line.point(λ, φ); - } - function lineStart() { - clip.point = pointLine; - line.lineStart(); - } - function lineEnd() { - clip.point = point; - line.lineEnd(); - } - var segments; - var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; - function pointRing(λ, φ) { - ringListener.point(λ, φ); - ring.push([ λ, φ ]); - } - function ringStart() { - ringListener.lineStart(); - ring = []; - } - function ringEnd() { - pointRing(ring[0][0], ring[0][1]); - ringListener.lineEnd(); - var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; - ring.pop(); - polygon.push(ring); - ring = null; - if (!n) return; - if (clean & 1) { - segment = ringSegments[0]; - var n = segment.length - 1, i = -1, point; - listener.lineStart(); - while (++i < n) listener.point((point = segment[i])[0], point[1]); - listener.lineEnd(); - return; - } - if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); - segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); - } - return clip; - }; - } - function d3_geo_clipSegmentLength1(segment) { - return segment.length > 1; - } - function d3_geo_clipBufferListener() { - var lines = [], line; - return { - lineStart: function() { - lines.push(line = []); - }, - point: function(λ, φ) { - line.push([ λ, φ ]); - }, - lineEnd: d3_noop, - buffer: function() { - var buffer = lines; - lines = []; - line = null; - return buffer; - }, - rejoin: function() { - if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); - } - }; - } - function d3_geo_clipSort(a, b) { - return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); - } - function d3_geo_pointInPolygon(point, polygon) { - var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; - d3_geo_areaRingSum.reset(); - for (var i = 0, n = polygon.length; i < n; ++i) { - var ring = polygon[i], m = ring.length; - if (!m) continue; - var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; - while (true) { - if (j === m) j = 0; - point = ring[j]; - var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; - d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); - if (Math.abs(φ) < ε) southPole = true; - polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; - if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { - var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); - d3_geo_cartesianNormalize(arc); - var intersection = d3_geo_cartesianCross(meridianNormal, arc); - d3_geo_cartesianNormalize(intersection); - var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); - if (parallel > φarc) { - winding += antimeridian ^ dλ >= 0 ? 1 : -1; - } - } - if (!j++) break; - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; - } - if (Math.abs(polarAngle) > ε) polar = true; - } - return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; - } - var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); - function d3_geo_clipAntimeridianLine(listener) { - var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; - return { - lineStart: function() { - listener.lineStart(); - clean = 1; - }, - point: function(λ1, φ1) { - var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); - if (Math.abs(dλ - π) < ε) { - listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - listener.point(λ1, φ0); - clean = 0; - } else if (sλ0 !== sλ1 && dλ >= π) { - if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; - if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; - φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - clean = 0; - } - listener.point(λ0 = λ1, φ0 = φ1); - sλ0 = sλ1; - }, - lineEnd: function() { - listener.lineEnd(); - λ0 = φ0 = NaN; - }, - clean: function() { - return 2 - clean; - } - }; - } - function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { - var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); - return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; - } - function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { - var φ; - if (from == null) { - φ = direction * π / 2; - listener.point(-π, φ); - listener.point(0, φ); - listener.point(π, φ); - listener.point(π, 0); - listener.point(π, -φ); - listener.point(0, -φ); - listener.point(-π, -φ); - listener.point(-π, 0); - listener.point(-π, φ); - } else if (Math.abs(from[0] - to[0]) > ε) { - var s = (from[0] < to[0] ? 1 : -1) * π; - φ = direction * s / 2; - listener.point(-s, φ); - listener.point(0, φ); - listener.point(s, φ); - } else { - listener.point(to[0], to[1]); - } - } - var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; - function d3_geo_clipAntimeridianPolygonContains(polygon) { - return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); - } - function d3_geo_clipCircle(radius) { - var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); - return d3_geo_clip(visible, clipLine, interpolate, polygonContains); - function visible(λ, φ) { - return Math.cos(λ) * Math.cos(φ) > cr; - } - function clipLine(listener) { - var point0, c0, v0, v00, clean; - return { - lineStart: function() { - v00 = v0 = false; - clean = 1; - }, - point: function(λ, φ) { - var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; - if (!point0 && (v00 = v0 = v)) listener.lineStart(); - if (v !== v0) { - point2 = intersect(point0, point1); - if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { - point1[0] += ε; - point1[1] += ε; - v = visible(point1[0], point1[1]); - } - } - if (v !== v0) { - clean = 0; - if (v) { - listener.lineStart(); - point2 = intersect(point1, point0); - listener.point(point2[0], point2[1]); - } else { - point2 = intersect(point0, point1); - listener.point(point2[0], point2[1]); - listener.lineEnd(); - } - point0 = point2; - } else if (notHemisphere && point0 && smallRadius ^ v) { - var t; - if (!(c & c0) && (t = intersect(point1, point0, true))) { - clean = 0; - if (smallRadius) { - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - } else { - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - } - } - } - if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { - listener.point(point1[0], point1[1]); - } - point0 = point1, v0 = v, c0 = c; - }, - lineEnd: function() { - if (v0) listener.lineEnd(); - point0 = null; - }, - clean: function() { - return clean | (v00 && v0) << 1; - } - }; - } - function intersect(a, b, two) { - var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); - var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; - if (!determinant) return !two && a; - var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); - d3_geo_cartesianAdd(A, B); - var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); - if (t2 < 0) return; - var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); - d3_geo_cartesianAdd(q, A); - q = d3_geo_spherical(q); - if (!two) return q; - var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; - if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; - var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; - if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; - if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { - var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); - d3_geo_cartesianAdd(q1, A); - return [ q, d3_geo_spherical(q1) ]; - } - } - function code(λ, φ) { - var r = smallRadius ? radius : π - radius, code = 0; - if (λ < -r) code |= 1; else if (λ > r) code |= 2; - if (φ < -r) code |= 4; else if (φ > r) code |= 8; - return code; - } - function polygonContains(polygon) { - return d3_geo_pointInPolygon(point, polygon); - } - } - var d3_geo_clipViewMAX = 1e9; - function d3_geo_clipView(x0, y0, x1, y1) { - return function(listener) { - var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - listener = bufferListener; - segments = []; - polygon = []; - }, - polygonEnd: function() { - listener = listener_; - if ((segments = d3.merge(segments)).length) { - listener.polygonStart(); - d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); - listener.polygonEnd(); - } else if (insidePolygon([ x0, y0 ])) { - listener.polygonStart(), listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(), listener.polygonEnd(); - } - segments = polygon = ring = null; - } - }; - function inside(point) { - var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); - return i; - } - function insidePolygon(p) { - var wn = 0, n = polygon.length, y = p[1]; - for (var i = 0; i < n; ++i) { - for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { - b = v[j]; - if (a[1] <= y) { - if (b[1] > y && isLeft(a, b, p) > 0) ++wn; - } else { - if (b[1] <= y && isLeft(a, b, p) < 0) --wn; - } - a = b; - } - } - return wn !== 0; - } - function isLeft(a, b, c) { - return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); - } - function interpolate(from, to, direction, listener) { - var a = 0, a1 = 0; - if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { - do { - listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); - } while ((a = (a + direction + 4) % 4) !== a1); - } else { - listener.point(to[0], to[1]); - } - } - function visible(x, y) { - return x0 <= x && x <= x1 && y0 <= y && y <= y1; - } - function point(x, y) { - if (visible(x, y)) listener.point(x, y); - } - var x__, y__, v__, x_, y_, v_, first; - function lineStart() { - clip.point = linePoint; - if (polygon) polygon.push(ring = []); - first = true; - v_ = false; - x_ = y_ = NaN; - } - function lineEnd() { - if (segments) { - linePoint(x__, y__); - if (v__ && v_) bufferListener.rejoin(); - segments.push(bufferListener.buffer()); - } - clip.point = point; - if (v_) listener.lineEnd(); - } - function linePoint(x, y) { - x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); - y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); - var v = visible(x, y); - if (polygon) ring.push([ x, y ]); - if (first) { - x__ = x, y__ = y, v__ = v; - first = false; - if (v) { - listener.lineStart(); - listener.point(x, y); - } - } else { - if (v && v_) listener.point(x, y); else { - var a = [ x_, y_ ], b = [ x, y ]; - if (clipLine(a, b)) { - if (!v_) { - listener.lineStart(); - listener.point(a[0], a[1]); - } - listener.point(b[0], b[1]); - if (!v) listener.lineEnd(); - } else if (v) { - listener.lineStart(); - listener.point(x, y); - } - } - } - x_ = x, y_ = y, v_ = v; - } - return clip; - }; - function corner(p, direction) { - return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; - } - function compare(a, b) { - return comparePoints(a.point, b.point); - } - function comparePoints(a, b) { - var ca = corner(a, 1), cb = corner(b, 1); - return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; - } - function clipLine(a, b) { - var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; - if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; - if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { - if (t[1] < 1) { - b[0] = a[0] + t[1] * dx; - b[1] = a[1] + t[1] * dy; - } - if (t[0] > 0) { - a[0] += t[0] * dx; - a[1] += t[0] * dy; - } - return true; - } - return false; - } - } - function d3_geo_clipViewT(num, denominator, t) { - if (Math.abs(denominator) < ε) return num <= 0; - var u = num / denominator; - if (denominator > 0) { - if (u > t[1]) return false; - if (u > t[0]) t[0] = u; - } else { - if (u < t[0]) return false; - if (u < t[1]) t[1] = u; - } - return true; - } - function d3_geo_compose(a, b) { - function compose(x, y) { - return x = a(x, y), b(x[0], x[1]); - } - if (a.invert && b.invert) compose.invert = function(x, y) { - return x = b.invert(x, y), x && a.invert(x[0], x[1]); - }; - return compose; - } - function d3_geo_conic(projectAt) { - var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); - p.parallels = function(_) { - if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; - return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); - }; - return p; - } - function d3_geo_conicEqualArea(φ0, φ1) { - var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; - function forward(λ, φ) { - var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; - return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = ρ0 - y; - return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; - }; - return forward; - } - (d3.geo.conicEqualArea = function() { - return d3_geo_conic(d3_geo_conicEqualArea); - }).raw = d3_geo_conicEqualArea; - d3.geo.albers = function() { - return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); - }; - d3.geo.albersUsa = function() { - var lower48 = d3.geo.albers(); - var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); - var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); - var point, pointStream = { - point: function(x, y) { - point = [ x, y ]; - } - }, lower48Point, alaskaPoint, hawaiiPoint; - function albersUsa(coordinates) { - var x = coordinates[0], y = coordinates[1]; - point = null; - (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); - return point; - } - albersUsa.invert = function(coordinates) { - var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; - return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); - }; - albersUsa.stream = function(stream) { - var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); - return { - point: function(x, y) { - lower48Stream.point(x, y); - alaskaStream.point(x, y); - hawaiiStream.point(x, y); - }, - sphere: function() { - lower48Stream.sphere(); - alaskaStream.sphere(); - hawaiiStream.sphere(); - }, - lineStart: function() { - lower48Stream.lineStart(); - alaskaStream.lineStart(); - hawaiiStream.lineStart(); - }, - lineEnd: function() { - lower48Stream.lineEnd(); - alaskaStream.lineEnd(); - hawaiiStream.lineEnd(); - }, - polygonStart: function() { - lower48Stream.polygonStart(); - alaskaStream.polygonStart(); - hawaiiStream.polygonStart(); - }, - polygonEnd: function() { - lower48Stream.polygonEnd(); - alaskaStream.polygonEnd(); - hawaiiStream.polygonEnd(); - } - }; - }; - albersUsa.precision = function(_) { - if (!arguments.length) return lower48.precision(); - lower48.precision(_); - alaska.precision(_); - hawaii.precision(_); - return albersUsa; - }; - albersUsa.scale = function(_) { - if (!arguments.length) return lower48.scale(); - lower48.scale(_); - alaska.scale(_ * .35); - hawaii.scale(_); - return albersUsa.translate(lower48.translate()); - }; - albersUsa.translate = function(_) { - if (!arguments.length) return lower48.translate(); - var k = lower48.scale(), x = +_[0], y = +_[1]; - lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; - alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; - hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; - return albersUsa; - }; - return albersUsa.scale(1070); - }; - var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: function() { - d3_geo_pathAreaPolygon = 0; - d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; - }, - polygonEnd: function() { - d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; - d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); - } - }; - function d3_geo_pathAreaRingStart() { - var x00, y00, x0, y0; - d3_geo_pathArea.point = function(x, y) { - d3_geo_pathArea.point = nextPoint; - x00 = x0 = x, y00 = y0 = y; - }; - function nextPoint(x, y) { - d3_geo_pathAreaPolygon += y0 * x - x0 * y; - x0 = x, y0 = y; - } - d3_geo_pathArea.lineEnd = function() { - nextPoint(x00, y00); - }; - } - var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; - var d3_geo_pathBounds = { - point: d3_geo_pathBoundsPoint, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop - }; - function d3_geo_pathBoundsPoint(x, y) { - if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; - if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; - if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; - if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; - } - function d3_geo_pathBuffer() { - var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; - var stream = { - point: point, - lineStart: function() { - stream.point = pointLineStart; - }, - lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointCircle = d3_geo_pathBufferCircle(_); - return stream; - }, - result: function() { - if (buffer.length) { - var result = buffer.join(""); - buffer = []; - return result; - } - } - }; - function point(x, y) { - buffer.push("M", x, ",", y, pointCircle); - } - function pointLineStart(x, y) { - buffer.push("M", x, ",", y); - stream.point = pointLine; - } - function pointLine(x, y) { - buffer.push("L", x, ",", y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - buffer.push("Z"); - } - return stream; - } - function d3_geo_pathBufferCircle(radius) { - return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; - } - var d3_geo_pathCentroid = { - point: d3_geo_pathCentroidPoint, - lineStart: d3_geo_pathCentroidLineStart, - lineEnd: d3_geo_pathCentroidLineEnd, - polygonStart: function() { - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; - }, - polygonEnd: function() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; - d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; - } - }; - function d3_geo_pathCentroidPoint(x, y) { - d3_geo_centroidX0 += x; - d3_geo_centroidY0 += y; - ++d3_geo_centroidZ0; - } - function d3_geo_pathCentroidLineStart() { - var x0, y0; - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - }; - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } - } - function d3_geo_pathCentroidLineEnd() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - } - function d3_geo_pathCentroidRingStart() { - var x00, y00, x0, y0; - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); - }; - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - z = y0 * x - x0 * y; - d3_geo_centroidX2 += z * (x0 + x); - d3_geo_centroidY2 += z * (y0 + y); - d3_geo_centroidZ2 += z * 3; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } - d3_geo_pathCentroid.lineEnd = function() { - nextPoint(x00, y00); - }; - } - function d3_geo_pathContext(context) { - var pointRadius = 4.5; - var stream = { - point: point, - lineStart: function() { - stream.point = pointLineStart; - }, - lineEnd: lineEnd, - polygonStart: function() { - stream.lineEnd = lineEndPolygon; - }, - polygonEnd: function() { - stream.lineEnd = lineEnd; - stream.point = point; - }, - pointRadius: function(_) { - pointRadius = _; - return stream; - }, - result: d3_noop - }; - function point(x, y) { - context.moveTo(x, y); - context.arc(x, y, pointRadius, 0, 2 * π); - } - function pointLineStart(x, y) { - context.moveTo(x, y); - stream.point = pointLine; - } - function pointLine(x, y) { - context.lineTo(x, y); - } - function lineEnd() { - stream.point = point; - } - function lineEndPolygon() { - context.closePath(); - } - return stream; - } - function d3_geo_resample(project) { - var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; - function resample(stream) { - var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; - var resample = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - stream.polygonStart(); - resample.lineStart = ringStart; - }, - polygonEnd: function() { - stream.polygonEnd(); - resample.lineStart = lineStart; - } - }; - function point(x, y) { - x = project(x, y); - stream.point(x[0], x[1]); - } - function lineStart() { - x0 = NaN; - resample.point = linePoint; - stream.lineStart(); - } - function linePoint(λ, φ) { - var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); - resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); - stream.point(x0, y0); - } - function lineEnd() { - resample.point = point; - stream.lineEnd(); - } - function ringStart() { - lineStart(); - resample.point = ringPoint; - resample.lineEnd = ringEnd; - } - function ringPoint(λ, φ) { - linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; - resample.point = linePoint; - } - function ringEnd() { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); - resample.lineEnd = lineEnd; - lineEnd(); - } - return resample; - } - function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { - var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; - if (d2 > 4 * δ2 && depth--) { - var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; - if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); - stream.point(x2, y2); - resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); - } - } - } - resample.precision = function(_) { - if (!arguments.length) return Math.sqrt(δ2); - maxDepth = (δ2 = _ * _) > 0 && 16; - return resample; - }; - return resample; - } - d3.geo.path = function() { - var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; - function path(object) { - if (object) { - if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); - if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); - d3.geo.stream(object, cacheStream); - } - return contextStream.result(); - } - path.area = function(object) { - d3_geo_pathAreaSum = 0; - d3.geo.stream(object, projectStream(d3_geo_pathArea)); - return d3_geo_pathAreaSum; - }; - path.centroid = function(object) { - d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); - return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; - }; - path.bounds = function(object) { - d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); - d3.geo.stream(object, projectStream(d3_geo_pathBounds)); - return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; - }; - path.projection = function(_) { - if (!arguments.length) return projection; - projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; - return reset(); - }; - path.context = function(_) { - if (!arguments.length) return context; - contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); - if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); - return reset(); - }; - path.pointRadius = function(_) { - if (!arguments.length) return pointRadius; - pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); - return path; - }; - function reset() { - cacheStream = null; - return path; - } - return path.projection(d3.geo.albersUsa()).context(null); - }; - function d3_geo_pathProjectStream(project) { - var resample = d3_geo_resample(function(λ, φ) { - return project([ λ * d3_degrees, φ * d3_degrees ]); - }); - return function(stream) { - stream = resample(stream); - return { - point: function(λ, φ) { - stream.point(λ * d3_radians, φ * d3_radians); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - }; - } - d3.geo.projection = d3_geo_projection; - d3.geo.projectionMutator = d3_geo_projectionMutator; - function d3_geo_projection(project) { - return d3_geo_projectionMutator(function() { - return project; - })(); - } - function d3_geo_projectionMutator(projectAt) { - var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { - x = project(x, y); - return [ x[0] * k + δx, δy - x[1] * k ]; - }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; - function projection(point) { - point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); - return [ point[0] * k + δx, δy - point[1] * k ]; - } - function invert(point) { - point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); - return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; - } - projection.stream = function(output) { - if (stream) stream.valid = false; - stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); - stream.valid = true; - return stream; - }; - projection.clipAngle = function(_) { - if (!arguments.length) return clipAngle; - preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); - return invalidate(); - }; - projection.clipExtent = function(_) { - if (!arguments.length) return clipExtent; - clipExtent = _; - postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); - return invalidate(); - }; - projection.scale = function(_) { - if (!arguments.length) return k; - k = +_; - return reset(); - }; - projection.translate = function(_) { - if (!arguments.length) return [ x, y ]; - x = +_[0]; - y = +_[1]; - return reset(); - }; - projection.center = function(_) { - if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; - λ = _[0] % 360 * d3_radians; - φ = _[1] % 360 * d3_radians; - return reset(); - }; - projection.rotate = function(_) { - if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; - δλ = _[0] % 360 * d3_radians; - δφ = _[1] % 360 * d3_radians; - δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; - return reset(); - }; - d3.rebind(projection, projectResample, "precision"); - function reset() { - projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); - var center = project(λ, φ); - δx = x - center[0] * k; - δy = y + center[1] * k; - return invalidate(); - } - function invalidate() { - if (stream) { - stream.valid = false; - stream = null; - } - return projection; - } - return function() { - project = projectAt.apply(this, arguments); - projection.invert = project.invert && invert; - return reset(); - }; - } - function d3_geo_projectionRadiansRotate(rotate, stream) { - return { - point: function(x, y) { - y = rotate(x * d3_radians, y * d3_radians), x = y[0]; - stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); - }, - sphere: function() { - stream.sphere(); - }, - lineStart: function() { - stream.lineStart(); - }, - lineEnd: function() { - stream.lineEnd(); - }, - polygonStart: function() { - stream.polygonStart(); - }, - polygonEnd: function() { - stream.polygonEnd(); - } - }; - } - function d3_geo_equirectangular(λ, φ) { - return [ λ, φ ]; - } - (d3.geo.equirectangular = function() { - return d3_geo_projection(d3_geo_equirectangular); - }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; - d3.geo.rotation = function(rotate) { - rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); - function forward(coordinates) { - coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - } - forward.invert = function(coordinates) { - coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - }; - return forward; - }; - function d3_geo_rotation(δλ, δφ, δγ) { - return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; - } - function d3_geo_forwardRotationλ(δλ) { - return function(λ, φ) { - return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; - }; - } - function d3_geo_rotationλ(δλ) { - var rotation = d3_geo_forwardRotationλ(δλ); - rotation.invert = d3_geo_forwardRotationλ(-δλ); - return rotation; - } - function d3_geo_rotationφγ(δφ, δγ) { - var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); - function rotation(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; - return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; - } - rotation.invert = function(λ, φ) { - var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; - return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; - }; - return rotation; - } - d3.geo.circle = function() { - var origin = [ 0, 0 ], angle, precision = 6, interpolate; - function circle() { - var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; - interpolate(null, null, 1, { - point: function(x, y) { - ring.push(x = rotate(x, y)); - x[0] *= d3_degrees, x[1] *= d3_degrees; - } - }); - return { - type: "Polygon", - coordinates: [ ring ] - }; - } - circle.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return circle; - }; - circle.angle = function(x) { - if (!arguments.length) return angle; - interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); - return circle; - }; - circle.precision = function(_) { - if (!arguments.length) return precision; - interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); - return circle; - }; - return circle.angle(90); - }; - function d3_geo_circleInterpolate(radius, precision) { - var cr = Math.cos(radius), sr = Math.sin(radius); - return function(from, to, direction, listener) { - if (from != null) { - from = d3_geo_circleAngle(cr, from); - to = d3_geo_circleAngle(cr, to); - if (direction > 0 ? from < to : from > to) from += direction * 2 * π; - } else { - from = radius + direction * 2 * π; - to = radius; - } - var point; - for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { - listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); - } - }; - } - function d3_geo_circleAngle(cr, point) { - var a = d3_geo_cartesian(point); - a[0] -= cr; - d3_geo_cartesianNormalize(a); - var angle = d3_acos(-a[1]); - return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); - } - d3.geo.distance = function(a, b) { - var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; - return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); - }; - d3.geo.graticule = function() { - var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; - function graticule() { - return { - type: "MultiLineString", - coordinates: lines() - }; - } - function lines() { - return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { - return Math.abs(x % DX) > ε; - }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { - return Math.abs(y % DY) > ε; - }).map(y)); - } - graticule.lines = function() { - return lines().map(function(coordinates) { - return { - type: "LineString", - coordinates: coordinates - }; - }); - }; - graticule.outline = function() { - return { - type: "Polygon", - coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] - }; - }; - graticule.extent = function(_) { - if (!arguments.length) return graticule.minorExtent(); - return graticule.majorExtent(_).minorExtent(_); - }; - graticule.majorExtent = function(_) { - if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; - X0 = +_[0][0], X1 = +_[1][0]; - Y0 = +_[0][1], Y1 = +_[1][1]; - if (X0 > X1) _ = X0, X0 = X1, X1 = _; - if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; - return graticule.precision(precision); - }; - graticule.minorExtent = function(_) { - if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; - x0 = +_[0][0], x1 = +_[1][0]; - y0 = +_[0][1], y1 = +_[1][1]; - if (x0 > x1) _ = x0, x0 = x1, x1 = _; - if (y0 > y1) _ = y0, y0 = y1, y1 = _; - return graticule.precision(precision); - }; - graticule.step = function(_) { - if (!arguments.length) return graticule.minorStep(); - return graticule.majorStep(_).minorStep(_); - }; - graticule.majorStep = function(_) { - if (!arguments.length) return [ DX, DY ]; - DX = +_[0], DY = +_[1]; - return graticule; - }; - graticule.minorStep = function(_) { - if (!arguments.length) return [ dx, dy ]; - dx = +_[0], dy = +_[1]; - return graticule; - }; - graticule.precision = function(_) { - if (!arguments.length) return precision; - precision = +_; - x = d3_geo_graticuleX(y0, y1, 90); - y = d3_geo_graticuleY(x0, x1, precision); - X = d3_geo_graticuleX(Y0, Y1, 90); - Y = d3_geo_graticuleY(X0, X1, precision); - return graticule; - }; - return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); - }; - function d3_geo_graticuleX(y0, y1, dy) { - var y = d3.range(y0, y1 - ε, dy).concat(y1); - return function(x) { - return y.map(function(y) { - return [ x, y ]; - }); - }; - } - function d3_geo_graticuleY(x0, x1, dx) { - var x = d3.range(x0, x1 - ε, dx).concat(x1); - return function(y) { - return x.map(function(x) { - return [ x, y ]; - }); - }; - } - function d3_source(d) { - return d.source; - } - function d3_target(d) { - return d.target; - } - d3.geo.greatArc = function() { - var source = d3_source, source_, target = d3_target, target_; - function greatArc() { - return { - type: "LineString", - coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] - }; - } - greatArc.distance = function() { - return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); - }; - greatArc.source = function(_) { - if (!arguments.length) return source; - source = _, source_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.target = function(_) { - if (!arguments.length) return target; - target = _, target_ = typeof _ === "function" ? null : _; - return greatArc; - }; - greatArc.precision = function() { - return arguments.length ? greatArc : 0; - }; - return greatArc; - }; - d3.geo.interpolate = function(source, target) { - return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); - }; - function d3_geo_interpolate(x0, y0, x1, y1) { - var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); - var interpolate = d ? function(t) { - var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; - return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; - } : function() { - return [ x0 * d3_degrees, y0 * d3_degrees ]; - }; - interpolate.distance = d; - return interpolate; - } - d3.geo.length = function(object) { - d3_geo_lengthSum = 0; - d3.geo.stream(object, d3_geo_length); - return d3_geo_lengthSum; - }; - var d3_geo_lengthSum; - var d3_geo_length = { - sphere: d3_noop, - point: d3_noop, - lineStart: d3_geo_lengthLineStart, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop - }; - function d3_geo_lengthLineStart() { - var λ0, sinφ0, cosφ0; - d3_geo_length.point = function(λ, φ) { - λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); - d3_geo_length.point = nextPoint; - }; - d3_geo_length.lineEnd = function() { - d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; - }; - function nextPoint(λ, φ) { - var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); - d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; - } - } - function d3_geo_azimuthal(scale, angle) { - function azimuthal(λ, φ) { - var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); - return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; - } - azimuthal.invert = function(x, y) { - var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); - return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; - }; - return azimuthal; - } - var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { - return Math.sqrt(2 / (1 + cosλcosφ)); - }, function(ρ) { - return 2 * Math.asin(ρ / 2); - }); - (d3.geo.azimuthalEqualArea = function() { - return d3_geo_projection(d3_geo_azimuthalEqualArea); - }).raw = d3_geo_azimuthalEqualArea; - var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { - var c = Math.acos(cosλcosφ); - return c && c / Math.sin(c); - }, d3_identity); - (d3.geo.azimuthalEquidistant = function() { - return d3_geo_projection(d3_geo_azimuthalEquidistant); - }).raw = d3_geo_azimuthalEquidistant; - function d3_geo_conicConformal(φ0, φ1) { - var cosφ0 = Math.cos(φ0), t = function(φ) { - return Math.tan(π / 4 + φ / 2); - }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; - if (!n) return d3_geo_mercator; - function forward(λ, φ) { - var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); - return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); - return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; - }; - return forward; - } - (d3.geo.conicConformal = function() { - return d3_geo_conic(d3_geo_conicConformal); - }).raw = d3_geo_conicConformal; - function d3_geo_conicEquidistant(φ0, φ1) { - var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; - if (Math.abs(n) < ε) return d3_geo_equirectangular; - function forward(λ, φ) { - var ρ = G - φ; - return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; - } - forward.invert = function(x, y) { - var ρ0_y = G - y; - return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; - }; - return forward; - } - (d3.geo.conicEquidistant = function() { - return d3_geo_conic(d3_geo_conicEquidistant); - }).raw = d3_geo_conicEquidistant; - var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / cosλcosφ; - }, Math.atan); - (d3.geo.gnomonic = function() { - return d3_geo_projection(d3_geo_gnomonic); - }).raw = d3_geo_gnomonic; - function d3_geo_mercator(λ, φ) { - return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; - } - d3_geo_mercator.invert = function(x, y) { - return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; - }; - function d3_geo_mercatorProjection(project) { - var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; - m.scale = function() { - var v = scale.apply(m, arguments); - return v === m ? clipAuto ? m.clipExtent(null) : m : v; - }; - m.translate = function() { - var v = translate.apply(m, arguments); - return v === m ? clipAuto ? m.clipExtent(null) : m : v; - }; - m.clipExtent = function(_) { - var v = clipExtent.apply(m, arguments); - if (v === m) { - if (clipAuto = _ == null) { - var k = π * scale(), t = translate(); - clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); - } - } else if (clipAuto) { - v = null; - } - return v; - }; - return m.clipExtent(null); - } - (d3.geo.mercator = function() { - return d3_geo_mercatorProjection(d3_geo_mercator); - }).raw = d3_geo_mercator; - var d3_geo_orthographic = d3_geo_azimuthal(function() { - return 1; - }, Math.asin); - (d3.geo.orthographic = function() { - return d3_geo_projection(d3_geo_orthographic); - }).raw = d3_geo_orthographic; - var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { - return 1 / (1 + cosλcosφ); - }, function(ρ) { - return 2 * Math.atan(ρ); - }); - (d3.geo.stereographic = function() { - return d3_geo_projection(d3_geo_stereographic); - }).raw = d3_geo_stereographic; - function d3_geo_transverseMercator(λ, φ) { - var B = Math.cos(φ) * Math.sin(λ); - return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; - } - d3_geo_transverseMercator.invert = function(x, y) { - return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; - }; - (d3.geo.transverseMercator = function() { - return d3_geo_mercatorProjection(d3_geo_transverseMercator); - }).raw = d3_geo_transverseMercator; - d3.geom = {}; - d3.svg = {}; - function d3_svg_line(projection) { - var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; - function line(data) { - var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); - function segment() { - segments.push("M", interpolate(projection(points), tension)); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); - } else if (points.length) { - segment(); - points = []; - } - } - if (points.length) segment(); - return segments.length ? segments.join("") : null; - } - line.x = function(_) { - if (!arguments.length) return x; - x = _; - return line; - }; - line.y = function(_) { - if (!arguments.length) return y; - y = _; - return line; - }; - line.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return line; - }; - line.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - return line; - }; - line.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return line; - }; - return line; - } - d3.svg.line = function() { - return d3_svg_line(d3_identity); - }; - function d3_svg_lineX(d) { - return d[0]; - } - function d3_svg_lineY(d) { - return d[1]; - } - var d3_svg_lineInterpolators = d3.map({ - linear: d3_svg_lineLinear, - "linear-closed": d3_svg_lineLinearClosed, - step: d3_svg_lineStep, - "step-before": d3_svg_lineStepBefore, - "step-after": d3_svg_lineStepAfter, - basis: d3_svg_lineBasis, - "basis-open": d3_svg_lineBasisOpen, - "basis-closed": d3_svg_lineBasisClosed, - bundle: d3_svg_lineBundle, - cardinal: d3_svg_lineCardinal, - "cardinal-open": d3_svg_lineCardinalOpen, - "cardinal-closed": d3_svg_lineCardinalClosed, - monotone: d3_svg_lineMonotone - }); - d3_svg_lineInterpolators.forEach(function(key, value) { - value.key = key; - value.closed = /-closed$/.test(key); - }); - function d3_svg_lineLinear(points) { - return points.join("L"); - } - function d3_svg_lineLinearClosed(points) { - return d3_svg_lineLinear(points) + "Z"; - } - function d3_svg_lineStep(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); - if (n > 1) path.push("H", p[0]); - return path.join(""); - } - function d3_svg_lineStepBefore(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); - return path.join(""); - } - function d3_svg_lineStepAfter(points) { - var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; - while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); - return path.join(""); - } - function d3_svg_lineCardinalOpen(points, tension) { - return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineCardinalClosed(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), - points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); - } - function d3_svg_lineCardinal(points, tension) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); - } - function d3_svg_lineHermite(points, tangents) { - if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { - return d3_svg_lineLinear(points); - } - var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; - if (quad) { - path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; - p0 = points[1]; - pi = 2; - } - if (tangents.length > 1) { - t = tangents[1]; - p = points[pi]; - pi++; - path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - for (var i = 2; i < tangents.length; i++, pi++) { - p = points[pi]; - t = tangents[i]; - path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; - } - } - if (quad) { - var lp = points[pi]; - path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; - } - return path; - } - function d3_svg_lineCardinalTangents(points, tension) { - var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; - while (++i < n) { - p0 = p1; - p1 = p2; - p2 = points[i]; - tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); - } - return tangents; - } - function d3_svg_lineBasis(points) { - if (points.length < 3) return d3_svg_lineLinear(points); - var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; - points.push(points[n - 1]); - while (++i <= n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - points.pop(); - path.push("L", pi); - return path.join(""); - } - function d3_svg_lineBasisOpen(points) { - if (points.length < 4) return d3_svg_lineLinear(points); - var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; - while (++i < 3) { - pi = points[i]; - px.push(pi[0]); - py.push(pi[1]); - } - path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); - --i; - while (++i < n) { - pi = points[i]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBasisClosed(points) { - var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; - while (++i < 4) { - pi = points[i % n]; - px.push(pi[0]); - py.push(pi[1]); - } - path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; - --i; - while (++i < m) { - pi = points[i % n]; - px.shift(); - px.push(pi[0]); - py.shift(); - py.push(pi[1]); - d3_svg_lineBasisBezier(path, px, py); - } - return path.join(""); - } - function d3_svg_lineBundle(points, tension) { - var n = points.length - 1; - if (n) { - var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; - while (++i <= n) { - p = points[i]; - t = i / n; - p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); - p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); - } - } - return d3_svg_lineBasis(points); - } - function d3_svg_lineDot4(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; - } - var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; - function d3_svg_lineBasisBezier(path, x, y) { - path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); - } - function d3_svg_lineSlope(p0, p1) { - return (p1[1] - p0[1]) / (p1[0] - p0[0]); - } - function d3_svg_lineFiniteDifferences(points) { - var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); - while (++i < j) { - m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; - } - m[i] = d; - return m; - } - function d3_svg_lineMonotoneTangents(points) { - var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; - while (++i < j) { - d = d3_svg_lineSlope(points[i], points[i + 1]); - if (Math.abs(d) < 1e-6) { - m[i] = m[i + 1] = 0; - } else { - a = m[i] / d; - b = m[i + 1] / d; - s = a * a + b * b; - if (s > 9) { - s = d * 3 / Math.sqrt(s); - m[i] = s * a; - m[i + 1] = s * b; - } - } - } - i = -1; - while (++i <= j) { - s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); - tangents.push([ s || 0, m[i] * s || 0 ]); - } - return tangents; - } - function d3_svg_lineMonotone(points) { - return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); - } - d3.geom.hull = function(vertices) { - var x = d3_svg_lineX, y = d3_svg_lineY; - if (arguments.length) return hull(vertices); - function hull(data) { - if (data.length < 3) return []; - var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; - if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, - vertices = []; i < n; ++i) { - vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); - } - for (i = 1; i < n; ++i) { - if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; - } - for (i = 0; i < n; ++i) { - if (i === h) continue; - y1 = vertices[i][1] - vertices[h][1]; - x1 = vertices[i][0] - vertices[h][0]; - points.push({ - angle: Math.atan2(y1, x1), - index: i - }); - } - points.sort(function(a, b) { - return a.angle - b.angle; - }); - a = points[0].angle; - v = points[0].index; - u = 0; - for (i = 1; i < plen; ++i) { - j = points[i].index; - if (a == points[i].angle) { - x1 = vertices[v][0] - vertices[h][0]; - y1 = vertices[v][1] - vertices[h][1]; - x2 = vertices[j][0] - vertices[h][0]; - y2 = vertices[j][1] - vertices[h][1]; - if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { - points[i].index = -1; - continue; - } else { - points[u].index = -1; - } - } - a = points[i].angle; - u = i; - v = j; - } - stack.push(h); - for (i = 0, j = 0; i < 2; ++j) { - if (points[j].index > -1) { - stack.push(points[j].index); - i++; - } - } - sp = stack.length; - for (;j < plen; ++j) { - if (points[j].index < 0) continue; - while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { - --sp; - } - stack[sp++] = points[j].index; - } - var poly = []; - for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); - return poly; - } - hull.x = function(_) { - return arguments.length ? (x = _, hull) : x; - }; - hull.y = function(_) { - return arguments.length ? (y = _, hull) : y; - }; - return hull; - }; - function d3_geom_hullCCW(i1, i2, i3, v) { - var t, a, b, c, d, e, f; - t = v[i1]; - a = t[0]; - b = t[1]; - t = v[i2]; - c = t[0]; - d = t[1]; - t = v[i3]; - e = t[0]; - f = t[1]; - return (f - b) * (c - a) - (d - b) * (e - a) > 0; - } - d3.geom.polygon = function(coordinates) { - d3_subclass(coordinates, d3_geom_polygonPrototype); - return coordinates; - }; - var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; - d3_geom_polygonPrototype.area = function() { - var i = -1, n = this.length, a, b = this[n - 1], area = 0; - while (++i < n) { - a = b; - b = this[i]; - area += a[1] * b[0] - a[0] * b[1]; - } - return area * .5; - }; - d3_geom_polygonPrototype.centroid = function(k) { - var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; - if (!arguments.length) k = -1 / (6 * this.area()); - while (++i < n) { - a = b; - b = this[i]; - c = a[0] * b[1] - b[0] * a[1]; - x += (a[0] + b[0]) * c; - y += (a[1] + b[1]) * c; - } - return [ x * k, y * k ]; - }; - d3_geom_polygonPrototype.clip = function(subject) { - var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; - while (++i < n) { - input = subject.slice(); - subject.length = 0; - b = this[i]; - c = input[(m = input.length - closed) - 1]; - j = -1; - while (++j < m) { - d = input[j]; - if (d3_geom_polygonInside(d, a, b)) { - if (!d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - subject.push(d); - } else if (d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - c = d; - } - if (closed) subject.push(subject[0]); - a = b; - } - return subject; - }; - function d3_geom_polygonInside(p, a, b) { - return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); - } - function d3_geom_polygonIntersect(c, d, a, b) { - var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); - return [ x1 + ua * x21, y1 + ua * y21 ]; - } - function d3_geom_polygonClosed(coordinates) { - var a = coordinates[0], b = coordinates[coordinates.length - 1]; - return !(a[0] - b[0] || a[1] - b[1]); - } - d3.geom.delaunay = function(vertices) { - var edges = vertices.map(function() { - return []; - }), triangles = []; - d3_geom_voronoiTessellate(vertices, function(e) { - edges[e.region.l.index].push(vertices[e.region.r.index]); - }); - edges.forEach(function(edge, i) { - var v = vertices[i], cx = v[0], cy = v[1]; - edge.forEach(function(v) { - v.angle = Math.atan2(v[0] - cx, v[1] - cy); - }); - edge.sort(function(a, b) { - return a.angle - b.angle; - }); - for (var j = 0, m = edge.length - 1; j < m; j++) { - triangles.push([ v, edge[j], edge[j + 1] ]); - } - }); - return triangles; - }; - d3.geom.voronoi = function(points) { - var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; - if (arguments.length) return voronoi(points); - function voronoi(data) { - var points, polygons = data.map(function() { - return []; - }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; - if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), - i = 0; i < n; ++i) { - points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; - } - d3_geom_voronoiTessellate(points, function(e) { - var s1, s2, x1, x2, y1, y2; - if (e.a === 1 && e.b >= 0) { - s1 = e.ep.r; - s2 = e.ep.l; - } else { - s1 = e.ep.l; - s2 = e.ep.r; - } - if (e.a === 1) { - y1 = s1 ? s1.y : -Z; - x1 = e.c - e.b * y1; - y2 = s2 ? s2.y : Z; - x2 = e.c - e.b * y2; - } else { - x1 = s1 ? s1.x : -Z; - y1 = e.c - e.a * x1; - x2 = s2 ? s2.x : Z; - y2 = e.c - e.a * x2; - } - var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; - polygons[e.region.l.index].push(v1, v2); - polygons[e.region.r.index].push(v1, v2); - }); - polygons = polygons.map(function(polygon, i) { - var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { - return Math.atan2(v[0] - cx, v[1] - cy); - }), order = d3.range(polygon.length).sort(function(a, b) { - return angle[a] - angle[b]; - }); - return order.filter(function(d, i) { - return !i || angle[d] - angle[order[i - 1]] > ε; - }).map(function(d) { - return polygon[d]; - }); - }); - polygons.forEach(function(polygon, i) { - var n = polygon.length; - if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); - if (n > 2) return; - var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; - if (Math.abs(dy) < ε) { - var y = y0 < y1 ? -Z : Z; - polygon.push([ -Z, y ], [ Z, y ]); - } else if (dx < ε) { - var x = x0 < x1 ? -Z : Z; - polygon.push([ x, -Z ], [ x, Z ]); - } else { - var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; - if (Math.abs(z) < ε) { - polygon.push([ dy < 0 ? y : -y, y ]); - } else { - if (z > 0) y *= -1; - polygon.push([ -Z, y ], [ Z, y ]); - } - } - }); - if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); - for (i = 0; i < n; ++i) polygons[i].point = data[i]; - return polygons; - } - voronoi.x = function(_) { - return arguments.length ? (x = _, voronoi) : x; - }; - voronoi.y = function(_) { - return arguments.length ? (y = _, voronoi) : y; - }; - voronoi.clipExtent = function(_) { - if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; - if (_ == null) clipPolygon = null; else { - var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; - clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); - } - return voronoi; - }; - voronoi.size = function(_) { - if (!arguments.length) return clipPolygon && clipPolygon[2]; - return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); - }; - voronoi.links = function(data) { - var points, graph = data.map(function() { - return []; - }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; - if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), - i = 0; i < n; ++i) { - points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; - } - d3_geom_voronoiTessellate(points, function(e) { - var l = e.region.l.index, r = e.region.r.index; - if (graph[l][r]) return; - graph[l][r] = graph[r][l] = true; - links.push({ - source: data[l], - target: data[r] - }); - }); - return links; - }; - voronoi.triangles = function(data) { - if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); - var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; - while (++i < n) { - (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; - } - return d3.geom.delaunay(points).map(function(triangle) { - return triangle.map(function(point) { - return point.data; - }); - }); - }; - return voronoi; - }; - var d3_geom_voronoiOpposite = { - l: "r", - r: "l" - }; - function d3_geom_voronoiTessellate(points, callback) { - var Sites = { - list: points.map(function(v, i) { - return { - index: i, - x: v[0], - y: v[1] - }; - }).sort(function(a, b) { - return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; - }), - bottomSite: null - }; - var EdgeList = { - list: [], - leftEnd: null, - rightEnd: null, - init: function() { - EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); - EdgeList.leftEnd.r = EdgeList.rightEnd; - EdgeList.rightEnd.l = EdgeList.leftEnd; - EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); - }, - createHalfEdge: function(edge, side) { - return { - edge: edge, - side: side, - vertex: null, - l: null, - r: null - }; - }, - insert: function(lb, he) { - he.l = lb; - he.r = lb.r; - lb.r.l = he; - lb.r = he; - }, - leftBound: function(p) { - var he = EdgeList.leftEnd; - do { - he = he.r; - } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); - he = he.l; - return he; - }, - del: function(he) { - he.l.r = he.r; - he.r.l = he.l; - he.edge = null; - }, - right: function(he) { - return he.r; - }, - left: function(he) { - return he.l; - }, - leftRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; - }, - rightRegion: function(he) { - return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; - } - }; - var Geom = { - bisect: function(s1, s2) { - var newEdge = { - region: { - l: s1, - r: s2 - }, - ep: { - l: null, - r: null - } - }; - var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; - newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; - if (adx > ady) { - newEdge.a = 1; - newEdge.b = dy / dx; - newEdge.c /= dx; - } else { - newEdge.b = 1; - newEdge.a = dx / dy; - newEdge.c /= dy; - } - return newEdge; - }, - intersect: function(el1, el2) { - var e1 = el1.edge, e2 = el2.edge; - if (!e1 || !e2 || e1.region.r == e2.region.r) { - return null; - } - var d = e1.a * e2.b - e1.b * e2.a; - if (Math.abs(d) < 1e-10) { - return null; - } - var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; - if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { - el = el1; - e = e1; - } else { - el = el2; - e = e2; - } - var rightOfSite = xint >= e.region.r.x; - if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { - return null; - } - return { - x: xint, - y: yint - }; - }, - rightOf: function(he, p) { - var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; - if (rightOfSite && he.side === "l") { - return 1; - } - if (!rightOfSite && he.side === "r") { - return 0; - } - if (e.a === 1) { - var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; - if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { - above = fast = dyp >= e.b * dxp; - } else { - above = p.x + p.y * e.b > e.c; - if (e.b < 0) { - above = !above; - } - if (!above) { - fast = 1; - } - } - if (!fast) { - var dxs = topsite.x - e.region.l.x; - above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); - if (e.b < 0) { - above = !above; - } - } - } else { - var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; - above = t1 * t1 > t2 * t2 + t3 * t3; - } - return he.side === "l" ? above : !above; - }, - endPoint: function(edge, side, site) { - edge.ep[side] = site; - if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; - callback(edge); - }, - distance: function(s, t) { - var dx = s.x - t.x, dy = s.y - t.y; - return Math.sqrt(dx * dx + dy * dy); - } - }; - var EventQueue = { - list: [], - insert: function(he, site, offset) { - he.vertex = site; - he.ystar = site.y + offset; - for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { - var next = list[i]; - if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { - continue; - } else { - break; - } - } - list.splice(i, 0, he); - }, - del: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} - ls.splice(i, 1); - }, - empty: function() { - return EventQueue.list.length === 0; - }, - nextEvent: function(he) { - for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { - if (ls[i] == he) return ls[i + 1]; - } - return null; - }, - min: function() { - var elem = EventQueue.list[0]; - return { - x: elem.vertex.x, - y: elem.ystar - }; - }, - extractMin: function() { - return EventQueue.list.shift(); - } - }; - EdgeList.init(); - Sites.bottomSite = Sites.list.shift(); - var newSite = Sites.list.shift(), newIntStar; - var lbnd, rbnd, llbnd, rrbnd, bisector; - var bot, top, temp, p, v; - var e, pm; - while (true) { - if (!EventQueue.empty()) { - newIntStar = EventQueue.min(); - } - if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { - lbnd = EdgeList.leftBound(newSite); - rbnd = EdgeList.right(lbnd); - bot = EdgeList.rightRegion(lbnd); - e = Geom.bisect(bot, newSite); - bisector = EdgeList.createHalfEdge(e, "l"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(lbnd, bisector); - if (p) { - EventQueue.del(lbnd); - EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); - } - lbnd = bisector; - bisector = EdgeList.createHalfEdge(e, "r"); - EdgeList.insert(lbnd, bisector); - p = Geom.intersect(bisector, rbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, newSite)); - } - newSite = Sites.list.shift(); - } else if (!EventQueue.empty()) { - lbnd = EventQueue.extractMin(); - llbnd = EdgeList.left(lbnd); - rbnd = EdgeList.right(lbnd); - rrbnd = EdgeList.right(rbnd); - bot = EdgeList.leftRegion(lbnd); - top = EdgeList.rightRegion(rbnd); - v = lbnd.vertex; - Geom.endPoint(lbnd.edge, lbnd.side, v); - Geom.endPoint(rbnd.edge, rbnd.side, v); - EdgeList.del(lbnd); - EventQueue.del(rbnd); - EdgeList.del(rbnd); - pm = "l"; - if (bot.y > top.y) { - temp = bot; - bot = top; - top = temp; - pm = "r"; - } - e = Geom.bisect(bot, top); - bisector = EdgeList.createHalfEdge(e, pm); - EdgeList.insert(llbnd, bisector); - Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); - p = Geom.intersect(llbnd, bisector); - if (p) { - EventQueue.del(llbnd); - EventQueue.insert(llbnd, p, Geom.distance(p, bot)); - } - p = Geom.intersect(bisector, rrbnd); - if (p) { - EventQueue.insert(bisector, p, Geom.distance(p, bot)); - } - } else { - break; - } - } - for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { - callback(lbnd.edge); - } - } - d3.geom.quadtree = function(points, x1, y1, x2, y2) { - var x = d3_svg_lineX, y = d3_svg_lineY, compat; - if (compat = arguments.length) { - x = d3_geom_quadtreeCompatX; - y = d3_geom_quadtreeCompatY; - if (compat === 3) { - y2 = y1; - x2 = x1; - y1 = x1 = 0; - } - return quadtree(points); - } - function quadtree(data) { - var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; - if (x1 != null) { - x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; - } else { - x2_ = y2_ = -(x1_ = y1_ = Infinity); - xs = [], ys = []; - n = data.length; - if (compat) for (i = 0; i < n; ++i) { - d = data[i]; - if (d.x < x1_) x1_ = d.x; - if (d.y < y1_) y1_ = d.y; - if (d.x > x2_) x2_ = d.x; - if (d.y > y2_) y2_ = d.y; - xs.push(d.x); - ys.push(d.y); - } else for (i = 0; i < n; ++i) { - var x_ = +fx(d = data[i], i), y_ = +fy(d, i); - if (x_ < x1_) x1_ = x_; - if (y_ < y1_) y1_ = y_; - if (x_ > x2_) x2_ = x_; - if (y_ > y2_) y2_ = y_; - xs.push(x_); - ys.push(y_); - } - } - var dx = x2_ - x1_, dy = y2_ - y1_; - if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; - function insert(n, d, x, y, x1, y1, x2, y2) { - if (isNaN(x) || isNaN(y)) return; - if (n.leaf) { - var nx = n.x, ny = n.y; - if (nx != null) { - if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { - insertChild(n, d, x, y, x1, y1, x2, y2); - } else { - var nPoint = n.point; - n.x = n.y = n.point = null; - insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); - insertChild(n, d, x, y, x1, y1, x2, y2); - } - } else { - n.x = x, n.y = y, n.point = d; - } - } else { - insertChild(n, d, x, y, x1, y1, x2, y2); - } - } - function insertChild(n, d, x, y, x1, y1, x2, y2) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; - n.leaf = false; - n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); - if (right) x1 = sx; else x2 = sx; - if (bottom) y1 = sy; else y2 = sy; - insert(n, d, x, y, x1, y1, x2, y2); - } - var root = d3_geom_quadtreeNode(); - root.add = function(d) { - insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); - }; - root.visit = function(f) { - d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); - }; - i = -1; - if (x1 == null) { - while (++i < n) { - insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); - } - --i; - } else data.forEach(root.add); - xs = ys = data = d = null; - return root; - } - quadtree.x = function(_) { - return arguments.length ? (x = _, quadtree) : x; - }; - quadtree.y = function(_) { - return arguments.length ? (y = _, quadtree) : y; - }; - quadtree.extent = function(_) { - if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; - if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], - y2 = +_[1][1]; - return quadtree; - }; - quadtree.size = function(_) { - if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; - if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; - return quadtree; - }; - return quadtree; - }; - function d3_geom_quadtreeCompatX(d) { - return d.x; - } - function d3_geom_quadtreeCompatY(d) { - return d.y; - } - function d3_geom_quadtreeNode() { - return { - leaf: true, - nodes: [], - point: null, - x: null, - y: null - }; - } - function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { - if (!f(node, x1, y1, x2, y2)) { - var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; - if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); - if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); - if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); - if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); - } - } - d3.interpolateRgb = d3_interpolateRgb; - function d3_interpolateRgb(a, b) { - a = d3.rgb(a); - b = d3.rgb(b); - var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; - return function(t) { - return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); - }; - } - d3.interpolateObject = d3_interpolateObject; - function d3_interpolateObject(a, b) { - var i = {}, c = {}, k; - for (k in a) { - if (k in b) { - i[k] = d3_interpolate(a[k], b[k]); - } else { - c[k] = a[k]; - } - } - for (k in b) { - if (!(k in a)) { - c[k] = b[k]; - } - } - return function(t) { - for (k in i) c[k] = i[k](t); - return c; - }; - } - d3.interpolateNumber = d3_interpolateNumber; - function d3_interpolateNumber(a, b) { - b -= a = +a; - return function(t) { - return a + b * t; - }; - } - d3.interpolateString = d3_interpolateString; - function d3_interpolateString(a, b) { - var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; - a = a + "", b = b + ""; - d3_interpolate_number.lastIndex = 0; - for (i = 0; m = d3_interpolate_number.exec(b); ++i) { - if (m.index) s.push(b.substring(s0, s1 = m.index)); - q.push({ - i: s.length, - x: m[0] - }); - s.push(null); - s0 = d3_interpolate_number.lastIndex; - } - if (s0 < b.length) s.push(b.substring(s0)); - for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { - o = q[i]; - if (o.x == m[0]) { - if (o.i) { - if (s[o.i + 1] == null) { - s[o.i - 1] += o.x; - s.splice(o.i, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } else { - s[o.i - 1] += o.x + s[o.i + 1]; - s.splice(o.i, 2); - for (j = i + 1; j < n; ++j) q[j].i -= 2; - } - } else { - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - for (j = i + 1; j < n; ++j) q[j].i--; - } - } - q.splice(i, 1); - n--; - i--; - } else { - o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); - } - } - while (i < n) { - o = q.pop(); - if (s[o.i + 1] == null) { - s[o.i] = o.x; - } else { - s[o.i] = o.x + s[o.i + 1]; - s.splice(o.i + 1, 1); - } - n--; - } - if (s.length === 1) { - return s[0] == null ? (o = q[0].x, function(t) { - return o(t) + ""; - }) : function() { - return b; - }; - } - return function(t) { - for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; - } - var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; - d3.interpolate = d3_interpolate; - function d3_interpolate(a, b) { - var i = d3.interpolators.length, f; - while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; - return f; - } - d3.interpolators = [ function(a, b) { - var t = typeof b; - return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); - } ]; - d3.interpolateArray = d3_interpolateArray; - function d3_interpolateArray(a, b) { - var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; - for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); - for (;i < na; ++i) c[i] = a[i]; - for (;i < nb; ++i) c[i] = b[i]; - return function(t) { - for (i = 0; i < n0; ++i) c[i] = x[i](t); - return c; - }; - } - var d3_ease_default = function() { - return d3_identity; - }; - var d3_ease = d3.map({ - linear: d3_ease_default, - poly: d3_ease_poly, - quad: function() { - return d3_ease_quad; - }, - cubic: function() { - return d3_ease_cubic; - }, - sin: function() { - return d3_ease_sin; - }, - exp: function() { - return d3_ease_exp; - }, - circle: function() { - return d3_ease_circle; - }, - elastic: d3_ease_elastic, - back: d3_ease_back, - bounce: function() { - return d3_ease_bounce; - } - }); - var d3_ease_mode = d3.map({ - "in": d3_identity, - out: d3_ease_reverse, - "in-out": d3_ease_reflect, - "out-in": function(f) { - return d3_ease_reflect(d3_ease_reverse(f)); - } - }); - d3.ease = function(name) { - var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; - t = d3_ease.get(t) || d3_ease_default; - m = d3_ease_mode.get(m) || d3_identity; - return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); - }; - function d3_ease_clamp(f) { - return function(t) { - return t <= 0 ? 0 : t >= 1 ? 1 : f(t); - }; - } - function d3_ease_reverse(f) { - return function(t) { - return 1 - f(1 - t); - }; - } - function d3_ease_reflect(f) { - return function(t) { - return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); - }; - } - function d3_ease_quad(t) { - return t * t; - } - function d3_ease_cubic(t) { - return t * t * t; - } - function d3_ease_cubicInOut(t) { - if (t <= 0) return 0; - if (t >= 1) return 1; - var t2 = t * t, t3 = t2 * t; - return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); - } - function d3_ease_poly(e) { - return function(t) { - return Math.pow(t, e); - }; - } - function d3_ease_sin(t) { - return 1 - Math.cos(t * π / 2); - } - function d3_ease_exp(t) { - return Math.pow(2, 10 * (t - 1)); - } - function d3_ease_circle(t) { - return 1 - Math.sqrt(1 - t * t); - } - function d3_ease_elastic(a, p) { - var s; - if (arguments.length < 2) p = .45; - if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; - return function(t) { - return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); - }; - } - function d3_ease_back(s) { - if (!s) s = 1.70158; - return function(t) { - return t * t * ((s + 1) * t - s); - }; - } - function d3_ease_bounce(t) { - return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; - } - d3.interpolateHcl = d3_interpolateHcl; - function d3_interpolateHcl(a, b) { - a = d3.hcl(a); - b = d3.hcl(b); - var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; - if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; - if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; - return function(t) { - return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; - }; - } - d3.interpolateHsl = d3_interpolateHsl; - function d3_interpolateHsl(a, b) { - a = d3.hsl(a); - b = d3.hsl(b); - var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; - if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; - if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; - return function(t) { - return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; - }; - } - d3.interpolateLab = d3_interpolateLab; - function d3_interpolateLab(a, b) { - a = d3.lab(a); - b = d3.lab(b); - var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; - return function(t) { - return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; - }; - } - d3.interpolateRound = d3_interpolateRound; - function d3_interpolateRound(a, b) { - b -= a; - return function(t) { - return Math.round(a + b * t); - }; - } - d3.transform = function(string) { - var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); - return (d3.transform = function(string) { - if (string != null) { - g.setAttribute("transform", string); - var t = g.transform.baseVal.consolidate(); - } - return new d3_transform(t ? t.matrix : d3_transformIdentity); - })(string); - }; - function d3_transform(m) { - var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; - if (r0[0] * r1[1] < r1[0] * r0[1]) { - r0[0] *= -1; - r0[1] *= -1; - kx *= -1; - kz *= -1; - } - this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; - this.translate = [ m.e, m.f ]; - this.scale = [ kx, ky ]; - this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; - } - d3_transform.prototype.toString = function() { - return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; - }; - function d3_transformDot(a, b) { - return a[0] * b[0] + a[1] * b[1]; - } - function d3_transformNormalize(a) { - var k = Math.sqrt(d3_transformDot(a, a)); - if (k) { - a[0] /= k; - a[1] /= k; - } - return k; - } - function d3_transformCombine(a, b, k) { - a[0] += k * b[0]; - a[1] += k * b[1]; - return a; - } - var d3_transformIdentity = { - a: 1, - b: 0, - c: 0, - d: 1, - e: 0, - f: 0 - }; - d3.interpolateTransform = d3_interpolateTransform; - function d3_interpolateTransform(a, b) { - var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; - if (ta[0] != tb[0] || ta[1] != tb[1]) { - s.push("translate(", null, ",", null, ")"); - q.push({ - i: 1, - x: d3_interpolateNumber(ta[0], tb[0]) - }, { - i: 3, - x: d3_interpolateNumber(ta[1], tb[1]) - }); - } else if (tb[0] || tb[1]) { - s.push("translate(" + tb + ")"); - } else { - s.push(""); - } - if (ra != rb) { - if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; - q.push({ - i: s.push(s.pop() + "rotate(", null, ")") - 2, - x: d3_interpolateNumber(ra, rb) - }); - } else if (rb) { - s.push(s.pop() + "rotate(" + rb + ")"); - } - if (wa != wb) { - q.push({ - i: s.push(s.pop() + "skewX(", null, ")") - 2, - x: d3_interpolateNumber(wa, wb) - }); - } else if (wb) { - s.push(s.pop() + "skewX(" + wb + ")"); - } - if (ka[0] != kb[0] || ka[1] != kb[1]) { - n = s.push(s.pop() + "scale(", null, ",", null, ")"); - q.push({ - i: n - 4, - x: d3_interpolateNumber(ka[0], kb[0]) - }, { - i: n - 2, - x: d3_interpolateNumber(ka[1], kb[1]) - }); - } else if (kb[0] != 1 || kb[1] != 1) { - s.push(s.pop() + "scale(" + kb + ")"); - } - n = q.length; - return function(t) { - var i = -1, o; - while (++i < n) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; - } - function d3_uninterpolateNumber(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return (x - a) * b; - }; - } - function d3_uninterpolateClamp(a, b) { - b = b - (a = +a) ? 1 / (b - a) : 0; - return function(x) { - return Math.max(0, Math.min(1, (x - a) * b)); - }; - } - d3.layout = {}; - d3.layout.bundle = function() { - return function(links) { - var paths = [], i = -1, n = links.length; - while (++i < n) paths.push(d3_layout_bundlePath(links[i])); - return paths; - }; - }; - function d3_layout_bundlePath(link) { - var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; - while (start !== lca) { - start = start.parent; - points.push(start); - } - var k = points.length; - while (end !== lca) { - points.splice(k, 0, end); - end = end.parent; - } - return points; - } - function d3_layout_bundleAncestors(node) { - var ancestors = [], parent = node.parent; - while (parent != null) { - ancestors.push(node); - node = parent; - parent = parent.parent; - } - ancestors.push(node); - return ancestors; - } - function d3_layout_bundleLeastCommonAncestor(a, b) { - if (a === b) return a; - var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; - while (aNode === bNode) { - sharedNode = aNode; - aNode = aNodes.pop(); - bNode = bNodes.pop(); - } - return sharedNode; - } - d3.layout.chord = function() { - var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; - function relayout() { - var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; - chords = []; - groups = []; - k = 0, i = -1; - while (++i < n) { - x = 0, j = -1; - while (++j < n) { - x += matrix[i][j]; - } - groupSums.push(x); - subgroupIndex.push(d3.range(n)); - k += x; - } - if (sortGroups) { - groupIndex.sort(function(a, b) { - return sortGroups(groupSums[a], groupSums[b]); - }); - } - if (sortSubgroups) { - subgroupIndex.forEach(function(d, i) { - d.sort(function(a, b) { - return sortSubgroups(matrix[i][a], matrix[i][b]); - }); - }); - } - k = (2 * π - padding * n) / k; - x = 0, i = -1; - while (++i < n) { - x0 = x, j = -1; - while (++j < n) { - var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; - subgroups[di + "-" + dj] = { - index: di, - subindex: dj, - startAngle: a0, - endAngle: a1, - value: v - }; - } - groups[di] = { - index: di, - startAngle: x0, - endAngle: x, - value: (x - x0) / k - }; - x += padding; - } - i = -1; - while (++i < n) { - j = i - 1; - while (++j < n) { - var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; - if (source.value || target.value) { - chords.push(source.value < target.value ? { - source: target, - target: source - } : { - source: source, - target: target - }); - } - } - } - if (sortChords) resort(); - } - function resort() { - chords.sort(function(a, b) { - return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); - }); - } - chord.matrix = function(x) { - if (!arguments.length) return matrix; - n = (matrix = x) && matrix.length; - chords = groups = null; - return chord; - }; - chord.padding = function(x) { - if (!arguments.length) return padding; - padding = x; - chords = groups = null; - return chord; - }; - chord.sortGroups = function(x) { - if (!arguments.length) return sortGroups; - sortGroups = x; - chords = groups = null; - return chord; - }; - chord.sortSubgroups = function(x) { - if (!arguments.length) return sortSubgroups; - sortSubgroups = x; - chords = null; - return chord; - }; - chord.sortChords = function(x) { - if (!arguments.length) return sortChords; - sortChords = x; - if (chords) resort(); - return chord; - }; - chord.chords = function() { - if (!chords) relayout(); - return chords; - }; - chord.groups = function() { - if (!groups) relayout(); - return groups; - }; - return chord; - }; - d3.layout.force = function() { - var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; - function repulse(node) { - return function(quad, x1, _, x2) { - if (quad.point !== node) { - var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); - if ((x2 - x1) * dn < theta) { - var k = quad.charge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - return true; - } - if (quad.point && isFinite(dn)) { - var k = quad.pointCharge * dn * dn; - node.px -= dx * k; - node.py -= dy * k; - } - } - return !quad.charge; - }; - } - force.tick = function() { - if ((alpha *= .99) < .005) { - event.end({ - type: "end", - alpha: alpha = 0 - }); - return true; - } - var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; - for (i = 0; i < m; ++i) { - o = links[i]; - s = o.source; - t = o.target; - x = t.x - s.x; - y = t.y - s.y; - if (l = x * x + y * y) { - l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; - x *= l; - y *= l; - t.x -= x * (k = s.weight / (t.weight + s.weight)); - t.y -= y * k; - s.x += x * (k = 1 - k); - s.y += y * k; - } - } - if (k = alpha * gravity) { - x = size[0] / 2; - y = size[1] / 2; - i = -1; - if (k) while (++i < n) { - o = nodes[i]; - o.x += (x - o.x) * k; - o.y += (y - o.y) * k; - } - } - if (charge) { - d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); - i = -1; - while (++i < n) { - if (!(o = nodes[i]).fixed) { - q.visit(repulse(o)); - } - } - } - i = -1; - while (++i < n) { - o = nodes[i]; - if (o.fixed) { - o.x = o.px; - o.y = o.py; - } else { - o.x -= (o.px - (o.px = o.x)) * friction; - o.y -= (o.py - (o.py = o.y)) * friction; - } - } - event.tick({ - type: "tick", - alpha: alpha - }); - }; - force.nodes = function(x) { - if (!arguments.length) return nodes; - nodes = x; - return force; - }; - force.links = function(x) { - if (!arguments.length) return links; - links = x; - return force; - }; - force.size = function(x) { - if (!arguments.length) return size; - size = x; - return force; - }; - force.linkDistance = function(x) { - if (!arguments.length) return linkDistance; - linkDistance = typeof x === "function" ? x : +x; - return force; - }; - force.distance = force.linkDistance; - force.linkStrength = function(x) { - if (!arguments.length) return linkStrength; - linkStrength = typeof x === "function" ? x : +x; - return force; - }; - force.friction = function(x) { - if (!arguments.length) return friction; - friction = +x; - return force; - }; - force.charge = function(x) { - if (!arguments.length) return charge; - charge = typeof x === "function" ? x : +x; - return force; - }; - force.gravity = function(x) { - if (!arguments.length) return gravity; - gravity = +x; - return force; - }; - force.theta = function(x) { - if (!arguments.length) return theta; - theta = +x; - return force; - }; - force.alpha = function(x) { - if (!arguments.length) return alpha; - x = +x; - if (alpha) { - if (x > 0) alpha = x; else alpha = 0; - } else if (x > 0) { - event.start({ - type: "start", - alpha: alpha = x - }); - d3.timer(force.tick); - } - return force; - }; - force.start = function() { - var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; - for (i = 0; i < n; ++i) { - (o = nodes[i]).index = i; - o.weight = 0; - } - for (i = 0; i < m; ++i) { - o = links[i]; - if (typeof o.source == "number") o.source = nodes[o.source]; - if (typeof o.target == "number") o.target = nodes[o.target]; - ++o.source.weight; - ++o.target.weight; - } - for (i = 0; i < n; ++i) { - o = nodes[i]; - if (isNaN(o.x)) o.x = position("x", w); - if (isNaN(o.y)) o.y = position("y", h); - if (isNaN(o.px)) o.px = o.x; - if (isNaN(o.py)) o.py = o.y; - } - distances = []; - if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; - strengths = []; - if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; - charges = []; - if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; - function position(dimension, size) { - var neighbors = neighbor(i), j = -1, m = neighbors.length, x; - while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; - return Math.random() * size; - } - function neighbor() { - if (!neighbors) { - neighbors = []; - for (j = 0; j < n; ++j) { - neighbors[j] = []; - } - for (j = 0; j < m; ++j) { - var o = links[j]; - neighbors[o.source.index].push(o.target); - neighbors[o.target.index].push(o.source); - } - } - return neighbors[i]; - } - return force.resume(); - }; - force.resume = function() { - return force.alpha(.1); - }; - force.stop = function() { - return force.alpha(0); - }; - force.drag = function() { - if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); - if (!arguments.length) return drag; - this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); - }; - function dragmove(d) { - d.px = d3.event.x, d.py = d3.event.y; - force.resume(); - } - return d3.rebind(force, event, "on"); - }; - function d3_layout_forceDragstart(d) { - d.fixed |= 2; - } - function d3_layout_forceDragend(d) { - d.fixed &= ~6; - } - function d3_layout_forceMouseover(d) { - d.fixed |= 4; - d.px = d.x, d.py = d.y; - } - function d3_layout_forceMouseout(d) { - d.fixed &= ~4; - } - function d3_layout_forceAccumulate(quad, alpha, charges) { - var cx = 0, cy = 0; - quad.charge = 0; - if (!quad.leaf) { - var nodes = quad.nodes, n = nodes.length, i = -1, c; - while (++i < n) { - c = nodes[i]; - if (c == null) continue; - d3_layout_forceAccumulate(c, alpha, charges); - quad.charge += c.charge; - cx += c.charge * c.cx; - cy += c.charge * c.cy; - } - } - if (quad.point) { - if (!quad.leaf) { - quad.point.x += Math.random() - .5; - quad.point.y += Math.random() - .5; - } - var k = alpha * charges[quad.point.index]; - quad.charge += quad.pointCharge = k; - cx += k * quad.point.x; - cy += k * quad.point.y; - } - quad.cx = cx / quad.charge; - quad.cy = cy / quad.charge; - } - var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; - d3.layout.hierarchy = function() { - var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; - function recurse(node, depth, nodes) { - var childs = children.call(hierarchy, node, depth); - node.depth = depth; - nodes.push(node); - if (childs && (n = childs.length)) { - var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; - while (++i < n) { - d = recurse(childs[i], j, nodes); - d.parent = node; - c.push(d); - v += d.value; - } - if (sort) c.sort(sort); - if (value) node.value = v; - } else if (value) { - node.value = +value.call(hierarchy, node, depth) || 0; - } - return node; - } - function revalue(node, depth) { - var children = node.children, v = 0; - if (children && (n = children.length)) { - var i = -1, n, j = depth + 1; - while (++i < n) v += revalue(children[i], j); - } else if (value) { - v = +value.call(hierarchy, node, depth) || 0; - } - if (value) node.value = v; - return v; - } - function hierarchy(d) { - var nodes = []; - recurse(d, 0, nodes); - return nodes; - } - hierarchy.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return hierarchy; - }; - hierarchy.children = function(x) { - if (!arguments.length) return children; - children = x; - return hierarchy; - }; - hierarchy.value = function(x) { - if (!arguments.length) return value; - value = x; - return hierarchy; - }; - hierarchy.revalue = function(root) { - revalue(root, 0); - return root; - }; - return hierarchy; - }; - function d3_layout_hierarchyRebind(object, hierarchy) { - d3.rebind(object, hierarchy, "sort", "children", "value"); - object.nodes = object; - object.links = d3_layout_hierarchyLinks; - return object; - } - function d3_layout_hierarchyChildren(d) { - return d.children; - } - function d3_layout_hierarchyValue(d) { - return d.value; - } - function d3_layout_hierarchySort(a, b) { - return b.value - a.value; - } - function d3_layout_hierarchyLinks(nodes) { - return d3.merge(nodes.map(function(parent) { - return (parent.children || []).map(function(child) { - return { - source: parent, - target: child - }; - }); - })); - } - d3.layout.partition = function() { - var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; - function position(node, x, dx, dy) { - var children = node.children; - node.x = x; - node.y = node.depth * dy; - node.dx = dx; - node.dy = dy; - if (children && (n = children.length)) { - var i = -1, n, c, d; - dx = node.value ? dx / node.value : 0; - while (++i < n) { - position(c = children[i], x, d = c.value * dx, dy); - x += d; - } - } - } - function depth(node) { - var children = node.children, d = 0; - if (children && (n = children.length)) { - var i = -1, n; - while (++i < n) d = Math.max(d, depth(children[i])); - } - return 1 + d; - } - function partition(d, i) { - var nodes = hierarchy.call(this, d, i); - position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); - return nodes; - } - partition.size = function(x) { - if (!arguments.length) return size; - size = x; - return partition; - }; - return d3_layout_hierarchyRebind(partition, hierarchy); - }; - d3.layout.pie = function() { - var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; - function pie(data) { - var values = data.map(function(d, i) { - return +value.call(pie, d, i); - }); - var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); - var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); - var index = d3.range(data.length); - if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { - return values[j] - values[i]; - } : function(i, j) { - return sort(data[i], data[j]); - }); - var arcs = []; - index.forEach(function(i) { - var d; - arcs[i] = { - data: data[i], - value: d = values[i], - startAngle: a, - endAngle: a += d * k - }; - }); - return arcs; - } - pie.value = function(x) { - if (!arguments.length) return value; - value = x; - return pie; - }; - pie.sort = function(x) { - if (!arguments.length) return sort; - sort = x; - return pie; - }; - pie.startAngle = function(x) { - if (!arguments.length) return startAngle; - startAngle = x; - return pie; - }; - pie.endAngle = function(x) { - if (!arguments.length) return endAngle; - endAngle = x; - return pie; - }; - return pie; - }; - var d3_layout_pieSortByValue = {}; - d3.layout.stack = function() { - var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; - function stack(data, index) { - var series = data.map(function(d, i) { - return values.call(stack, d, i); - }); - var points = series.map(function(d) { - return d.map(function(v, i) { - return [ x.call(stack, v, i), y.call(stack, v, i) ]; - }); - }); - var orders = order.call(stack, points, index); - series = d3.permute(series, orders); - points = d3.permute(points, orders); - var offsets = offset.call(stack, points, index); - var n = series.length, m = series[0].length, i, j, o; - for (j = 0; j < m; ++j) { - out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); - for (i = 1; i < n; ++i) { - out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); - } - } - return data; - } - stack.values = function(x) { - if (!arguments.length) return values; - values = x; - return stack; - }; - stack.order = function(x) { - if (!arguments.length) return order; - order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; - return stack; - }; - stack.offset = function(x) { - if (!arguments.length) return offset; - offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; - return stack; - }; - stack.x = function(z) { - if (!arguments.length) return x; - x = z; - return stack; - }; - stack.y = function(z) { - if (!arguments.length) return y; - y = z; - return stack; - }; - stack.out = function(z) { - if (!arguments.length) return out; - out = z; - return stack; - }; - return stack; - }; - function d3_layout_stackX(d) { - return d.x; - } - function d3_layout_stackY(d) { - return d.y; - } - function d3_layout_stackOut(d, y0, y) { - d.y0 = y0; - d.y = y; - } - var d3_layout_stackOrders = d3.map({ - "inside-out": function(data) { - var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { - return max[a] - max[b]; - }), top = 0, bottom = 0, tops = [], bottoms = []; - for (i = 0; i < n; ++i) { - j = index[i]; - if (top < bottom) { - top += sums[j]; - tops.push(j); - } else { - bottom += sums[j]; - bottoms.push(j); - } - } - return bottoms.reverse().concat(tops); - }, - reverse: function(data) { - return d3.range(data.length).reverse(); - }, - "default": d3_layout_stackOrderDefault - }); - var d3_layout_stackOffsets = d3.map({ - silhouette: function(data) { - var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o > max) max = o; - sums.push(o); - } - for (j = 0; j < m; ++j) { - y0[j] = (max - sums[j]) / 2; - } - return y0; - }, - wiggle: function(data) { - var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; - y0[0] = o = o0 = 0; - for (j = 1; j < m; ++j) { - for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; - for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { - for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { - s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; - } - s2 += s3 * data[i][j][1]; - } - y0[j] = o -= s1 ? s2 / s1 * dx : 0; - if (o < o0) o0 = o; - } - for (j = 0; j < m; ++j) y0[j] -= o0; - return y0; - }, - expand: function(data) { - var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; - for (j = 0; j < m; ++j) { - for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; - if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; - } - for (j = 0; j < m; ++j) y0[j] = 0; - return y0; - }, - zero: d3_layout_stackOffsetZero - }); - function d3_layout_stackOrderDefault(data) { - return d3.range(data.length); - } - function d3_layout_stackOffsetZero(data) { - var j = -1, m = data[0].length, y0 = []; - while (++j < m) y0[j] = 0; - return y0; - } - function d3_layout_stackMaxIndex(array) { - var i = 1, j = 0, v = array[0][1], k, n = array.length; - for (;i < n; ++i) { - if ((k = array[i][1]) > v) { - j = i; - v = k; - } - } - return j; - } - function d3_layout_stackReduceSum(d) { - return d.reduce(d3_layout_stackSum, 0); - } - function d3_layout_stackSum(p, d) { - return p + d[1]; - } - d3.layout.histogram = function() { - var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; - function histogram(data, i) { - var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; - while (++i < m) { - bin = bins[i] = []; - bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); - bin.y = 0; - } - if (m > 0) { - i = -1; - while (++i < n) { - x = values[i]; - if (x >= range[0] && x <= range[1]) { - bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; - bin.y += k; - bin.push(data[i]); - } - } - } - return bins; - } - histogram.value = function(x) { - if (!arguments.length) return valuer; - valuer = x; - return histogram; - }; - histogram.range = function(x) { - if (!arguments.length) return ranger; - ranger = d3_functor(x); - return histogram; - }; - histogram.bins = function(x) { - if (!arguments.length) return binner; - binner = typeof x === "number" ? function(range) { - return d3_layout_histogramBinFixed(range, x); - } : d3_functor(x); - return histogram; - }; - histogram.frequency = function(x) { - if (!arguments.length) return frequency; - frequency = !!x; - return histogram; - }; - return histogram; - }; - function d3_layout_histogramBinSturges(range, values) { - return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); - } - function d3_layout_histogramBinFixed(range, n) { - var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; - while (++x <= n) f[x] = m * x + b; - return f; - } - function d3_layout_histogramRange(values) { - return [ d3.min(values), d3.max(values) ]; - } - d3.layout.tree = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; - function tree(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0]; - function firstWalk(node, previousSibling) { - var children = node.children, layout = node._tree; - if (children && (n = children.length)) { - var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; - while (++i < n) { - child = children[i]; - firstWalk(child, previousChild); - ancestor = apportion(child, previousChild, ancestor); - previousChild = child; - } - d3_layout_treeShift(node); - var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - layout.mod = layout.prelim - midpoint; - } else { - layout.prelim = midpoint; - } - } else { - if (previousSibling) { - layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); - } - } - } - function secondWalk(node, x) { - node.x = node._tree.prelim + x; - var children = node.children; - if (children && (n = children.length)) { - var i = -1, n; - x += node._tree.mod; - while (++i < n) { - secondWalk(children[i], x); - } - } - } - function apportion(node, previousSibling, ancestor) { - if (previousSibling) { - var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; - while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { - vom = d3_layout_treeLeft(vom); - vop = d3_layout_treeRight(vop); - vop._tree.ancestor = node; - shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); - if (shift > 0) { - d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); - sip += shift; - sop += shift; - } - sim += vim._tree.mod; - sip += vip._tree.mod; - som += vom._tree.mod; - sop += vop._tree.mod; - } - if (vim && !d3_layout_treeRight(vop)) { - vop._tree.thread = vim; - vop._tree.mod += sim - sop; - } - if (vip && !d3_layout_treeLeft(vom)) { - vom._tree.thread = vip; - vom._tree.mod += sip - som; - ancestor = node; - } - } - return ancestor; - } - d3_layout_treeVisitAfter(root, function(node, previousSibling) { - node._tree = { - ancestor: node, - prelim: 0, - mod: 0, - change: 0, - shift: 0, - number: previousSibling ? previousSibling._tree.number + 1 : 0 - }; - }); - firstWalk(root); - secondWalk(root, -root._tree.prelim); - var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; - d3_layout_treeVisitAfter(root, nodeSize ? function(node) { - node.x *= size[0]; - node.y = node.depth * size[1]; - delete node._tree; - } : function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = node.depth / y1 * size[1]; - delete node._tree; - }); - return nodes; - } - tree.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return tree; - }; - tree.size = function(x) { - if (!arguments.length) return nodeSize ? null : size; - nodeSize = (size = x) == null; - return tree; - }; - tree.nodeSize = function(x) { - if (!arguments.length) return nodeSize ? size : null; - nodeSize = (size = x) != null; - return tree; - }; - return d3_layout_hierarchyRebind(tree, hierarchy); - }; - function d3_layout_treeSeparation(a, b) { - return a.parent == b.parent ? 1 : 2; - } - function d3_layout_treeLeft(node) { - var children = node.children; - return children && children.length ? children[0] : node._tree.thread; - } - function d3_layout_treeRight(node) { - var children = node.children, n; - return children && (n = children.length) ? children[n - 1] : node._tree.thread; - } - function d3_layout_treeSearch(node, compare) { - var children = node.children; - if (children && (n = children.length)) { - var child, n, i = -1; - while (++i < n) { - if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { - node = child; - } - } - } - return node; - } - function d3_layout_treeRightmost(a, b) { - return a.x - b.x; - } - function d3_layout_treeLeftmost(a, b) { - return b.x - a.x; - } - function d3_layout_treeDeepest(a, b) { - return a.depth - b.depth; - } - function d3_layout_treeVisitAfter(node, callback) { - function visit(node, previousSibling) { - var children = node.children; - if (children && (n = children.length)) { - var child, previousChild = null, i = -1, n; - while (++i < n) { - child = children[i]; - visit(child, previousChild); - previousChild = child; - } - } - callback(node, previousSibling); - } - visit(node, null); - } - function d3_layout_treeShift(node) { - var shift = 0, change = 0, children = node.children, i = children.length, child; - while (--i >= 0) { - child = children[i]._tree; - child.prelim += shift; - child.mod += shift; - shift += child.shift + (change += child.change); - } - } - function d3_layout_treeMove(ancestor, node, shift) { - ancestor = ancestor._tree; - node = node._tree; - var change = shift / (node.number - ancestor.number); - ancestor.change += change; - node.change -= change; - node.shift += shift; - node.prelim += shift; - node.mod += shift; - } - function d3_layout_treeAncestor(vim, node, ancestor) { - return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; - } - d3.layout.pack = function() { - var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; - function pack(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { - return radius; - }; - root.x = root.y = 0; - d3_layout_treeVisitAfter(root, function(d) { - d.r = +r(d.value); - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - if (padding) { - var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; - d3_layout_treeVisitAfter(root, function(d) { - d.r += dr; - }); - d3_layout_treeVisitAfter(root, d3_layout_packSiblings); - d3_layout_treeVisitAfter(root, function(d) { - d.r -= dr; - }); - } - d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); - return nodes; - } - pack.size = function(_) { - if (!arguments.length) return size; - size = _; - return pack; - }; - pack.radius = function(_) { - if (!arguments.length) return radius; - radius = _ == null || typeof _ === "function" ? _ : +_; - return pack; - }; - pack.padding = function(_) { - if (!arguments.length) return padding; - padding = +_; - return pack; - }; - return d3_layout_hierarchyRebind(pack, hierarchy); - }; - function d3_layout_packSort(a, b) { - return a.value - b.value; - } - function d3_layout_packInsert(a, b) { - var c = a._pack_next; - a._pack_next = b; - b._pack_prev = a; - b._pack_next = c; - c._pack_prev = b; - } - function d3_layout_packSplice(a, b) { - a._pack_next = b; - b._pack_prev = a; - } - function d3_layout_packIntersects(a, b) { - var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; - return .999 * dr * dr > dx * dx + dy * dy; - } - function d3_layout_packSiblings(node) { - if (!(nodes = node.children) || !(n = nodes.length)) return; - var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; - function bound(node) { - xMin = Math.min(node.x - node.r, xMin); - xMax = Math.max(node.x + node.r, xMax); - yMin = Math.min(node.y - node.r, yMin); - yMax = Math.max(node.y + node.r, yMax); - } - nodes.forEach(d3_layout_packLink); - a = nodes[0]; - a.x = -a.r; - a.y = 0; - bound(a); - if (n > 1) { - b = nodes[1]; - b.x = b.r; - b.y = 0; - bound(b); - if (n > 2) { - c = nodes[2]; - d3_layout_packPlace(a, b, c); - bound(c); - d3_layout_packInsert(a, c); - a._pack_prev = c; - d3_layout_packInsert(c, b); - b = a._pack_next; - for (i = 3; i < n; i++) { - d3_layout_packPlace(a, b, c = nodes[i]); - var isect = 0, s1 = 1, s2 = 1; - for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { - if (d3_layout_packIntersects(j, c)) { - isect = 1; - break; - } - } - if (isect == 1) { - for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { - if (d3_layout_packIntersects(k, c)) { - break; - } - } - } - if (isect) { - if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); - i--; - } else { - d3_layout_packInsert(a, c); - b = c; - bound(c); - } - } - } - } - var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; - for (i = 0; i < n; i++) { - c = nodes[i]; - c.x -= cx; - c.y -= cy; - cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); - } - node.r = cr; - nodes.forEach(d3_layout_packUnlink); - } - function d3_layout_packLink(node) { - node._pack_next = node._pack_prev = node; - } - function d3_layout_packUnlink(node) { - delete node._pack_next; - delete node._pack_prev; - } - function d3_layout_packTransform(node, x, y, k) { - var children = node.children; - node.x = x += k * node.x; - node.y = y += k * node.y; - node.r *= k; - if (children) { - var i = -1, n = children.length; - while (++i < n) d3_layout_packTransform(children[i], x, y, k); - } - } - function d3_layout_packPlace(a, b, c) { - var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; - if (db && (dx || dy)) { - var da = b.r + c.r, dc = dx * dx + dy * dy; - da *= da; - db *= db; - var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); - c.x = a.x + x * dx + y * dy; - c.y = a.y + x * dy - y * dx; - } else { - c.x = a.x + db; - c.y = a.y; - } - } - d3.layout.cluster = function() { - var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; - function cluster(d, i) { - var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; - d3_layout_treeVisitAfter(root, function(node) { - var children = node.children; - if (children && children.length) { - node.x = d3_layout_clusterX(children); - node.y = d3_layout_clusterY(children); - } else { - node.x = previousNode ? x += separation(node, previousNode) : 0; - node.y = 0; - previousNode = node; - } - }); - var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; - d3_layout_treeVisitAfter(root, nodeSize ? function(node) { - node.x = (node.x - root.x) * size[0]; - node.y = (root.y - node.y) * size[1]; - } : function(node) { - node.x = (node.x - x0) / (x1 - x0) * size[0]; - node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; - }); - return nodes; - } - cluster.separation = function(x) { - if (!arguments.length) return separation; - separation = x; - return cluster; - }; - cluster.size = function(x) { - if (!arguments.length) return nodeSize ? null : size; - nodeSize = (size = x) == null; - return cluster; - }; - cluster.nodeSize = function(x) { - if (!arguments.length) return nodeSize ? size : null; - nodeSize = (size = x) != null; - return cluster; - }; - return d3_layout_hierarchyRebind(cluster, hierarchy); - }; - function d3_layout_clusterY(children) { - return 1 + d3.max(children, function(child) { - return child.y; - }); - } - function d3_layout_clusterX(children) { - return children.reduce(function(x, child) { - return x + child.x; - }, 0) / children.length; - } - function d3_layout_clusterLeft(node) { - var children = node.children; - return children && children.length ? d3_layout_clusterLeft(children[0]) : node; - } - function d3_layout_clusterRight(node) { - var children = node.children, n; - return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; - } - d3.layout.treemap = function() { - var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); - function scale(children, k) { - var i = -1, n = children.length, child, area; - while (++i < n) { - area = (child = children[i]).value * (k < 0 ? 0 : k); - child.area = isNaN(area) || area <= 0 ? 0 : area; - } - } - function squarify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while ((n = remaining.length) > 0) { - row.push(child = remaining[n - 1]); - row.area += child.area; - if (mode !== "squarify" || (score = worst(row, u)) <= best) { - remaining.pop(); - best = score; - } else { - row.area -= row.pop().area; - position(row, u, rect, false); - u = Math.min(rect.dx, rect.dy); - row.length = row.area = 0; - best = Infinity; - } - } - if (row.length) { - position(row, u, rect, true); - row.length = row.area = 0; - } - children.forEach(squarify); - } - } - function stickify(node) { - var children = node.children; - if (children && children.length) { - var rect = pad(node), remaining = children.slice(), child, row = []; - scale(remaining, rect.dx * rect.dy / node.value); - row.area = 0; - while (child = remaining.pop()) { - row.push(child); - row.area += child.area; - if (child.z != null) { - position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); - row.length = row.area = 0; - } - } - children.forEach(stickify); - } - } - function worst(row, u) { - var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; - while (++i < n) { - if (!(r = row[i].area)) continue; - if (r < rmin) rmin = r; - if (r > rmax) rmax = r; - } - s *= s; - u *= u; - return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; - } - function position(row, u, rect, flush) { - var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; - if (u == rect.dx) { - if (flush || v > rect.dy) v = rect.dy; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dy = v; - x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); - } - o.z = true; - o.dx += rect.x + rect.dx - x; - rect.y += v; - rect.dy -= v; - } else { - if (flush || v > rect.dx) v = rect.dx; - while (++i < n) { - o = row[i]; - o.x = x; - o.y = y; - o.dx = v; - y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); - } - o.z = false; - o.dy += rect.y + rect.dy - y; - rect.x += v; - rect.dx -= v; - } - } - function treemap(d) { - var nodes = stickies || hierarchy(d), root = nodes[0]; - root.x = 0; - root.y = 0; - root.dx = size[0]; - root.dy = size[1]; - if (stickies) hierarchy.revalue(root); - scale([ root ], root.dx * root.dy / root.value); - (stickies ? stickify : squarify)(root); - if (sticky) stickies = nodes; - return nodes; - } - treemap.size = function(x) { - if (!arguments.length) return size; - size = x; - return treemap; - }; - treemap.padding = function(x) { - if (!arguments.length) return padding; - function padFunction(node) { - var p = x.call(treemap, node, node.depth); - return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); - } - function padConstant(node) { - return d3_layout_treemapPad(node, x); - } - var type; - pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], - padConstant) : padConstant; - return treemap; - }; - treemap.round = function(x) { - if (!arguments.length) return round != Number; - round = x ? Math.round : Number; - return treemap; - }; - treemap.sticky = function(x) { - if (!arguments.length) return sticky; - sticky = x; - stickies = null; - return treemap; - }; - treemap.ratio = function(x) { - if (!arguments.length) return ratio; - ratio = x; - return treemap; - }; - treemap.mode = function(x) { - if (!arguments.length) return mode; - mode = x + ""; - return treemap; - }; - return d3_layout_hierarchyRebind(treemap, hierarchy); - }; - function d3_layout_treemapPadNull(node) { - return { - x: node.x, - y: node.y, - dx: node.dx, - dy: node.dy - }; - } - function d3_layout_treemapPad(node, padding) { - var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; - if (dx < 0) { - x += dx / 2; - dx = 0; - } - if (dy < 0) { - y += dy / 2; - dy = 0; - } - return { - x: x, - y: y, - dx: dx, - dy: dy - }; - } - d3.random = { - normal: function(µ, σ) { - var n = arguments.length; - if (n < 2) σ = 1; - if (n < 1) µ = 0; - return function() { - var x, y, r; - do { - x = Math.random() * 2 - 1; - y = Math.random() * 2 - 1; - r = x * x + y * y; - } while (!r || r > 1); - return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); - }; - }, - logNormal: function() { - var random = d3.random.normal.apply(d3, arguments); - return function() { - return Math.exp(random()); - }; - }, - irwinHall: function(m) { - return function() { - for (var s = 0, j = 0; j < m; j++) s += Math.random(); - return s / m; - }; - } - }; - d3.scale = {}; - function d3_scaleExtent(domain) { - var start = domain[0], stop = domain[domain.length - 1]; - return start < stop ? [ start, stop ] : [ stop, start ]; - } - function d3_scaleRange(scale) { - return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); - } - function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { - var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); - return function(x) { - return i(u(x)); - }; - } - function d3_scale_nice(domain, nice) { - var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; - if (x1 < x0) { - dx = i0, i0 = i1, i1 = dx; - dx = x0, x0 = x1, x1 = dx; - } - domain[i0] = nice.floor(x0); - domain[i1] = nice.ceil(x1); - return domain; - } - function d3_scale_niceStep(step) { - return step ? { - floor: function(x) { - return Math.floor(x / step) * step; - }, - ceil: function(x) { - return Math.ceil(x / step) * step; - } - } : d3_scale_niceIdentity; - } - var d3_scale_niceIdentity = { - floor: d3_identity, - ceil: d3_identity - }; - function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { - var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; - if (domain[k] < domain[0]) { - domain = domain.slice().reverse(); - range = range.slice().reverse(); - } - while (++j <= k) { - u.push(uninterpolate(domain[j - 1], domain[j])); - i.push(interpolate(range[j - 1], range[j])); - } - return function(x) { - var j = d3.bisect(domain, x, 1, k) - 1; - return i[j](u[j](x)); - }; - } - d3.scale.linear = function() { - return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); - }; - function d3_scale_linear(domain, range, interpolate, clamp) { - var output, input; - function rescale() { - var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; - output = linear(domain, range, uninterpolate, interpolate); - input = linear(range, domain, uninterpolate, d3_interpolate); - return scale; - } - function scale(x) { - return output(x); - } - scale.invert = function(y) { - return input(y); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.map(Number); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.rangeRound = function(x) { - return scale.range(x).interpolate(d3_interpolateRound); - }; - scale.clamp = function(x) { - if (!arguments.length) return clamp; - clamp = x; - return rescale(); - }; - scale.interpolate = function(x) { - if (!arguments.length) return interpolate; - interpolate = x; - return rescale(); - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - scale.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - scale.nice = function(m) { - d3_scale_linearNice(domain, m); - return rescale(); - }; - scale.copy = function() { - return d3_scale_linear(domain, range, interpolate, clamp); - }; - return rescale(); - } - function d3_scale_linearRebind(scale, linear) { - return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); - } - function d3_scale_linearNice(domain, m) { - return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); - } - function d3_scale_linearNiceStep(domain) { - var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; - return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); - } - function d3_scale_linearTickRange(domain, m) { - var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; - if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; - extent[0] = Math.ceil(extent[0] / step) * step; - extent[1] = Math.floor(extent[1] / step) * step + step * .5; - extent[2] = step; - return extent; - } - function d3_scale_linearTicks(domain, m) { - return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); - } - function d3_scale_linearTickFormat(domain, m, format) { - var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); - return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { - return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); - }) : ",." + precision + "f"); - } - d3.scale.log = function() { - return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); - }; - function d3_scale_log(linear, base, positive, domain) { - function log(x) { - return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); - } - function pow(x) { - return positive ? Math.pow(base, x) : -Math.pow(base, -x); - } - function scale(x) { - return linear(log(x)); - } - scale.invert = function(x) { - return pow(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - positive = x[0] >= 0; - linear.domain((domain = x.map(Number)).map(log)); - return scale; - }; - scale.base = function(_) { - if (!arguments.length) return base; - base = +_; - linear.domain(domain.map(log)); - return scale; - }; - scale.nice = function() { - var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); - linear.domain(niced); - domain = niced.map(pow); - return scale; - }; - scale.ticks = function() { - var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; - if (isFinite(j - i)) { - if (positive) { - for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); - ticks.push(pow(i)); - } else { - ticks.push(pow(i)); - for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); - } - for (i = 0; ticks[i] < u; i++) {} - for (j = ticks.length; ticks[j - 1] > v; j--) {} - ticks = ticks.slice(i, j); - } - return ticks; - }; - scale.tickFormat = function(n, format) { - if (!arguments.length) return d3_scale_logFormat; - if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); - var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, - Math.floor), e; - return function(d) { - return d / pow(f(log(d) + e)) <= k ? format(d) : ""; - }; - }; - scale.copy = function() { - return d3_scale_log(linear.copy(), base, positive, domain); - }; - return d3_scale_linearRebind(scale, linear); - } - var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { - floor: function(x) { - return -Math.ceil(-x); - }, - ceil: function(x) { - return -Math.floor(-x); - } - }; - d3.scale.pow = function() { - return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); - }; - function d3_scale_pow(linear, exponent, domain) { - var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); - function scale(x) { - return linear(powp(x)); - } - scale.invert = function(x) { - return powb(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return domain; - linear.domain((domain = x.map(Number)).map(powp)); - return scale; - }; - scale.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - scale.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - scale.nice = function(m) { - return scale.domain(d3_scale_linearNice(domain, m)); - }; - scale.exponent = function(x) { - if (!arguments.length) return exponent; - powp = d3_scale_powPow(exponent = x); - powb = d3_scale_powPow(1 / exponent); - linear.domain(domain.map(powp)); - return scale; - }; - scale.copy = function() { - return d3_scale_pow(linear.copy(), exponent, domain); - }; - return d3_scale_linearRebind(scale, linear); - } - function d3_scale_powPow(e) { - return function(x) { - return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); - }; - } - d3.scale.sqrt = function() { - return d3.scale.pow().exponent(.5); - }; - d3.scale.ordinal = function() { - return d3_scale_ordinal([], { - t: "range", - a: [ [] ] - }); - }; - function d3_scale_ordinal(domain, ranger) { - var index, range, rangeBand; - function scale(x) { - return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; - } - function steps(start, step) { - return d3.range(domain.length).map(function(i) { - return start + step * i; - }); - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = []; - index = new d3_Map(); - var i = -1, n = x.length, xi; - while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); - return scale[ranger.t].apply(scale, ranger.a); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - rangeBand = 0; - ranger = { - t: "range", - a: arguments - }; - return scale; - }; - scale.rangePoints = function(x, padding) { - if (arguments.length < 2) padding = 0; - var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); - range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); - rangeBand = 0; - ranger = { - t: "rangePoints", - a: arguments - }; - return scale; - }; - scale.rangeBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); - range = steps(start + step * outerPadding, step); - if (reverse) range.reverse(); - rangeBand = step * (1 - padding); - ranger = { - t: "rangeBands", - a: arguments - }; - return scale; - }; - scale.rangeRoundBands = function(x, padding, outerPadding) { - if (arguments.length < 2) padding = 0; - if (arguments.length < 3) outerPadding = padding; - var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; - range = steps(start + Math.round(error / 2), step); - if (reverse) range.reverse(); - rangeBand = Math.round(step * (1 - padding)); - ranger = { - t: "rangeRoundBands", - a: arguments - }; - return scale; - }; - scale.rangeBand = function() { - return rangeBand; - }; - scale.rangeExtent = function() { - return d3_scaleExtent(ranger.a[0]); - }; - scale.copy = function() { - return d3_scale_ordinal(domain, ranger); - }; - return scale.domain(domain); - } - d3.scale.category10 = function() { - return d3.scale.ordinal().range(d3_category10); - }; - d3.scale.category20 = function() { - return d3.scale.ordinal().range(d3_category20); - }; - d3.scale.category20b = function() { - return d3.scale.ordinal().range(d3_category20b); - }; - d3.scale.category20c = function() { - return d3.scale.ordinal().range(d3_category20c); - }; - var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); - var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); - var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); - var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); - d3.scale.quantile = function() { - return d3_scale_quantile([], []); - }; - function d3_scale_quantile(domain, range) { - var thresholds; - function rescale() { - var k = 0, q = range.length; - thresholds = []; - while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); - return scale; - } - function scale(x) { - if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; - } - scale.domain = function(x) { - if (!arguments.length) return domain; - domain = x.filter(function(d) { - return !isNaN(d); - }).sort(d3.ascending); - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.quantiles = function() { - return thresholds; - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; - }; - scale.copy = function() { - return d3_scale_quantile(domain, range); - }; - return rescale(); - } - d3.scale.quantize = function() { - return d3_scale_quantize(0, 1, [ 0, 1 ]); - }; - function d3_scale_quantize(x0, x1, range) { - var kx, i; - function scale(x) { - return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; - } - function rescale() { - kx = range.length / (x1 - x0); - i = range.length - 1; - return scale; - } - scale.domain = function(x) { - if (!arguments.length) return [ x0, x1 ]; - x0 = +x[0]; - x1 = +x[x.length - 1]; - return rescale(); - }; - scale.range = function(x) { - if (!arguments.length) return range; - range = x; - return rescale(); - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - y = y < 0 ? NaN : y / kx + x0; - return [ y, y + 1 / kx ]; - }; - scale.copy = function() { - return d3_scale_quantize(x0, x1, range); - }; - return rescale(); - } - d3.scale.threshold = function() { - return d3_scale_threshold([ .5 ], [ 0, 1 ]); - }; - function d3_scale_threshold(domain, range) { - function scale(x) { - if (x <= x) return range[d3.bisect(domain, x)]; - } - scale.domain = function(_) { - if (!arguments.length) return domain; - domain = _; - return scale; - }; - scale.range = function(_) { - if (!arguments.length) return range; - range = _; - return scale; - }; - scale.invertExtent = function(y) { - y = range.indexOf(y); - return [ domain[y - 1], domain[y] ]; - }; - scale.copy = function() { - return d3_scale_threshold(domain, range); - }; - return scale; - } - d3.scale.identity = function() { - return d3_scale_identity([ 0, 1 ]); - }; - function d3_scale_identity(domain) { - function identity(x) { - return +x; - } - identity.invert = identity; - identity.domain = identity.range = function(x) { - if (!arguments.length) return domain; - domain = x.map(identity); - return identity; - }; - identity.ticks = function(m) { - return d3_scale_linearTicks(domain, m); - }; - identity.tickFormat = function(m, format) { - return d3_scale_linearTickFormat(domain, m, format); - }; - identity.copy = function() { - return d3_scale_identity(domain); - }; - return identity; - } - d3.svg.arc = function() { - var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function arc() { - var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, - a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); - return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; - } - arc.innerRadius = function(v) { - if (!arguments.length) return innerRadius; - innerRadius = d3_functor(v); - return arc; - }; - arc.outerRadius = function(v) { - if (!arguments.length) return outerRadius; - outerRadius = d3_functor(v); - return arc; - }; - arc.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return arc; - }; - arc.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return arc; - }; - arc.centroid = function() { - var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; - return [ Math.cos(a) * r, Math.sin(a) * r ]; - }; - return arc; - }; - var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; - function d3_svg_arcInnerRadius(d) { - return d.innerRadius; - } - function d3_svg_arcOuterRadius(d) { - return d.outerRadius; - } - function d3_svg_arcStartAngle(d) { - return d.startAngle; - } - function d3_svg_arcEndAngle(d) { - return d.endAngle; - } - d3.svg.line.radial = function() { - var line = d3_svg_line(d3_svg_lineRadial); - line.radius = line.x, delete line.x; - line.angle = line.y, delete line.y; - return line; - }; - function d3_svg_lineRadial(points) { - var point, i = -1, n = points.length, r, a; - while (++i < n) { - point = points[i]; - r = point[0]; - a = point[1] + d3_svg_arcOffset; - point[0] = r * Math.cos(a); - point[1] = r * Math.sin(a); - } - return points; - } - function d3_svg_area(projection) { - var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; - function area(data) { - var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { - return x; - } : d3_functor(x1), fy1 = y0 === y1 ? function() { - return y; - } : d3_functor(y1), x, y; - function segment() { - segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); - } - while (++i < n) { - if (defined.call(this, d = data[i], i)) { - points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); - points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); - } else if (points0.length) { - segment(); - points0 = []; - points1 = []; - } - } - if (points0.length) segment(); - return segments.length ? segments.join("") : null; - } - area.x = function(_) { - if (!arguments.length) return x1; - x0 = x1 = _; - return area; - }; - area.x0 = function(_) { - if (!arguments.length) return x0; - x0 = _; - return area; - }; - area.x1 = function(_) { - if (!arguments.length) return x1; - x1 = _; - return area; - }; - area.y = function(_) { - if (!arguments.length) return y1; - y0 = y1 = _; - return area; - }; - area.y0 = function(_) { - if (!arguments.length) return y0; - y0 = _; - return area; - }; - area.y1 = function(_) { - if (!arguments.length) return y1; - y1 = _; - return area; - }; - area.defined = function(_) { - if (!arguments.length) return defined; - defined = _; - return area; - }; - area.interpolate = function(_) { - if (!arguments.length) return interpolateKey; - if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; - interpolateReverse = interpolate.reverse || interpolate; - L = interpolate.closed ? "M" : "L"; - return area; - }; - area.tension = function(_) { - if (!arguments.length) return tension; - tension = _; - return area; - }; - return area; - } - d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; - d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; - d3.svg.area = function() { - return d3_svg_area(d3_identity); - }; - d3.svg.area.radial = function() { - var area = d3_svg_area(d3_svg_lineRadial); - area.radius = area.x, delete area.x; - area.innerRadius = area.x0, delete area.x0; - area.outerRadius = area.x1, delete area.x1; - area.angle = area.y, delete area.y; - area.startAngle = area.y0, delete area.y0; - area.endAngle = area.y1, delete area.y1; - return area; - }; - d3.svg.chord = function() { - var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; - function chord(d, i) { - var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); - return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; - } - function subgroup(self, f, d, i) { - var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; - return { - r: r, - a0: a0, - a1: a1, - p0: [ r * Math.cos(a0), r * Math.sin(a0) ], - p1: [ r * Math.cos(a1), r * Math.sin(a1) ] - }; - } - function equals(a, b) { - return a.a0 == b.a0 && a.a1 == b.a1; - } - function arc(r, p, a) { - return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; - } - function curve(r0, p0, r1, p1) { - return "Q 0,0 " + p1; - } - chord.radius = function(v) { - if (!arguments.length) return radius; - radius = d3_functor(v); - return chord; - }; - chord.source = function(v) { - if (!arguments.length) return source; - source = d3_functor(v); - return chord; - }; - chord.target = function(v) { - if (!arguments.length) return target; - target = d3_functor(v); - return chord; - }; - chord.startAngle = function(v) { - if (!arguments.length) return startAngle; - startAngle = d3_functor(v); - return chord; - }; - chord.endAngle = function(v) { - if (!arguments.length) return endAngle; - endAngle = d3_functor(v); - return chord; - }; - return chord; - }; - function d3_svg_chordRadius(d) { - return d.radius; - } - d3.svg.diagonal = function() { - var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; - function diagonal(d, i) { - var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { - x: p0.x, - y: m - }, { - x: p3.x, - y: m - }, p3 ]; - p = p.map(projection); - return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; - } - diagonal.source = function(x) { - if (!arguments.length) return source; - source = d3_functor(x); - return diagonal; - }; - diagonal.target = function(x) { - if (!arguments.length) return target; - target = d3_functor(x); - return diagonal; - }; - diagonal.projection = function(x) { - if (!arguments.length) return projection; - projection = x; - return diagonal; - }; - return diagonal; - }; - function d3_svg_diagonalProjection(d) { - return [ d.x, d.y ]; - } - d3.svg.diagonal.radial = function() { - var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; - diagonal.projection = function(x) { - return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; - }; - return diagonal; - }; - function d3_svg_diagonalRadialProjection(projection) { - return function() { - var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; - return [ r * Math.cos(a), r * Math.sin(a) ]; - }; - } - d3.svg.symbol = function() { - var type = d3_svg_symbolType, size = d3_svg_symbolSize; - function symbol(d, i) { - return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); - } - symbol.type = function(x) { - if (!arguments.length) return type; - type = d3_functor(x); - return symbol; - }; - symbol.size = function(x) { - if (!arguments.length) return size; - size = d3_functor(x); - return symbol; - }; - return symbol; - }; - function d3_svg_symbolSize() { - return 64; - } - function d3_svg_symbolType() { - return "circle"; - } - function d3_svg_symbolCircle(size) { - var r = Math.sqrt(size / π); - return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; - } - var d3_svg_symbols = d3.map({ - circle: d3_svg_symbolCircle, - cross: function(size) { - var r = Math.sqrt(size / 5) / 2; - return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; - }, - diamond: function(size) { - var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; - return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; - }, - square: function(size) { - var r = Math.sqrt(size) / 2; - return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; - }, - "triangle-down": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; - }, - "triangle-up": function(size) { - var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; - return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; - } - }); - d3.svg.symbolTypes = d3_svg_symbols.keys(); - var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); - function d3_transition(groups, id) { - d3_subclass(groups, d3_transitionPrototype); - groups.id = id; - return groups; - } - var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; - d3_transitionPrototype.call = d3_selectionPrototype.call; - d3_transitionPrototype.empty = d3_selectionPrototype.empty; - d3_transitionPrototype.node = d3_selectionPrototype.node; - d3_transitionPrototype.size = d3_selectionPrototype.size; - d3.transition = function(selection) { - return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); - }; - d3.transition.prototype = d3_transitionPrototype; - d3_transitionPrototype.select = function(selector) { - var id = this.id, subgroups = [], subgroup, subnode, node; - selector = d3_selection_selector(selector); - for (var j = -1, m = this.length; ++j < m; ) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { - if ("__data__" in node) subnode.__data__ = node.__data__; - d3_transitionNode(subnode, i, id, node.__transition__[id]); - subgroup.push(subnode); - } else { - subgroup.push(null); - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.selectAll = function(selector) { - var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; - selector = d3_selection_selectorAll(selector); - for (var j = -1, m = this.length; ++j < m; ) { - for (var group = this[j], i = -1, n = group.length; ++i < n; ) { - if (node = group[i]) { - transition = node.__transition__[id]; - subnodes = selector.call(node, node.__data__, i, j); - subgroups.push(subgroup = []); - for (var k = -1, o = subnodes.length; ++k < o; ) { - if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); - subgroup.push(subnode); - } - } - } - } - return d3_transition(subgroups, id); - }; - d3_transitionPrototype.filter = function(filter) { - var subgroups = [], subgroup, group, node; - if (typeof filter !== "function") filter = d3_selection_filter(filter); - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i)) { - subgroup.push(node); - } - } - } - return d3_transition(subgroups, this.id); - }; - d3_transitionPrototype.tween = function(name, tween) { - var id = this.id; - if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); - return d3_selection_each(this, tween == null ? function(node) { - node.__transition__[id].tween.remove(name); - } : function(node) { - node.__transition__[id].tween.set(name, tween); - }); - }; - function d3_transition_tween(groups, name, value, tween) { - var id = groups.id; - return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); - } : (value = tween(value), function(node) { - node.__transition__[id].tween.set(name, value); - })); - } - d3_transitionPrototype.attr = function(nameNS, value) { - if (arguments.length < 2) { - for (value in nameNS) this.attr(value, nameNS[value]); - return this; - } - var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - function attrTween(b) { - return b == null ? attrNull : (b += "", function() { - var a = this.getAttribute(name), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttribute(name, i(t)); - }); - }); - } - function attrTweenNS(b) { - return b == null ? attrNullNS : (b += "", function() { - var a = this.getAttributeNS(name.space, name.local), i; - return a !== b && (i = interpolate(a, b), function(t) { - this.setAttributeNS(name.space, name.local, i(t)); - }); - }); - } - return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); - }; - d3_transitionPrototype.attrTween = function(nameNS, tween) { - var name = d3.ns.qualify(nameNS); - function attrTween(d, i) { - var f = tween.call(this, d, i, this.getAttribute(name)); - return f && function(t) { - this.setAttribute(name, f(t)); - }; - } - function attrTweenNS(d, i) { - var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); - return f && function(t) { - this.setAttributeNS(name.space, name.local, f(t)); - }; - } - return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); - }; - d3_transitionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.style(priority, name[priority], value); - return this; - } - priority = ""; - } - function styleNull() { - this.style.removeProperty(name); - } - function styleString(b) { - return b == null ? styleNull : (b += "", function() { - var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; - return a !== b && (i = d3_interpolate(a, b), function(t) { - this.style.setProperty(name, i(t), priority); - }); - }); - } - return d3_transition_tween(this, "style." + name, value, styleString); - }; - d3_transitionPrototype.styleTween = function(name, tween, priority) { - if (arguments.length < 3) priority = ""; - function styleTween(d, i) { - var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); - return f && function(t) { - this.style.setProperty(name, f(t), priority); - }; - } - return this.tween("style." + name, styleTween); - }; - d3_transitionPrototype.text = function(value) { - return d3_transition_tween(this, "text", value, d3_transition_text); - }; - function d3_transition_text(b) { - if (b == null) b = ""; - return function() { - this.textContent = b; - }; - } - d3_transitionPrototype.remove = function() { - return this.each("end.transition", function() { - var p; - if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); - }); - }; - d3_transitionPrototype.ease = function(value) { - var id = this.id; - if (arguments.length < 1) return this.node().__transition__[id].ease; - if (typeof value !== "function") value = d3.ease.apply(d3, arguments); - return d3_selection_each(this, function(node) { - node.__transition__[id].ease = value; - }); - }; - d3_transitionPrototype.delay = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; - } : (value |= 0, function(node) { - node.__transition__[id].delay = value; - })); - }; - d3_transitionPrototype.duration = function(value) { - var id = this.id; - return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { - node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); - } : (value = Math.max(1, value | 0), function(node) { - node.__transition__[id].duration = value; - })); - }; - d3_transitionPrototype.each = function(type, listener) { - var id = this.id; - if (arguments.length < 2) { - var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; - d3_transitionInheritId = id; - d3_selection_each(this, function(node, i, j) { - d3_transitionInherit = node.__transition__[id]; - type.call(node, node.__data__, i, j); - }); - d3_transitionInherit = inherit; - d3_transitionInheritId = inheritId; - } else { - d3_selection_each(this, function(node) { - var transition = node.__transition__[id]; - (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); - }); - } - return this; - }; - d3_transitionPrototype.transition = function() { - var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if (node = group[i]) { - transition = Object.create(node.__transition__[id0]); - transition.delay += transition.duration; - d3_transitionNode(node, i, id1, transition); - } - subgroup.push(node); - } - } - return d3_transition(subgroups, id1); - }; - function d3_transitionNode(node, i, id, inherit) { - var lock = node.__transition__ || (node.__transition__ = { - active: 0, - count: 0 - }), transition = lock[id]; - if (!transition) { - var time = inherit.time; - transition = lock[id] = { - tween: new d3_Map(), - time: time, - ease: inherit.ease, - delay: inherit.delay, - duration: inherit.duration - }; - ++lock.count; - d3.timer(function(elapsed) { - var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; - if (delay <= elapsed) return start(elapsed); - d3_timer_replace(start, delay, time); - function start(elapsed) { - if (lock.active > id) return stop(); - lock.active = id; - transition.event && transition.event.start.call(node, d, i); - transition.tween.forEach(function(key, value) { - if (value = value.call(node, d, i)) { - tweened.push(value); - } - }); - if (tick(elapsed)) return 1; - d3_timer_replace(tick, 0, time); - } - function tick(elapsed) { - if (lock.active !== id) return stop(); - var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; - while (n > 0) { - tweened[--n].call(node, e); - } - if (t >= 1) { - stop(); - transition.event && transition.event.end.call(node, d, i); - return 1; - } - } - function stop() { - if (--lock.count) delete lock[id]; else delete node.__transition__; - return 1; - } - }, 0, time); - } - } - d3.svg.axis = function() { - var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; - function axis(g) { - g.each(function() { - var g = d3.select(this); - var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; - var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); - var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; - var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), - d3.transition(path)); - var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; - this.__chart__ = scale1; - tickEnter.append("line"); - tickEnter.append("text"); - var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); - switch (orient) { - case "bottom": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); - lineEnter.attr("y2", tickMajorSize); - textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); - textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); - text.attr("dy", ".71em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); - break; - } - - case "top": - { - tickTransform = d3_svg_axisX; - subtickEnter.attr("y2", -tickMinorSize); - subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); - lineEnter.attr("y2", -tickMajorSize); - textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); - textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); - text.attr("dy", "0em").style("text-anchor", "middle"); - pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); - break; - } - - case "left": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", -tickMinorSize); - subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", -tickMajorSize); - textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); - lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); - textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "end"); - pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); - break; - } - - case "right": - { - tickTransform = d3_svg_axisY; - subtickEnter.attr("x2", tickMinorSize); - subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); - lineEnter.attr("x2", tickMajorSize); - textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); - lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); - textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); - text.attr("dy", ".32em").style("text-anchor", "start"); - pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); - break; - } - } - if (scale.rangeBand) { - var dx = scale1.rangeBand() / 2, x = function(d) { - return scale1(d) + dx; - }; - tickEnter.call(tickTransform, x); - tickUpdate.call(tickTransform, x); - } else { - tickEnter.call(tickTransform, scale0); - tickUpdate.call(tickTransform, scale1); - tickExit.call(tickTransform, scale1); - subtickEnter.call(tickTransform, scale0); - subtickUpdate.call(tickTransform, scale1); - subtickExit.call(tickTransform, scale1); - } - }); - } - axis.scale = function(x) { - if (!arguments.length) return scale; - scale = x; - return axis; - }; - axis.orient = function(x) { - if (!arguments.length) return orient; - orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; - return axis; - }; - axis.ticks = function() { - if (!arguments.length) return tickArguments_; - tickArguments_ = arguments; - return axis; - }; - axis.tickValues = function(x) { - if (!arguments.length) return tickValues; - tickValues = x; - return axis; - }; - axis.tickFormat = function(x) { - if (!arguments.length) return tickFormat_; - tickFormat_ = x; - return axis; - }; - axis.tickSize = function(x, y) { - if (!arguments.length) return tickMajorSize; - var n = arguments.length - 1; - tickMajorSize = +x; - tickMinorSize = n > 1 ? +y : tickMajorSize; - tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; - return axis; - }; - axis.tickPadding = function(x) { - if (!arguments.length) return tickPadding; - tickPadding = +x; - return axis; - }; - axis.tickSubdivide = function(x) { - if (!arguments.length) return tickSubdivide; - tickSubdivide = +x; - return axis; - }; - return axis; - }; - var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { - top: 1, - right: 1, - bottom: 1, - left: 1 - }; - function d3_svg_axisX(selection, x) { - selection.attr("transform", function(d) { - return "translate(" + x(d) + ",0)"; - }); - } - function d3_svg_axisY(selection, y) { - selection.attr("transform", function(d) { - return "translate(0," + y(d) + ")"; - }); - } - function d3_svg_axisSubdivide(scale, ticks, m) { - subticks = []; - if (m && ticks.length > 1) { - var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; - while (++i < n) { - for (j = m; --j > 0; ) { - if ((v = +ticks[i] - j * d) >= extent[0]) { - subticks.push(v); - } - } - } - for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { - subticks.push(v); - } - } - return subticks; - } - d3.svg.brush = function() { - var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; - function brush(g) { - g.each(function() { - var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; - g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); - bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); - fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); - tz.enter().append("g").attr("class", function(d) { - return "resize " + d; - }).style("cursor", function(d) { - return d3_svg_brushCursor[d]; - }).append("rect").attr("x", function(d) { - return /[ew]$/.test(d) ? -3 : null; - }).attr("y", function(d) { - return /^[ns]/.test(d) ? -3 : null; - }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); - tz.style("display", brush.empty() ? "none" : null); - tz.exit().remove(); - if (x) { - e = d3_scaleRange(x); - bg.attr("x", e[0]).attr("width", e[1] - e[0]); - redrawX(g); - } - if (y) { - e = d3_scaleRange(y); - bg.attr("y", e[0]).attr("height", e[1] - e[0]); - redrawY(g); - } - redraw(g); - }); - } - function redraw(g) { - g.selectAll(".resize").attr("transform", function(d) { - return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; - }); - } - function redrawX(g) { - g.select(".extent").attr("x", extent[0][0]); - g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); - } - function redrawY(g) { - g.select(".extent").attr("y", extent[0][1]); - g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); - } - function brushstart() { - var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = mouse(), offset; - var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); - if (d3.event.changedTouches) { - w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); - } else { - w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); - } - if (dragging) { - origin[0] = extent[0][0] - origin[0]; - origin[1] = extent[0][1] - origin[1]; - } else if (resizing) { - var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); - offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; - origin[0] = extent[ex][0]; - origin[1] = extent[ey][1]; - } else if (d3.event.altKey) center = origin.slice(); - g.style("pointer-events", "none").selectAll(".resize").style("display", null); - d3.select("body").style("cursor", eventTarget.style("cursor")); - event_({ - type: "brushstart" - }); - brushmove(); - function mouse() { - var touches = d3.event.changedTouches; - return touches ? d3.touches(target, touches)[0] : d3.mouse(target); - } - function keydown() { - if (d3.event.keyCode == 32) { - if (!dragging) { - center = null; - origin[0] -= extent[1][0]; - origin[1] -= extent[1][1]; - dragging = 2; - } - d3_eventPreventDefault(); - } - } - function keyup() { - if (d3.event.keyCode == 32 && dragging == 2) { - origin[0] += extent[1][0]; - origin[1] += extent[1][1]; - dragging = 0; - d3_eventPreventDefault(); - } - } - function brushmove() { - var point = mouse(), moved = false; - if (offset) { - point[0] += offset[0]; - point[1] += offset[1]; - } - if (!dragging) { - if (d3.event.altKey) { - if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; - origin[0] = extent[+(point[0] < center[0])][0]; - origin[1] = extent[+(point[1] < center[1])][1]; - } else center = null; - } - if (resizingX && move1(point, x, 0)) { - redrawX(g); - moved = true; - } - if (resizingY && move1(point, y, 1)) { - redrawY(g); - moved = true; - } - if (moved) { - redraw(g); - event_({ - type: "brush", - mode: dragging ? "move" : "resize" - }); - } - } - function move1(point, scale, i) { - var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; - if (dragging) { - r0 -= position; - r1 -= size + position; - } - min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; - if (dragging) { - max = (min += position) + size; - } else { - if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); - if (position < min) { - max = min; - min = position; - } else { - max = position; - } - } - if (extent[0][i] !== min || extent[1][i] !== max) { - extentDomain = null; - extent[0][i] = min; - extent[1][i] = max; - return true; - } - } - function brushend() { - brushmove(); - g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); - d3.select("body").style("cursor", null); - w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); - dragRestore(); - event_({ - type: "brushend" - }); - } - } - brush.x = function(z) { - if (!arguments.length) return x; - x = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.y = function(z) { - if (!arguments.length) return y; - y = z; - resizes = d3_svg_brushResizes[!x << 1 | !y]; - return brush; - }; - brush.clamp = function(z) { - if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; - if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; - return brush; - }; - brush.extent = function(z) { - var x0, x1, y0, y1, t; - if (!arguments.length) { - z = extentDomain || extent; - if (x) { - x0 = z[0][0], x1 = z[1][0]; - if (!extentDomain) { - x0 = extent[0][0], x1 = extent[1][0]; - if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - } - } - if (y) { - y0 = z[0][1], y1 = z[1][1]; - if (!extentDomain) { - y0 = extent[0][1], y1 = extent[1][1]; - if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - } - } - return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; - } - extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; - if (x) { - x0 = z[0], x1 = z[1]; - if (y) x0 = x0[0], x1 = x1[0]; - extentDomain[0][0] = x0, extentDomain[1][0] = x1; - if (x.invert) x0 = x(x0), x1 = x(x1); - if (x1 < x0) t = x0, x0 = x1, x1 = t; - extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; - } - if (y) { - y0 = z[0], y1 = z[1]; - if (x) y0 = y0[1], y1 = y1[1]; - extentDomain[0][1] = y0, extentDomain[1][1] = y1; - if (y.invert) y0 = y(y0), y1 = y(y1); - if (y1 < y0) t = y0, y0 = y1, y1 = t; - extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; - } - return brush; - }; - brush.clear = function() { - extentDomain = null; - extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; - return brush; - }; - brush.empty = function() { - return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; - }; - return d3.rebind(brush, event, "on"); - }; - var d3_svg_brushCursor = { - n: "ns-resize", - e: "ew-resize", - s: "ns-resize", - w: "ew-resize", - nw: "nwse-resize", - ne: "nesw-resize", - se: "nwse-resize", - sw: "nesw-resize" - }; - var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; - d3.time = {}; - var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; - function d3_time_utc() { - this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); - } - d3_time_utc.prototype = { - getDate: function() { - return this._.getUTCDate(); - }, - getDay: function() { - return this._.getUTCDay(); - }, - getFullYear: function() { - return this._.getUTCFullYear(); - }, - getHours: function() { - return this._.getUTCHours(); - }, - getMilliseconds: function() { - return this._.getUTCMilliseconds(); - }, - getMinutes: function() { - return this._.getUTCMinutes(); - }, - getMonth: function() { - return this._.getUTCMonth(); - }, - getSeconds: function() { - return this._.getUTCSeconds(); - }, - getTime: function() { - return this._.getTime(); - }, - getTimezoneOffset: function() { - return 0; - }, - valueOf: function() { - return this._.valueOf(); - }, - setDate: function() { - d3_time_prototype.setUTCDate.apply(this._, arguments); - }, - setDay: function() { - d3_time_prototype.setUTCDay.apply(this._, arguments); - }, - setFullYear: function() { - d3_time_prototype.setUTCFullYear.apply(this._, arguments); - }, - setHours: function() { - d3_time_prototype.setUTCHours.apply(this._, arguments); - }, - setMilliseconds: function() { - d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); - }, - setMinutes: function() { - d3_time_prototype.setUTCMinutes.apply(this._, arguments); - }, - setMonth: function() { - d3_time_prototype.setUTCMonth.apply(this._, arguments); - }, - setSeconds: function() { - d3_time_prototype.setUTCSeconds.apply(this._, arguments); - }, - setTime: function() { - d3_time_prototype.setTime.apply(this._, arguments); - } - }; - var d3_time_prototype = Date.prototype; - var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; - var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; - function d3_time_interval(local, step, number) { - function round(date) { - var d0 = local(date), d1 = offset(d0, 1); - return date - d0 < d1 - date ? d0 : d1; - } - function ceil(date) { - step(date = local(new d3_time(date - 1)), 1); - return date; - } - function offset(date, k) { - step(date = new d3_time(+date), k); - return date; - } - function range(t0, t1, dt) { - var time = ceil(t0), times = []; - if (dt > 1) { - while (time < t1) { - if (!(number(time) % dt)) times.push(new Date(+time)); - step(time, 1); - } - } else { - while (time < t1) times.push(new Date(+time)), step(time, 1); - } - return times; - } - function range_utc(t0, t1, dt) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = t0; - return range(utc, t1, dt); - } finally { - d3_time = Date; - } - } - local.floor = local; - local.round = round; - local.ceil = ceil; - local.offset = offset; - local.range = range; - var utc = local.utc = d3_time_interval_utc(local); - utc.floor = utc; - utc.round = d3_time_interval_utc(round); - utc.ceil = d3_time_interval_utc(ceil); - utc.offset = d3_time_interval_utc(offset); - utc.range = range_utc; - return local; - } - function d3_time_interval_utc(method) { - return function(date, k) { - try { - d3_time = d3_time_utc; - var utc = new d3_time_utc(); - utc._ = date; - return method(utc, k)._; - } finally { - d3_time = Date; - } - }; - } - d3.time.year = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setMonth(0, 1); - return date; - }, function(date, offset) { - date.setFullYear(date.getFullYear() + offset); - }, function(date) { - return date.getFullYear(); - }); - d3.time.years = d3.time.year.range; - d3.time.years.utc = d3.time.year.utc.range; - d3.time.day = d3_time_interval(function(date) { - var day = new d3_time(2e3, 0); - day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); - return day; - }, function(date, offset) { - date.setDate(date.getDate() + offset); - }, function(date) { - return date.getDate() - 1; - }); - d3.time.days = d3.time.day.range; - d3.time.days.utc = d3.time.day.utc.range; - d3.time.dayOfYear = function(date) { - var year = d3.time.year(date); - return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); - }; - d3_time_daySymbols.forEach(function(day, i) { - day = day.toLowerCase(); - i = 7 - i; - var interval = d3.time[day] = d3_time_interval(function(date) { - (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); - return date; - }, function(date, offset) { - date.setDate(date.getDate() + Math.floor(offset) * 7); - }, function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); - }); - d3.time[day + "s"] = interval.range; - d3.time[day + "s"].utc = interval.utc.range; - d3.time[day + "OfYear"] = function(date) { - var day = d3.time.year(date).getDay(); - return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); - }; - }); - d3.time.week = d3.time.sunday; - d3.time.weeks = d3.time.sunday.range; - d3.time.weeks.utc = d3.time.sunday.utc.range; - d3.time.weekOfYear = d3.time.sundayOfYear; - d3.time.format = function(template) { - var n = template.length; - function format(date) { - var string = [], i = -1, j = 0, c, p, f; - while (++i < n) { - if (template.charCodeAt(i) === 37) { - string.push(template.substring(j, i)); - if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); - if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); - string.push(c); - j = i + 1; - } - } - string.push(template.substring(j, i)); - return string.join(""); - } - format.parse = function(string) { - var d = { - y: 1900, - m: 0, - d: 1, - H: 0, - M: 0, - S: 0, - L: 0 - }, i = d3_time_parse(d, template, string, 0); - if (i != string.length) return null; - if ("p" in d) d.H = d.H % 12 + d.p * 12; - var date = new d3_time(); - if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { - date.setFullYear(d.y, 0, 1); - date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); - } else date.setFullYear(d.y, d.m, d.d); - date.setHours(d.H, d.M, d.S, d.L); - return date; - }; - format.toString = function() { - return template; - }; - return format; - }; - function d3_time_parse(date, template, string, j) { - var c, p, i = 0, n = template.length, m = string.length; - while (i < n) { - if (j >= m) return -1; - c = template.charCodeAt(i++); - if (c === 37) { - p = d3_time_parsers[template.charAt(i++)]; - if (!p || (j = p(date, string, j)) < 0) return -1; - } else if (c != string.charCodeAt(j++)) { - return -1; - } - } - return j; - } - function d3_time_formatRe(names) { - return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); - } - function d3_time_formatLookup(names) { - var map = new d3_Map(), i = -1, n = names.length; - while (++i < n) map.set(names[i].toLowerCase(), i); - return map; - } - function d3_time_formatPad(value, fill, width) { - var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; - return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); - } - var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; - var d3_time_formatPads = { - "-": "", - _: " ", - "0": "0" - }; - var d3_time_formats = { - a: function(d) { - return d3_time_dayAbbreviations[d.getDay()]; - }, - A: function(d) { - return d3_time_days[d.getDay()]; - }, - b: function(d) { - return d3_time_monthAbbreviations[d.getMonth()]; - }, - B: function(d) { - return d3_time_months[d.getMonth()]; - }, - c: d3.time.format(d3_time_formatDateTime), - d: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - e: function(d, p) { - return d3_time_formatPad(d.getDate(), p, 2); - }, - H: function(d, p) { - return d3_time_formatPad(d.getHours(), p, 2); - }, - I: function(d, p) { - return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); - }, - j: function(d, p) { - return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); - }, - L: function(d, p) { - return d3_time_formatPad(d.getMilliseconds(), p, 3); - }, - m: function(d, p) { - return d3_time_formatPad(d.getMonth() + 1, p, 2); - }, - M: function(d, p) { - return d3_time_formatPad(d.getMinutes(), p, 2); - }, - p: function(d) { - return d.getHours() >= 12 ? "PM" : "AM"; - }, - S: function(d, p) { - return d3_time_formatPad(d.getSeconds(), p, 2); - }, - U: function(d, p) { - return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); - }, - w: function(d) { - return d.getDay(); - }, - W: function(d, p) { - return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); - }, - x: d3.time.format(d3_time_formatDate), - X: d3.time.format(d3_time_formatTime), - y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 100, p, 2); - }, - Y: function(d, p) { - return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); - }, - Z: d3_time_zone, - "%": function() { - return "%"; - } - }; - var d3_time_parsers = { - a: d3_time_parseWeekdayAbbrev, - A: d3_time_parseWeekday, - b: d3_time_parseMonthAbbrev, - B: d3_time_parseMonth, - c: d3_time_parseLocaleFull, - d: d3_time_parseDay, - e: d3_time_parseDay, - H: d3_time_parseHour24, - I: d3_time_parseHour24, - j: d3_time_parseDayOfYear, - L: d3_time_parseMilliseconds, - m: d3_time_parseMonthNumber, - M: d3_time_parseMinutes, - p: d3_time_parseAmPm, - S: d3_time_parseSeconds, - U: d3_time_parseWeekNumberSunday, - w: d3_time_parseWeekdayNumber, - W: d3_time_parseWeekNumberMonday, - x: d3_time_parseLocaleDate, - X: d3_time_parseLocaleTime, - y: d3_time_parseYear, - Y: d3_time_parseFullYear, - "%": d3_time_parseLiteralPercent - }; - function d3_time_parseWeekdayAbbrev(date, string, i) { - d3_time_dayAbbrevRe.lastIndex = 0; - var n = d3_time_dayAbbrevRe.exec(string.substring(i)); - return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseWeekday(date, string, i) { - d3_time_dayRe.lastIndex = 0; - var n = d3_time_dayRe.exec(string.substring(i)); - return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseWeekdayNumber(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 1)); - return n ? (date.w = +n[0], i + n[0].length) : -1; - } - function d3_time_parseWeekNumberSunday(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i)); - return n ? (date.U = +n[0], i + n[0].length) : -1; - } - function d3_time_parseWeekNumberMonday(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i)); - return n ? (date.W = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMonthAbbrev(date, string, i) { - d3_time_monthAbbrevRe.lastIndex = 0; - var n = d3_time_monthAbbrevRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseMonth(date, string, i) { - d3_time_monthRe.lastIndex = 0; - var n = d3_time_monthRe.exec(string.substring(i)); - return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; - } - function d3_time_parseLocaleFull(date, string, i) { - return d3_time_parse(date, d3_time_formats.c.toString(), string, i); - } - function d3_time_parseLocaleDate(date, string, i) { - return d3_time_parse(date, d3_time_formats.x.toString(), string, i); - } - function d3_time_parseLocaleTime(date, string, i) { - return d3_time_parse(date, d3_time_formats.X.toString(), string, i); - } - function d3_time_parseFullYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 4)); - return n ? (date.y = +n[0], i + n[0].length) : -1; - } - function d3_time_parseYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; - } - function d3_time_expandYear(d) { - return d + (d > 68 ? 1900 : 2e3); - } - function d3_time_parseMonthNumber(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.m = n[0] - 1, i + n[0].length) : -1; - } - function d3_time_parseDay(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.d = +n[0], i + n[0].length) : -1; - } - function d3_time_parseDayOfYear(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 3)); - return n ? (date.j = +n[0], i + n[0].length) : -1; - } - function d3_time_parseHour24(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.H = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMinutes(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.M = +n[0], i + n[0].length) : -1; - } - function d3_time_parseSeconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 2)); - return n ? (date.S = +n[0], i + n[0].length) : -1; - } - function d3_time_parseMilliseconds(date, string, i) { - d3_time_numberRe.lastIndex = 0; - var n = d3_time_numberRe.exec(string.substring(i, i + 3)); - return n ? (date.L = +n[0], i + n[0].length) : -1; - } - var d3_time_numberRe = /^\s*\d+/; - function d3_time_parseAmPm(date, string, i) { - var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); - return n == null ? -1 : (date.p = n, i); - } - var d3_time_amPmLookup = d3.map({ - am: 0, - pm: 1 - }); - function d3_time_zone(d) { - var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; - return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); - } - function d3_time_parseLiteralPercent(date, string, i) { - d3_time_percentRe.lastIndex = 0; - var n = d3_time_percentRe.exec(string.substring(i, i + 1)); - return n ? i + n[0].length : -1; - } - d3.time.format.utc = function(template) { - var local = d3.time.format(template); - function format(date) { - try { - d3_time = d3_time_utc; - var utc = new d3_time(); - utc._ = date; - return local(utc); - } finally { - d3_time = Date; - } - } - format.parse = function(string) { - try { - d3_time = d3_time_utc; - var date = local.parse(string); - return date && date._; - } finally { - d3_time = Date; - } - }; - format.toString = local.toString; - return format; - }; - var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); - d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; - function d3_time_formatIsoNative(date) { - return date.toISOString(); - } - d3_time_formatIsoNative.parse = function(string) { - var date = new Date(string); - return isNaN(date) ? null : date; - }; - d3_time_formatIsoNative.toString = d3_time_formatIso.toString; - d3.time.second = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 1e3) * 1e3); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 1e3); - }, function(date) { - return date.getSeconds(); - }); - d3.time.seconds = d3.time.second.range; - d3.time.seconds.utc = d3.time.second.utc.range; - d3.time.minute = d3_time_interval(function(date) { - return new d3_time(Math.floor(date / 6e4) * 6e4); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 6e4); - }, function(date) { - return date.getMinutes(); - }); - d3.time.minutes = d3.time.minute.range; - d3.time.minutes.utc = d3.time.minute.utc.range; - d3.time.hour = d3_time_interval(function(date) { - var timezone = date.getTimezoneOffset() / 60; - return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); - }, function(date, offset) { - date.setTime(date.getTime() + Math.floor(offset) * 36e5); - }, function(date) { - return date.getHours(); - }); - d3.time.hours = d3.time.hour.range; - d3.time.hours.utc = d3.time.hour.utc.range; - d3.time.month = d3_time_interval(function(date) { - date = d3.time.day(date); - date.setDate(1); - return date; - }, function(date, offset) { - date.setMonth(date.getMonth() + offset); - }, function(date) { - return date.getMonth(); - }); - d3.time.months = d3.time.month.range; - d3.time.months.utc = d3.time.month.utc.range; - function d3_time_scale(linear, methods, format) { - function scale(x) { - return linear(x); - } - scale.invert = function(x) { - return d3_time_scaleDate(linear.invert(x)); - }; - scale.domain = function(x) { - if (!arguments.length) return linear.domain().map(d3_time_scaleDate); - linear.domain(x); - return scale; - }; - scale.nice = function(m) { - return scale.domain(d3_scale_nice(scale.domain(), m)); - }; - scale.ticks = function(m, k) { - var extent = d3_scaleExtent(scale.domain()); - if (typeof m !== "function") { - var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); - if (i == d3_time_scaleSteps.length) return methods.year(extent, m); - if (!i) return linear.ticks(m).map(d3_time_scaleDate); - if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; - m = methods[i]; - k = m[1]; - m = m[0].range; - } - return m(extent[0], new Date(+extent[1] + 1), k); - }; - scale.tickFormat = function() { - return format; - }; - scale.copy = function() { - return d3_time_scale(linear.copy(), methods, format); - }; - return d3_scale_linearRebind(scale, linear); - } - function d3_time_scaleDate(t) { - return new Date(t); - } - function d3_time_scaleFormat(formats) { - return function(date) { - var i = formats.length - 1, f = formats[i]; - while (!f[1](date)) f = formats[--i]; - return f[0](date); - }; - } - function d3_time_scaleSetYear(y) { - var d = new Date(y, 0, 1); - d.setFullYear(y); - return d; - } - function d3_time_scaleGetYear(d) { - var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; - var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; - var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { - return d.getMonth(); - } ], [ d3.time.format("%b %d"), function(d) { - return d.getDate() != 1; - } ], [ d3.time.format("%a %d"), function(d) { - return d.getDay() && d.getDate() != 1; - } ], [ d3.time.format("%I %p"), function(d) { - return d.getHours(); - } ], [ d3.time.format("%I:%M"), function(d) { - return d.getMinutes(); - } ], [ d3.time.format(":%S"), function(d) { - return d.getSeconds(); - } ], [ d3.time.format(".%L"), function(d) { - return d.getMilliseconds(); - } ] ]; - var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); - d3_time_scaleLocalMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); - }; - d3.time.scale = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); - }; - var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { - return [ m[0].utc, m[1] ]; - }); - var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { - return d.getUTCMonth(); - } ], [ d3.time.format.utc("%b %d"), function(d) { - return d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%a %d"), function(d) { - return d.getUTCDay() && d.getUTCDate() != 1; - } ], [ d3.time.format.utc("%I %p"), function(d) { - return d.getUTCHours(); - } ], [ d3.time.format.utc("%I:%M"), function(d) { - return d.getUTCMinutes(); - } ], [ d3.time.format.utc(":%S"), function(d) { - return d.getUTCSeconds(); - } ], [ d3.time.format.utc(".%L"), function(d) { - return d.getUTCMilliseconds(); - } ] ]; - var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); - function d3_time_scaleUTCSetYear(y) { - var d = new Date(Date.UTC(y, 0, 1)); - d.setUTCFullYear(y); - return d; - } - function d3_time_scaleUTCGetYear(d) { - var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); - return y + (d - d0) / (d1 - d0); - } - d3_time_scaleUTCMethods.year = function(extent, m) { - return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); - }; - d3.time.scale.utc = function() { - return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); - }; - d3.text = d3_xhrType(function(request) { - return request.responseText; - }); - d3.json = function(url, callback) { - return d3_xhr(url, "application/json", d3_json, callback); - }; - function d3_json(request) { - return JSON.parse(request.responseText); - } - d3.html = function(url, callback) { - return d3_xhr(url, "text/html", d3_html, callback); - }; - function d3_html(request) { - var range = d3_document.createRange(); - range.selectNode(d3_document.body); - return range.createContextualFragment(request.responseText); - } - d3.xml = d3_xhrType(function(request) { - return request.responseXML; - }); - return d3; -}(); -},{}],29:[function(require,module,exports){ -require("./d3"); -module.exports = d3; -(function () { delete this.d3; })(); // unset global - -},{"./d3":28}],30:[function(require,module,exports){ -var ich = require('icanhaz') - -module.exports.ich = ich - -module.exports.getKeywordCount = function(data, keyword) { - var group = [] - data.forEach(function (d) { - for(var key in d) { - var value = d[key].toString().toLowerCase() - if (value.match(keyword.toLowerCase())) group.push(d) - } - }) - return group.length - if (group = []) return "0" -} - -module.exports.getKeyword = function(data, keyword) { - var group = [] - data.forEach(function (d) { - for(var key in d) { - var value = d[key].toString().toLowerCase() - if (value.match(keyword.toLowerCase())) group.push(d) - } - }) - return group - if (group = []) return "no matches" -} - -module.exports.getColumnTotal = function(data, column) { - var total = [] - data.forEach(function (d) { - if (d[column] === "") return - total.push(+d[column]) - }) - return total.reduce(function(a,b) { - return a + b - }) -} - -module.exports.getColumnAverage = function(data, column) { - var total = getColumnTotal(data, column) - var average = total / data.length - return average -} - -module.exports.getMax = function(data, column) { - var result = [] - data.forEach(function (element){ - if (result.length === 0) return result.push(element) - else { - if (element[column].valueOf() > result[0][column].valueOf()) { - result.length = 0 - return result.push(element) - } - if (element[column].valueOf() === result[0][column].valueOf()) { - return result.push(element) - } - } - }) - return result -} - -module.exports.getMin = function(data, column) { - var result = [] - data.forEach(function (element){ - if (result.length === 0) return result.push(element) - else { - if (element[column].valueOf() < result[0][column].valueOf()) { - result.length = 0 - return result.push(element) - } - if (element[column].valueOf() === result[0][column].valueOf()) { - return result.push(element) - } - } - }) - return result -} - -// out of the data, filter something from a category -module.exports.getMatches = function (data, filter, category) { - var matches = [] - data.forEach(function (element) { - var projectType = element[category].toString().toLowerCase() - if (projectType === filter.toLowerCase()) matches.push(element) - }) - return matches -} - -module.exports.mostFrequent = function(data, category) { - var count = {} - for (var i = 0; i < data.length; i++) { - if (!count[data[i][category]]) { - count[data[i][category]] = 0 - } - count[data[i][category]]++ - } - var sortable = [] - for (var category in count) { - sortable.push([category, count[category]]) - } - sortable.sort(function(a, b) {return b[1] - a[1]}) - return sortable - // returns array of arrays, in order -} - -// thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ -module.exports.deepCopy = function(obj) { - if (Object.prototype.toString.call(obj) === '[object Array]') { - var out = [], i = 0, len = obj.length; - for ( ; i < len; i++ ) { - out[i] = arguments.callee(obj[i]); - } - return out; - } - if (typeof obj === 'object') { - var out = {}, i; - for ( i in obj ) { - out[i] = arguments.callee(obj[i]); - } - return out; - } - return obj; -} - -module.exports.getOccurance = function(data, category) { - var occuranceCount = {} - for (var i = 0; i < data.length; i++) { - if (!occuranceCount[data[i][category]]) { - occuranceCount[data[i][category]] = 0 - } - occuranceCount[data[i][category]]++ - } - return occuranceCount - // returns object, keys alphabetical -} - -module.exports.makeColorArrayOfObject = function(data, colors, category) { - var category = category - var keys = Object.keys(data) - var counter = 1 - var colorIndex - return keys.map(function(key){ - if (keys.length > colors.length || keys.length <= colors.length ) { - colorIndex = counter % colors.length - } - var h = {units: data[key], hexcolor: colors[colorIndex]} - h[category] = key - counter++ - colorIndex = counter - return h - }) -} - -module.exports.makeArrayOfObject = function(data) { - var keys = Object.keys(data) - return keys.map(function(key){ - // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} - var h = {label: key, units: data[key]} - return h - }) -} - -},{"icanhaz":31}],31:[function(require,module,exports){ -/*! -ICanHaz.js version 0.10.2 -- by @HenrikJoreteg -More info at: http://icanhazjs.com -*/ -(function () { -/* - mustache.js — Logic-less templates in JavaScript - - See http://mustache.github.com/ for more info. -*/ - -var Mustache = function () { - var _toString = Object.prototype.toString; - - Array.isArray = Array.isArray || function (obj) { - return _toString.call(obj) == "[object Array]"; - } - - var _trim = String.prototype.trim, trim; - - if (_trim) { - trim = function (text) { - return text == null ? "" : _trim.call(text); - } - } else { - var trimLeft, trimRight; - - // IE doesn't match non-breaking spaces with \s. - if ((/\S/).test("\xA0")) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; - } else { - trimLeft = /^\s+/; - trimRight = /\s+$/; - } - - trim = function (text) { - return text == null ? "" : - text.toString().replace(trimLeft, "").replace(trimRight, ""); - } - } - - var escapeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - - function escapeHTML(string) { - return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { - return escapeMap[s] || s; - }); - } - - var regexCache = {}; - var Renderer = function () {}; - - Renderer.prototype = { - otag: "{{", - ctag: "}}", - pragmas: {}, - buffer: [], - pragmas_implemented: { - "IMPLICIT-ITERATOR": true - }, - context: {}, - - render: function (template, context, partials, in_recursion) { - // reset buffer & set context - if (!in_recursion) { - this.context = context; - this.buffer = []; // TODO: make this non-lazy - } - - // fail fast - if (!this.includes("", template)) { - if (in_recursion) { - return template; - } else { - this.send(template); - return; - } - } - - // get the pragmas together - template = this.render_pragmas(template); - - // render the template - var html = this.render_section(template, context, partials); - - // render_section did not find any sections, we still need to render the tags - if (html === false) { - html = this.render_tags(template, context, partials, in_recursion); - } - - if (in_recursion) { - return html; - } else { - this.sendLines(html); - } - }, - - /* - Sends parsed lines - */ - send: function (line) { - if (line !== "") { - this.buffer.push(line); - } - }, - - sendLines: function (text) { - if (text) { - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) { - this.send(lines[i]); - } - } - }, - - /* - Looks for %PRAGMAS - */ - render_pragmas: function (template) { - // no pragmas - if (!this.includes("%", template)) { - return template; - } - - var that = this; - var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { - return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); - }); - - return template.replace(regex, function (match, pragma, options) { - if (!that.pragmas_implemented[pragma]) { - throw({message: - "This implementation of mustache doesn't understand the '" + - pragma + "' pragma"}); - } - that.pragmas[pragma] = {}; - if (options) { - var opts = options.split("="); - that.pragmas[pragma][opts[0]] = opts[1]; - } - return ""; - // ignore unknown pragmas silently - }); - }, - - /* - Tries to find a partial in the curent scope and render it - */ - render_partial: function (name, context, partials) { - name = trim(name); - if (!partials || partials[name] === undefined) { - throw({message: "unknown_partial '" + name + "'"}); - } - if (!context || typeof context[name] != "object") { - return this.render(partials[name], context, partials, true); - } - return this.render(partials[name], context[name], partials, true); - }, - - /* - Renders inverted (^) and normal (#) sections - */ - render_section: function (template, context, partials) { - if (!this.includes("#", template) && !this.includes("^", template)) { - // did not render anything, there were no sections - return false; - } - - var that = this; - - var regex = this.getCachedRegex("render_section", function (otag, ctag) { - // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder - return new RegExp( - "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) - - otag + // {{ - "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) - ctag + // }} - - "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped - - otag + // {{ - "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). - ctag + // }} - - "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. - - "g"); - }); - - - // for each {{#foo}}{{/foo}} section do... - return template.replace(regex, function (match, before, type, name, content, after) { - // before contains only tags, no sections - var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", - - // after may contain both sections and tags, so use full rendering function - renderedAfter = after ? that.render(after, context, partials, true) : "", - - // will be computed below - renderedContent, - - value = that.find(name, context); - - if (type === "^") { // inverted section - if (!value || Array.isArray(value) && value.length === 0) { - // false or empty list, render it - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } else if (type === "#") { // normal section - if (Array.isArray(value)) { // Enumerable, Let's loop! - renderedContent = that.map(value, function (row) { - return that.render(content, that.create_context(row), partials, true); - }).join(""); - } else if (that.is_object(value)) { // Object, Use it as subcontext! - renderedContent = that.render(content, that.create_context(value), - partials, true); - } else if (typeof value == "function") { - // higher order section - renderedContent = value.call(context, content, function (text) { - return that.render(text, context, partials, true); - }); - } else if (value) { // boolean section - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } - - return renderedBefore + renderedContent + renderedAfter; - }); - }, - - /* - Replace {{foo}} and friends with values from our view - */ - render_tags: function (template, context, partials, in_recursion) { - // tit for tat - var that = this; - - var new_regex = function () { - return that.getCachedRegex("render_tags", function (otag, ctag) { - return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); - }); - }; - - var regex = new_regex(); - var tag_replace_callback = function (match, operator, name) { - switch(operator) { - case "!": // ignore comments - return ""; - case "=": // set new delimiters, rebuild the replace regexp - that.set_delimiters(name); - regex = new_regex(); - return ""; - case ">": // render partial - return that.render_partial(name, context, partials); - case "{": // the triple mustache is unescaped - case "&": // & operator is an alternative unescape method - return that.find(name, context); - default: // escape the value - return escapeHTML(that.find(name, context)); - } - }; - var lines = template.split("\n"); - for(var i = 0; i < lines.length; i++) { - lines[i] = lines[i].replace(regex, tag_replace_callback, this); - if (!in_recursion) { - this.send(lines[i]); - } - } - - if (in_recursion) { - return lines.join("\n"); - } - }, - - set_delimiters: function (delimiters) { - var dels = delimiters.split(" "); - this.otag = this.escape_regex(dels[0]); - this.ctag = this.escape_regex(dels[1]); - }, - - escape_regex: function (text) { - // thank you Simon Willison - if (!arguments.callee.sRE) { - var specials = [ - '/', '.', '*', '+', '?', '|', - '(', ')', '[', ']', '{', '}', '\\' - ]; - arguments.callee.sRE = new RegExp( - '(\\' + specials.join('|\\') + ')', 'g' - ); - } - return text.replace(arguments.callee.sRE, '\\$1'); - }, - - /* - find `name` in current `context`. That is find me a value - from the view object - */ - find: function (name, context) { - name = trim(name); - - // Checks whether a value is thruthy or false or 0 - function is_kinda_truthy(bool) { - return bool === false || bool === 0 || bool; - } - - var value; - - // check for dot notation eg. foo.bar - if (name.match(/([a-z_]+)\./ig)) { - var childValue = this.walk_context(name, context); - if (is_kinda_truthy(childValue)) { - value = childValue; - } - } else { - if (is_kinda_truthy(context[name])) { - value = context[name]; - } else if (is_kinda_truthy(this.context[name])) { - value = this.context[name]; - } - } - - if (typeof value == "function") { - return value.apply(context); - } - if (value !== undefined) { - return value; - } - // silently ignore unkown variables - return ""; - }, - - walk_context: function (name, context) { - var path = name.split('.'); - // if the var doesn't exist in current context, check the top level context - var value_context = (context[path[0]] != undefined) ? context : this.context; - var value = value_context[path.shift()]; - while (value != undefined && path.length > 0) { - value_context = value; - value = value[path.shift()]; - } - // if the value is a function, call it, binding the correct context - if (typeof value == "function") { - return value.apply(value_context); - } - return value; - }, - - // Utility methods - - /* includes tag */ - includes: function (needle, haystack) { - return haystack.indexOf(this.otag + needle) != -1; - }, - - // by @langalex, support for arrays of strings - create_context: function (_context) { - if (this.is_object(_context)) { - return _context; - } else { - var iterator = "."; - if (this.pragmas["IMPLICIT-ITERATOR"]) { - iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; - } - var ctx = {}; - ctx[iterator] = _context; - return ctx; - } - }, - - is_object: function (a) { - return a && typeof a == "object"; - }, - - /* - Why, why, why? Because IE. Cry, cry cry. - */ - map: function (array, fn) { - if (typeof array.map == "function") { - return array.map(fn); - } else { - var r = []; - var l = array.length; - for(var i = 0; i < l; i++) { - r.push(fn(array[i])); - } - return r; - } - }, - - getCachedRegex: function (name, generator) { - var byOtag = regexCache[this.otag]; - if (!byOtag) { - byOtag = regexCache[this.otag] = {}; - } - - var byCtag = byOtag[this.ctag]; - if (!byCtag) { - byCtag = byOtag[this.ctag] = {}; - } - - var regex = byCtag[name]; - if (!regex) { - regex = byCtag[name] = generator(this.otag, this.ctag); - } - - return regex; - } - }; - - return({ - name: "mustache.js", - version: "0.4.0", - - /* - Turns a template and view into HTML - */ - to_html: function (template, view, partials, send_fun) { - var renderer = new Renderer(); - if (send_fun) { - renderer.send = send_fun; - } - renderer.render(template, view || {}, partials); - if (!send_fun) { - return renderer.buffer.join("\n"); - } - } - }); -}(); -/*! - ICanHaz.js -- by @HenrikJoreteg -*/ -/*global */ -(function () { - function trim(stuff) { - if (''.trim) return stuff.trim(); - else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - var ich = { - VERSION: "0.10.2", - templates: {}, - - // grab jquery or zepto if it's there - $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, - - // public function for adding templates - // can take a name and template string arguments - // or can take an object with name/template pairs - // We're enforcing uniqueness to avoid accidental template overwrites. - // If you want a different template, it should have a different name. - addTemplate: function (name, templateString) { - if (typeof name === 'object') { - for (var template in name) { - this.addTemplate(template, name[template]); - } - return; - } - if (ich[name]) { - console.error("Invalid name: " + name + "."); - } else if (ich.templates[name]) { - console.error("Template \"" + name + " \" exists"); - } else { - ich.templates[name] = templateString; - ich[name] = function (data, raw) { - data = data || {}; - var result = Mustache.to_html(ich.templates[name], data, ich.templates); - return (ich.$ && !raw) ? ich.$(trim(result)) : result; - }; - } - }, - - // clears all retrieval functions and empties cache - clearAll: function () { - for (var key in ich.templates) { - delete ich[key]; - } - ich.templates = {}; - }, - - // clears/grabs - refresh: function () { - ich.clearAll(); - ich.grabTemplates(); - }, - - // grabs templates from the DOM and caches them. - // Loop through and add templates. - // Whitespace at beginning and end of all templates inside - - - - - - - - - - - - - - - - -
    diff --git a/docs/basics.html b/docs/basics.html index 31ca641f..4c33ce50 100644 --- a/docs/basics.html +++ b/docs/basics.html @@ -112,7 +112,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/building.html b/docs/building.html index 42ebc0c4..68efdf21 100644 --- a/docs/building.html +++ b/docs/building.html @@ -69,7 +69,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/changelog.html b/docs/changelog.html index 1c09ca7d..0e01c18d 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -84,7 +84,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/fork-n-go.html b/docs/fork-n-go.html index 275b497b..e63f573b 100644 --- a/docs/fork-n-go.html +++ b/docs/fork-n-go.html @@ -66,7 +66,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/sheetsee-core.html b/docs/sheetsee-core.html index 3e7bcc4a..67bb8538 100644 --- a/docs/sheetsee-core.html +++ b/docs/sheetsee-core.html @@ -141,7 +141,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/sheetsee-maps.html b/docs/sheetsee-maps.html index 2c99a3ee..a90fde9b 100644 --- a/docs/sheetsee-maps.html +++ b/docs/sheetsee-maps.html @@ -103,7 +103,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/sheetsee-tables.html b/docs/sheetsee-tables.html index 337561fd..dc22ea3c 100644 --- a/docs/sheetsee-tables.html +++ b/docs/sheetsee-tables.html @@ -132,7 +132,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/tips.html b/docs/tips.html index 7c4227fa..98b6dcf0 100644 --- a/docs/tips.html +++ b/docs/tips.html @@ -105,7 +105,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/index.html b/index.html index 3149b7b4..7acba8ce 100644 --- a/index.html +++ b/index.html @@ -128,7 +128,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/scripts/template.hbs b/scripts/template.hbs index 4c31cce2..a2f1bb70 100644 --- a/scripts/template.hbs +++ b/scripts/template.hbs @@ -45,7 +45,7 @@
  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    From c9593705ad58e6011244d8a453f78d0cd5bf0226 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Tue, 21 Mar 2017 14:09:57 -0400 Subject: [PATCH 146/157] Update sheetsee link --- demos/demo-map.html | 2 +- demos/demo-table.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/demo-map.html b/demos/demo-map.html index 8f7bf514..31519c5d 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -8,7 +8,7 @@ - +
    -

    sheetsee

    -

    Sheetsee.js

    -

    Sheetsee.js is a JavaScript library, or box of goodies, if you will, that makes it easy to use a Google Spreadsheet as the database feeding the tables, charts and maps on a website. Once set up, any changes to the spreadsheet will auto-saved by Google and be live on your site when a visitor refreshes the page.

    -

    Using Google Spreadsheets as the backend database is awesome because it is easy to use, share and collaborate with.

    -

    To use sheetsee.js you'll definitely need to know HTML, CSS and know JavaScript or be not afraid of it and just type what these docs tell you to type. Also, see JavaScript for Cats, Eloquent JavaScript or Mozilla's Developer Network.

    - -

    Dependencies

    -

    Sheetsee.js depends on a few other awesome JavaScript libraries to make all this happen. First, Tabletop.js gets the data from the Google Spreadsheet and makes it nice. Once you have your data Sheetsee.js makes it easy to set up tables or templates with IChanHas.js (built on mustache.js), maps with Mapbox.js, and charts with d3.js. And jQuery of course powers most of the interactions. It also has many sorting and filtering functions built in so that you can display different parts of your data if you want. Each of these are explained in more detail below.

    - -

    CSS

    -

    Sheetsee.js comes with a bare minimum stylesheet. This way you can customize your site to look the way you want to it or to match an existing site's design.

    - -

    Client-side or Server-side

    -

    Sheetsee.js comes in two flavors, client-side (this repo) and server-side (sheetsee-cache). The client-side is the most approachable and straightforward, you just include sheetsee.js and the dependencies on your page and use sheetsee.js as normal.

    -

    The server-side version is built with Node.js and you'll need to understand Node and be publishing to a server that runs Node.js apps. This version saves the data on the server so that the browser doesn't have to fetch from Google at every request, which can sometimes be slow. You can set when the cache expires. It also allows for offline development, huzzah!

    - -
    -

    The Short & Sweet

    -
      -
    1. Link to Sheetsee.js and dependencies in your HTML header.
    2. -
    3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
    4. -
    5. Create templates for tables in <script> tags.
    6. -
    7. Create a script tag that waits for the document to load and then executes any of the map, chart or tables you've specified in it.
    8. -
    9. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information everytime they load the page.
    10. -
    -
    - -

    Bare Minimum Setup

    -

    Ignoring some HTML things to conserve space, you get the point. This gives you a page with a map of your spreadsheets points.

    -
    <html>
    -    <head>
    -        <script type="text/javascript" src="http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.js"></script>
    -        <script type="text/javascript" src="js/ICanHaz.js"></script>
    -        <script type="text/javascript" src="js/jquery.js"></script>
    -        <script type="text/javascript" src="js/tabletop.js"></script>
    -        <script type="text/javascript" src="js/d3.js"></script>
    -        <script type="text/javascript" src="js/sheetsee.js"></script>
    -        <link href='http://api.tiles.mapbox.com/mapbox.js/v1.0.0/mapbox.css' rel='stylesheet' />
    -    </head>
    -    <style> #map {height: 600px; width: 600px;} </style>
    -    <body>
    -    <div id="map"></div>
    -    <script type="text/javascript">
    -      document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -      })
    -      function showInfo(data) {
    -        gData = data
    -        optionsJSON = ["something", "something"]
    -        var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -        var map = Sheetsee.loadMap("map")
    -        Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -        var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, 11)
    -        // customize the popup content
    -        addPopups(map, markerLayer)
    -        function addPopups(map, markerLayer) {
    -          markerLayer.on('click', function(e) {
    -            var feature = e.layer.feature
    -            var popupContent = '<h3>' + feature.opts.something + '</h3>'
    -            e.layer.bindPopup(popupContent,{closeButton: false})
    -          })
    -        }
    -      }
    -    </script>
    -    </body>
    -</html>
    - -

    Awesome Possibilities

    -
      -
    1. Small newsrooms with data for stories but small dev teams.
    2. -
    3. Friends or groups collaborating on data for a website/project.
    4. -
    5. Using iftt.com to auto populate spreadsheets which are hooked to a website with Sheetsee.js.
    6. -
    - -

    Examples

    -
      -
    1. Hack Spots
    2. -
    3. James Sconfitto make a map of his relationship with his wife <3
    4. -
    - -

    Getting Started

    -

    This bit is the same for both client-side and server-side versions.

    -

    Your Data

    -

    sheetsee

    -

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

    -

    sheetsee

    -

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    -
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    - -

    Hexcolor

    -

    sheetsee

    -

    You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    - -

    Geocoding

    -

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin - that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    - sheetsee -

    Publishing Your Spreadsheet

    -

    sheetsee

    -

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    -

    sheetsee

    -

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet.

    -

    Your Website

    -

    Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet.

    -

    For now, create empty div placeholders for the map, chart and tables you plan on including.

    -

    Hooking Up Your Data

    -

    Here the paths diverge:

    -

    Client-side Hookup

    -

    For client-siders, all you need to do is include the depences and sheetsee in your HTML <head> and then in a script tag at the bottom of your page, right before the </body> tag, you'll include this:

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        var gData
    -        var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    -        Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    -    })
    -    function showInfo(data) {
    -        gData = data
    -        //
    -        //everything you do with sheetsee goes here
    -        //
    -    }
    -</script>
    -

    The URL variable is the key from your spreadsheet's longer URL, explained above. Tabletop.init() takes that URL and execute's Tabletop, when it's done generating the table it executes the callback showInfo function. It's inside of this function that you'll then use your spreadsheet data, gData, to do all the Sheetsee.js goodness with.

    -

    Server-side Hookup

    -

    The server-side version is in the repo sheetsee-cache. It uses Node.js to go to Google, get the spreadsheet data (with a Node.js version of Tabletop.js, thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data.

    -

    When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled.

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        // table/templating things the rest can be in their own script tags if you'd like
    -    })
    -</script>
    -

    Running Locally

    -

    You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay!

    -

    Once you clone the repo, navigate there in Terminal, install the node modules and launch the server.

    -
    cd sheetsee-cache
    -npm install
    -node server.js
    -

    This will launch a local server you can visit and develop locally with in your browser.

    -

    Working With Your Data

    -

    Tabletop.js will return all of your data and it will be passed into your site as an array of objects called gData. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like.

    -

    Play Along!

    -

    This page is using sheetsee. If you (are in Chrome and) right click on the page and select Inspect Element it will bring up the Web Inspector. Select the Console tab. Now you can interact with the data and functions from Sheetsee. Give the functions below a try - gData is the variable with the data (from this spreadsheet). - sheetsee -

    Sheetsee.getKeyword(data, keyword)

    -

    This takes in your data, an array of objects, and searches for a string, keyword, in each piece of your data (formerly the cells of your spreadsheet). It returns an array of each row that contained a keyword match. Similarly, using `getKeywordCount(data, keyword)` will return just the number of times the keyword occured.

    -
    getKeyword(gData, "cat")
    -// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}]
    -

    Sheetsee.getColumnTotal(data, column)

    -

    Given your data, an array of objects and a string column header, this functions sums each cell in that column, so they best be numbers.

    -
    getColumnTotal(gData, "cuddlability")
    -// returns 11
    -

    Sheetsee.getAveragefromColumn(data, column)

    -

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    -
    getColumnAverage(gData, "cuddlability")
    -// returns 1.8333333333333333
    -

    Sheetsee.getMin(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    -
    getMin(gData, "cuddlability")
    -// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}]
    - -

    Sheetsee.getMax(data, column)

    -

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    -
    getMax(gData, "cuddlability")
    -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...}
    - -
    - - -

    Don't Forget JavaScript Math

    -

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    -
    var profit09 = Sheetsee.getColumnTotal(gData, "2009")
    -var profit10 = Sheetsee.getColumnTotal(gData, "2010")
    -var difference = profit09 - profit10
    -

    What These Little Bits are Good For

    -

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about icanhas.js. View source on this page to see how I created "Most Cuddlable".

    - -

    Sheetsee.getMatches(data, filter, category)

    -

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    -
    getMatches(gData, "dog", "kind")
    -

    Returns an array of objects matching the category's filter.

    -
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    - -

    Sheetsee.getOccurance(data, category)

    -

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    -
    getOccurance(gData, "kind")
    -

    Returns an object with keys and values for each variation of the category and its occurance.

    -
    {"dog": 3, "cat": 3}
    - -

    Sheetsee.makeColorArrayOfObject(data, colors)

    -

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    -

    This function takes in your data, as an object, an array of hexidecimal color strings which you define and the category you used in getOccurance().

    -
    var kinds = getOccurance(gData, "kind")
    -var kindColors = ["#ff00ff", "#DCF13C"]
    -var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors, "kind")
    -

    It will return an array of objects with units as the title of the occurance amount like so:

    -
    [{"kind": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"kind": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    -

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    - -

    Make a Map

    -
    -

    Sheetsee.js uses Mapbox.js, a Leaflet.js plugin, to make maps.

    -

    Create an empty <div> in your HTML, with an id.

    -
    <div id="map"></div>
    -

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    - -

    Sheetsee.createGeoJSON(data, optionsJSON)

    -

    This takes in your data and the parts of your data, optionsJSON, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data.

    -
    var optionsJSON = ["name", "breed", "cuddlability"]
    -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    -

    It will return an array in the special geoJSON format that map making things love.

    -
    [{
    -  "geometry": {"type": "Point", "coordinates": [long, lat]},
    -  "properties": {
    -    "marker-size": "small",
    -    "marker-color": lineItem.hexcolor
    -  },
    -  "opts": {the options you pass in},
    -}}
    - -

    Sheetsee.loadMap(mapDiv)

    -

    To create a simple map, with no data, you simply call `.loadMap() and pass in a string of the mapDiv (with no #) from your HTML.

    -
    var map = Sheetsee.loadMap("map")
    - -

    Sheetsee.addTileLayer(map, tileLayer)

    -

    To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

    -
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    -

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    - -

    Sheetsee.addMarkerLayer(geoJSON, map, zoomLevel)

    -

    To add makers to your map, use this function and pass in your geoJSON so that it can get the coordinates, your map so that it places the markers there and a zoom level.

    -
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, 11)
    - -

    Sheetsee.addPopups(map, markerLayer)

    -

    To customize the marker popup content in your map use this function and pass in your map and markerLayer.

    -
     Sheetsee.addPopups(map, markerLayer)
    -

    To customize the marker popup content in your map you'll need to use this entire function on your website.

    -
    function addPopups(map, markerLayer) {
    -  markerLayer.on('click', function(e) {
    -    var feature = e.layer.feature
    -    var popupContent = '<h2>' + feature.opts.name + '</h2>' +
    -                        '<h3>' + feature.opts.breed + '</h3>'
    -    e.layer.bindPopup(popupContent,{closeButton: false,})
    -  })
    -}
    -

    You will edit the popupContent variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use feature.opts and then one of the column headers you passed into createGeoJSON().

    - -

    Make a Table

    - -
    -

    Example - Local Pet Friends

    - - Clear - no matches -
    -
    - - -

    Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for searches and table headers can be used to sort the data in that column. For each of these you'll need a <div> in your html, a <script> template and a <script> that calls table functions.

    -

    Your HTML Placeholder <div>

    -

    This is as simple as an empty <div> with an id. This id should match the script tempate id in the next section.

    -
     <div id="siteTable"></div>
    -

    Your <script> Template

    -

    Your template is the mockup of what you'd like your table to look like and what content it should show. Most of this is up to you but if you want users to be able to click on headers and sort that column you must make a table row with table headers with the class tHeader.

    -

    The variables inside the {{}} must match the column headers in your spreadsheet. Lowercase (?) and remember spaces are ommited, so "Place Name" will become "placename".

    -
    <script id="siteTable" type="text/html">
    -    <table>
    -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    -      {{#rows}}
    -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    -      {{/rows}}
    -  </table>
    -</script>
    -

    Your <script> Execution

    -
    <script type="text/javascript">
    -    document.addEventListener('DOMContentLoaded', function() {
    -        Sheetsee.makeTable(gData, "#siteTable")
    -        Sheetsee.initiateTableFilter(gData, "#tableFilter", "#siteTable")
    -    })
    -</script>
    -

    To create another table, simply repeat the steps with the corresponding data and divs.

    -
    <div id="secondTable"></div>
    -<script id="secondTable"> // your table template here </script>
    -<script>
    -  Sheetsee.makeTable(otherData, "#secondTable")
    -  Sheetsee.initiateTableFilter(otherData, "#secondFilter", "#secondTable")
    -</script>
    -
    -

    Learn more about the things you can do with mustache.js.

    - -

    Sheetsee.makeTable(data, targetDiv)

    -

    You'll call this to make a table out of a data and tell it what targetDiv in the html to render it in (this should also be the same id as your script template id).

    -
    Sheetsee.makeTable(gData, "#siteTable")
    - -

    Table Filter/Search

    -

    If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html:

    -
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    -<span class="clear button">Clear</span>
    -<span class="noMatches">no matches</span>
    - -

    Sheetsee.initiateTableFilter(data, filterDiv, tableDiv)

    -

    You will then call this function to make that input live:

    -
    Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable")
    - -

    Make a Chart

    -

    Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an array of objects, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting.

    -

    You'll have to experiement with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    -

    You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee.

    - -

    Bar Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    -
    <div id="barChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • xaxis is optional text label for your x axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3BarChart() function with your data and options.

    -
    Sheetsee.d3BarChart(data, barOptions)
    - -

    Line Chart

    - -
    -
    -
    - -

    To create a line chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="lineChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options.

    -
    var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • yaxis is optional text label for your y axis
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3LineChart() function with your data and options.

    -
    Sheetsee.d3LineChart(data, lineOptions)
    - -

    Pie Chart

    - -
    -
    -
    - -

    To create a bar chart you'll need to add a placeholder <div> in your html with an id.

    -
    <div id="pieChart"></div>
    -

    In your CSS, give it dimensions.

    -
    #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    -

    In a <script> tag set up your options. You must include labels and units, this tells it what you're charting. Because for the pie chart we're using data we got from getOccurance() and makeColorArrayofObject(), our units are already called units. If we were using original data, we might have units as "cuddleability" or something else.

    -
    var pieOptions = {labels: "kind", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    -
      -
    • labels is a string, usually a column header, it's what you call what you're charting
    • -
    • units is a string, usually a column header, it's the value you're charting
    • -
    • m is your margins: top, right, bottom, left
    • -
    • w and h are width and height, this should match your CSS specs
    • -
    • div is the id for the <div> in your HTML
    • -
    • hiColor is the highlight color of your choosing!
    • -
    -

    Then call the d3PieChart() function with your data and options.

    -
    Sheetsee.d3PieChart(data, pieOptions)
    - -

    Don't forget, right click this page, select View Source and scroll to the bottom and see exactly how these charts were set up!

    - - -

    Big Time Thanks

    -

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georga.

    -

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    -

    Thanks to Max Ogden for emotional support, teaching me JavaScript and working on the harder parts of Sheetsee.js - especially for making Tabletop.js for Node.js.

    -

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    -

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    - -

    Licensed under BSD. East Bay represent!

    - - - - - - - - - diff --git a/index.html b/index.html deleted file mode 100644 index 27151c7a..00000000 --- a/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - Yo, yo, yo! - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/js/ICanHaz.js b/js/ICanHaz.js deleted file mode 100644 index 25a14ac6..00000000 --- a/js/ICanHaz.js +++ /dev/null @@ -1,542 +0,0 @@ -/*! -ICanHaz.js version 0.10 -- by @HenrikJoreteg -More info at: http://icanhazjs.com -*/ -(function () { -/* - mustache.js — Logic-less templates in JavaScript - - See http://mustache.github.com/ for more info. -*/ - -var Mustache = function () { - var _toString = Object.prototype.toString; - - Array.isArray = Array.isArray || function (obj) { - return _toString.call(obj) == "[object Array]"; - } - - var _trim = String.prototype.trim, trim; - - if (_trim) { - trim = function (text) { - return text == null ? "" : _trim.call(text); - } - } else { - var trimLeft, trimRight; - - // IE doesn't match non-breaking spaces with \s. - if ((/\S/).test("\xA0")) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; - } else { - trimLeft = /^\s+/; - trimRight = /\s+$/; - } - - trim = function (text) { - return text == null ? "" : - text.toString().replace(trimLeft, "").replace(trimRight, ""); - } - } - - var escapeMap = { - "&": "&", - "<": "<", - ">": ">", - '"': '"', - "'": ''' - }; - - function escapeHTML(string) { - return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { - return escapeMap[s] || s; - }); - } - - var regexCache = {}; - var Renderer = function () {}; - - Renderer.prototype = { - otag: "{{", - ctag: "}}", - pragmas: {}, - buffer: [], - pragmas_implemented: { - "IMPLICIT-ITERATOR": true - }, - context: {}, - - render: function (template, context, partials, in_recursion) { - // reset buffer & set context - if (!in_recursion) { - this.context = context; - this.buffer = []; // TODO: make this non-lazy - } - - // fail fast - if (!this.includes("", template)) { - if (in_recursion) { - return template; - } else { - this.send(template); - return; - } - } - - // get the pragmas together - template = this.render_pragmas(template); - - // render the template - var html = this.render_section(template, context, partials); - - // render_section did not find any sections, we still need to render the tags - if (html === false) { - html = this.render_tags(template, context, partials, in_recursion); - } - - if (in_recursion) { - return html; - } else { - this.sendLines(html); - } - }, - - /* - Sends parsed lines - */ - send: function (line) { - if (line !== "") { - this.buffer.push(line); - } - }, - - sendLines: function (text) { - if (text) { - var lines = text.split("\n"); - for (var i = 0; i < lines.length; i++) { - this.send(lines[i]); - } - } - }, - - /* - Looks for %PRAGMAS - */ - render_pragmas: function (template) { - // no pragmas - if (!this.includes("%", template)) { - return template; - } - - var that = this; - var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { - return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); - }); - - return template.replace(regex, function (match, pragma, options) { - if (!that.pragmas_implemented[pragma]) { - throw({message: - "This implementation of mustache doesn't understand the '" + - pragma + "' pragma"}); - } - that.pragmas[pragma] = {}; - if (options) { - var opts = options.split("="); - that.pragmas[pragma][opts[0]] = opts[1]; - } - return ""; - // ignore unknown pragmas silently - }); - }, - - /* - Tries to find a partial in the curent scope and render it - */ - render_partial: function (name, context, partials) { - name = trim(name); - if (!partials || partials[name] === undefined) { - throw({message: "unknown_partial '" + name + "'"}); - } - if (!context || typeof context[name] != "object") { - return this.render(partials[name], context, partials, true); - } - return this.render(partials[name], context[name], partials, true); - }, - - /* - Renders inverted (^) and normal (#) sections - */ - render_section: function (template, context, partials) { - if (!this.includes("#", template) && !this.includes("^", template)) { - // did not render anything, there were no sections - return false; - } - - var that = this; - - var regex = this.getCachedRegex("render_section", function (otag, ctag) { - // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder - return new RegExp( - "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) - - otag + // {{ - "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) - ctag + // }} - - "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped - - otag + // {{ - "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). - ctag + // }} - - "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. - - "g"); - }); - - - // for each {{#foo}}{{/foo}} section do... - return template.replace(regex, function (match, before, type, name, content, after) { - // before contains only tags, no sections - var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", - - // after may contain both sections and tags, so use full rendering function - renderedAfter = after ? that.render(after, context, partials, true) : "", - - // will be computed below - renderedContent, - - value = that.find(name, context); - - if (type === "^") { // inverted section - if (!value || Array.isArray(value) && value.length === 0) { - // false or empty list, render it - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } else if (type === "#") { // normal section - if (Array.isArray(value)) { // Enumerable, Let's loop! - renderedContent = that.map(value, function (row) { - return that.render(content, that.create_context(row), partials, true); - }).join(""); - } else if (that.is_object(value)) { // Object, Use it as subcontext! - renderedContent = that.render(content, that.create_context(value), - partials, true); - } else if (typeof value == "function") { - // higher order section - renderedContent = value.call(context, content, function (text) { - return that.render(text, context, partials, true); - }); - } else if (value) { // boolean section - renderedContent = that.render(content, context, partials, true); - } else { - renderedContent = ""; - } - } - - return renderedBefore + renderedContent + renderedAfter; - }); - }, - - /* - Replace {{foo}} and friends with values from our view - */ - render_tags: function (template, context, partials, in_recursion) { - // tit for tat - var that = this; - - var new_regex = function () { - return that.getCachedRegex("render_tags", function (otag, ctag) { - return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); - }); - }; - - var regex = new_regex(); - var tag_replace_callback = function (match, operator, name) { - switch(operator) { - case "!": // ignore comments - return ""; - case "=": // set new delimiters, rebuild the replace regexp - that.set_delimiters(name); - regex = new_regex(); - return ""; - case ">": // render partial - return that.render_partial(name, context, partials); - case "{": // the triple mustache is unescaped - case "&": // & operator is an alternative unescape method - return that.find(name, context); - default: // escape the value - return escapeHTML(that.find(name, context)); - } - }; - var lines = template.split("\n"); - for(var i = 0; i < lines.length; i++) { - lines[i] = lines[i].replace(regex, tag_replace_callback, this); - if (!in_recursion) { - this.send(lines[i]); - } - } - - if (in_recursion) { - return lines.join("\n"); - } - }, - - set_delimiters: function (delimiters) { - var dels = delimiters.split(" "); - this.otag = this.escape_regex(dels[0]); - this.ctag = this.escape_regex(dels[1]); - }, - - escape_regex: function (text) { - // thank you Simon Willison - if (!arguments.callee.sRE) { - var specials = [ - '/', '.', '*', '+', '?', '|', - '(', ')', '[', ']', '{', '}', '\\' - ]; - arguments.callee.sRE = new RegExp( - '(\\' + specials.join('|\\') + ')', 'g' - ); - } - return text.replace(arguments.callee.sRE, '\\$1'); - }, - - /* - find `name` in current `context`. That is find me a value - from the view object - */ - find: function (name, context) { - name = trim(name); - - // Checks whether a value is thruthy or false or 0 - function is_kinda_truthy(bool) { - return bool === false || bool === 0 || bool; - } - - var value; - - // check for dot notation eg. foo.bar - if (name.match(/([a-z_]+)\./ig)) { - var childValue = this.walk_context(name, context); - if (is_kinda_truthy(childValue)) { - value = childValue; - } - } else { - if (is_kinda_truthy(context[name])) { - value = context[name]; - } else if (is_kinda_truthy(this.context[name])) { - value = this.context[name]; - } - } - - if (typeof value == "function") { - return value.apply(context); - } - if (value !== undefined) { - return value; - } - // silently ignore unkown variables - return ""; - }, - - walk_context: function (name, context) { - var path = name.split('.'); - // if the var doesn't exist in current context, check the top level context - var value_context = (context[path[0]] != undefined) ? context : this.context; - var value = value_context[path.shift()]; - while (value != undefined && path.length > 0) { - value_context = value; - value = value[path.shift()]; - } - // if the value is a function, call it, binding the correct context - if (typeof value == "function") { - return value.apply(value_context); - } - return value; - }, - - // Utility methods - - /* includes tag */ - includes: function (needle, haystack) { - return haystack.indexOf(this.otag + needle) != -1; - }, - - // by @langalex, support for arrays of strings - create_context: function (_context) { - if (this.is_object(_context)) { - return _context; - } else { - var iterator = "."; - if (this.pragmas["IMPLICIT-ITERATOR"]) { - iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; - } - var ctx = {}; - ctx[iterator] = _context; - return ctx; - } - }, - - is_object: function (a) { - return a && typeof a == "object"; - }, - - /* - Why, why, why? Because IE. Cry, cry cry. - */ - map: function (array, fn) { - if (typeof array.map == "function") { - return array.map(fn); - } else { - var r = []; - var l = array.length; - for(var i = 0; i < l; i++) { - r.push(fn(array[i])); - } - return r; - } - }, - - getCachedRegex: function (name, generator) { - var byOtag = regexCache[this.otag]; - if (!byOtag) { - byOtag = regexCache[this.otag] = {}; - } - - var byCtag = byOtag[this.ctag]; - if (!byCtag) { - byCtag = byOtag[this.ctag] = {}; - } - - var regex = byCtag[name]; - if (!regex) { - regex = byCtag[name] = generator(this.otag, this.ctag); - } - - return regex; - } - }; - - return({ - name: "mustache.js", - version: "0.4.0", - - /* - Turns a template and view into HTML - */ - to_html: function (template, view, partials, send_fun) { - var renderer = new Renderer(); - if (send_fun) { - renderer.send = send_fun; - } - renderer.render(template, view || {}, partials); - if (!send_fun) { - return renderer.buffer.join("\n"); - } - } - }); -}(); -/*! - ICanHaz.js -- by @HenrikJoreteg -*/ -/*global */ -(function () { - function trim(stuff) { - if (''.trim) return stuff.trim(); - else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); - } - var ich = { - VERSION: "0.10", - templates: {}, - - // grab jquery or zepto if it's there - $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, - - // public function for adding templates - // can take a name and template string arguments - // or can take an object with name/template pairs - // We're enforcing uniqueness to avoid accidental template overwrites. - // If you want a different template, it should have a different name. - addTemplate: function (name, templateString) { - if (typeof name === 'object') { - for (var template in name) { - this.addTemplate(template, name[template]); - } - return; - } - if (ich[name]) { - console.error("Invalid name: " + name + "."); - } else if (ich.templates[name]) { - console.error("Template \"" + name + " \" exists"); - } else { - ich.templates[name] = templateString; - ich[name] = function (data, raw) { - data = data || {}; - var result = Mustache.to_html(ich.templates[name], data, ich.templates); - return (ich.$ && !raw) ? ich.$(result) : result; - }; - } - }, - - // clears all retrieval functions and empties cache - clearAll: function () { - for (var key in ich.templates) { - delete ich[key]; - } - ich.templates = {}; - }, - - // clears/grabs - refresh: function () { - ich.clearAll(); - ich.grabTemplates(); - }, - - // grabs templates from the DOM and caches them. - // Loop through and add templates. - // Whitespace at beginning and end of all templates inside - - - - - - - - - -
    - - - -``` - -## Awesome Possibilities - -1. Small newsrooms with data for stories but small dev teams. -2. Friends or groups collaborating on data for a website/project. -3. Using [iftt.com](http://www.ifttt.com) to auto populate spreadsheets which are hooked to a website with Sheetsee.js. - -## Examples -1. [Hack Spots](http://jlord.github.io/hack-spots) -2. [James Sconfitto](https://twitter.com/jugglingnutcase) make a [map of his relationship](https://github.com/jugglingnutcase/katiejamie) with his wife <3 - -## Getting Started - -This bit is the same for both client-side and server-side versions. - -### Your Data - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) - -Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/nonos.png) - -There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting. - - [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] - -#### Hexcolor - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) - -You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! - -#### Geocoding - -If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) - that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. - -> image of lat and long column headers - -#### Publishing Your Spreadsheet - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) - -You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click _File_ > _Publish to the Web_. Then in the next window click _Start Publishing_; it will then turn into a _Stop Publishing_ button. - -![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) - -You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. - -### Your Website - -Before you get started with Sheetsee.js you should plan out your website. Design it, create the basic markup and stylesheet. - -For now, create empty `div` placeholders for the map, chart and tables you plan on including. - -## Hooking Up Your Data - -Here the paths diverge: - -### Client-side Hookup - -For client-siders, all you need to do is include the dependencies and sheetsee in your HTML `` and then in a script tag at the bottom of your page, right before the `` tag, you'll include this: - -``` html - -``` - -The **URL** variable is the key from your spreadsheet's longer URL, explained above. `Tabletop.init()` takes that URL and execute's Tabletop, when it's done generating the table it executes the callback `showInfo` function. It's inside of this function that you'll then use your spreadsheet data, **gData**, to do all the Sheetsee.js goodness with. - -### Server-side Hookup - -The server-side version is in the repo [sheetsee-cache](http://www.github.com/jllord/sheetsee-cache). It uses [Node.js](http://www.nodejs.org) to go to Google, get the spreadsheet data (with a Node.js version of [Tabletop.js](http://npmjs.org/tabletop), thanks Max Ogden!) and save it on the server. This means every user that visits the page doesn't have to wait on Google's response to load the charts from the data. - -When the server builds your page, it will build in your data as the variable gData. All you need to do is add your scripts to the bottom of the page. For the tables/templating you'll need to wrap them in an event listener so that it doesn't try and build them before the data has settled. - -``` html - -``` - -#### Running Locally - -You can run this locally and it will check your internet connection - if you're not online it will use the last saved data allowing you to develop offline, yay! - -Once you [clone the repo](http://www.github.com/jllord/sheetsee-cache), navigate there in Terminal, install the node modules and launch the server. - -``` sh -cd sheetsee-cache -npm install -node server.js -``` - -This will launch a local server you can visit and develop locally with in your browser. - -## Working With Your Data - -Tabletop.js will return all of your data and it will be passed into your site as an _array of objects_ called **gData**. Sheetsee.js has functions built in to help you filter or use that data in other ways if you'd like. - -### Sheetsee.getKeyword(data, keyword) - -This takes in your data, an _array of objects_, and searches for a _string_, **keyword**, in each piece of your **data** (formerly the cells of your spreadsheet). It returns an array of each element containing a **keyword** match. Similarly, using `getKeywordCount(data, "keyword)` will return the just the number of times the **keyword** occured. - -``` js -getKeyword(gData, "cat") -// returns [{breed: "Fat", kind: "cat", hexcolor: "#CDCF83"...}, {breed: "Grey", kind: "cat", hexcolor: "#9C9B9A"...}, {breed: "Creepy", kind: "cat", hexcolor: "#918376"...}] -``` - -### Sheetsee.getColumnTotal(data, column) - -Given your **data**, an _array of objects_ and a _string_ **column** header, this functions sums each cell in that column, so they best be numbers. - -``` js -getColumnTotal(gData, "cuddlability") -// returns 11 -``` - -### Sheetsee.getAveragefromColumn(data, column) - -A really simple function that builds on `getColumnTotal()` by returning the average number in a **column** of numbers. - -``` js -getColumnAverage(gData, "cuddlability") -// returns 1.8333333333333333 -``` - -### Sheetsee.getMin(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the lowest number value in the **column** you specify from your **data**. - -``` js -getMin(gData, "cuddlability") -// returns [{breed: "Fat", cuddlability: "0", hexcolor: "#CDCF83"...}, {breed: "Grey", cuddlability: "0", hexcolor: "#9C9B9A"...}, {breed: "Creepy", cuddlability: "0", hexcolor: "#918376"...}] -``` - -### Sheetsee.getMax(data, column) - -This will return an _array_ of _object_ or _objects_ (if there is a tie) of the element with the highest number value in the **column** you specify from your **data**. - -``` js -getMax(gData, "cuddlability") -// returns {breed: "Teacup Maltese", cuddlability: "5", hexcolor: "#ECECEC", kind: "Dog", lat: "37.74832", long: "-122.402158", name: "Coco"...} -``` - -### Don't Forget JavaScript Math - -Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that [here on MDN](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math). - -``` js -var profit09 = Sheetsee.getColumnTotal(gData, "2009") -var profit10 = Sheetsee.getColumnTotal(gData, "2010") -var difference = profit09 - profit10 -``` - -#### What These Little Bits are Good For - -You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with javascirpt math functions and knowing a little bit more about [icanhas.js](http://icanhazjs.com/). View source on this page to see how I created "Most Cuddlable". - -### Sheetsee.getMatches(data, filter, category) - -Takes **data** as an _array of objects_, a _string_ you'd like to **filter** and a _string_ of the **category** you want it to look in (a column header from your spreadsheet). - -``` js -getMatches(gData, "dog", "kind") -``` - -Returns an _array of objects_ matching the category's filter. - -``` js -[{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ] -``` +![sheetseeimg](https://raw.github.com/jlord/sheetsee-cache/master/img/sheetsee-03.png) +# Sheetsee.js -### Sheetsee.getOccurance(data, category) - -Takes **data** as an _array of objects_ and a _string_ for **category** (a column header from your spreadsheet) you want tally how often an element occured. - -``` js -getOccurance(gData, "kind") -``` - -Returns an object with keys and values for each variation of the category and its occurance. - -``` js -{"dog": 3, "cat": 3} -``` - -### Sheetsee.makeColorArrayOfObject(data, colors) - -If you use `getOccurance()` and want to then chart that data with d3.js, you'll need to make it into an _array_ (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset). - -This function takes in your data, as an _object_, and an _array_ of hexidecimal color strings which you define. - -``` js -var kinds = getOccurance(gData, "kind") -var kindColors = ["#ff00ff", "#DCF13C"] - -var kindData = makeColorArrayOfObjects(mostPopBreeds, kindColors) -``` - -It will return an array of objects formatted to go directly into a d3 chart with the appropriate _units_ and _label keys_, like so: - -``` js -[{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}] -``` - -If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements. - -## Make a Map - -Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js), a [Leaflet.js](http://leafletjs.com/) plugin, to make maps. - -Create an empty `
    ` in your HTML, with an id. - -``` html -
    -``` - -Next you'll need to create geoJSON out of your data so that it can be mapped. - -### Sheetsee.createGeoJSON(data, optionsJSON) - -This takes in your **data** and the parts of your data, **optionsJSON**, that you plan in your map's popups. If you're not going to have popups on your markers, don't worry about it then and just pass in your data. - -``` js -var optionsJSON = ["name", "breed", "cuddlability"] -var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON) -``` - -It will return an _array_ in the special geoJSON format that map making things love. - -``` js -[{ - "geometry": {"type": "Point", "coordinates": [long, lat]}, - "properties": { - "marker-size": "small", - "marker-color": lineItem.hexcolor - }, - "opts": {the options you pass in}, -}} -``` - - -### Sheetsee.loadMap(mapDiv) - -To create a simple map, with no data, you simply call `.loadMap() and pass in a _string_ of the **mapDiv** (with no #) from your HTML. - -``` js -var map = Sheetsee.loadMap("map") -``` - -### Sheetsee.addTileLayer(map, tileLayer) - -To add a tile layer, aka a custom map scheme/design/background, you'll use this function which takes in your **map** and the source of the **tileLayer**. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See [Mapbox's Documentation](http://mapbox.com/mapbox.js/api/v1.0.2/#L.mapbox.tileLayer) for more information. - -``` js -Sheetsee.addTileLayer(map, 'examples.map-20v6611k') -``` - -You can add tiles from awesome mapmakers like [Stamen](examples.map-20v6611k) or create your own in Mapbox's [Tilemill](http://www.mapbox.com/tilemill) or [online](https://tiles.mapbox.com/newmap#3.00/0.00/0.00). - -### Sheetsee.addMarkerLayer(geoJSON, map, zoomLevel) - -To add makers to your map, use this function and pass in your **geoJSON** so that it can get the coordinates, your **map** so that it places the markers there and a **zoom level**. - -``` js -var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, 11) -``` - -### Sheetsee.addPopups(map, markerLayer) - -To customize the marker popup content in your map you'll need to use this entire function on your website. - -``` js -function addPopups(map, markerLayer) { - markerLayer.on('click', function(e) { - var feature = e.layer.feature - var popupContent = '

    ' + feature.opts.name + '

    ' + - '

    ' + feature.opts.breed + '

    ' - e.layer.bindPopup(popupContent,{closeButton: false,}) - }) -} -``` - -You will edit the **popupContent** variable however you'd like your popups to look. To reference the data you sent to you geoJSON you'll use `feature.opts` and then one of the column headers you passed into `createGeoJSON().` - -## Make a Table - -Sheetsee.js supports making multiple tables or templates with IcanHas.js. The tables can have multiple inputs for filtering and table headers can be used to sort the data in that column. For each of these you'll need a `
    ` in your html, a ` -``` - -#### Your ` -``` - -To create another table, simply repeat the steps. - -``` html -
    - - -``` - - Learn more about the things you can do with [mustache.js](http://mustache.github.io/). - - -### Sheetsee.makeTable(data, targetDiv) - -You'll call this to make a table out of a **data** and tell it what **targetDiv** in the html to render it in (this should also be the same id as your script template id). - -``` js -Sheetsee.makeTable(gData, "#siteTable") -``` - -## Table Filter/Search - -If you want to have an input to allow users to search/filter the data in the table, you'll add this to your html: - -``` html - -Clear -no matches -``` - -### Sheetsee.initiateTableFilter(data, filterDiv, tableDiv) - -You will then call this function to make that input live: - -``` js -Sheetsee.initiateTableFilter(gData, "#TableFilter", "#siteTable") -``` - -## Make a Chart - -Sheetsee.js comes with a d3.js bar, pie and line chart. Each requires your data be an _array of objects_, formatted to contain "label" and "units" keys. See the section above on Your Data to learn about formatting. - -You'll have to experiement with the charts to find the correct size your `
    ` will need to be to hold the chart with your data in it nicely. - -You can also make your own d3 chart in a separate .js file, link to that and pass your data on to it. I'd love to see people building some other charts that will work with Sheetsee. - -### Bar Chart - -To create a bar chart you'll need to add a placeholder `
    ` in your HTML with an id. - -``` html -
    -``` - -In your CSS, give it dimensions. - -``` css -#barChart {height: 400px; max-width: 600px; background: #F8CDCD;} -``` - -In a ` + + + + + + + + +
    +

    Pennies by State

    +

    spreadsheet

    +
    +

    View Source // View Documentation

    + + +
    + + + + + diff --git a/demos/demo-map.html b/demos/demo-map.html new file mode 100644 index 00000000..b5489c66 --- /dev/null +++ b/demos/demo-map.html @@ -0,0 +1,79 @@ + + + + + Sheetsee Maps Demo + + + + + + + + + +
    +

    All Pennies Map

    +

    spreadsheet

    +

    +

    View Source // View Documentation

    + + + + + + diff --git a/demos/demo-table.html b/demos/demo-table.html new file mode 100644 index 00000000..53400923 --- /dev/null +++ b/demos/demo-table.html @@ -0,0 +1,123 @@ + + + + + Sheetsee Table Demo + + + + + + + + +
    +

    All Pennies

    +

    spreadsheet

    + +

    +

    California Pennies

    + +
    +

    Pretty Pennies

    +
    +

    View Source // View Documentation

    + + +
    + + + + + + + + + + + diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 00000000..55ff664a --- /dev/null +++ b/docs/about.md @@ -0,0 +1,39 @@ +# About + +Sheetsee.js began as a part of my [Code for America](http://www.codeforamerica.org) 2012 Fellowship project, [See Penny Work](http://www.seepennywork.in). The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet. + +In early 2013, after the CfA Fellowship, I recieved a grant from [Mozilla Open News](http://opennews.org/) to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2. + +The present version makes the project modular, customizable and with more maping and table features. + +## Built on top of Tabletop.js +Sheetsee would not exist were it not for [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js. + +### Sheetsee.js + Mapbox.js + d3.js +Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, **sheetsee-tables**, comes with sorting, filtering and pagination. **Sheetsee-maps** is built ontop of [Leaflet.js](http://leafletjs.com/) and [Mapbox.js](https://www.mapbox.com/mapbox.js/) and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, **Sheetee-charts** comes with three basic [d3.js](http://d3js.org) charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is [here](docs/custom-chart.md). + +## Hacked on Openly +- Sheetsee.js is open source software with a [BSD license](docs/license.md). +- Sheetsee.js is a labor of love by [jlord](http://www.github.com/jlord) ([twitter](http://www.twitter.com/jllord)) with support from [contributors](https://github.com/jlord/sheetsee.js/graphs/contributors). + +## Contact +- File a [new issue](https://github.com/jlord/sheetsee.js/issues/new) for ideas and bug reports. +- If your issue falls specifically with one of the modules, you can file it on its particular repo: + - [sheetsee](http://www.github.com/jlord/sheetsee/issues/new) + - [sheetsee-core](http://www.github.com/jlord/sheetsee-core/issues/new) + - [sheetsee-tables](http://www.github.com/jlord/sheetsee-tables/issues/new) + - [sheetsee-maps](http://www.github.com/jlord/sheetsee-maps/issues/new) + - [sheetsee-charts](http://www.github.com/jlord/sheetsee-charts/issues/new) +- [@jllord](http://www.twitter.com/jllord) on Twitter. + +## Big Time Thanks + +Thanks to [Code for America](http://www.codeforamerica.org) for providing the platform me to build the first version of sheetsee.js for Macon, Georgia. + +Thanks to [Dan Sinker](http://www.twitter.com/dansinker) at [Open News](http://www.mozillaopennews.org/) for having faith and getting things together to make this Code Sprint happen and thanks to [Matt Green](https://twitter.com/whatsnewmedia) at WBEZ for being a willing partner. + +Thanks to [Max Ogden](http://www.twitter.com/maxogden) for emotional support, teaching me JavaScript and answering lots of questions. + +Thanks to all the authors and contributors to Tabletop.js, [Mapbox.js](https://www.mapbox.com/mapbox.js/), [Leaflet.js](http://leafletjs.com/), jQuery, [ICanHas.js](http://icanhazjs.com/) and [d3.js](http://d3js.org). Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow. + +Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here. diff --git a/docs/basics.md b/docs/basics.md new file mode 100644 index 00000000..a073a3af --- /dev/null +++ b/docs/basics.md @@ -0,0 +1,93 @@ +# Spreadsheets as Databases + +Spreadsheets are a great _lightweight_ databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet! + +## The Short & Sweet + +1. Link to Sheetsee.js, [tabletop.js](https://github.com/jsoma/tabletop/) and [jQuery](http://www.jquery.org) in your HTML head. +2. Create a place holder `
    ` in your HTML for any chart, map or table you want to have. +3. Create templates for tables in ` + + + + + +
    + + + + + + +``` + +## Your Data + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/spreadsheettodata.png) + +Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data. + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/nonos.png) + +There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting. + + [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...] + +### Hexcolor + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/hexcolors.png) + +You must add a column to your spreadsheet with the heading _hexcolor_ (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This [color picker](http://color.hailpixel.com/) by [Devin Hunt](https://twitter.com/hailpixel) is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight! + +### Geocoding + +If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a [plugin](http://mapbox.com/tilemill/docs/guides/google-docs/#geocoding) + that does this for you in Google Docs. You can also use websites like [latlong.net](http://www.latlong.net/) to get the coordinates and paste them into rows with column headers _lat_ and _long_. + +### Publishing Your Spreadsheet + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/publish.png) + +You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click _File_ > _Publish to the Web_. Then in the next window click _Start Publishing_; it will then turn into a _Stop Publishing_ button. + +![sheetsee](https://raw.github.com/jllord/sheetsee-cache/master/img/key.png) + +You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. _Actually, you technically can use the whole URL, but it's so long..._ + +### CSS + +Sheetsee.js comes with a bare minimum stylesheet, `sss.csss`, which contains elements you'll want to style when using the feature they correspond to. diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 00000000..77822a65 --- /dev/null +++ b/docs/building.md @@ -0,0 +1,42 @@ +# Right-sizing + +You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at [github.com/jlord/sheetsee.js](https://github.com/jlord/sheetsee.js/blob/master/js/sheetsee.js). + +All bundle comes with [mapbox.js]() and [handlebars.js]() (since both are available on [NPM](http://www.npmjs.org)). Additionally you'll need to also include [tabletop.js](https://github.com/jsoma/tabletop) and [jQuery](http://www.jquery.com) in your HTML head like so: + +```HTML + + +``` + +**To build your Sheetsee you'll need [Node.js](http://www.nodejs.org) and [NPM](http://www.npmjs.org) (the latter comes with the former in most installs) on your computer and a command line.** + +#### Get Node/NPM + +Download Node.js from [nodejs.org/download](http://nodejs.org/download). For most users you can just download the Mac _.pkg_ or Windows _.msi_. Follow the install instructions, both include NPM. Once they're installed, proceed: + +## Install `sheetsee` from NPM +The `sheetsee` (with no '.js') module is the tool for building custom Sheetsee.js builds. Install `sheetsee` globally and then run it within the folder of your soon-to-be sheetsee.js project. + +_Install globally_ + +```bash +npm install -g sheetsee +``` + +_Run from within a project folder_ + +```bash +sheetsee [options] +``` + +Here are the options for the different modules. If you want save the generated file as _sheetsee.js_ then add the `--save` option. + +- `-m` or `-maps` for maps +- `-t` or `-tables` for tables +- `-c` or `-charts` for charts +- `--save` to write out the file* + +_* otherwise, defaults to standardout on your console which you can_ `| pbcopy` + +So for instance, `sheetsee -m -t --save` will build you a Sheetsee.js with the basic **data** functions, the **map** and **tables** sections built in and save it as a file named **sheetsee.js**. Running `sheetsee -m -t | pbcopy` will save the output to your clipboard. diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 00000000..78495125 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,27 @@ +### Sheetsee v3 + + +## August 13, 2013 +### Charting Intake + +D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart. + +Previously Sheetsee required you pass your data through a function, `addUnitsAndLabels()` which took in your data and the things you wanted to chart, reformatted your data for you so that you could pass it into one of the d3 charts. This is one more step than actually needs to happen. + +Now Sheetsee just asks for what you want your _labels_ and _units_ to be in the options you give it when calling the chart function. It then sorts the data correctly on the inside of the chart function. Yay, easier! + +```javascript +var options = { + labels: "name", + units: "cuddleability", + m: [60, 60, 30, 150], + w: 600, h: 400, + div: "#barChart", + xaxis: "no. of pennies", + hiColor: "#FF317D" +} +``` + +Thanks @maxogden for the help with this. + +### Started doing this changelong pretty late in the game. diff --git a/docs/custom-charts.md b/docs/custom-charts.md new file mode 100644 index 00000000..53476a61 --- /dev/null +++ b/docs/custom-charts.md @@ -0,0 +1,69 @@ +# Custom Charts + +It's easy to take a [D3.js](http://d3js.org/) chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too! + +Sheetsee charts currently work by taking in some options, like so: + +```javascript +var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"} +``` + +The _labels_ represent the actual thing you're charting and _units_ are how many of those things. Margin, width and height are _m, w, h_ and the `
    ` to build your chart in is _div_. Finally, you can supply a highlight color if you want. + +So, your chart could take the same options, but map them into your D3 code with the correct variables. An example from [maxogden/sheetsee-d3bubble](https://github.com/maxogden/sheetsee-d3bubble): + + +_Append the d3.js code with a map of your sheetsee options_ + +```JavaScript +Sheetsee.d3BubbleChart = function(data, options) { + var tree = {name: "data", children: []} + var groups = {} + + // data needs to look like this: + // var data = { name: "wahtever", children: [ + // { name: "group1", children: [ + // { name: 'bob', size: 3}, + // { name: 'judy', size: 5} + // ]}, + // { name: "group2", children: [ + // { name: 'jim', size: 10}, + // { name: 'bill', size: 5} + // ]} + // ]} + + data.map(function(r) { + var groupName = r[options.group] + groups[groupName] = true + }) + + Object.keys(groups).map(function(groupName) { + var groupMembers = [] + data.map(function(r) { + if (r[options.group] !== groupName) return + groupMembers.push({name: r[options.name], size: r[options.size]}) + }) + tree.children.push({name: groupName, children: groupMembers}) + }) + + // the rest of the code +``` + +_In your HTML call it like so_ + +```JavaScript + +``` + +There are lots of charts to get excited about in the [D3 gallery](https://github.com/mbostock/d3/wiki/Gallery). + +_View the [entire source](https://github.com/maxogden/sheetsee-d3bubble)_ diff --git a/docs/fork-n-go.md b/docs/fork-n-go.md new file mode 100644 index 00000000..d54bd540 --- /dev/null +++ b/docs/fork-n-go.md @@ -0,0 +1,32 @@ +# Fork-n-Go + +A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database. + +To awesome things that make this possible: **Forking** and [**GitHub Pages**](http://pages.github.com). + +On GitHub, a **fork** is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button. + +**GitHub Pages** is the hosting service that GitHub provides free to all users, organizations _and_ repositories. This means everyone of these entities or project can have it's own website at a predictable domain: + +- **organizations**: orgname.github.io +- **users**: username.github.io +- **repositories**: username.github.io/repositoryname + +To have a website for a repository all you need is a branch named `gh-pages`. GitHub will then look in that branch for web files and serve them up at the address. + +What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily. + +A Fork-n-Go example from my [blog post](http://jlord.us/fork-n-go/) on the topic: + +### Hack Spots Fork-n-Go + +I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do: + +- Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing. +- Fork the original repository. +- Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). +Commit your change. + +Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName. + +![forkcommit](http://jlord.s3.amazonaws.com/wp-content/uploads/forkcommit1.png) \ No newline at end of file diff --git a/docs/sheetsee-charts.md b/docs/sheetsee-charts.md new file mode 100644 index 00000000..a02ea045 --- /dev/null +++ b/docs/sheetsee-charts.md @@ -0,0 +1,145 @@ +# Sheetsee-charts + +_[View Demo](/demos/demo-chart.html)_ + +Sheetsee.js provides three [D3.js](http://d3js.org/) chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also use a custom D3 chart with Sheetsee, read about that [here](custom-charts.md). + +## Make a Chart + +Each chart requires your data be an _array of objects_, with objects containing `label` and `units` key/value pairs. + +Experiment with the charts to find the correct size your `
    ` will need to be to hold the chart with your data in it nicely. + +You can also make your own D3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information [here](custom-charts.md) on using your own chart. + +### Bar Chart + +To create a bar chart you'll need to add a placeholder `
    ` in your HTML with an id. + +```HTML +
    +``` + +In your CSS, give it dimensions. + +```CSS +#barChart {height: 400px; max-width: 600px; background: #F8CDCD;} +``` + +You'll also have these CSS elements to style however you'd like: + +```CSS +.labels text {text-align: right;} +.bar .labels text {fill: #333;} +.bar rect {fill: #e6e6e6;} +.axis {shape-rendering: crispEdges;} +.x.axis line {stroke: #fff; fill: none;} +.x.axis path {fill: none;} +.x.axis text {fill: #333;} +.xLabel {font-family: sans-serif; font-size: 9px;} +``` + +In a ` +``` diff --git a/docs/sheetsee-tables.md b/docs/sheetsee-tables.md new file mode 100644 index 00000000..370e3c26 --- /dev/null +++ b/docs/sheetsee-tables.md @@ -0,0 +1,132 @@ +# Sheetsee-tables + +_[View Demo](/demos/demo-table.html)_ + +With this module you can create tables of your data that are sortable, searchable and paginate-able. + +You'll need a placeholder `
    ` in your html, a ` +``` + +#### Your ` +``` + +To create another table, simply repeat the steps except for `initiateTableFilter()` + +```HTML +
    + + +``` + +Learn more about the things you can do with [ICanHaz.js](http://icanhazjs.com). + +### Sheetsee.makeTable(tableOptions) + +You pass in an object containing: + +- `data` your data array +- `pagination` how many rows displayed at one time, defaults to all +- `tableDiv` the
    placeholder in your HTML +- `filterDiv` the `
    ` containing your `` filter if using search + +```javascript +var tableOptions = { + "data": gData, + "pagination": 10, + "tableDiv": "#fullTable", + "filterDiv": "#fullTableFilter" + } +Sheetsee.makeTable(tableOptions) +``` + +#### Pagination + +If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for naviagtion, which you can style in your CSS: + +_HTML_ + +```HTML + +``` + +_CSS_ + +```CSS + +``` + +## Table Filter/Search + +If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want, placeholder text: + +```javascript + +``` + +### Sheetsee.initiateTableFilter(tableOptions) + +You will then call this function with your `tableOptions` to make that input live and connected to your table: + +```javascript +Sheetsee.initiateTableFilter(tableOptions) +``` + +It will connect that input to your data as well as inject this HTML for a button, which you can style yourself in your CSS: + +```HTML +Clear +no matches +``` + +_[View Demo](/demos/demo-table.html)_ diff --git a/docs/tips.md b/docs/tips.md new file mode 100644 index 00000000..e2f672ec --- /dev/null +++ b/docs/tips.md @@ -0,0 +1,96 @@ +# Tips + +A few things to think about beyond charts, maps and tables. + +## ICanHaz.js + +You can use templates for more than just tables. Use them to create lists `ol`, `ul`; array of images... You'll need a placeholder `
    ` in your HTML, a ` +``` + +_Script_ + +```JavaScript + +``` + +_non-table example output_ + +![lib](http://jlord.s3.amazonaws.com/wp-content/uploads/lending-ss.png) + +## Query Strings + +If your spreadsheet contains address information, using templates (Sheetsee.js uses a form of Mustache), you can embed those elements into a query string (aka a search URL) like Google Maps URL or Yelp. If you search for a location in Google Maps, you'll notice it creates a URL for that search. + +So, if you have information in your spreadsheet that would go inside a query string, make a template for inserting them into a link on your page. + +The basic elements are: a spreadsheet with address info + HTML template to create the query string. + +The Sheetsee [Hack-Spots](jlord.github.io/hack-spots) is an does such a thing. Here is the spreadsheet, with address information + +![img](http://jlord.s3.amazonaws.com/wp-content/uploads/Screen-Shot-2013-09-15-at-6.49.19-PM.png) + +In the HTML template for the table on the [Hack-Spots](jlord.github.io/hack-spots) page, the button’s links look like this: + +```HTML +View in Google Maps +Find on Yelp +``` +Here is the exact line of code on GitHub. + +We’re inserting the address, city, and state details from the spreadsheet into the structure of a query string for Google maps and Yelp. You can figure out the query string of a service by just using it (type in an address in Google Maps) and looking at the resulting URL. + +With a some CSS and such, the resulting website has a table with the hack spots and a button for viewing in Google Maps or Yelp: + +![img](http://jlord.s3.amazonaws.com/wp-content/uploads/Screen-Shot-2013-09-15-at-6.43.54-PM.png) + +When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM! + +## IFTTT + +[Ifttt.com](http://www.ifttt.com) offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets. + +## Row Numbers + +When Tabletop.js returns your spreadsheet data, it adds a key/value of `rownumber`. This is great to use when you need to uniquely match or find a row in your data. + +## Images + +Your spreadsheet can contain URLs to images which you can use to display the images on the page you build. Your template would look something like this: + +```HTML + +``` + +## Data as Classes + +You can use your data as classes to style with CSS. For instance, if you had data about recipes and a column called 'Taste' that contained either 'savory' or 'sweet'. In a table of the recipes you could do something like: + +```HTML + +``` + +Then in your CSS: + +```CSS +td .savory {} +td .sweet {} +``` diff --git a/package.json b/package.json new file mode 100644 index 00000000..28dea235 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "sheetsee.js", + "version": "0.0.0", + "description": "sheetsee.js documentation", + "main": "buildpage.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/jlord/sheetsee.js.git" + }, + "keywords": [ + "spreadsheet", + "data", + "visualize", + "google" + ], + "author": "jlord", + "license": "BSD-2-Clause", + "bugs": { + "url": "https://github.com/jlord/sheetsee.js/issues" + }, + "dependencies": { + "glob": "~3.2.8", + "marked": "~0.3.1", + "handlebars": "~1.3.0", + "mkdirp": "~0.3.5", + "path": "~0.4.9", + "cpr": "~0.1.1" + } +} diff --git a/template.hbs b/template.hbs new file mode 100644 index 00000000..18c49bd7 --- /dev/null +++ b/template.hbs @@ -0,0 +1,56 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    + {{{content}}} + + +
    + + + From ddbb8d5f55c87c8fcae848451d9858e2945f8db2 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sat, 8 Feb 2014 19:51:32 -0800 Subject: [PATCH 045/157] add site dir, fix rel link to demos --- .gitignore | 1 + site/assets/sss.css | 25 + site/assets/style.css | 51 + site/assets/styles/atelier-forest.light.css | 93 + site/demos/demo-chart.html | 92 + site/demos/demo-map.html | 79 + site/demos/demo-table.html | 123 + site/docs/about.html | 88 + site/docs/basics.html | 124 + site/docs/building.html | 82 + site/docs/changelog.html | 74 + site/docs/custom-charts.html | 110 + site/docs/fork-n-go.html | 79 + site/docs/sheetsee-charts.html | 151 + site/docs/sheetsee-core.html | 129 + site/docs/sheetsee-maps.html | 121 + site/docs/sheetsee-tables.html | 143 + site/docs/tips.html | 110 + site/img/fbi_spinner.gif | Bin 0 -> 1899 bytes site/img/hexcolors.png | Bin 0 -> 118186 bytes site/img/key.png | Bin 0 -> 40026 bytes site/img/latlong.png | Bin 0 -> 46644 bytes site/img/nonos.png | Bin 0 -> 49990 bytes site/img/publish.png | Bin 0 -> 50108 bytes site/img/sheetsee-03.png | Bin 0 -> 76716 bytes site/img/spreadsheettodata.png | Bin 0 -> 79410 bytes site/img/webconsole.png | Bin 0 -> 35675 bytes site/index.html | 129 + site/js/sheetsee.js | 25349 ++++++++++++++++++ template.hbs | 6 +- 30 files changed, 27156 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 site/assets/sss.css create mode 100644 site/assets/style.css create mode 100644 site/assets/styles/atelier-forest.light.css create mode 100644 site/demos/demo-chart.html create mode 100644 site/demos/demo-map.html create mode 100644 site/demos/demo-table.html create mode 100644 site/docs/about.html create mode 100644 site/docs/basics.html create mode 100644 site/docs/building.html create mode 100644 site/docs/changelog.html create mode 100644 site/docs/custom-charts.html create mode 100644 site/docs/fork-n-go.html create mode 100644 site/docs/sheetsee-charts.html create mode 100644 site/docs/sheetsee-core.html create mode 100644 site/docs/sheetsee-maps.html create mode 100644 site/docs/sheetsee-tables.html create mode 100644 site/docs/tips.html create mode 100644 site/img/fbi_spinner.gif create mode 100644 site/img/hexcolors.png create mode 100644 site/img/key.png create mode 100644 site/img/latlong.png create mode 100644 site/img/nonos.png create mode 100644 site/img/publish.png create mode 100644 site/img/sheetsee-03.png create mode 100644 site/img/spreadsheettodata.png create mode 100644 site/img/webconsole.png create mode 100644 site/index.html create mode 100644 site/js/sheetsee.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/site/assets/sss.css b/site/assets/sss.css new file mode 100644 index 00000000..de9fa702 --- /dev/null +++ b/site/assets/sss.css @@ -0,0 +1,25 @@ +/* General */ + +body {margin: 0px auto;} +a {color: #333;} +input:focus {outline: none;} + +/* Table */ + +table {text-align: left; width: 100%} +th {padding: 10px 0px;} +td, text {padding: 3px 20px 3px 0px; font-size: 14px;} +.noMatches {margin-left: 20px; font-size: 11px; font-style: italic; visibility: hidden;} + +/* Line Chart */ + +.axis {shape-rendering: crispEdges;} +.x.axis .minor, .y.axis .minor {stroke-opacity: .5;} +.x.axis {stroke-opacity: 1;} +.y.axis line, .y.axis path {fill: none; stroke: #acacac; stroke-width: 1;} +.bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);} +path.chartLine {stroke: #333; stroke-width: 3; fill: none;} +div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;} +circle {fill: #e6e6e6;} + +@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) {} diff --git a/site/assets/style.css b/site/assets/style.css new file mode 100644 index 00000000..a1cd61c6 --- /dev/null +++ b/site/assets/style.css @@ -0,0 +1,51 @@ +.container {max-width: 800px; margin: 0 auto; overflow: auto;} + +h3 {padding-top: 18px;} +h1 {font-size: 36px;} + +table {border-spacing: 0;} +tbody tr:nth-child(odd) {background-color: #f3f3f3;} +td {min-width: 140px; vertical-align: top; padding: 8px;} +tr {height: 50px;} +ul, ol {text-indent: 0; margin: 0; padding-left: 20px;} +ul li {padding-bottom: 6px; line-height: 22px;} + +footer {padding-top: 20px; margin-top: 60px; border-top: 1px solid #CCF4FF; -webkit-column-count: 6; column-count: 6; -webkit-column-gap: 20px; column-gap: 20px; -moz-column-count: 6; -moz-column-gap: 20px; height: 125px;} +footer ul {list-style: none; padding-left: 0px; font-family: Libre Baskerville, Baskerville, Georgia, serif;} +footer li {line-height: inherit; font-size: 10px;} +footer h4 {font-size: 10px; -webkit-column-break-before: always; break-before: always; -moz-column-break-before: always; } +footer h4 {margin-top: 0px;} +footer a {border: none;} + +.half {max-width: 50%; display: inline-block; vertical-align: top;} +.half:nth-child(odd) {padding-left: 20px;} + +/* older css */ + +body {font-family: Libre Baskerville, Baskerville, Georgia, serif; font-size: 14px; background: #fff; color: #333; border: 10px #47CCFC solid; margin: 0px; padding: 20px 20px 100px 20px; } +h1, h2, h3, h4, h5, h6 {font-family: Helvetica, Arial, sans-serif;} +h2 {margin-top: 40px;} + +img {width: 100%;} + +p a, a {color: #333; text-decoration: none; padding-bottom: 0px; border-bottom: 2px #CCF4FF solid;} +p a:visted {color: #ff00ff;} +a:hover {color: #47CCFC;} +a:active {color: #47CCFC;} +/*a:visited {color: #333;}*/ +small {padding: 10px 0px;} +p, ol {line-height: 24px;} + +pre {word-wrap: break-word; padding: 6px; background: #f0f0f0;} +code {font-family: "Consolas", "Ubuntu Mono", monospace; line-height: 22px; background: #f0f0f0; color: #636363; font-weight: normal;} + +/* funsies */ +::selection {background: #44FFB4;} +::-moz-selection {background: #44FFB4;} + +/* Table */ +.ssExample table {min-width: 600px;} +.tHeader::after {content: " \2193 \2191 "; font-size: 10px; padding-left: 3px; cursor: hand;} + +/* Map Popup Style */ +.leaflet-popup-content h2 {margin-bottom: 4px; margin-top: auto;} diff --git a/site/assets/styles/atelier-forest.light.css b/site/assets/styles/atelier-forest.light.css new file mode 100644 index 00000000..806ba739 --- /dev/null +++ b/site/assets/styles/atelier-forest.light.css @@ -0,0 +1,93 @@ +/* Base16 Atelier Forest Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ +/* https://github.com/jmblog/color-themes-for-highlightjs */ + +/* Atelier Forest Light Comment */ +.hljs-comment, +.hljs-title { + color: #766e6b; +} + +/* Atelier Forest Light Red */ +.hljs-variable, +.hljs-attribute, +.hljs-tag, +.hljs-regexp, +.ruby .hljs-constant, +.xml .hljs-tag .hljs-title, +.xml .hljs-pi, +.xml .hljs-doctype, +.html .hljs-doctype, +.css .hljs-id, +.css .hljs-class, +.css .hljs-pseudo { + color: #f22c40; +} + +/* Atelier Forest Light Orange */ +.hljs-number, +.hljs-preprocessor, +.hljs-pragma, +.hljs-built_in, +.hljs-literal, +.hljs-params, +.hljs-constant { + color: #df5320; +} + +/* Atelier Forest Light Yellow */ +.hljs-ruby .hljs-class .hljs-title, +.css .hljs-rules .hljs-attribute { + color: #d5911a; +} + +/* Atelier Forest Light Green */ +.hljs-string, +.hljs-value, +.hljs-inheritance, +.hljs-header, +.ruby .hljs-symbol, +.xml .hljs-cdata { + color: #5ab738; +} + +/* Atelier Forest Light Aqua */ +.css .hljs-hexcolor { + color: #00ad9c; +} + +/* Atelier Forest Light Blue */ +.hljs-function, +.python .hljs-decorator, +.python .hljs-title, +.ruby .hljs-function .hljs-title, +.ruby .hljs-title .hljs-keyword, +.perl .hljs-sub, +.javascript .hljs-title, +.coffeescript .hljs-title { + color: #407ee7; +} + +/* Atelier Forest Light Purple */ +.hljs-keyword, +.javascript .hljs-function { + color: #6666ea; +} + +.hljs { + display: block; + background: #f1efee; + color: #68615e; + padding: 0.5em; +} + +.coffeescript .javascript, +.javascript .xml, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +} diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html new file mode 100644 index 00000000..cc94c234 --- /dev/null +++ b/site/demos/demo-chart.html @@ -0,0 +1,92 @@ + + + + + Sheetsee Chart Demo + + + + + + + + + + +
    +

    Pennies by State

    +

    spreadsheet

    +
    +

    View Source // View Documentation

    + + +
    + + + + + diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html new file mode 100644 index 00000000..b5489c66 --- /dev/null +++ b/site/demos/demo-map.html @@ -0,0 +1,79 @@ + + + + + Sheetsee Maps Demo + + + + + + + + + +
    +

    All Pennies Map

    +

    spreadsheet

    +

    +

    View Source // View Documentation

    + + + + + + diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html new file mode 100644 index 00000000..53400923 --- /dev/null +++ b/site/demos/demo-table.html @@ -0,0 +1,123 @@ + + + + + Sheetsee Table Demo + + + + + + + + +
    +

    All Pennies

    +

    spreadsheet

    + +

    +

    California Pennies

    + +
    +

    Pretty Pennies

    +
    +

    View Source // View Documentation

    + + +
    + + + + + + + + + + + diff --git a/site/docs/about.html b/site/docs/about.html new file mode 100644 index 00000000..a69addb3 --- /dev/null +++ b/site/docs/about.html @@ -0,0 +1,88 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    About

    +

    Sheetsee.js began as a part of my Code for America 2012 Fellowship project, See Penny Work. The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet.

    +

    In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

    +

    The present version makes the project modular, customizable and with more maping and table features.

    +

    Built on top of Tabletop.js

    +

    Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js.

    +

    Sheetsee.js + Mapbox.js + d3.js

    +

    Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

    +

    Hacked on Openly

    + +

    Contact

    + +

    Big Time Thanks

    +

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georgia.

    +

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    +

    Thanks to Max Ogden for emotional support, teaching me JavaScript and answering lots of questions.

    +

    Thanks to all the authors and contributors to Tabletop.js, Mapbox.js, Leaflet.js, jQuery, ICanHas.js and d3.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    +

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    + + + +
    + + + diff --git a/site/docs/basics.html b/site/docs/basics.html new file mode 100644 index 00000000..aa2fe35d --- /dev/null +++ b/site/docs/basics.html @@ -0,0 +1,124 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Spreadsheets as Databases

    +

    Spreadsheets are a great lightweight databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet!

    +

    The Short & Sweet

    +
      +
    1. Link to Sheetsee.js, tabletop.js and jQuery in your HTML head.
    2. +
    3. Create a place holder <div> in your HTML for any chart, map or table you want to have.
    4. +
    5. Create templates for tables in <script> tags.
    6. +
    7. Inside of a <script> tag initialize Tabletop.js. It waits for the document to load and then initializes tabletop and calls back a function when it has returned with the spreadsheet data.
      document.addEventListener('DOMContentLoaded', function() {
      + var gData
      + var URL = "YOURSPREADSHEETSKEYHERE"
      + Tabletop.init( { key: URL, callback: callback, simpleSheet: true } )
      +})
      +
      +
    8. +
    9. Define the function that Tabletop.js calls when it returns with the data. This function will contain all the Sheetsee.js functions that you use for the maps, charts and tables you desire. Style it up with some CSS.
      function callback(data) {
      + // All the sheetsee things you want to do!
      +}
      +
      +
    10. +
    11. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information every time they load the page.
    12. +
    +

    Bare Minimum Setup

    +

    Ignoring some HTML things to conserve space, you get the point. This is a basic setup.

    +
    <html>
    +  <head>
    +    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    +    <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
    +    <script type="text/javascript" src='js/sheetsee.js'></script>
    +    <link rel="stylesheet" type="text/css" href="css/sss.css">
    +  </head>
    +  <body>
    +  <div id="placeholder"></div>
    +
    +  <script id="placeholder" type="text/html">
    +    // template if you so desire!
    +  </script>
    +
    +  <script type="text/javascript">
    +    document.addEventListener('DOMContentLoaded', function() {
    +        var URL = "YOURSPREADSHEETSKEYHERE"
    +        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } )
    +    })
    +    function myData(data) {
    +        All the sheetsee things you want to do!
    +    }
    +  </script>
    +  </body>
    +</html>
    +
    +

    Your Data

    +

    sheetsee

    +

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an oject in the final array that Tabletop.js delivers of your data.

    +

    sheetsee

    +

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    +
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    +

    Hexcolor

    +

    sheetsee

    +

    You must add a column to your spreadsheet with the heading hexcolor (case insensitive). The maps, charts and such use colors and this is the easiest way to standardize that. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    +

    Geocoding

    +

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin + that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    +

    Publishing Your Spreadsheet

    +

    sheetsee

    +

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    +

    sheetsee

    +

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. Actually, you technically can use the whole URL, but it's so long...

    +

    CSS

    +

    Sheetsee.js comes with a bare minimum stylesheet, sss.csss, which contains elements you'll want to style when using the feature they correspond to.

    + + + +
    + + + diff --git a/site/docs/building.html b/site/docs/building.html new file mode 100644 index 00000000..b1eb3099 --- /dev/null +++ b/site/docs/building.html @@ -0,0 +1,82 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Right-sizing

    +

    You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

    +

    All bundle comes with mapbox.js and handlebars.js (since both are available on NPM). Additionally you'll need to also include tabletop.js and jQuery in your HTML head like so:

    +
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
    +<script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
    +
    +

    To build your Sheetsee you'll need Node.js and NPM (the latter comes with the former in most installs) on your computer and a command line.

    +

    Get Node/NPM

    +

    Download Node.js from nodejs.org/download. For most users you can just download the Mac .pkg or Windows .msi. Follow the install instructions, both include NPM. Once they're installed, proceed:

    +

    Install sheetsee from NPM

    +

    The sheetsee (with no '.js') module is the tool for building custom Sheetsee.js builds. Install sheetsee globally and then run it within the folder of your soon-to-be sheetsee.js project.

    +

    Install globally

    +
    npm install -g sheetsee
    +
    +

    Run from within a project folder

    +
    sheetsee [options]
    +
    +

    Here are the options for the different modules. If you want save the generated file as sheetsee.js then add the --save option.

    +
      +
    • -m or -maps for maps
    • +
    • -t or -tables for tables
    • +
    • -c or -charts for charts
    • +
    • --save to write out the file*
    • +
    +

    * otherwise, defaults to standardout on your console which you can | pbcopy

    +

    So for instance, sheetsee -m -t --save will build you a Sheetsee.js with the basic data functions, the map and tables sections built in and save it as a file named sheetsee.js. Running sheetsee -m -t | pbcopy will save the output to your clipboard.

    + + + +
    + + + diff --git a/site/docs/changelog.html b/site/docs/changelog.html new file mode 100644 index 00000000..f31fe2a6 --- /dev/null +++ b/site/docs/changelog.html @@ -0,0 +1,74 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Sheetsee v3

    +

    August 13, 2013

    +

    Charting Intake

    +

    D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart.

    +

    Previously Sheetsee required you pass your data through a function, addUnitsAndLabels() which took in your data and the things you wanted to chart, reformatted your data for you so that you could pass it into one of the d3 charts. This is one more step than actually needs to happen.

    +

    Now Sheetsee just asks for what you want your labels and units to be in the options you give it when calling the chart function. It then sorts the data correctly on the inside of the chart function. Yay, easier!

    +
    var options = {
    +  labels: "name",
    +  units: "cuddleability",
    +  m: [60, 60, 30, 150],
    +  w: 600, h: 400,
    +  div: "#barChart",
    +  xaxis: "no. of pennies",
    +  hiColor: "#FF317D"
    +}
    +
    +

    Thanks @maxogden for the help with this.

    +

    Started doing this changelong pretty late in the game.

    + + + +
    + + + diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html new file mode 100644 index 00000000..2a8a27e2 --- /dev/null +++ b/site/docs/custom-charts.html @@ -0,0 +1,110 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Custom Charts

    +

    It's easy to take a D3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

    +

    Sheetsee charts currently work by taking in some options, like so:

    +
    var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    +
    +

    The labels represent the actual thing you're charting and units are how many of those things. Margin, width and height are m, w, h and the <div> to build your chart in is div. Finally, you can supply a highlight color if you want.

    +

    So, your chart could take the same options, but map them into your D3 code with the correct variables. An example from maxogden/sheetsee-d3bubble:

    +

    Append the d3.js code with a map of your sheetsee options

    +
    Sheetsee.d3BubbleChart = function(data, options) {
    +    var tree = {name: "data", children: []}
    +    var groups = {}
    +
    +    // data needs to look like this:
    +    // var data = { name: "wahtever", children: [
    +    //   { name: "group1", children: [
    +    //     { name: 'bob', size: 3},
    +    //     { name: 'judy', size: 5}
    +    //   ]},
    +    //   { name: "group2", children: [
    +    //     { name: 'jim', size: 10},
    +    //     { name: 'bill', size: 5}
    +    //   ]}
    +    // ]}
    +
    +    data.map(function(r) {
    +        var groupName = r[options.group]
    +        groups[groupName] = true
    +    })
    +
    +    Object.keys(groups).map(function(groupName) {
    +        var groupMembers = []
    +        data.map(function(r) {
    +            if (r[options.group] !== groupName) return
    +            groupMembers.push({name: r[options.name], size: r[options.size]})
    +        })
    +        tree.children.push({name: groupName, children: groupMembers})
    +    })
    +
    +  // the rest of the code
    +
    +

    In your HTML call it like so

    +
    <script type="text/javascript">
    +  document.addEventListener('DOMContentLoaded', function() {
    +    var URL = "0AvFUWxii39gXdFhqZzdTeU5DTWtOdENkQ1Y5bHdqT0E"
    +    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    +  })
    +
    +  function showInfo(data) {
    +    Sheetsee.d3BubbleChart(data, { name: 'name', size: 'cuddlability', group: 'kind', div: '#stuff'})
    +  }
    +</script>
    +
    +

    There are lots of charts to get excited about in the D3 gallery.

    +

    View the entire source

    + + + +
    + + + diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html new file mode 100644 index 00000000..01bbef36 --- /dev/null +++ b/site/docs/fork-n-go.html @@ -0,0 +1,79 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Fork-n-Go

    +

    A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

    +

    To awesome things that make this possible: Forking and GitHub Pages.

    +

    On GitHub, a fork is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button.

    +

    GitHub Pages is the hosting service that GitHub provides free to all users, organizations and repositories. This means everyone of these entities or project can have it's own website at a predictable domain:

    +
      +
    • organizations: orgname.github.io
    • +
    • users: username.github.io
    • +
    • repositories: username.github.io/repositoryname
    • +
    +

    To have a website for a repository all you need is a branch named gh-pages. GitHub will then look in that branch for web files and serve them up at the address.

    +

    What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily.

    +

    A Fork-n-Go example from my blog post on the topic:

    +

    Hack Spots Fork-n-Go

    +

    I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do:

    +
      +
    • Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing.
    • +
    • Fork the original repository.
    • +
    • Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). +Commit your change.
    • +
    +

    Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName.

    +

    forkcommit

    + + + +
    + + + diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html new file mode 100644 index 00000000..37d8bd5a --- /dev/null +++ b/site/docs/sheetsee-charts.html @@ -0,0 +1,151 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Sheetsee-charts

    +

    View Demo

    +

    Sheetsee.js provides three D3.js chart options to use with your spreadsheet data: a bar chart, line graph and pie chart. You can also use a custom D3 chart with Sheetsee, read about that here.

    +

    Make a Chart

    +

    Each chart requires your data be an array of objects, with objects containing label and units key/value pairs.

    +

    Experiment with the charts to find the correct size your <div> will need to be to hold the chart with your data in it nicely.

    +

    You can also make your own D3 chart in a separate .js file, link to that in your HTML head and pass your data on to it after Tabletop.js returns. Information here on using your own chart.

    +

    Bar Chart

    +

    To create a bar chart you'll need to add a placeholder <div> in your HTML with an id.

    +
    <div id="barChart"></div>
    +
    +

    In your CSS, give it dimensions.

    +
    #barChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    +
    +

    You'll also have these CSS elements to style however you'd like:

    +
    .labels text {text-align: right;}
    +.bar .labels text {fill: #333;}
    +.bar rect {fill: #e6e6e6;}
    +.axis {shape-rendering: crispEdges;}
    +.x.axis line {stroke: #fff; fill: none;}
    +.x.axis path {fill: none;}
    +.x.axis text {fill: #333;}
    +.xLabel {font-family: sans-serif; font-size: 9px;}
    +
    +

    In a <script> tag set up your options.

    +
    var barOptions = {labels: "name", units: "cuddleability", m: [60, 60, 30, 150], w: 600, h: 400, div: "#barChart", xaxis: "no. of pennies", hiColor: "#FF317D"}
    +
    +
      +
    • labels is a string, usually a column header, it's what you call what you're charting
    • +
    • units is a string, usually a column header, it's the value you're charting
    • +
    • m is margins: top, right, bottom, left
    • +
    • w and h are width and height, this should match your CSS specs
    • +
    • div is the id for the <div> in your HTML
    • +
    • xaxis is optional text label for your x axis
    • +
    • hiColor is the highlight color of your choosing!
    • +
    +

    Then call the d3BarChart() function with your data and options.

    +
    Sheetsee.d3BarChart(data, barOptions)
    +
    +

    Line Chart

    +

    To create a line chart you'll need to add a placeholder <div> in your html with an id.

    +
    <div id="lineChart"></div>
    +
    +

    In your CSS, give it dimensions.

    +
    #lineChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    +
    +

    And these chart elements to style:

    +
    .axis {shape-rendering: crispEdges;}
    +.x.axis .minor, .y.axis .minor {stroke-opacity: .5;}
    +.x.axis {stroke-opacity: 1;}
    +.y.axis line, .y.axis path {fill: none; stroke: #acacac; stroke-width: 1;}
    +.bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);}
    +path.chartLine {stroke: #333; stroke-width: 3; fill: none;}
    +div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;}
    +circle {fill: #e6e6e6;}
    +
    +

    In a <script> tag set up your options.

    +
    var lineOptions = {labels: "name", units: "cuddleability", m: [80, 100, 120, 100], w: 600, h: 400, div: "#lineChart", yaxis: "no. of pennies", hiColor: "#14ECC8"}
    +
    +
      +
    • labels is a string, usually a column header, it's what you call what you're charting
    • +
    • units is a string, usually a column header, it's the value you're charting
    • +
    • m is your margins: top, right, bottom, left
    • +
    • w and h are width and height, this should match your CSS specs
    • +
    • div is the id for the <div> in your HTML
    • +
    • yaxis is optional text label for your y axis
    • +
    • hiColor is the highlight color of your choosing!
    • +
    +

    Then call the d3LineChart() function with your data and options.

    +
    Sheetsee.d3LineChart(data, lineOptions)
    +
    +

    Pie Chart

    +

    To create a bar chart you'll need to add a placeholder <div> in your html with an id.

    +
    <div id="pieChart"></div>
    +
    +

    In your CSS, give it dimensions.

    +
    #pieChart {height: 400px; max-width: 600px; background: #F8CDCD;}
    +
    +

    Style chart elements:

    +
    .arc path { stroke: #fff;}
    +
    +

    In a <script> tag set up your options.

    +
    var pieOptions = {labels: "name", units: "units", m: [80, 80, 80, 80], w: 600, h: 400, div: "#pieChart", hiColor: "#14ECC8"}
    +
    +
      +
    • labels is a string, usually a column header, it's what you call what you're charting
    • +
    • units is a string, usually a column header, it's the value you're charting
    • +
    • m is your margins: top, right, bottom, left
    • +
    • w and h are width and height, this should match your CSS specs
    • +
    • div is the id for the <div> in your HTML
    • +
    • hiColor is the highlight color of your choosing!
    • +
    +

    Then call the d3PieChart() function with your data and options.

    +
    Sheetsee.d3PieChart(data, pieOptions)
    +
    + + + +
    + + + diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html new file mode 100644 index 00000000..c511a187 --- /dev/null +++ b/site/docs/sheetsee-core.html @@ -0,0 +1,129 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Sheetsee-core

    +

    This is the core module in sheetsee and is included in all builds. It contains the functions for building your custom file as well as the basic data manipulation functions.

    +

    Working With Your Data

    +

    Tabletop.js will fetch the data from your spreadsheet and return it as an array of objects. Sheetsee.js has functions built in to help you filter or reorganize the data if you'd like.

    +

    Sheetsee.getGroupCount(data, groupTerm)

    +

    This takes in your data, an array of objects, and searches for a string, groupTerm, in each piece of your data (formerly the cells of your spreadsheet). It returns the number of times it found the groupTerm.

    +
    getGroupCount(data, "cat")
    +// returns a number
    +
    +

    Sheetsee.getColumnTotal(data, column)

    +

    Given your data, an array of objects, and a string column header, this functions sums each cell in that column(so this collumn you mention best have numbers).

    +
    getColumnTotal(data, "cuddlability")
    +// returns number
    +
    +

    Sheetsee.getAveragefromColumn(data, column)

    +

    A really simple function that builds on getColumnTotal() by returning the average number in a column of numbers.

    +
    getColumnAverage(data, "cuddlability")
    +// returns number
    +
    +

    Sheetsee.getMin(data, column)

    +

    This will return an array of object or objects (if there is a tie) of the element with the lowest number value in the column you specify from your data.

    +
    getMin(data, "cuddlability")
    +// returns array
    +
    +

    Sheetsee.getMax(data, column)

    +

    This will return an array of object or objects (if there is a tie) of the element with the highest number value in the column you specify from your data.

    +
    getMin(data, "cuddlability")
    +// returns array
    +
    +

    Don't Forget JavaScript Math

    +

    Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    +
    var profit09 = Sheetsee.getColumnTotal(data, "2009")
    +var profit10 = Sheetsee.getColumnTotal(data, "2010")
    +var difference = profit09 - profit10
    +
    +

    What These Little Bits are Good For

    +

    You don't have to just create tables of your data. You can have other portions of your page that show things like, "The difference taco consumption between last week and this week is..." These are easy to create with JavaScript math functions and knowing a little bit more about icanhaz.js.

    +

    Sheetsee.getMatches(data, filter, category)

    +

    Takes data as an array of objects, a string you'd like to filter and a string of the category you want it to look in (a column header from your spreadsheet).

    +
    getMatches(data, "dog", "kind")
    +
    +

    Returns an array of objects matching the category's filter.

    +
    [{"name": "coco", "kind": "dog"...}, {"name": "wolfgang", "kind": "dog"...},{"name": "cooc", "kind": "dog"...} ]
    +
    +

    Sheetsee.getOccurance(data, category)

    +

    Takes data as an array of objects and a string for category (a column header from your spreadsheet) you want tally how often an element occured.

    +
    getOccurance(data, "kind")
    +
    +

    Returns an object with keys and values for each variation of the category and its occurance.

    +
    {"dog": 3, "cat": 3}
    +
    +

    Sheetsee.makeColorArrayOfObject(data, colors)

    +

    If you use getOccurance() and want to then chart that data with d3.js, you'll need to make it into an array (instead of an object) and add colors back in (since the hexcolor column applies to the datapoints in your original dataset and not this new dataset).

    +

    This function takes in your data, as an object, and an array of hexidecimal color strings which you define.

    +
    var kinds = getOccurance(data, "kind")
    +var kindColors = ["#ff00ff", "#DCF13C"]
    +
    +var kindData = makeColorArrayOfObjects(mostPopBreeds, breedColors)
    +
    +

    It will return an array of objects formatted to go directly into a d3 chart with the appropriate units and label keys, like so:

    +
    [{"label": "dog", "units": 2, "hexcolor": "#ff00ff"}, {"label": "cat", "units": 3, "hexcolor": "#DCF13C"}]
    +
    +

    If you pass in an array of just one color it will repeat that color for all items. If you pass fewer colors than data elements it will repeat the sequences of colors for the remainder elements.

    +

    Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)

    +

    If you're using data, the data directly from Tabletop, you'll need to format it before you use the d3 charts. You'll need to determine what part of your data you want to chart - what will be your label, what your charting, and what will be your units, how many of them are there (this should be a number).

    +
    var data =  [{"name": "coco", "kind": "dog", "cuddablity": 5}, {"name": "unagi", "kind": "cat", "cuddlability": 0}]
    +
    +

    For istance, if from our original data above we want to chart the age of each cat, we'll use:

    +
    Sheetsee.addUnitsLabels(data, "name", "cuddlability")
    +
    +

    Which will return an array, ready for the d3 charts:

    +
    [{"label": "coco", "kind": "dog", "units": 5}, {"label": "unagi", "kind": "cat", "units": 0}]
    +
    + + + +
    + + + diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html new file mode 100644 index 00000000..c8d4e6e3 --- /dev/null +++ b/site/docs/sheetsee-maps.html @@ -0,0 +1,121 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Sheetsee-maps

    +

    View Demo

    +

    Sheetsee.js uses Mapbox.js and Leaflet.js to make maps of your points, polygons, lines or multipolygons (all coordinate based). Details on what that actually looks like here.

    +

    You'll create a placeholder <div> in your HTML, CSS giving it a size and fire up a map from within <script> tags. You can also customize your popup content.

    +

    Your HTML Placeholder <div>

    +

    Create an empty <div> in your HTML, with an id (name). Add CSS to give it dimensions

    +
    <div id="map"></div>
    +
    +

    CSS

    +
    #map {width: 500px; height: 500px;}
    +
    +

    Your <script> Functions

    +

    Next you'll need to create geoJSON out of your data so that it can be mapped.

    +

    Sheetsee.createGeoJSON(data, optionsJSON)

    +

    This takes in your data and the parts of your data, optionsJSON, that you plan on including in your map's popups. These will be column headers in your spreadsheet. If you're not going to have popups on your markers, don't worry about it then and just pass in your data (by default it will use all the row's information).

    +
    var optionsJSON = ["name", "breed", "cuddlability"]
    +var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    +
    +

    It will return an array in the special geoJSON format that map making things love.

    +
    [{
    +  "geometry": {"type": "Point", "coordinates": [long, lat]},
    +  "properties": {
    +    "marker-size": "small",
    +    "marker-color": lineItem.hexcolor
    +  },
    +  "opts": {},
    +}}
    +
    +

    Sheetsee.loadMap(mapDiv)

    +

    To create a simple map, with no data, you simply call .loadMap() and pass in a string of the mapDiv (with no '#') from your HTML.

    +
    var map = Sheetsee.loadMap("map")
    +
    +

    Sheetsee.addTileLayer(map, tileLayer)

    +

    To add a tile layer (aka a custom map scheme/design/background) you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

    +
    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    +
    +

    You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

    +

    Sheetsee.addMarkerLayer(geoJSON, map)

    +

    To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

    +
    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
    +
    +

    Example template:

    +
    var popupTemplate = "<h4>Hello {{name}}</h4>"
    +
    +

    Source from the map demo:

    +
    <script type="text/javascript">
    +  document.addEventListener('DOMContentLoaded', function() {
    +    var gData
    +    var URL = "0Ao5u1U6KYND7dGN5QngweVJUWE16bTRob0d2a3dCbnc"
    +    Tabletop.init( { key: URL, callback: showInfo, simpleSheet: true } )
    +  })
    +
    +  function showInfo(data) {
    +    gData = data
    +    var optionsJSON = ["placename", "photo-url"]
    +    var template = "<ul><li><a href='{{photo-url}}' target='_blank'>"
    +                 + "<img src='{{photo-url}}'></a></li>"
    +                 + "<li><h4>{{placename}}</h4></li></ul>"
    +    var geoJSON = Sheetsee.createGeoJSON(gData, optionsJSON)
    +    var map = Sheetsee.loadMap("map")
    +    Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
    +    var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, template)
    +  }
    +</script>
    +
    + + + +
    + + + diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html new file mode 100644 index 00000000..3dbb2c98 --- /dev/null +++ b/site/docs/sheetsee-tables.html @@ -0,0 +1,143 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Sheetsee-tables

    +

    View Demo

    +

    With this module you can create tables of your data that are sortable, searchable and paginate-able.

    +

    You'll need a placeholder <div> in your html, a <script> mustache template and a <script> that initiates the table.

    +

    Your HTML Placeholder <div>

    +

    This is as simple as an empty <div> with an id. This id should match the script template id in the next section.

    +
    <div id="siteTable"></div>
    +
    +

    Your <script> Template

    +

    Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you!

    +

    Sorting

    +

    If you want users to be able to click on headers and sort that column, your template must include table headers with the class tHeader.

    +

    Example

    +

    The variables inside the {{}} must match the column headers in your spreadsheet. They should be lowercase and remember spaces are omitted, so "Place Name" will become "placename".

    +
    <script id="siteTable" type="text/html">
    +    <table>
    +    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    +      {{#rows}}
    +        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    +      {{/rows}}
    +  </table>
    +</script>
    +
    +

    Your <script> Execution

    +
    <script type="text/javascript">
    +    document.addEventListener('DOMContentLoaded', function() {
    +      var tableOptions = {
    +                          "data": gData, 
    +                          "pagination": 10, 
    +                          "tableDiv": "#fullTable", 
    +                          "filterDiv": "#fullTableFilter"
    +                          }
    +      Sheetsee.makeTable(tableOptions)
    +      Sheetsee.initiateTableFilter(tableOptions)
    +    })
    +</script>
    +
    +

    To create another table, simply repeat the steps except for initiateTableFilter()

    +
    <div id="secondTable"></div>
    +<script id="secondTable"> // your table template here </script>
    +<script>Sheetsee.makeTable(otherData, "#secondTable", 10)</script>
    +
    +

    Learn more about the things you can do with ICanHaz.js.

    +

    Sheetsee.makeTable(tableOptions)

    +

    You pass in an object containing:

    +
      +
    • data your data array
    • +
    • pagination how many rows displayed at one time, defaults to all
    • +
    • tableDiv the
      placeholder in your HTML
    • +
    • filterDiv the <div> containing your <input> filter if using search
    • +
    +
    var tableOptions = {
    +                    "data": gData, 
    +                    "pagination": 10, 
    +                    "tableDiv": "#fullTable", 
    +                    "filterDiv": "#fullTableFilter"
    +                    }
    +Sheetsee.makeTable(tableOptions)
    +
    +

    Pagination

    +

    If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for naviagtion, which you can style in your CSS:

    +

    HTML

    +
    <div id='Pagination' currentPage class='table-pagination'>
    +  Showing page {{currentPage}} of {{totalPages}}
    +  <a class='pagination-pre'>Previous</a><a class='pagination-next'>Next</a>
    +</div>
    +
    +

    CSS

    +
    <style>
    +  #Pagination {background: #eee;}
    +  .pagination-next, .pagination-pre {cursor: hand;}
    +  .no-pag {color: #acacac;}
    +</style>
    +
    + +

    If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want, placeholder text:

    +
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    +
    +

    Sheetsee.initiateTableFilter(tableOptions)

    +

    You will then call this function with your tableOptions to make that input live and connected to your table:

    +
    Sheetsee.initiateTableFilter(tableOptions)
    +
    +

    It will connect that input to your data as well as inject this HTML for a button, which you can style yourself in your CSS:

    +
    <span class="clear button">Clear</span>
    +<span class="noMatches">no matches</span>
    +
    +

    View Demo

    + + + +
    + + + diff --git a/site/docs/tips.html b/site/docs/tips.html new file mode 100644 index 00000000..08295f71 --- /dev/null +++ b/site/docs/tips.html @@ -0,0 +1,110 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Tips

    +

    A few things to think about beyond charts, maps and tables.

    +

    ICanHaz.js

    +

    You can use templates for more than just tables. Use them to create lists ol, ul; array of images... You'll need a placeholder <div> in your HTML, a <script> for your template and a script to call ICanHaz from your Tabletop.js callback. For a live example, see the bottom photo grid of the sheetsee-table demo.

    +

    HTML

    +
    <div id="divID"></div>
    +
    +

    Template

    +
    <script id="divID" type="text/html">
    +  {{#rows}}
    +    <div><img class="photo" src="{{some-variable}}"></div>
    +  {{/rows}}
    +</script>
    +
    +

    Script

    +
    <script type="text/html">
    +  // your other Sheetsee.js, Tabletop code above
    +  var html = Sheetsee.ich.divID({'rows': data})
    +  $('#divID').html(html)
    +</script>
    +
    +

    non-table example output

    +

    lib

    +

    Query Strings

    +

    If your spreadsheet contains address information, using templates (Sheetsee.js uses a form of Mustache), you can embed those elements into a query string (aka a search URL) like Google Maps URL or Yelp. If you search for a location in Google Maps, you'll notice it creates a URL for that search.

    +

    So, if you have information in your spreadsheet that would go inside a query string, make a template for inserting them into a link on your page.

    +

    The basic elements are: a spreadsheet with address info + HTML template to create the query string.

    +

    The Sheetsee Hack-Spots is an does such a thing. Here is the spreadsheet, with address information

    +

    img

    +

    In the HTML template for the table on the Hack-Spots page, the button’s links look like this:

    +
    <a class="button" href="https://maps.google.com/maps?q={{address}},{{city}},{{state}}" target="_blank">View in Google Maps</a>
    +<a class="button" href="http://www.yelp.com/search?find_desc={{name}}&find_loc={{city}},{{state}}" target="_blank">Find on Yelp</a>
    +
    +

    Here is the exact line of code on GitHub.

    +

    We’re inserting the address, city, and state details from the spreadsheet into the structure of a query string for Google maps and Yelp. You can figure out the query string of a service by just using it (type in an address in Google Maps) and looking at the resulting URL.

    +

    With a some CSS and such, the resulting website has a table with the hack spots and a button for viewing in Google Maps or Yelp:

    +

    img

    +

    When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM!

    +

    IFTTT

    +

    Ifttt.com offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets.

    +

    Row Numbers

    +

    When Tabletop.js returns your spreadsheet data, it adds a key/value of rownumber. This is great to use when you need to uniquely match or find a row in your data.

    +

    Images

    +

    Your spreadsheet can contain URLs to images which you can use to display the images on the page you build. Your template would look something like this:

    +
    <img src='{{imgurl}}'/>
    +
    +

    Data as Classes

    +

    You can use your data as classes to style with CSS. For instance, if you had data about recipes and a column called 'Taste' that contained either 'savory' or 'sweet'. In a table of the recipes you could do something like:

    +
    <tr><td class="{{taste}}"></tr>
    +
    +

    Then in your CSS:

    +
    td .savory {}
    +td .sweet {}
    +
    + + + +
    + + + diff --git a/site/img/fbi_spinner.gif b/site/img/fbi_spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..872ede51dae7ff71785364dddf4ec960d90268b3 GIT binary patch literal 1899 zcmY+Dc~DdL8is%8B!LKl1PB3QM1kaBAR#~`gjFD{2^@AXIjquP1%x1Lk$X)~A~^v{ zUFqO-w2Gp28+33)K}A5NDxzGgxLdFLsN=pX_u!S8_P_7HXWsXF-nfKVc~Bt>u)rG( ztX#P=EiFy0R=;`k=Iz_J2M!!SQS|oh+xz$L@9OF*FE7u|&d$ilsH>}c{P^+Bn>TxU zdbV%hzI*rXr%#_=x^(H(sZ$LN4Wpx@LZR^9y?fo=-GzmP)z#G_BO@C&Y&d=T^p-7K zZr!?d<;s=&_wPS^_^`FL_4DV?2!h1M#^&bce)#a=?%lhCgM*!&o$ubgTfcrij^ig! zo;-5oNMB#y#fuj`JUrUl+xP9;cjwNXiHV7^v9TRHb{sr-@X3=W+qP|Ev)KP*dK3%wQVR(4>*|TR~zI-`z=FIu?=hv)R zbN%}Dt5>h`c)XoEcl!JLQz(?Ova%H`R=j`zesXg1#fulmk00;t?KPXtFJHd=`0-;~ zTidZ?$9C=7b@=e%fq{Xcp`kr{_VoAn@7=ri)vH%qw{E?0{`&Q6y z@8e5>003_9sZ<)61S0Y#pTq*dazu~e7=ni~l!j*9#Y%-q<}1BI(_65JEFqSffdz{_ znqBx9%UPQr;5278=EX-5Us$UXf)sigm*T>*qhd@oWJB@6*US>r<;}CpRy3=E4AMDe zc9y@C`V|#BhA#xNCBNi^2A236X#C*;W z+XSnAiejRIIzBR=tQ23uhj;MIZHY(L=b07MKC zC%!zp9+&whQxjZ4v7M(a?jlZ*QN3`loIK;a2GoovYiV?klXy`{2|ePhF>J}7KodNJ z`{$4Ugt7pggywyPW(tf1@Q`_f{F$IYxY(TJ>k1Y|cQ`LH@(Vx>M3lF_8PNIG5V{aLu*(Nxixe|6hHWoUK(3&ai7LDr7RlLh3v6>OYAIq` zp>kc7Go&>SNlZgS@?`?q_a}{tI%iLdvw*vpn8wk7XsTOlU`yh(dKxVy4#iEhFq$X? zrMjw2Qd(j-EtI1$i7ovilPLSgY13r#p>zO|%`!=HzCII>c48)bQcM>U z#oB!U+voF!LeG9-$u{fcnHk&>q|1$jDu`(PI-FMAAtaOQ54R9CY@@Y~h~e1T z!l9PYGC4D`%E7TxjTdFGd>Kv<7v|R>4$d|RuNF>)mKc`SDPU4|+vueRWD^Xcl(3I+ zIvX@K5IVX2DOZd15FXCPnoLvc#PMJ;VrpW_S66Tvf1s?!q*MD;)-_7_9Lc{uRFWKa zc!&neOT!#JGbOxojtEOC{|Tyyw?M#5%s#>8S4>r1gb9RbQvU3-Xlc_NUu5v_!jffv z6IM-bBv*pqCY%F7Gm{CT61IjDe{K&7Y$pUi)KY)e0wg*h-$V9Ym@Rv;E(kcTQ$cy$ z)bz-CM5$FhN@}ewb1=!Hoxlt=n)5xI*a)PqxCZ;?)Bpeg literal 0 HcmV?d00001 diff --git a/site/img/hexcolors.png b/site/img/hexcolors.png new file mode 100644 index 0000000000000000000000000000000000000000..83c98d93c525de9a4f1c0ef47d34107585834b0a GIT binary patch literal 118186 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 BqLlyu literal 0 HcmV?d00001 diff --git a/site/img/key.png b/site/img/key.png new file mode 100644 index 0000000000000000000000000000000000000000..94ef13b1e366324312f2ac11e6fc3cd781dc486d GIT binary patch literal 40026 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 P1Nc~4*qK+J^}hQ*^4P7F literal 0 HcmV?d00001 diff --git a/site/img/latlong.png b/site/img/latlong.png new file mode 100644 index 0000000000000000000000000000000000000000..343e393e2c13d5815128eedeb7fc30065277a150 GIT binary patch literal 46644 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 V_G_`>X`lf=QWCN+^2BsL{x9{wQjY)t literal 0 HcmV?d00001 diff --git a/site/img/nonos.png b/site/img/nonos.png new file mode 100644 index 0000000000000000000000000000000000000000..15ab0a7f0fe93378d5e2a914609dbe6edf725a35 GIT binary patch literal 49990 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%0A&=<(KV!+rLY9H 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 DT`Cx% literal 0 HcmV?d00001 diff --git a/site/img/publish.png b/site/img/publish.png new file mode 100644 index 0000000000000000000000000000000000000000..c0ff710177b05b647761447640a8f9291360c045 GIT binary patch literal 50108 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 B>`wpy literal 0 HcmV?d00001 diff --git a/site/img/sheetsee-03.png b/site/img/sheetsee-03.png new file mode 100644 index 0000000000000000000000000000000000000000..a9a4154d6b9127d6d32d4d5cb29edacc36ed15fc GIT binary patch literal 76716 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 literal 0 HcmV?d00001 diff --git a/site/img/spreadsheettodata.png b/site/img/spreadsheettodata.png new file mode 100644 index 0000000000000000000000000000000000000000..d787d9f2cbb8a575c0f29751d1668ab1ccf24120 GIT binary patch literal 79410 zcmdSAby$?&*Ef38sem*hsf0ArEh&v)AYDUuNH@|U3Jem0NGZ~tgS2!vjC3<}4a}S| zzTe+-o$ER8InR5&|D5}enSI~0_g=BrT6?X}z9&jcL+KVi4L$$>x0IjAYXbl#s)_yt z7aR43>`JLaeNnqB=(_7TS-N|gx`Kem7EWd$24x3RE08wG)WX~42S@?{FsyB!>ALHx ztBILAIdGf)>cj2j;EWm#020z(&Zg#eAa@2ckd=+2BonL=!o*->A<6VoP@PxZSq@}v z^Tfv$q~oLU%-qM$T-1U|T8cr!OAIxE1IXQ!!OOwk(M`-tlIi!nVyO17$2?37zq`2G zNizLmN>^QrLC(n)#30Dc%Vo|h#K#~cz|AMXD=Hw$$-vLc$IHXV&%-Os#m6fqC@jXy z$ME-JLQ!+IuoTmlSNuy0btlPW?e6X@#>3<3>B;T+h}+54iib~BRFsF8pNF5H3)O?m z&D+u4)Qii}jrpG$0 zyiA>W__%p_92|bh^}Dy5yEf=QZ2Y&q-JW?ngLt$-ZcZMq=BV|sWd3I`N_YQjLccnq zxDnHIwLvY4slB|DxrYPD(Op?yk_q(-w}p*`7_Wc`FCU+<0Ix7VuaF2IpC})%=wo3K zeo;j}etAU!#ee4b@5ah2DhMkmDhSC62+Q&DDe%ia=9QHd5tWw}k`q-B6n*^9SY<~y zcT-1m&_8r-P;~!}75rb06_axXnYufXx%n8>P0ei_ ze?9rNK!4*07k(f5XB5yX1eyTKw;5jR(aH&oA@%FXr;kBa{vP zYW{2dsGEP?2jqzI8CR5Zj2ckO18Dpv%JPq&dCl%N-}0jE_TIR>Ekhz#47%;$FQeT= zGhKiiOKM82B4pFuC1cc`1T#agO~jjx=X>JEw>3ZtD06E2#y@6JdGatF>!;OF?m4Zw zi7JWB1|hF!d7&Rws0C=`oi(BR2Cg=D*Fn=eYgPV;9Qz>S)S_)~J1w?n=O@6UR>F1U z`{;!+!v#ab=L?%i{pU_t{2vI>etSLY!^A-+l=Gh(z~tW+01*DC9rSN^0O0-4W8hZ+ z`g^th(?ESw{g*bzf7<`0Y4V?^|7Ym@Kal)CLZ|h=F#G>oI{&k!`k(3Tf8QkjXLKgo z#Vr0>B8L(Kv2N8~IxCW!iQ=YfeF^Ce$62`?WQ}(qjd3KAWg@&1MTz{^5VLYGY{#hEYppR9Oj6>E2EABcm*^5S@zbr zdrT)!Ydl_!+;2-I{%AgLYp9k(8x&}?tCWLa~%ZMf_iifbx_ z85ZL;!?No4J?t&kzg{8pB^JY#N`@z9sKqSfy)S7MqbC}W?cR#>o19GYca4>2=l(Md z(hqAoJA7C{-4~waJ?H%BJ?5*nYMexoPm95(cjyf&Cc)242yY4)=DclxI z^Vt_9YMKKqpFg}mOE@5k;(a{x0)9V2s(dd)x28-B93r-RoTQSf6l)iID0qj~VhVv* z-VAk($2Hc>R4q}eCU&W(^yc2W=I)$&8+&l`{4V>rBM?MC{70ABK2&Cp7ryCDyfH~x zb_uDijdsokh>$kw9SKK1(gf!idUk#x`d7Xku39jz?EG&luW(jfR(1nh``(hg-^j6# zK^DG_i}Q<{b}eXIF~WUH|8&I?7LhDVqt7;HXHNF~?!SvR{FH9xeHx(Y`VxWb2{+z9 z3HT}=5EE0*pw{P9{$h$3>&knNrcdGHTtZ+dX0bDY1d;#diXYXW6)(z0{`zTBo&UBV(evVkaunC%;o!Hbn7ha0CvNwlL&dz9kv{Qhc> zXwcwr7xQiG>Gua2n$;aUlK9$54kX}}WB99YblGd?oWq^<+h2yc+NcW5Q`^&&79q6D z46+`TL@Dn@JYgV)S2i?8qovKej&JLEUXH)w}z zc-RLr7R&Y*viyObo!IETTeD|5r$8YlJIoW1k|3K`MWyIzY9HuotUgvSazk0C-S;-A>R3YyImZ^=;E4-%5h zCWDB38HWX`3RMiJEVoRgj`DmT!w*;3q}*w5TI}8ccb`V>X^#`pjNM|n$Z(j~St5)< zhArM?Md?hYG7cqM%E{1Y$vMJS+0j_R;`bN;;M;?rn8d%-o{eu(Ufcj@eZ^Vy*33o9 zjFzPv+(!}6T-2OlTdJB-IzxOAZAr1Iec@Rt0-kHIUi3xQd2^mqSWm<|n1#xN*NhrO z3~eY76`qe9Ya~0jXp2K~-kb*lK~Cr&)UfM+kpRlNsJ*XYc~4U4j&U4rBU`+WV7V7g zq;T|};^c_T+r39N)hAvDV%(e*V-_NYsAT)@KTCPI4 zna0X-LLW^jX42%6VUq_3^s(}2$s`RJl4QtivX$`+;@I? z{67IIGNDCA#^Vt<{>DAwdX$)#yRGnO_Lutq#%-rahfSp6Y83=P=AOGLSNT z-di+_^%~cdq(D9FhL)*Gorcql{29dc-0q7V5cJ&gUd1ndfb55O)T;CFhlX5{&n=k8qfOm?PuhgLz?vMx`yULHzZE!nrDV)dmb()6Q-?lAnIZsh zAB$IUW^%{Ukg&o!Nw%er7(PY|`A&Rf&S|k$k5dI5O!eCH8w^kfcBVA#=GHtcR6X4I zjy3xtFoepR`rT^Qx7LU!d`t>`iFUky%(3du*QO}~uLVTR@{R4mbF-XldDldoPwsXn z9KDX+!^v(7`eo**>u1E{2bixe*vqFaJM5M~1?7^RAqx&-5*|_$X5V~>*bcvVPQaFq z33p_{Qy@E!Tuhyf)1&$oj?BYw7nud$`MpKacy0t}@yiz?oT@$3;_J4C@4=mcqh_g8 z>lK^b%xM1vKobXk+iNM<9T*UEW=ip1B{t$X(x7s#Van@Fqg^E1EgUQ!&Dpl*9C5}^ zHB_>{Fj?NK-2WgAT*iqrwLxJ{ec_}18rk7kQhaQ;p9eA8fGo(}e%D&B3T8n}R5Z~%-eMW=?! zW!%F8hW?6<@#Eld?hqTjM^kbCc#Rj|EeZRu>7n*}|3;{wWO>R)ilxR8U6ps70?K&m z`{cZe$HkrEtGs9f!3I4dNJam~n)yP!**cbtZVQfjvSB|XtLP>(^@#$;Ar47sceJ08 zD7G;Tx}wOw6{NK{Lh4c@m0)0=!zgOZP_E9v?Rg>2b{0V*DF*dr>i? zjK+SZLLvHnIDe`mNsu63_;0U3ee^!Q?xO?nA_D;xoP4xj*bnOZR&$Y{{krZkhbu3bb_KEALHnK5)-O4JM z3+D0}mtXVUGMz6t%~(N38b%B%=$y02eb8ZZDu=JL&9ybtgQt}k7$tF;Md9+Uug)l` z&-?T1#YMl3RrfHk+n$OKCEA}vQL8xwI=@js8DxC;@e7Mw5R3b~-h6J|lbGRJ#U0(W z&hR^?eFLS*Y^3a|T_Srfi<9krPf1u5Hgmr%tq0-44Zr|FdE6#NNujt0WPeJMzhrv^zC-klraTWE!mY!S$12y4tN0_{w@YzhJ7Zwp*;Wyh@~b@wZ) z*;+UsmHLkM3c$q8u(G)RrdPdcCvyRCl4~?d=AgUO4j=f!0vNG_Rjdq_h z>ZdmQAV6)7rPL!^{xWahJL6u)8oBJOcXNqL*G7GGvaxAP;8r0wOHH5Go+G+;BMg_o zlE3ux1nC1_Hw1o%RB~4&Ld~vQ{<4;Kn>V-f{oHbm?<@R@!KmZB>91ZZj zE}sW^CAjD%nX)m}#8KNgdWhBxTXD2`r>|b+FBe=ao;A{r4Q+`t!i??TZ%|D_Njkl1 z{;s)hdU&v34y3DMU;y{+4|B}n(5dp8kH9mVaI~Ay41M7n27Q_I&z0dN`qmDQn7wt$0 zh1ns+bBZx;k1spr1?9pWQ-{wJ6-2}&0 z>6$j)F(oS#CC+_Fju8D0@|!QP3FvPCw^BbhOM0W%$f!80D{}W?J z_mMc~p+hB2ESRZM_ggJ|7h!CRKfnX}saz=WUXhH%=O}W34cho&20*cY|uc!-(BUw8_1MU zZTXE*>5Xl3O2U`&NcZ$gsfmHWLEW!>2saCQCSIkOdpHfEcn0t5sw9dWOcUge@$5Zz zbNB|ThDnTiT-6|p6NZ`H%n0uUU)?^kG-HhzKKPSO^I(y*0#0T+4_1v%n2jk%?XlFh z`6t4w!gkdkrOBM9AiGK$SYBYbTPzN3UJjiD7Nmo6{ao|d)A>}oQ=@t>6Q&GS*r2w3S(Dy zmEBy?!}hv!l?qgJqM8j#;p%Sp9u)x>vAycz zdx&tLJ1k) zoBs4C&CwZ-mg=GgfFZT-#zkCBg=z6*F8|Ik0eyPTuI{Q3rRgKnNZd91Z*vOHJ(Ifr z*VSq9B?C-~VybMtKI498MQWce^TG^fOM|9p@l~!2Iw0Qu9*DTEv(yCN?W)Lrp_Krz zY$QIc#K<{-D>Nyl(24nT?ZBNZuH_5K6n;8h*!w=o{TGmNLb6W3+pD58!jCZn^}q++ zBJUq-3jRtpzSW`0P>u+$E-XNV5>PppFQknY#xqrF+sD!6R4rxoZD+$dU8;;zx&%GA z&4Kj#Fd)8SY+Cv08-TH}A~k}kjpQHIbv z(8x>(2Bsc=N+|VZ7-~AcJgUkXVjg?+Reh@D7^+*zpMm2LezK>J3=#szFva+-; zz^%E<43oFuScePg0}gCPSzdOH$q0b9E; zjpu2nPV=-)u_U49)?R#2Ey0H6?+3xV&1JO3b00FTDZ^6`7=l&6%=^kc-zH#N_@+*v zn>zclWYwH=b8g^pi}S_YrJtMt^t8#aubo6_F}3g{&RX&983=zss<{94aGMd2>0l`t zY$}cwYXj^@QMJ*w=e^~rY$d*-o|OpsVkV)V#%GT+gvr~59nI1rRG$P#8?5BJU7_)s zT<6+ui&;;C7VY8^Blb^24K-KcV7Ov%6D_1jj)w zhk#1qpkf@EnKMjX6;uY@dkb~LK`ZmZ-|#JL8asUnqb~H-A4T73gU+uD-EVbAuN&0$ zBv>B?j%lu{0^QQeAZApA{iYZ@u~5NT*AjzHDU=Pn9Kr}Uf-fTeV1jE3;Z65|v_a&_ zWMK6I8GOg4g))fdwh0Zv2_4S*1+s{CIe?t_O7kgfdmb zFVU_hF|>R}C`THQs^Jn{J)zZc-!O`;Z;Y4e4KIF6)rueKXSkb=KHImHrJh<^@FpG@ z_ylZAY^ODB1UAEwAP4Us6-_x@rx!16%B6!VvPb}wbf^jf_xJD@ve%8&nC|T|aWRiu zPY|Vd(dWa_Ho1;f!Z=t1ss*Iakoa75=cN%IX|1JsZ`yHBs;pvtWeEsSga0Pt6J0@m z-^mb;I>2nmB8H6TE|@P2{=B^>yZggf$Q`80MbU-Z>}9F!1*#JH8`w=giJX~}X)P}Z z-DGi}oaRXpwhjO?X{iv|7+>7Y5MyD?Lc1b|tNKS(bvQu*#=O`lYJZ3F;!{Be9Fgm> zK+PAVduWh@n2Z~Z47q#oN4}aOQ}i9{fV$QUQ-MOk4u}I4V2S=q$ls+A@Kt+t=QiMg zQcvD~zf)$pV>D7vZyux7eyNl%Ov>)b=+YA^l`nKbUCbkMxddGhzcsLa#G}G@TpS=IYDE?KbFR~ z-?`&ik9$<6s}?!@K>o7uf@_M@ta<8=CN}#|Ii?PR%-5w`fp1 z*8`&3G=Fm>;QF+D(O|V|b&z9nPJ}3p!(o;m;(%_w>!w#}2 ztIW-Od5T}Rt#dIqXlN7mYFO1&y0@=NRf0XgQ8XarjbA;}Si{pWIz%({!N&jy$?Z-> z=~Djeu+wW&Grj!Mp|y)#TvmB1-L;RT0Xz6Wwrt^JieCyeA(w|taRT{|WQ5ISS`~8N zch^Vl>fD|U3oMQ?{nUkmbp;3D+yr6SYSv6TT-^?bb>x!uv38xEIUnS{!0aGHDO+JK zu&6utt>){(Kf>xyqB~g}bQ-5A-ah_DPiz{2J0=m9^9@DuFL)}mJJ;bP73>&oUrT|Y zK^-9clyjbIIGkFqe^K05ZOhq(b$4x(ltKNNtNzM|UEZRizYEz{m9cSp{Gh?p_|k4w zRd0@4e{Sw_<4N^6`M=9%&o5OoMYX&zNzgj*3YDtyeNPB(V_6>fh<(|BoXbb+*SZu( zSFRoZScSe-i8P9!nN6`UB5w2J~7DRdSC@r|HXH+ zr^%RF2cT$_iLl9gP@zfb6{g;SlX^VgT08FrtGr8$CpJ4R`X2S-J`m8$Qv0n95$$iU zkIoA3%$fxjt@%AHp<#vg?u^1@QpW_X-8Q>5kXKc9Ps-=lR)kW(M@&8n zR}-3JxzKfTc~2D^vUYfrdnyM;_Hp-a;Z>sDAD9~#L7thRM3(Um`4d9fgg!{*7*p=l zqy(n(vc^!=R-fTWU_x3Xf4c1ZwUeSt#Znn{#k$&GPoTI}SYjw` zgs(*%u~NMuYMimcp2&{nPe9=9VV^aFK4|6_J2u=Ij=`RC;|?BL;Ne-3I<^nPa_`ra zqTVq4I^~yKO0t4j`-aZ%ZsW~${3+{vrUOYuaAO${?T48A?XrQbo^GQIOycn$%p>WY z44pafO1=t}cR@=K)I=j$JaI;fxV1A_O@xFW&_~O1Ho2zX#1C2Vamy7E@ok>Z`}oY> zT6&1JcUw-2BXO?8LsK*ILQ(+A%m8bq^g`lEc~*>j+cR4HK-QUhDM$NjcXW5S&Trxk zcPWO=e?xcuahNGFcHA6xjs_IUVzlN+2fZvY_@u@nw=tOc*~x!L-~Dv^`PC|`^oKak zno?s(0M@%x?3?5Bj|DTQQ)4{HWrsp)lxN6zS4JEqTna~^Plsbqhd~xkv#d=^Luq1` znB;1*|&d+|dvK-MV`K9>pQe{zUCXeSzDPLPnTtgICM z+^VA~sSt7dUQP@pPYxMsy9(NFFHUb}?-($}rY7QZvYVK?g?+h9@orH?K3MFKMx?&M>x^0oWq5rcmr=(98 zv9HK>dc^Q6$myg$B{eWRH@6ihyqH}Ya9X6XgM>qo0arh9q&GW$9mmK#4`|1f=m?N1 zy{S2_qsF!6gsRtkz_~UkeYXYr#Fp76YJO~(AIBlcZp7Vi_Asv?N#O7(EDK)SG4f$` zZ}dx!J1*PJ!zc9khF+Pdz}gzk_y)3iI%VvshYZ}`2pFWkW3rE2Ge&?K5LY`kD5Hyl zx12X8Y;SLCh5RD#L3(hpw_e5rB@0`Za+?Nh+Ms(GAF6E$i9=k1D!4`~JQ|$H-|_bL zMP@)2r>9r=<{FE_BFKhauvPe6}9=OrdgD;YBZI|KoJ1dpHJ} zq+}uKFV0@Mt@l%>rKVo+3`rxeyE)Mti9b0!LSKD^TL>%glL97}iGh1t#G3KKFusCK zeKd@)rhPPoXs$eqrwvR9)15D|c%8Jf$(T8=;d49csClhAUZC{}POQV#VbkIdICiYL zo(Lj9HIiJsbo%KE<_2Xf03?y1J!pNYeY_)`+l`!^)w}8ryjHqOhg{yh+JhqYGDu|d z)oFmPuC7fdeBhFS@s+tRX0wYDv{nmi=N|rbvky!i zfsW1f^_N5)IVnvATaO@**Q=b9+d;R%B2ReQE1RS~7aNZ+_guUbDLn2Uxqb^g`nIoR zoL#1Y%juq%9eb3II&*@8c3h>oG8{Gc?KZw_u1Za4)8%^;o#1f=@N~yfZMc>&>K9x} zICLF0+n%90PV7&HxkYy#g}u(iU_v06qGoM0RKX)mkn!Um?)9hHPi)T9U-Qux`sozk zWIA>qoJ1N`GWT2zbh_qP8qO&WQ5TzI2D8HD=sz(zBRwXe}yaFg*}m(>5HBlEy)ZRa~R}o5rO@YA-My(t%nx0 zqM_}0db?U>>9@EP$hQq{kK*$7w=4d#EzUzs`#*UcAy74~A1H+Z*enOecfwI=W8%6m zPb~;)L&g=C0N_RRTl|`G#Jr*L z8EquxWkW^xcZLpWV6C&kRXLLE)G@_oPO9{GqFYGAAO5yB%9Dp#Ca9_4fIwHiDVpc5 zc8M*#&$3Axz(1>I$Ykj)L2PvR$j;r%`(_+5X@>7{=ENISjs%kE$wmLb@Dni+M8Igu zWd^Vv0E|-wOyogn(RuCc$0C5jm2vMAH!JJI;m`^Ard+%7M0*P$o94n0Y=D;Cpd0ZU zE0=lmIqbFiM-enV2|DTbtSvMCP$4oPC^|cXmI@vC+5zxNNyQuB0MBYhgP64eeAz&w z@dldS0vu6}w|d);p*68qny}td0%VY?L9G{c3?HLOef(Yn@2@-`SVK_w2kb{Nt*;`?gqD)yEW) zpnhw`Us{joVL1XbTn|tL9_iNZxw+k^;yoKm^ndZI{>k1gw512YJjVHy#(s%yOT1Y8 zlqGwRr&#(vE3xi5@Oj1A1>~UA?v40~?L1-q`UUPGc ziqh9hL|azUaO&o>Sv&W&qoKmHS>aD8V+4TYm>EgwEMg+6He<>|N5iYq1}b!Sr7*XY zo#eO+Xaz`Bmvi+QzF~o879BZc%}4gzdCDuA)3-ev@Mc1LOSzU(D35WG6Y52#< zqB`u~!oZ;T1e@5CHYN(4U?`4y>VJE;fpo{M&4`WR%|ls+k|GL6eL#9{z ziF=sTPdoKouP~d7_Kpc4k?r)KkT)?|pBtSN2H04QvJgU&)5pFiUMe;*y#D)r#<}qQ z7V-}|^7)YRh*`Sp!4L<}z*RT*pKj+QbWzVAn2>DcPv3qEPeu4`oIR3|38#sF1n#cW z;=V7)_qnzuWSL|HtDt7Fg(hl=Z|`PJkKQAZYgF&#ifu5RY-0keX&1EYk=b*{pZMnt zIxmpKJZ0#4&#>8Nf*Q$l0}M}4`)pZJZb2Qtx-uT_uAD>~Tn-xfEO+j?6P?ISy!)iO z46PkqD!swF8TGgyV3=J18I{YrI$-d(I|`7UU?bwz$jUvh-pgxjgm39XYTlF-HL49s zBZ&RCb?EbBx{*;*BNvty+U0d8{1bkwy#8+IJW;2r?uQdLK3+~dHwmz`e8?;2p)e&5 z-v>09M|kJ4F`rs3b<0G_-FNVQTDr3d%LQ@U`&Db>AKvet^t5%!Gr9Xr&Y1$${; zte;GL2i|2JU|&UMRNPg+CgqKAjAtG5WYF}s-C`0d|23Ai3 zM{yaf&r+KPz>>VTOu2*c(7{j(uPWySDRJ zKYLx<4+p29D?I|`_W|5Ox2x_>Eqp)!C@`&I4MN6hN`v_L&gTz+Vc@m z#+%%8ahNA^i&M)aEd&NQ@hF0Q)`*=WUa;_IYPsNoCxg^4EUG_;GCaD@8p zAtcr~he+1=)yoqV_f^S0X*|5+H)xT#)67XaqyPDp8|_U0)Yg*Gt!Eu@6oL`-4(g?T zHW_#jN-rXbw!IzVu76SUwS-XmV(?`LgubA$gc4fiSv6`H3>zMPRJzRmWwG?Nm5b{E zqt7NI2_0>&RR`>4ficr~H2>0a(Mg!@{DQOOky%~`L_y4mVoA(mXmp}sQm&N@A$1Ea zpN(jhWZ`ld^N0#-o)&jDAA^w0#EZ>pyvk?Y-DdmTIT7=qOyS7`&gH7OPEhZ1Qn9tp zj?I*EnyiN1X+njr(d}OAM1D-KLc-n-mdOc0GjB_B+?{aJ8C&kQd^4YOtChC=JN;A) z$EAJR^uBS|XxYn!vy4Exuv0!P5D6c=8XqUan!?#sathnbw<{7TL1GDCxx?$IUNGi~GM@T&MxJ9NBX$1hU$8e$|oRI_Gq_AxwUwdXyZR=R~T@=fB6Fns3F=nqpAOU6OJWDM4nTAuE@vg(oQVEE~3-)a^HBuD7idQ7-N zIC)^ZRwiMkV|F4M-&Vn@oj#C_Ch*$m?L;CIK$p3HU|Wth#q@tc27*kJwCUn6kD%sLhy>xDACyb3U|n#M!L= zvSDMZ_YkRiqPP9Z#~POP^e0zVp0QFwYK~cYTx&NWmbSsv+XZuodXUu-6*@m1cBo(R zbqzZ%$Mfp~fv03O-ZJ2YR!1d$V%cb)Xlok}TkUKk@M38H)*~K8&hb34)Eqf&p-m^0-Sy9mJ zA>6~jzHVeBVtti$nBJ0l)ozccYz;!3=nw-FoXDE;KBA_2ShHsArpOxgs^gvggUkc( zhI`y|N|I-_-W>_LUC>(c!?QJyQNPScb&I}~Wf0B1@uVmVlB2{sNy@VVNp%-@sU|VY z)EQLoNZq2yBimurpW%F8^#ZZpk6y05(Abo~bn*Td#wxscR#PjgDvI^fuC!Tk%bi?& z>ziFR^ZWNFO6QzsREuRRxat~opLpHn$zR0W%h_e63|p;5hDaSQVq0j`&j9=L8i9&xN=~E7FR=y zl^%Dsn`n)MK;LjvDEPZBdOx6hg)27JL4D{pmT%+YYj5^Wv~?rlFcwgmKDBFe|I89J z<`--6B#Omh(1%}P|4tlz!&oh&|E{DsZW7n|io)iN3BFyuRBmVDBebwMID3^E8J^LZ z^|Emny}-UC6en zUogv_iULwTb0XM!Q;;alr2NYNH_j(iorV*57UZ1>40Hec3QT1yzpc7@b4QhYl~8hB zyLe}AC`&p^+}O?S_=a=b&U#4=a9p^0o;ub>ej6-mu*%RZK6r4&8KHU&uXr6RhIp6- z|7xnsM$j&U*352?{-90vDP^c_zt4OmN9SfF;{`}{Tg2(5th;Xdxsf`D6&*7{qb8{p z+MXEv)!R1$dRdAKwM@a zKP(=l)DB;r?riPOR93Z|J-i9rfT~I3U;sfTXoaLb;#9zkejq!4t(qFJC@d}>umUc= zS)yKO_hj{_ZpY2;Kt8{%(qX)uO%PCBLWlmM;?g{y2iRm)|!uto}M_XI(#KFtP*wDx`Qi|TuLyQ2}2NYk?y4yvh&emw2>dAVb+bw?> z4tT5UR_O``xl9=_j<5*kR;HBVU;17k1B9Ae^xf2E5 zabgEOMLgsHVXv zA$l$~vHjTjhc2ue;c-F0L{y}OiUINX%d0~hAP)eK?Xxc;&T7S(48&I6&pWr@((sh7 zS7++1KN&@~5%8?WCqnX8T2RQY2lmi#HVx{=P_`Z_)~!UYBLEC!{N z5Ryx&qW&|ZVq#42o(fL%B7_`<_EseiwU6=%ufuSpFM`L8O7vEZQFUAama+F%R%WJ0 z*fk0O8Jy=kqUCQ9TW6KNj53$e>h7Tk@a`W%UJr?P0UojLSFCR!Vu~~vxu(BV0wi0} z9uUJ-NoLV1hH!rhxyiKh%GBjq6%P^u0NWky3%To1K|4S$yDdyN7u<$a;5-;zi0A=9L<(CU2wn< zlw79aVB6P09M}5yeBbQq0E6{Zm@k@XQS3gW=P2>%^TuZry)}vgowPV);>QX!KWhNv zQA~&ZkA{W~Jr~}@%FJ-yT>xax_|A3pZjBYZU-py+6)?oWMY!9f-!la?5bi%>FV+kz zG0S)Oa*5SjvbeF0C;GN|G~_h>NN> z`)TqMQiwWWtx-a|12ptgg&(}KkJnr7JxOq;71oF}$4U86`$6LJ-JPk;BgUL=`6hL# zu$m?w8;Qg&DsO1BWB3QzBh@0-1p%kGDu>OdK2(7xSC17xplb;x-4F-GltP}cA`a-T z#+ge;PT6?Mw);n)9g#hFuM@vfFrlsz{jNY>FMlvcw>MX#pW8;d*Z29yI0YAcE>`Ko z0g=mqA^Mky)7hK4=S(Y%`wI=%bMlSgh(MhKE6$yyjkGmcZBljHt%o7GRFt2dhigX$ zgqE?O-z=*3)@7~Qu7imSDnQ;50`DRv-k*LB_Kb`4mrRk9rOlx;b^ov|olEUJ-&U94 zM(Cm^c?;981iJ7S;Y?PKIY+@MDI*bc(`a zHvOga-lhEORx?cJorusuZkec`b4`^{q^>jK ztTj-g)G{)ez;msXPu&hF%6MlYgeI6SoUQw!USocpbI0)Y)EMFuv%AG6@dVH3K}=zb zKG8DKNY0^l>;R#rqlc+6mEXN;c5LL(U?D*l!ke$DpPu2=?K<7&Zc@}Lx~tTQNYA*X zLuR+A@E&v!@G5Dt$ztrI!9o>|z+?IYk|~ypV?3|g<0-9x?!YxmvbQ;E)d4JDPPpLS zOO6YP{LMs=sUOu9igvqKPiihM-tKn%Cuf9ZRVP^^vG;`JG}?MX?>k|jD&7iyw5H2}!J~KAjrF6M8?6>0`w7Vz0678G^K zImzoF%hR~``8J6(G4Y0kfS6N=n&wC%omAFzEzd`p7~}f4>2ltw@waJvC-Gh>c54iP z6AOhg?&b9R-X3XfN!5vO#J(fI+?rn<(+`1q^(-qUu3k?79T#qKVain*y-+@P6C_g$@6CIi?S z+${r|^{`aT3?o-4Q=K-iuxC#0GrOIU!t3a!Wvfu5vmQjz)V%lb*KWu;(^;QEQ#ZP3cB@hZF8p0fGWIQkKV zjXABNfqXjib-n&Mv6F40d0RDcpIiNL*Ug2xdDZk~XNY!d z=$Dx3Si)r*ZIiy84#^|-e$d$dvEIVGwo~8E2x$Ff+WG1Gk@TQj?3Yg(zhP)eT6BO1 zRl-pTfkFZpRw+JBSqG@i!h(YL*uZjQxjrzH`0j_nE>Yop2dCcRDWO{+ z%M2X}TggSAL8XFByVrVWhLxV27%%AbGcR&gFBKBh>L$~t51{%9eaUt$u2~-j-5U*R zYu26?lmt%{kyh-Yk7s^J4d8znzayqpvG%TrNc<7$BPl3{T~$+7z?F@8U*88re&;!r zZqmzZ{e$_>;+Z1%{ncTi1e<5f7M}j z5{MpVXe(x#XKT}!_o~F5iY7*3NMUyJx~#IrxM;VlX1_CSQxwCA2ekXGnot%I$dqB; z?by%*?vAVP0CTm<(ON|Y77_n=pC1BKfTRpvsP^&YmiV@WxwN?osXZLUJI`|Y@>5r z2GHcLhdXG9mhAW?8Aa8uZ3owXTUldVX+AozK5KT3?-Q5FtUsb#Ix7qHRjtHg78&jQvO-5D?VTXjU z7rRcS{RupJM=M{CYX?7`J?|2tgRZX*4ZO-KP7WMglUNsAu%u-xnyQw{Z^B*aQ?~%S zzIyC5Rzgx>Uwf$#VpQYordqb$=C6pDlyxPCft06AmQbg-2{w!KyS0MG>9iU(cIZyf4*LT6^|1ILZYHpCm8=#A3yVFlvs+z_{&ahW&ae^%)LyA@UjL>0 z{{rGb9lu~OlpE~2DU`iRurW%1$_A$IPR-KPsqFW2OMk2&H|fiJ-{sE_J?){;n($MR z@yHIpqQ2~h0F)5bWZ`C|3axemdAhsSeAC`711T;KaOmZG9xI>+Kp!pB^S{q)B;ABC zx3D|j_6x|@G#eCBw9rq2?8z|gasNxsFE*C+u;HN+YWsGmTg`TC{%XMRDUQ*;O_fWRpWIwor)%QtRAxhy3t%vB-GXtb+ zSiL#XR0TJOBi8c;Y~{U{x_r#qm6G(8pgYzJ*z(%w&P*FKxxC6b0SqjRyD&fNtofPm z-R`MlGIey5PsNwf5@=J2^T*Xw`=g!oA9oGYk@!*CdMaxg{B&F6iq`EJkssGu@}p2i zTw*)LfSq+)siy!{g==pTM_<+~KR_TS?jDQ>}v_CHB;i8%Gdwo{Ys z%fri2oAx2A*4A~7(8)xC5{aXnp=i1|kd+D%{ z12uQ{)AsPn{yjM3^0&^G_L-HhN*SMm+h$A37)6uuVK~s&Ydnkzw(C>{Ec!YrJ0EGvsxepDCY z++|-L*UIM$>&Gl7zqoh65MQrLU9(WWQPiSkK;{!r3?|U8?UvuTXDYD&B2pKvo?lVFy zkqz{l{3#mS-l*l#IK5XqBR#PQwH{umA2w-u)tGxW#$EFB3)=IuI6u|8ET>>yUGCj} z_)CMice|||&3C~y#=AfsHEYzD8JD_{J?uC&ZwSz?_>{T<+P8B)?nfWkzGD5S1Dv*? z%ip?ymi9Wz`freF|5$u#wW?LdLv-i+ZSxUeJAWY0wKHVzB~VRB;V=KN$=2ij%N=XY zjsRm7a_>Vdg8Mw;ggx$6irR=Kf=h+UPq%BNcwdVV6zX@_*kO*jWBRKhc(R}mDT~@G>;tR?H*m zFY&ZHmT~M#6Jp^!>>*^m3?gkSR7Re5L{WB5uMIP3`_;C%c9?2`cRRQGE0HAdikQr-dmsZ@lqF*;>M%fBt#-Qd!cmv$O0JFj%awo>`hrXFqa_cTP|! z;tz{wohZEA^OdWQ{n_R?LaivzI#FEKR(U`3%rkV?U3V4!EX}f0JC98{@H}*9Wh%Dd;{IrM)yvOibj~o12?ID;Bl1uuDEs z{+9YVEnMMnnS<=;afz~>H7-%Mqr*jB&hoa)#xd$VbDD9$G$O3(H&CDmW5(D^yA)Zi zww7LQnN|K0?ATrZ^Mce9^f1KgEgwUW0M;tN4d0ccAbkH?q7JZ?HyQo zNg*n>%inTJxM>!6Q5IgQBH!8$Udp~L14TSQ@;jDPulHzyGKy{+F0v{aPIiyCnHck?TrK zyEY5}00sa60001#hH#^Fwl^#!%1(;y-bcHmunc?Pw|Uzp%ria>0p@W5kKb#B1>V`o z?wD?Ypp~t;nkRd?Z&Zmyu|37x<1V7UmBpVrwyQ+*wM*eSS!_YaVzre8aFj)}yv_l0 zPWwFR8ufWSX>jRM>pqjI?m6W%Z)KbV9{cq4NXLM2zIP?ihq)ZnMaZu~vJV%aLW~*( zB6}z7poNAo04n#7=`tNh+&gIV6+}!*JlpO+4L*7FG^h&6@=*#6*UaBtrmpG^{|7s|J`hAhZWi6<# z|5vp0s-=GIiXQ?1KsCY!tsUl21pq3M74HFX#~pW+ZDuUT2LM=`tn7GifI5M^1FM5y z9{}ZoZU7*AtGjLlaBHdeJ40u_Sp@>*J@w#RIf#D%z>>wk?3Ez9|FwpWP#t4Ngs#?s_RC3Ch8@;|MLiHOK zReVY&&&nI4NTUz$+!-uQJ9pYagp8Ot%Yo&W(4!$Bd22><{9 zpt=nJuf1AFANk!c(tUSl<^Fp=bRW^+L-g83qFd`$Divuu))S>&gOiK)9DHn=_H7TN z7FExeG@absOkEx^1}0{xJ5oV%cXo(&Vx+Z|cM)nbZvi#!~+?5f$>PyZV4sW77uSW8Tw z?4h@}FPt%}hWhEJnVt$U%w3|Xkw2$>!{4R#>(^6VU7ZNOLjU1Eyvs{y2Q2I4BKia5 z-r{eL@y|DGfP5Mj0001hRimtj0Ni@_ee}n__1@g?Cmwl7ngQsoD<=MDDY38B5&!*< zJx4Q{j5C#0W@eg(b`m{sZv<c?PwpY6wznW`<^D$js2hkruJ7g-)I0Z8K8z1}pBK z8hGu$44pDsvCq=UJy}^B*c|jXcr}xKIO~Gho^*K}bH{t>_Si9+#lr(ui8E74s%h${Y4M(tp7UjR?cDB)>6LTo>{Hb9rE$9F_xtJV zU;jFN?JI}r1DU7t9cCMk@8#X!>zIt?+_u>OY<>gChoJ!g004jiz{a!R*h8Oro=s3kq=OQv`M9Z*hp2Vm$*jl}*FDtHL&rwr)WPT8weJ|EJnU5R zxSicQ>FU=-8ni^tiZni8`HGd>_iAa6YH6SU(w(J|p3P3H`09MeWtNho z0~C#9_eG*HI(F);mY{{l_LkXmQXdRC^&(prLe#vyho&FfOIMEXq7zfIzMl2jl+4?R zv#&OKh(n-OZy{6)5j+1{XJ2Vqfunt4241>RE|+@{agMA`uqc*r;c~C zsq&f|=pBt#9j%M?Odf-PDdufG0^GXwn??a8`fJGD;U9Ve0001h0l+^O>AyX+gMQ<| z?@;%bzeOLv^UW)E<=L}8qG!eO)7vfGmp8W1vE(t@xwSsq1$fhD+A}ysLywKoV?*6E zxTlq_?>LqdJ^MB_(`VHFBT+is)k^L0sr<)+vc-MkXHni88mQ~=6de&|I`-&6r%Z3? zW|5vgMcX#F(w|L5Xk_e3dhFOCN(?_hcXf=4+HS8ehg5w@pQYoI$LWk#IcCnDq#MC zXL3fdtupP;sk9%Yagp}BJF@4W?-v`ShOK+E`P9-)ZQ?lzy5&nxHeY6@j!|=aFNJrH z(34L-MjbRvySCj-iF7tk_wunv`Pc#N*wsen&RLsLAe?=7%w#Pm)@S{O+)DQjH1fUeGEAQl8qzM385rMSdL7eqBdu+ZsTwV(@S|WBZz$K6%tB@6qWb?Ff@ora!4CdQ0oQbn1Z&ZJkY1 zsHu~_cWQu|oZ{U|6X|1g*OBb`($Al8j(=3tmky)8%x<+@H<TxF7EE3j%b)tC-*t`H6rq*jq~N4NY5sjFZ(idQ!?QkcW-n%Z58*u z_2e{#;|ba%oR9k>f?};*wC&~~{UCFQ!j*J0 zmtLel`@Ma1wyw_c1>oZ`baMolaS`=o5%^w@_ngHLVEP6q+m?SJE}~-5FM<>q`{k=i z1o;wfb%`Gni%yQO3UK@SP2`BK-gY*}nxF@r=VYvE!#+ZNo`7NwnyS;akd{CIYGc9x=% z?UXpxNQsljXkaQyr;Z(_fu8)Iom-^sf0LUCp{Ml)0Eb<9}Lf@y$`z}_Q06zk}q#!!%^ z)UoZBJpGY4_U7QK*9CjVo+X*eLz_jKQz_T?#H>>W@;%Z+TkGd7JJF7PB1@+6uz@8J zY;2>Kr>7|t4rh%>jWJ3*IZKoJr@pq&_6V9S_O{l0 z6=!YR z<|8Z|^Y%y(@rPJo4s%d~ShgM?FvTeg>@hYH40D>~_4?#-Vte4`bO7A2+C# zi^}6>7bAfAJW`43Bmm`Z0Jun}|N5k}HvLF1wLOyiWTuCoIzhj*5}g6+vKMitP---q zPGvXktqrv4&@}CE{+^p3Qo;GZ^udf+4|#l9EIt;LKl#4ox_8HDYcSh`q^&Lcx4bbd ztIjBGXviA%TROX`W8Vn1oNTAxcDgKb>m*|3iruUDhz0;)YAKm3~#>ijF)5_kb9$O!xS_ zDRjklDd45mShgmQiv3A#w`^5DVHgGy-0Cb115&t-mLMOLp~CClM|jz;1hPn1n$soo zrPmPh@?IJYF+D2w$@o#(x^L+{5M?6)6E|)elZCbg=ba%NK091ML zvk3zLC>dq!1E7xX`QvZX21DonzrHxH60YcH!GZyJ9iw z5FsX)Tk9#6JnJaeR3h7o|Jci-R>TKrcSjp-jWp%H3{`zOYt)w-QD1CdXFp1PeZily zdhsoDLaU7F$#LiFraoU+mS7`wbqDD1J-CMoe?b*8cFO-({F;4roh)Y8dtJ#}^ z`j>B$lP9)(Ih#029eq=@J=R03ok2!{mW2aKNW8Lz!9O}WM&K0vMI@0ri*w;<( z4)c5B*)J`4Pn_dt-7z5s!!-Bo0G&$DTV*Cj55s#HSTfTm_c`PK6S{NH*&v&qDubUq z^&dww!KU%O5j;<0_9S+dA)uh=?zHMzm|?v)`jDzr1eJ+^>~O*hgKd#^({N zFzb*7Uer_1#1K8u+(nx=%+km2(YKK3SYY}dA4 z=hzQn{D0YF`?70n>lWqROxxbwP2WD=E8g}g+P}G#zDk|cu|LR0Bk^{hnxb?tLSTQ0oJk-0%VQVSlK#jo$se zI7I@dL>=8nweSB+ih4~(&tiRR>_3Y?i@nYegzb?KDRn(>oUo-mDdL}`Ga~K(c7Z{m zp0AycZN}Y`zw7spz$(Q$T?V*1-*5l+$pU9W5alXu6e4dU!w1?`O$DCO=(x;M+ z;iCJtjkLKnd+d9(V`ZKWt2`}(dhqq5aq*WwYYa)BP14cc!%q4SetRD|S-*XE?pgni z@vLXx6Fs7Ao9UiSG5Y3{yJTmWf7EOR=Qv>&fihm4fOa2p z+XN3=h?np-LQ9A*oj*p5-WSAa9(6JPNMp_d1AvE-0RR{PN=+~lqn9Uwv@f=cy6!!m z+rD$}qjYG0hco}T?7EzIZiIGkZl`Sxhn@YkI}g(7qdnRE!3dpv?lFpOzL%OCvJq*>j3dADxEpMHArX9eo2UYdwuyAt}lHf2kCfwFExKXE7aw&pBTy*O;+R7{>$0F z?=>w4>H8;lxwiN@^^CjghZ?twGxpNt!5B4aE%yPgjA4=XgHbK*ch0AM`s`746=bDaLuRJ1Ja z5mX?e&P|UEIgbCD8?rrUYdeq7|9do6IRnk!6rtgP2j~m?`sx0sAEvsxItu>EC+UOk zwzwJ(gMe*FfGwVNw3Ua!z~*DXZMwm7LT?34P?1|4*@0S&vfa0nnrMp~&fvlBsU$7I_H2QWUUJ`=&Q_+cR zE}gi7`jT*!izBFsL)cM{ploU1%wiTCE_W9I36cOgUwgIS?(EF$%x`Ar`e2 zNM?e?v%sD`#nMkRr2}h2pM$%uPoEO#kij#4i#)Hl z?j2mc=`zE@PE$V&n&L`x zI0$Q>1H+pnD*^&*KU|8kwcn$wSFe_>Io!pI7qxXahR9?xE7Z?!9mZ}LAOkH5qx;s+ z3Ty{R$89MS`CwJ2`Rm(4UYLVDDu}D@WRmdI)T8Ud5(3Wb%<*Q(Q&F-?^Qz0I<@4IR znY6R*ZYLX+3A1;|$O(i;Qt0asz0p zm(>hqkC$2amsuPybMf-WjdCbOz0=rr5~FEGa!hvtVC0{Yo>eonjBHX8J*4*t&&4Y< zf-P~R+pm9y%`j6zi1FU?x$vzlu9D5BlDHQc@$9kkP+x*{6xL_jEW*(D=dCz22Xs{F zkuY(DN6S~@*4b;00o{z$_LWfiI$v?!x!+k#bI?bZ#!GT%F)ofyAE3c~~K`0G>(UkbXBnjJxVuL92* zw{Qz8uu+La&s8KKuZoY7{k^`_(6tg(9&yxO<2d_=apoDIllkdc3h<r0{IhuK zc_9xK*H7&IkNAVXIFCQbUAT^CE3i+pYKQ09``8L(akf0y^_#4lg)KJDLc(n%@5SV2 zqv=@L!P{7UsdaPy{HDnSFAv&p{>&d$RaL8g>;E>9E&cj`B@g+}N6HnGczCh18B~J} zYn}h?HrKW-lPMlF<;NroKg7b)eA8tR z!%RuxU`m%E2ng&Z1;F9Mhs(Aw^7#M|*quaA$b^89iPC_Q|0AO8%Cm0D-Uq;HEG{m> zf|%=-0aip_u}}i=Bwxv+7~rqp$fHycC{15X9kfvs>^bH?fI47nMrqB!D}nq|(%EC+ zYoXa_2Ah%plhDnUvvvD38&n9m*%30iH_d)~v0@=2anB`m&uGs7=1s`I=3Aggf4#u% z6wS)j$>kLV680cFj~U3SM0YG;btNnS1a_YSKtMo1Kwx*mCW=5{>qO0p*emNG=6qaL zdD5_Eo)x^k)rdBNZrsu-YF6O9Jt z`6zKwXf-r(Cx@ZBR z01yxm5D*X$5GcJ8z>NG`t->(6#(VSUpQVa`>pDe%k>fy{NxC}{Y_^jUBaePRbVgd8 zj0|pctu|FM$eZBk&x&+YqDq$-^lYa`cQ(sS$v-Vaziul(FhYGw_Y5V|)Lfnt=8(>k zZ9gO1R-W@iOtDbXcV~_v6YM>DxE%^SOjgz?b(sGGm8dh1{ybVrK(ZxP7Ci>?)y>ZO zt@<>@7rk$!80cX6ij`O%J6Jx2b3uWfqX1ZlKLY=W&#J#~dCPRP{DWFJ<{?ai!A&Kl&$$vxMhojDm!Xfyh3oj*-?kd>Xp^3=`VY0a()OkQc;PqM8j z$Cwhq$aAGd8a~(K$8Y_~FGG6d?yb*E zMusG%V0XFUa^!Qdo`E!*M6KJ6+CsKT2a4L}D;GYKCV7$zPDh|5f`FuyWc$?XVTa4@ zD!49-t#^S6kPbPCSxG{QR<5HKO-)U3I_yPCn2-yB63b;;R=*WCB9n(*E;x3cfY~gR z0Jc2DUw{3Ej=0+l!YZ)#2~do}p%UQWNI0;1jkAX%+!9BID9LGLq*fzQ^qP^$wiZ7h zuN$kK!=2*NlUZCnj8r+X)=8X)5i!{yy^VmTscsLqiRFC>y4iaJ%&@}>vaXDWx9Q#I zVX%f@N1myIsE#QoPHJ^-Qg?Cz<&(&Be=J|7Y1+&(L31>zDOFCHnf_Cy0DGndE0zM9 zGHNqqW{Ao9&e<+VU~4{_n)lzW!qux+3r=wPxo7YV`6k@`)~r%%;d3o${m6az>ioNL z^CslY$_bz})QH9&39smw#Lpsr>j8R3f~}?z{c}q=;kF8yMl^T;pKO}LR|?wdi-hld z6&}0mX-t#wnPdbt^_@6F(&=&w%CH$&(WG-jRcTHD z=jP^ezZ)AHA0($ejBIP`^R1KuH@GuBs2Tsu+;NQ#L39Vz%`I{Fv@;F=5*LRSpQ1|# z28x2MAN1LFjwcQ_J5Fc6>kLf9X(u{|B0S>@2vlf0pl#sfMw}iB>^@YLbLOgVyIm#! z%g=oapZ=5M@P9kNhhZ z&++$dCSxW(?y5ZT+6qitpm@^bLDrmGGBK%^b!P#AoeF9(aY__}z>ZM>X!zNWWF(hw zQh&#%&#Nl;twehMix@@&rZ3E)8}sOkC0E8*sRV+75F(L&xNSBx1|vviQiz26@T8nk z$$=Cbg2$cR!`ST!B6=>RUY`urt24&^H1S$(4|1PfheAh2<0PTHuy0J_A$!ySFd&i+R>$?RG{VB0~L z)i7TJ(pEac6c7r4EyFE$-iJpXc?3_!K8&Aywg=C=xTQlV#D_xI^Nui@Ty8?xZ1`$t zWJRT%PGM|f7@eKHaCNj{e{C%s0fIo`H)*d*!CUNfE6xuL`_O~2FB5g-q z(}`>)G2id(Ak=m@HP^@<*r+EL?b(@kP)t_ zL+3yeXUMbDR0tR1;>e&Iq9j^ z04KSFf;wC46eT6F!`r~HkaL0cpsbw$J{NxkANa-*#2(H%{j!}yo405y z05WKAj{^PE*%_3kz~AFWZ!6BuhSA;R$bH>I;}42M#7RUts}$3t;E z5Dnx;0C%~K2kfq6R53S(Kz$7YXvT>%Ap`?~>`nrij5=$4B{vnbfISVPxW~CND0AM^ zL7o~yh9*S9Q4d5v)=k|gD!E9hzgzttw7IfuKRGdxJ*P78h;0H&23q>=6O$P4a)CFm zsActLclwZ+bs-UtVkjwLHadWbdD7V0vKbILgzSD>jU!jN>nbU^T>r!`xX#b zFP4@rgF5Xtax39<>`3BoG*e#)2{*GKPznsMf7XW8X8#I`Tb>{wARr(husan1H{bp) zJlg#&y#GDFj)&E+=Mj87_AqYSvK*u^*`D1gWHH)_b~@qS&_Msk{6sqvLxJ4>H_K+D zgZ<5_Gq89xhUi!i29D2=0~ncG!~-saXB4|`+QDu*@>n&BV159)yMk!4XL+gLpWPbP zsf zL{lAJ)xUslm$XVQ0z@vFb#fsV3Ja7H2WqoBsjdEs(62)q>UO?TSTSi*MyC6Do4vua zR@MVn_XGq41OxB*AcPBQK19w#=N46S{}sJJ0=9!* z48$aOJjP#jP5pm4F@m0{Lx>K9;0uNjAQ#%)%?^aIjzFp4 zP?eOuNF*b0F?0W9e3*Pk4(~)Jx}N>*lyxcsY$l|?5Ql&Q0s;a80^5p;Z~}MbY# z6tj{0$rro>KDW+RvbG81Z9wAq5H2p8j~*x|U(Q^_#3T2jCz^nqPC=TLREJ>=)c(?5 zizYYlL@b85B*W$FA{2fGZ}o&RE2kh!QTUJcU=If2qpX64Cw$>^EIdETsBi5-Gl}^v zO(8PalOZP)2-bPgJ0M}d*jB8hQ1XlxtE;oJdMTMin$&qB5<+9oJg$E=p7p%V>Rn%t z0+otdgy!gW)PIZmngAm4StOGZqWuBXwGNO@b`U{NEozvhfUJ{?8@yaJ2)Pg_9qdjI zK2FZ>Z|ox9g%pyBAtG}UJZHi>p8z|eTVAiCz{*O1-%?P?lb+sLV5yW80s;a80s^~G z0k9p&Br!Umz4$2VL9$)#t9WD|$*mu8~i@({~b+r`s^p?nT{!gX)d| zfzwks?Q@b44m3Z|h8q*T_`ezx$T&QhzA%aV<_B=J?jY(K+wrxw(>T8vLUzK?0Z&&O zuCwsVcC4gb-GKOoDe~+vy!CactM}q>8#*w(FaoFG|0TsiSkK{Z2y7e<^eoQd4;#kFci|xFy*+SukK^$!_fC6J8w#JzH(Et!Gdc67 z{8ijFn?+g*7uL1`Ma8D$jyvuM(XGVTZ$CNQo0N`|ZdXRr+fA*HmM1M&_S>-;@2`)S zuTz1Fl$j7~E6y^@*C;(i4egxrvgsXKZ8ol6y;`;=aThOMq?NWw3WW?C(A#0R8{DJ& z$gjG@Lfh@eap}UN&}RjT!c$K@wQiZnTMv2aQJ^wqB9n9CXVBJnxm;|dJqc{|6O?8$ zX)Iai&!5MUBS$Lcedgxoa=#lJ8y_U6J&btsPWY^FgB^5C@-jKDv-3;rp!R*&kae1{ ztUG7ey=&YvFSCP>S37Q$ivmFNVM5xWhn%L#af-CdKJqusTY~)dZo*)=4{Uor5`V>6 zK`_P0Ap6t9&T6^kd5)H^hrTmc2HsM7Zs+4=m!^&K#_~cH1McB<+IFdHswM2enSotmYQ z-atAHjjW{TOP7+GYMxixNo+W|Av7ALMcEIP%e--vM6(8RiJd`duWr( zSJDywlBdJWwEe{pN9LEHtbGwM^MCqo!$mySLd#fFxKt9>Q;z~W7hA3XIDGhU*%rp8 z`T!89Sh6ByLO{rbC_7O%<%Pw?MN?gal^z0XXZH2W0The4^kJ)X#9y&cIFzFTAkEE4 z)7k2@2}yD?GUuQs%^Z=Sh#8R~?l}sNMox=ZXU(S}gPWygPVU@TSy!FVOl{e74lPZ7 zEiv~TxMw5G8p6Y#NwaI|Qj{+%SIy!gy$S6$P2ydp04QQM+p-?neSVGhA#DvgCqMdU zv~oPjF1dC6ip*O*h#t!Q#-X(<;R8TGKtMo1K%kPL_u6l!1TgavU_{Vu1t=G+ z`~@f#P;UIpX9C7E$8_LGXFVs$(Ln~1ltfSmSIx+pPtQ@uUk0A%wLvXC8WxLJNrawHVG=R7Qadf&;My3u1lyFOi_^40QhRNhu) zKs~`LMeG_dypA*mS)Desa-3t=pesu!Cl`F3dSGng@8Jk3Sl#o_I1SS1X64_)oX8Eb ze4S+VKA7iSsMq{O9jPq@&H0Fv0pX@Hbk-samC*(69lDu3?YD@UFB?s!oq6&y%ECz; z@tm2)xW z<>c;b^{BPMAd8#6+qAZeh)%xdxISBE;TOzyj^Jd{!O6;k@BttoARr(hAW+HB6MyZu z{#>Y1fR9rj#>&i}f=;a5z-p@i#X`}rZQy6j%$!xR>j_3iH3C$}&BoKgXNV1CTlLSe zFmzDtFJNHrV1sKq|J89GvL6u;U1od7y0KBXJ@Y6Qw(g1yTJSsMCT?3PV@C%-mmX2h-s+wZWD=HV1J zZ`T9|A2+K{iBk@2r+n%2rR`kMZShi?;-Pln=JouaA&@qrg^zAk#oJ@hxy8|09a1q zz3=%b`LR8F6lc;hW@ja&(iy;B3zypsx6=WE-Hjz87xR(?IYqaGw!=x~!sQfOxb0$O z!kTZ^yuYt({+>-VTapmCe} z1?q>OlPLfs&IiJ}6r>fP09eM^P+L|tqHO)wQ%($_&bw9#>p61{(_KwsWVt(s)0iF# z;_jY_HFv6RKaKA_8HQ6ZxLt-cq9HHZhu40SPERc$>~j_r$9V7nKG`%!`WCk+Qh`nR zhS|`De_4#8sbX~4*N~k23xvm>M0IsF_U+pTd-dD!{tvtvCgj@6++R=p3soZ6^2A+9 z>;5+r83X8B6%3;k1;d-#3nkWECdNw?{s-U1X*Phy=LaOB*OCFqU%Fj z%6Q-$;uDLgg?)H;OrNT5`rDIrL{VU4G!u%yc51w4cayuB-mO8I(SOMMePpZqHB z{^LPROibYKK0ScDm2a96d#kfX(2dshoB08-nJ5ADWZz6lV3ikv@<3V?!McgGvslM_ zG<*q`ifj~{VgA3BzIeJRb=9#jGl6_5P zsS;>x8|$6U49zj61od;!W946iy@Sl;!_Azv_Ay7B>9SS;EdS_>@SnJdM`Q0s-M;L# zebt+n-rBu|GwLAeZ7vsTb7OKlJi$Jk?&!{4%On#B2Rym`i9Nx7NZf!wBh&kC_1+#& zKVq>F1Oh{lGr0hWgaf(fLn8^iAigbSI-pMCWcwKQymu0jF3&1cT4z%Lb7$IcBb6dl zjs#655DbJ6iS)xw>a{T#QLmfVcLr1BdZ0hPYH*&6^^#|!Vw6(0!^c^4_e<~$oO!IcBl~YSOx@hw;+h(&DyOz+`BF0EuD|-6anfCt{C%wC-R&B z^YUxdMjA?3?jBZ-sx<&D7wX`RInL}s@lGt)Q;*vPt1?!tJ4&p~(EO25M|#d89C>aA zH2()FxP4!+pl5}Ho`W(J6ei}1ly*Sbq z%MRcPVGP!JF)-o6`1CYB)f7c*>v2p>%rZhJBV1F5&VdU!Gc}FrXg`LJdvQxBE(kzb z4yYwOLC*hgkI!(Ow!15em!m<{s-LSA#wLc*+1U$MM;jcqwWO8GIHA^eGF#t7UTA&) zl3L%?j{q>y8-|o?+9||Z`|+&$tUy`H#FZ;}hMXVp8GMf%9z>-m0!_7QUvU@hD=uXF ziYeAt+!=^v>%QqkmMt`QqlJVQb^rn!#bqh3n*7&t!sMtsN;@ZHD&+&SuNFs}kK#4^ zuHnbe$(W6g;*%E*Nwyhr=gGc4Y@x(F-xh(2!Fi|7_IK+^IU9f`N?>-Z&8`LYiUu~Q z@79qv?e`&rfpSGFS=ek{xsWo+gv55heC_=jr-I!6=Vo%^;I?|y*X6K9c?H>4fQ1rY zKZ^4ipjiwg3Y6b&0|kP=#C77)ZxP3}3Au#zSZ>hd;G}-*QEnHJQVy3R$XX0|P~aAu zn+WZ__8ZinmC}Ij_z`1@qMV#v5%Rl`NvGjx=)m0U5E|4$Rukr4n81-ovtR#(SU)C6 z`02}0cql9M%%Ub$gZsy_j=mP+BcQRy7Ut2Sc3mF)^i~D0@*cx%Sjj#kPh6^W=gAKdbLWQpX2KeLqR+yV=(TYONEU zmC@vLsx!vDXBhDgGQwfB{ggIf)rhR#)L7Cv*nr&-#iKXL5 z)|8b8y+6nl24G?7?Cx1EAAU9fmN-R%niq~p8Rkc)e1MKTHSpIdeI$s`XoiZoENRXfHpMFUrjTY}s>mbC4nx>$kveIMWfRLuy&9-aP>e9o~>9csf zQFf+|@cQzUgP+M|F{a$~U1RwiCo=hsFnL^HY3#?!@&S5oq4LIUm#FvXZX}m!6Xn_{ ztJfjs7r@O3pP31K!S%>lJ@CX+D?hCqWL_b+o;F`>+hR^3wLW5jmG=u=A2F<-rC(2* z=h92Fe#j4tT_%btFBZ0e%ZtpFR|BUg)5=eCemTa%QTdu-@pg0Zd)QWw`*q78f(DAU za#jFT!}su6_}E{|3!lTA{hvYfn`dyidJD5*ccQ&NiuS$;WH||GHjbgrUi7rqM=_L?FdH4f1nGkIyi-xX@)`17Z2e_d9BtQyjW+J?!5xBoa1HJRcekLy zo#5`l-GaMAI>j%`Rb9C3Jwbne=od14#!z=JoIE0l7%9lHl zzZ$UUjh5s6-@G+25lj2XdGrTtjt(1|mcfW(=HgZAoQw;}(Xh~DE5r8qJwU;pRtj?Q zJHU#o3}oSsMdARpIiD-i%@U4u?e}AcQ-GNq&V0J*#*KQ&caUL?b7zE^w>=S~Ss1do z*ZDAVjr4*CeX1P_=Yjq8^a}oj!O-i3_UX{FZxG!}3*Ct_EFco*WI2p2^Q0x64&AMf z8Ib*R$&h1Sv&E1DU*fhXaW^>@KY$+f&S2{Vc!fzxqeFBDlI$AgCd}e78LZS>FNseK z#(l_=l%>*t5rDW$I~XRLzSUY)9WSKREbgP*Ue0%1cj?Er5wX(Y@9{eO+N{EV#$g z^8TV4fKAzX~}3PQIypqY4>*dyLkfftW=#*Jj` zXm>e)$pcC*M~uMpEcQBiLFDsH6b_y695XDj!$Ab9_Nc7qJxEkM`%CKMZdc+T+;HjX zcZT}H`6a|cej-&&9=CPi-yl71>VL8j3f6)W|Ncnr)Dl?#slW`d&*Vy`l{bUBmKy<$ z>LST`&nO0+86;i#o{cDN;ifti3?PR1+|OznWxL>}TOfab2{EFoC|$T2={3wN2tbQ7 z+3YX+ppZPNwj7tz*MF!gv~#r&MXoNLtZA{Ub3R)wc<{!wt%_UHH=r@TeYaaJVO+~7 zA*z~ZVErlyp{&3B``J>bnR`|q5euu!5f%+x zG)r;9zNY`)Q|xd~)PrcXHx-+Zj53g$`(9)i8U-G@A(*uyPBzb9;`cZuY^{0Nd)Vyv z@<$I#KwydXlPkw9lC#@H{ZBsVi6wXbGEj&7>H6$G?c6Mq18ZJr_Cu>gTPg?GoqLCq z_tC5Wisidw8Wuu2^L0Ahi>vORT> zIKS^erV~SifgXeU$?e}N4HIAyLiWZALM6ywQgA^))z_Hqmp?UK@4Vmg+6t+UB&(Mb zSQ>Fi`D-5)_}L$x{;}QGB8J?7$82awqX`z?7y4VC{gLSPX3^m9%pT#w7a~CwJe1?9 zmm5)G@FyE+FLrq7^cYAsm3TD#>f7r6jh{QOq5J*=J!AB}g)<~xdW}WX914@j zgum9ANVSlGO~L9}KP2qUAbP5qN+l#AIF#5%LyBEL1}*-BCdAA{I;HJUN~u!yM+%3*eP~PB zy3I$66d2+rZoc)ci}rds?#;b0j~hwVaAYgQezCM?t#fN4H2?+2X1kw%eU5(<6P<3f z$L8KsO+<$1_74l*wY(YS5+fu|n1!30vs|{K`fwuQEcx>txdwf+3e+|)8owFkdM+8@j<`&o%-nozFl!$LRX6zv%@ zU^Pz7$w<7u&hWDK>f7~1%=!gG3N45$u!V(1vlPgh%rt7tL46|`zYc*8<%{n`jb%ymPAQ=F+ zIFOcCR2ciOdtZO>Y$bMVt*kte)nk3}HoAlgpgmptwhzl+-LPlwrYF7>A0^D*e#_-% zwNvwJ80C`A45^o?f9)dnHW5s=RV1BBU+v zMFZ_>au=P>vM+Jeu2lVJm-eFjSBxQ15aZz=%n8#@k>U{vnxlbfRLX>r^(kvZ@ypfE z5)E^O(Tv@iCg}mOD$~~E&^ix`l)l1~dJ z*x)jN$P+Bo1YDi`a)u2-p6_ zClCHF_aBHiEC?el)VZ6HJta}gRvLyN^sCT#0f_&ue87rb5VIu!=_ml`$ltjTW+qM; zI&^d;(!+!(1%UkmNO|kvpE9Z+W*8Iye9k=96?s3xkPc(fyW8S?!?PMkCpwy)d&~d3 zSK!5~k^MbpKxvMbtk2tjY9%*Bqi~HG)|RSY+|N*d{M5;EYyCfPRYdpxsUN;}D-&PU zlu2@qo^Iy-ZY|$c)YZ*Bmi)kXrNWbg!_R>2R6rW<-n^gfA^2{h2E5Dyk!SHiP^k}_ z#{@Cc*BzZg4eVeIYNwtFS&kF{*@0;?SsxIOpyF0wKZe!` z89@2+Z1E9eaeQy_67ubwV+}zhH#Y48@4q1$om{vb0OtR01MP-bi476*^L`lX@hcXl zVMw13YFe=&t`SL1)0Sf0prN^#W}H1aLr2NxuX~Z{I|r4okRf7E|38#(g;bE9Oa?dny*Gy8eH3=h z?_?1{CHeHCR$nlakkC?~9y-V%6>rVRE&cvzrWYq!*s&U4efS7Q&vnM{1w28+pTon5 z+??lbzxQt$`3uJ7l6-Ioc$UB{7F_=C^w3L~PbPhvwaU2o&uF!XrVPsD%8HK1Q(n^1 zTG{^w*;6beq6z{N8q?XUhA)zFD4m66!p|TK5=3OawzRy+NLCW_c?Mm+&^zCq?1D_E zX|;TbD26%PNK9Qhhb~my5&_BZjprC3srT$dvPL_+8Qf1LcDNFAS^3O$Y$YKEq( z-;u{({XEAA74i)98^ZFeZ{Puy@--3g={WQeGC9B{n5F0idd zRAtLIdo_&0`c;rh)fz1W*%KFjV5*MA(zG<3-#qkzUzmZ9{iLRGdt4qHXMQ+5)}$}C znoj1|M-@cShvX}FdMUKge!jp0@6GW2b;dq?ZItB2=x&mquvkQO#Ydinj>#kE7F)#8 zl{DW}&sYl2Wf-$S7B=G!0(BrK*y@GltM8qh zc(wH;&b0Dt_0PmTf&{pXE4U;bon3;57px@>UYrxZBjwKJ8FgOZs3sQ zX+#$Psfv`DiINd~{a>3v_JsMXUa!t7w!jyoeg~K0{K4mzzGH9rT{tW;t{a42G(sf50BI>mwKk>8~^ zlj&>rovLMD&j`InE)+>elWFDqH{qohSIK#X4THiL0?4)GIOs>GY!7o8(93>aX6ZK? zgR!&jBj0ds;Izu2=$s3f98;?AyvG-qA06w_9_e7ceOJq3570F8Nb3`sV=!oK%r1CG zJpTeCa!8Bkl#@kj|LWTLz6=^%-})CI1-$u(TWl|-<`C~QTiBYct%8^prSP}AS{Q2> zF-%VUOZqSapP1v??Qq4%cwe#1FFOH_QhT_?3*3f~6xQ&|+Xtg*QlZ#!xkw#{$ok+D z4m)Wg;mC;2fz4{2a3b^uFh9H-QIX*l$5E|>nXz>QNtB0|4LT2v*VT&=wip~)?IbZC zrmsT}>-(yPLAKH%oZ)X!f07mdt?+da=^J3n_aXP%K$ocd_2l;Sefec-`!*LWK;r-A z6dmh_8;9c4W7Q#Dq3xa-+enDvS!f3Zv8NCD6ZYC>ugpgXZY);7xyTfV4=HL%OOL@Y zKtS|M#<$==clP|>o}c~B2X{=7tg!^yU8e))TmX}8~11=p)C{O5Q#C2O!rmM zNkb~2W7Tt_K;C4efhKnmoG0^z(@qDD4e6kl6;bO^X)ev;Ig%jW^Fp73283z6ze$%Z zr?(+@{z>tTX#!TNAzHSXJnoPT``_MpuFK%Ieh+(Z#yNDga-D2>X(IhqpUmP8ks8@D z4F>0?(*)tjlQGu`kyDyRyI7OLx2k*PdhSq61w-=w8q7(MQ2d@s=*eifIb(d;{{%_y79nBcy# ztHi0FP*;J`@$xcxTX#9CEBiJzI~g0nND(G{E0nY&&evhMZG_=PpYdzIRzV2Wqg6_L zWD4o2_c}AhKa|F%tHn-mP~;L6RH)9=8yKRp@Div^Zg2_EH@Vp)sGKiiT4{WNXIK~E zY=g=)*_;=I3$LljYu#44kc1Ln*`Pr^7sq+GPM_` zkn0W8dtctYw}d)xQfkcL9Cva_s4w;=OZr18Mp`zbx((QR9F8m{KB|%-WD`7BnXfGR zoym)06KHG><C3HC{`l89^-=YuY z!a^SBU!#3yuQnKcM&)1I+)0_XH#W`%t)E~ts_i8MPPSZ{y<^j}k1B@KA#bH{P?9DF zfM)dt-gvTkaBbb$m6fGPS6W+r37ct(qdP~^H3U<*SBfMhMKhHE%=WtkDPs%<2~;h< zFQNGP%Zvn81jV;>b`x_uXZd*#3}kuvmA-%<%gvzBY$)T#<`iAbWf1kT)_P&nT$2K6k5hZtuQ$S7%k~WhftX^0`tl{|g_aibvwI`jp zf|=t$aT($k7}z|W_si}T??TN;ob2L>#DPU@9_d)|afid#d`PUqFv?rku%bDU)DP4V z59ABQIp94cw_oN_h6C^xXh|05S59B3cL#crq53v0NI=AuNJ(yB#X9 zXSbK>@OEZ%5@$#b^*2UGY{K~%IJCR7w%t+5mg(6Fp&f(~r3_boJ&zlDf)#rx0|sg&mnjav3#<_yn?SmHl`>&~!*4?9q9We!PlcLr7P|V;%s*dv9KULtVX4ZeP1{ z_C_xALz`0#_PGWV-8YG_uhpzkDKJm;)l|b>83ooB@rgA~<=hm8@UqrpobDq)Cww^> zp!P?H=tgpG#KJ0?me-3dNLR%2wm|5u5PjA9!)Y;RP4wBasx^o^R&Y!zr0Eh3Ct&E; z2>C&XL*PB*^ytyV@=uv9U_=m|(e4*O%v1TrF@JoS#YG(Oa~Z-j0wL{v1VS`o)#rSN zf~75le=aMagZ1L_GRC#5u0)nk3OsX=m0?Wq%1>&`AB91F$v#cOV>cWigquHgoeane zs^~A3A>QFL6sC;ke#(bTQUp!CH7%b zlL1=!9gJ)Fu-+)WzaQ|3Z_$q^Lmzdiw+Vf78kJ=)wl%8hsWGIV=(&YX=_`)aCTu(- z1R~WDnsR)r-6rLKS8e#^Ow=O#%R=cyRq8U!T)4?A8T^4r_L)O-wfwF8!~V(Pld zlV1g&V)|dN-+9Gv4B($N5XnBn`#xZ!Q&G|et^0LsA&dJ$Y_xvm4Z+7B7XPcEWMB9i za2g)wS`_jX)vSaQ|1g4VT`>l87@cw^CX1jI<9WHWG>EqDpPNn3n(Ic;%M~()TileE zZn`fXWP^L@)SVRpOnM)cF$NrUse#6jwWO8Y$uU!(w3kfwu#+MsoaZ1!gHQYoJ>B18 zsfe3|X0oMDQ$f$5leEPhnPjV@Xa$`)^4f8gB{_gS5aDUb()%iIT0jaGj)g+V2XcCk zr1PY?N)@oO^N`y!&f!$VPCs$?wH4&CG_iH^kW}-;O2rF9&mPoO+SRJ=dx-hK8QnL` z3+4Fo+XIf5rK}&CnnwqqOYn1^@u^NE2W6*vE#*$|!Z=p`iB)ht%tatF|AQ6Mp72ZD zbpMbOn@!@yj)1^AG4l_Mo6^76<2G*!K5v0oDIEGLLY1f&?<#b1a$2pdVWYG2Rzm__ zI%l(lsRz1?+hun4bbSbuFxkd-*xFN$JaGrppH39X5+NQoDdB3Qj}REQaArrK+SOd(s!-q z10cV7*eMUiM-b`uswLKwG}4Sam~?NB>+)l_duP@%a0{7u@S`uIV3Iy}|M&;YtggDrV*hWdt>wym;D*=8l#CgPUTXM6wZ!Z~BIv@`;Uj zcKJao_3qj!=Yx19Al3h4!}$D4F%ttcqB*sO%ri;ItCKF?sfyv+w%~NSy+n_PsLCDx zHq$)cKFTg{c|lm$Msw@31gwsKpdhOyrn5x~$ON7D89hRJZT?~*(Wp`O2cYdWGfjwB zjh8;)L{fTW)*MnP`V0D>ZYV<>tp*x2ic2!1dSSx0?R)axwV z?k<$*Il;7>k!WMKQsfNXY7G8_cDX+&kNw$3s7&D>sAowL`mI~~WhTL+JG5rc5(>mZ z+|-48e+zUxu;ua9o&9X>y~mrl635ib6OcW+rOk|tT{mvktLR#)fg%dCXPq9f8&As~ ztf^`jtIC?_?yC))y`bsXAiaGK3sa;)zH7@zjhHzOhf7F4TU!8S%s)6bU$j==i6%6GI z`FtQXjU}`NZIY(GnL$D`L>#~Li2m~E6K9A9mozTerWvc9{$H{T5eKUYN50nht8}Cj zUVGRz%5&Hf6F#4|DX7jMnFH$S#7`OEbJq`GKeW;94SNgH8Hx&a{pa)Re#tU_DP$f+ z~;F6uUOm?Y$`jS`98;B);Rw%-qB z@!d`#;owylbP_2y0PP^`!V^6%rpmp*JtYhaE^@G%yGL5nc3?#2bsWmALOprD8Wa%SmTxb&Ln(q^WJ8!!gcDJ9-x9jWZweehI_w4wS9YRDGO%+5$}M9C`+1A_xuL~vIAZnCt>{b^nx55J>w0Da#|xu z>ytIMgt}Z;>3Nys-nbv0Jih#$ZUH%#JM2Gfep;!=zcCE^j?9PoHDlF-P--R{h)!@i z-S15nzH-hu^y>SKJBwJ{><5e}cY+*Vl60w>w1k+|dHQfndTUv#BXf%0n|n=Uu3sa4e@X@xi$k?8Ma)8Fwo@vnL9+GmC@dJ~nI$qn6x`V@)s66gX#ab2ZQyw7Z3 zvUL^%6X!Y1%taKd{{)^HPL2gMAHF@lO0u$yOG}7fJ$$WY3sIps?{~WK+?+q`_e(z% zOc10Z_>?3zMQ?oXs_iGJ%o8QWT)#Yj?tY<$`6?JdYwSfNz!%K^^@>Ig+4&w=E>KuG5*6^ zDG2Q|t+AT@diyzpvb#8E>v?8t+tB~X)JN%s)~9xF@9#?-so0*V0@T$nMn8qXGh)Sa zCT1^P2>)B#7bF$L<9_V&@D+uP(jv+bN$5#gNP4G2Ak6VOefQKBBXNuNm-dUt#w*37 zC!&`(hrSLFi|Chw^7Dk%FaG7w%FD06{7aj+tez|ha?k2qv& zBoT~sS7>wkUE5Z^-t{%m@#WKSy*-xMK@gSbTX+Xt;PtFMdjWpXL~~$8$mU3^+dz*h9g9VCe(|AKR@VOpOr zN0${9yE5n^xXK$FPh6pmPp5dQe(`UUMuVzp#X(TLyGEF+JZ!8jJ1ew+Q2C{Lpxh7G zbLKmRoT2*&lGd|RM|W>N2Flciuc66V8?%Q85sIALbDiFcdpy4p%(Q@8&l84yYKCF$ zUMwHg`B3vnl-kcmV{qhOC4V5bvT+1FJhyDHu;uN3kLfntgvAsi`LK zDi`y08DJN6dsGA#YuU+p@pW58PLej54w3Au<8U^l;_|UV}C=Tv| zv+Nw@L6~{krQ598Wi05lynXU)1G{Kn=o8cW$VL*LevkduWUn;`G?Hx4IG-9lf2Bdm zV3ECJaZ2@0Lw3&;z%oOu&_X!dFdTUJ1j@0wzpt)2%zdu(jz3U(d?wkgvC85a(j-wI ztX0}=UO7YVBw)Y1K=DrbRd*vg#QA;EEH;Yuz#(*~yGE*fNy{9EE`zhPSZZZvH&R!3 z(YMoTZtR>DJZTYe3z7fX=@YYd#Au!CKuCM>%g?fLS~WSlN3kl?oN>O%Z*lRI8Su=? z(^8KjVrseSV7~-0gNEz|!)6 zuC~ujm3i$nY*Y%=hZ1{R?p~OVJU{AihZ^$pY}%6Kc$<0GFuFvpEnouR^PX(O&r_}U zG57KM6h8i_dCzF$pp-R`{Nwo>&lLJwzMM^Blx?CN3%vds)BX#2jt58mzPW4&nVix( z_q6TyMQ&&*$+i-EL54+9G-jnF<*f^pRA}4d!S20t_p^Jh#rl(V!?*$Eu#2AFnmzQ! zz79|66Wx6xM1)+$0_)oEY58=gLrxXwHtSBZl^dT!f2 zDX+V$5@p6GhMl@>09&h*T~^KPD)wFROEPcXZD7xu>hF+Ti~ZbG{=wx1zIF0rhw&NP84{L>Z3Y<4BrBs;}4`R zJ(kZav~{jHwLQ2%5aB$zovjv-*YM$8yF^baj}2IJ%BF`f7_vbE*gg2KZdVe&orC2V zne7g9TUeFlv5|F!j~gNczke=v@~P}bOwge z8Gg!dfg7vfGyng|XibNe?#y9Ei5BK#h-KHON4enFI{Uz|QQG_AvMf62#3IW2A2 zt9nI*yyKB>Rn&b$y8kq^v=E5JJU1P?VY=Fex&t`?DyfiObBHJtAeM-iqDYJ^?Dl9H zDIHx4hAoO|O!3Zj9nAnDpvmCPSmY_NY3lXKTVo15;fA)IjbI~(P@aZqv~2fGOGc)Q zv7h@w7>;n$-9hdKfsS4qkjC^Mx=shKZXa=!+;Qmfa0h&7ufq`9#@;>YvS$0b8pjhcfyx6Kq}wYLG1t;~XX~#DANDu!qXZnAGIT z54eEOHF~IF!Y?x-aqDrWUOV4aZ2!N@K(%CV7SO~rkq~L|u9<;i0iP0`5%7PyS2MP` z9Yh|ZaM0_eudv@ie{SEh-zzIn@O=37owOJ4khIrMH!C$dYoL;f{JTE*o6To}7<8%l z)6~`^9ZUKMnamAj7$Nh~sesv>jI>P8#{L?v!%aH2jIg;>(t4X3bzriu>OEpJBtMY^ zO_pMq6&dMU5$CG+T7=?4z1u|0o=3M<-KUS1;mvXc*gUXSLi|8-SF6=^@H!& zh&?^ExtH(v`OHsmq-ro znG)e`7{+2BCBLGg^x?XQ&pLUkJ4(0EWVhcjv;+CY?MA+pxFykF&~ggHQ>$+dQxKPp zhb#OHOVGoYwfqu?hOG7=e(&qEFq@D!|w1-dp&L|1H>F|952dln@_SixQ5S^nI z89vO|sRjGLzdAMmCXoI8s5{)y>lk#^RO1Wr4tgOVv3Z8iSuekvZ#X7M3$wf;5)+CQ zShqT z(Sr8(IgdH-`_vT_w}&|XAG!i5>Gzb2NezYBKVhwz7@mV72zj{&%lr=<&Lmpl<|5kL zpSz%rzq+%3MzIDGqv}jI0%P_+p#>xNymNPm+I&LrqC3AmO?R9t+IC^?yRXk{TbR?j zU8VzEyiBo3Oy@AjTFZNWNA$Z{T&WC;|j&jVJ3(;MTLfLbDEmVL9nBZE}=H?FefibjLBR}5#c#{I{})4+sm zmmC(){ z%Y9Rx9E9If7f9^o6rbd!ndnSImI_AEgBHn*=CHUMN#_WZPkb_ zDer~lbJCbgN0W;4Oz#*(;ubnDTH>!gidm>IW;f?B zxzYDYqJrqUY2Twx115uDZcfT0l~q@>SE*hNOM% z?#tDN&(^Fh7%`6#2g38xmfiSA4V!9>{iv+P8~nG1YZrl!8ho45p?8Q0b6_~7<%C*w zeqqdx8z(9u{oKUu{rfwj!SLKYVa!i!R`VtzHvvD0po{9Cz(3vL{3QBgv3_ zsfAaIbH|nl9M!!b!_92mS}sMNO_?dvBitD(6s<7{tb_;zPBPK4>hu(SF8U7l7*RS% z7}+^n>d?3yKMJM%QK96G(u1|ft5^4}DA46bMfJV^y@Ktr@CWq`&)@nkyly8CVW6-k zXBp4$1P)7K&@+<6u372{Zd4?mRiU=YR#i?M41j>=kh%egTYh877 zsqxz$l06CRZMrz9QJ8{oHSkKcR^j2{lOe{u5JWa~x4r|D`=7J~BFsC({h!CdaKeLv zj`j(7A|ZRiOFL%g*7$>hS&y!zEa4U<0@5-Kr_pkh?pyOLJH_O}5t#zsuXH|=(}>TE z!mQ@X`Rv9TH5%-NRd}TwV>v@OVZYsmjmMMeVIGkcD{N=*@bDIcK5|HY9*T|rog3BN zsGCwhIV8+CD50#9Jdy=IkkSO*WH1hnNZY*Stl?br>VI&buW>P@W9N|38orA*olma4 z)a&@)`N6w8nIEBKp&Rr=%Zh!JzW82+V!~(fhKY7Jyw$gYP{Iw{gDrCvwkeqqU)I3z zsnt%8cwiJu=9R0=4TaM?o4{O0LC(ABnCg?EdL}2;XRbz$lP;!0cYYUsK_p?EH|cEy|c^nwa4KfAka`WXr!8@TaQm z^dLdF`R~fD6U>45Vv6RlfgA8}F7mEA7SLs8mgTt4ik@mLk8n}px32<~Iz|l>7d&?GvTL%e ze7kApOV{b2y⪙P{yu!sByulR~7t;A(Ag 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 SF4+zM@K{+}sZ0SJ`u_l!Lg9`8 literal 0 HcmV?d00001 diff --git a/site/img/webconsole.png b/site/img/webconsole.png new file mode 100644 index 0000000000000000000000000000000000000000..610ad9bef6febbed85eddbcf5146c9ae14d5206b GIT binary patch literal 35675 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 E0H&Thi~s-t literal 0 HcmV?d00001 diff --git a/site/index.html b/site/index.html new file mode 100644 index 00000000..5b235412 --- /dev/null +++ b/site/index.html @@ -0,0 +1,129 @@ + + + + + Sheetsee.js + + + + + + + + + + + +

    +

    sheetseeimg

    +

    Sheetsee.js

    +

    Sheetsee.js is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts.

    +

    Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

    +

    Modules

    +

    Each of sheetsee.js's features are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ModuleContainsDocs
    sheetsee-coreIncluded in any build. Gets you started and has the working-with-your-data functions.Doc
    sheetsee-tablesContains everything you'll need to create a table including sortable columns, pagination and search.Doc
    sheetsee-mapsFor making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js.Doc
    sheetsee-chartsIncludes 3 basic d3 charts: bar, line and pie. You can also use your own.Doc
    +

    Making Things

    +

    What can you make with Sheetsee.js? Lost of things, here are some examples:

    + +

    List your sheetsee project here: file an issue or pull request.

    +

    Demos

    +

    Demos pages for the documentation.

    + +

    Documentation

    +

    More resources on using Sheetsee.js:

    +

    Getting Started

    + +

    Ideas

    + +

    Use

    + + + + +
    + + + diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js new file mode 100644 index 00000000..72f45e90 --- /dev/null +++ b/site/js/sheetsee.js @@ -0,0 +1,25349 @@ +;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreateCallback = require('lodash._basecreatecallback'), + keys = require('lodash.keys'), + objectTypes = require('lodash._objecttypes'); + +/** + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources will overwrite property assignments of previous + * sources. If a callback is provided it will be executed to produce the + * assigned values. The callback is bound to `thisArg` and invoked with two + * arguments; (objectValue, sourceValue). + * + * @static + * @memberOf _ + * @type Function + * @alias extend + * @category Objects + * @param {Object} object The destination object. + * @param {...Object} [source] The source objects. + * @param {Function} [callback] The function to customize assigning values. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns the destination object. + * @example + * + * _.assign({ 'name': 'moe' }, { 'age': 40 }); + * // => { 'name': 'moe', 'age': 40 } + * + * var defaults = _.partialRight(_.assign, function(a, b) { + * return typeof a == 'undefined' ? b : a; + * }); + * + * var food = { 'name': 'apple' }; + * defaults(food, { 'name': 'banana', 'type': 'fruit' }); + * // => { 'name': 'apple', 'type': 'fruit' } + */ +var assign = function(object, source, guard) { + var index, iterable = object, result = iterable; + if (!iterable) return result; + var args = arguments, + argsIndex = 0, + argsLength = typeof guard == 'number' ? 2 : args.length; + if (argsLength > 3 && typeof args[argsLength - 2] == 'function') { + var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2); + } else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') { + callback = args[--argsLength]; + } + while (++argsIndex < argsLength) { + iterable = args[argsIndex]; + if (iterable && objectTypes[typeof iterable]) { + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]; + } + } + } + return result +}; + +module.exports = assign; + +},{"lodash._basecreatecallback":3,"lodash._objecttypes":22,"lodash.keys":23}],3:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var bind = require('lodash.bind'), + identity = require('lodash.identity'), + setBindData = require('lodash._setbinddata'), + support = require('lodash.support'); + +/** Used to detected named functions */ +var reFuncName = /^function[ \n\r\t]+\w/; + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** Native method shortcuts */ +var fnToString = Function.prototype.toString; + +/** + * The base implementation of `_.createCallback` without support for creating + * "_.pluck" or "_.where" style callbacks. + * + * @private + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + */ +function baseCreateCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + // exit early if there is no `thisArg` + if (typeof thisArg == 'undefined') { + return func; + } + var bindData = func.__bindData__ || (support.funcNames && !func.name); + if (typeof bindData == 'undefined') { + var source = reThis && fnToString.call(func); + if (!support.funcNames && source && !reFuncName.test(source)) { + bindData = true; + } + if (support.funcNames || !bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = !support.funcDecomp || reThis.test(source); + setBindData(func, bindData); + } + } + // exit early if there are no `this` references or `func` is bound + if (bindData !== true && (bindData && bindData[1] & 1)) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 2: return function(a, b) { + return func.call(thisArg, a, b); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return bind(func, thisArg); +} + +module.exports = baseCreateCallback; + +},{"lodash._setbinddata":4,"lodash.bind":12,"lodash.identity":19,"lodash.support":20}],4:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var getObject = require('lodash._getobject'), + noop = require('lodash._noop'), + reNative = require('lodash._renative'), + releaseObject = require('lodash._releaseobject'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +var defineProperty = (function() { + try { + var o = {}, + func = reNative.test(func = Object.defineProperty) && func, + result = func(o, o, o) && func; + } catch(e) { } + return result; +}()); + +/** + * Sets `this` binding data on a given function. + * + * @private + * @param {Function} func The function to set data on. + * @param {*} value The value to set. + */ +var setBindData = !defineProperty ? noop : function(func, value) { + var descriptor = getObject(); + descriptor.value = value; + defineProperty(func, '__bindData__', descriptor); + releaseObject(descriptor); +}; + +module.exports = setBindData; + +},{"lodash._getobject":5,"lodash._noop":7,"lodash._releaseobject":8,"lodash._renative":11}],5:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectPool = require('lodash._objectpool'); + +/** + * Gets an object from the object pool or creates a new one if the pool is empty. + * + * @private + * @returns {Object} The object from the pool. + */ +function getObject() { + return objectPool.pop() || { + 'array': null, + 'cache': null, + 'configurable': false, + 'criteria': null, + 'enumerable': false, + 'false': false, + 'index': 0, + 'leading': false, + 'maxWait': 0, + 'null': false, + 'number': null, + 'object': null, + 'push': null, + 'string': null, + 'trailing': false, + 'true': false, + 'undefined': false, + 'value': null, + 'writable': false + }; +} + +module.exports = getObject; + +},{"lodash._objectpool":6}],6:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to pool arrays and objects used internally */ +var objectPool = []; + +module.exports = objectPool; + +},{}],7:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A no-operation function. + * + * @private + */ +function noop() { + // no operation performed +} + +module.exports = noop; + +},{}],8:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var maxPoolSize = require('lodash._maxpoolsize'), + objectPool = require('lodash._objectpool'); + +/** + * Releases the given object back to the object pool. + * + * @private + * @param {Object} [object] The object to release. + */ +function releaseObject(object) { + var cache = object.cache; + if (cache) { + releaseObject(cache); + } + object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null; + if (objectPool.length < maxPoolSize) { + objectPool.push(object); + } +} + +module.exports = releaseObject; + +},{"lodash._maxpoolsize":9,"lodash._objectpool":10}],9:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used as the max size of the `arrayPool` and `objectPool` */ +var maxPoolSize = 40; + +module.exports = maxPoolSize; + +},{}],10:[function(require,module,exports){ +module.exports=require(6) +},{}],11:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Used to detect if a method is native */ +var reNative = RegExp('^' + + String(objectProto.valueOf) + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + .replace(/valueOf|for [^\]]+/g, '.+?') + '$' +); + +module.exports = reNative; + +},{}],12:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var createBound = require('lodash._createbound'), + reNative = require('lodash._renative'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeSlice = arrayRef.slice; + +/** + * Creates a function that, when called, invokes `func` with the `this` + * binding of `thisArg` and prepends any additional `bind` arguments to those + * provided to the bound function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var func = function(greeting) { + * return greeting + ' ' + this.name; + * }; + * + * func = _.bind(func, { 'name': 'moe' }, 'hi'); + * func(); + * // => 'hi moe' + */ +function bind(func, thisArg) { + return arguments.length > 2 + ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg) + : createBound(func, 1, null, null, thisArg); +} + +module.exports = bind; + +},{"lodash._createbound":13,"lodash._renative":18}],13:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var createObject = require('lodash._createobject'), + isFunction = require('lodash.isfunction'), + isObject = require('lodash.isobject'), + reNative = require('lodash._renative'), + setBindData = require('lodash._setbinddata'), + support = require('lodash.support'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var push = arrayRef.push, + toString = objectProto.toString, + unshift = arrayRef.unshift; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, + nativeSlice = arrayRef.slice; + +/** + * Creates a function that, when called, either curries or invokes `func` + * with an optional `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of method flags to compose. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` + * 8 - `_.curry` (bound) + * 16 - `_.partial` + * 32 - `_.partialRight` + * @param {Array} [partialArgs] An array of arguments to prepend to those + * provided to the new function. + * @param {Array} [partialRightArgs] An array of arguments to append to those + * provided to the new function. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new bound function. + */ +function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + isPartial = bitmask & 16, + isPartialRight = bitmask & 32, + key = func; + + if (!isBindKey && !isFunction(func)) { + throw new TypeError; + } + if (isPartial && !partialArgs.length) { + bitmask &= ~16; + isPartial = partialArgs = false; + } + if (isPartialRight && !partialRightArgs.length) { + bitmask &= ~32; + isPartialRight = partialRightArgs = false; + } + var bindData = func && func.__bindData__; + if (bindData) { + if (isBind && !(bindData[1] & 1)) { + bindData[4] = thisArg; + } + if (!isBind && bindData[1] & 1) { + bitmask |= 8; + } + if (isCurry && !(bindData[1] & 4)) { + bindData[5] = arity; + } + if (isPartial) { + push.apply(bindData[2] || (bindData[2] = []), partialArgs); + } + if (isPartialRight) { + push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + } + bindData[1] |= bitmask; + return createBound.apply(null, bindData); + } + // use `Function#bind` if it exists and is fast + // (in V8 `Function#bind` is slower except when partially applied) + if (isBind && !(isBindKey || isCurry || isPartialRight) && + (support.fastBind || (nativeBind && isPartial))) { + if (isPartial) { + var args = [thisArg]; + push.apply(args, partialArgs); + } + var bound = isPartial + ? nativeBind.apply(func, args) + : nativeBind.call(func, thisArg); + } + else { + bound = function() { + // `Function#bind` spec + // http://es5.github.io/#x15.3.4.5 + var args = arguments, + thisBinding = isBind ? thisArg : this; + + if (isCurry || isPartial || isPartialRight) { + args = nativeSlice.call(args); + if (isPartial) { + unshift.apply(args, partialArgs); + } + if (isPartialRight) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity); + } + } + if (isBindKey) { + func = thisBinding[key]; + } + if (this instanceof bound) { + // ensure `new bound` is an instance of `func` + thisBinding = createObject(func.prototype); + + // mimic the constructor's `return` behavior + // http://es5.github.io/#x13.2.2 + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisBinding, args); + }; + } + setBindData(bound, nativeSlice.call(arguments)); + return bound; +} + +module.exports = createBound; + +},{"lodash._createobject":14,"lodash._renative":18,"lodash._setbinddata":4,"lodash.isfunction":16,"lodash.isobject":17,"lodash.support":20}],14:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('lodash.isobject'), + noop = require('lodash._noop'), + reNative = require('lodash._renative'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate; + +/** + * Creates a new object with the specified `prototype`. + * + * @private + * @param {Object} prototype The prototype object. + * @returns {Object} Returns the new object. + */ +function createObject(prototype) { + return isObject(prototype) ? nativeCreate(prototype) : {}; +} + +module.exports = createObject; + +},{"lodash._noop":15,"lodash._renative":18,"lodash.isobject":17}],15:[function(require,module,exports){ +module.exports=require(7) +},{}],16:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * Checks if `value` is a function. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + */ +function isFunction(value) { + return typeof value == 'function'; +} + +module.exports = isFunction; + +},{}],17:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('lodash._objecttypes'); + +/** + * Checks if `value` is the language type of Object. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // check if the value is the ECMAScript language type of Object + // http://es5.github.io/#x8 + // and avoid a V8 bug + // http://code.google.com/p/v8/issues/detail?id=2291 + return !!(value && objectTypes[typeof value]); +} + +module.exports = isObject; + +},{"lodash._objecttypes":22}],18:[function(require,module,exports){ +module.exports=require(11) +},{}],19:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var moe = { 'name': 'moe' }; + * moe === _.identity(moe); + * // => true + */ +function identity(value) { + return value; +} + +module.exports = identity; + +},{}],20:[function(require,module,exports){ +var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var reNative = require('lodash._renative'); + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var toString = objectProto.toString; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind; + +/** Detect various environments */ +var isIeOpera = reNative.test(global.attachEvent), + isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); + +/** + * An object used to flag environments features. + * + * @static + * @memberOf _ + * @type Object + */ +var support = {}; + +/** + * Detect if `Function#bind` exists and is inferred to be fast (all but V8). + * + * @memberOf _.support + * @type boolean + */ +support.fastBind = nativeBind && !isV8; + +/** + * Detect if functions can be decompiled by `Function#toString` + * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). + * + * @memberOf _.support + * @type boolean + */ +support.funcDecomp = !reNative.test(global.WinRTError) && reThis.test(function() { return this; }); + +/** + * Detect if `Function#name` is supported (all but IE). + * + * @memberOf _.support + * @type boolean + */ +support.funcNames = typeof Function.name == 'string'; + +module.exports = support; + +},{"lodash._renative":21}],21:[function(require,module,exports){ +module.exports=require(11) +},{}],22:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to determine if values are of the language type Object */ +var objectTypes = { + 'boolean': false, + 'function': true, + 'object': true, + 'number': false, + 'string': false, + 'undefined': false +}; + +module.exports = objectTypes; + +},{}],23:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('lodash.isobject'), + reNative = require('lodash._renative'), + shimKeys = require('lodash._shimkeys'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys; + +/** + * Creates an array composed of the own enumerable property names of an object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + * @example + * + * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); + * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) + */ +var keys = !nativeKeys ? shimKeys : function(object) { + if (!isObject(object)) { + return []; + } + return nativeKeys(object); +}; + +module.exports = keys; + +},{"lodash._renative":24,"lodash._shimkeys":25,"lodash.isobject":26}],24:[function(require,module,exports){ +module.exports=require(11) +},{}],25:[function(require,module,exports){ +/** + * Lo-Dash 2.1.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('lodash._objecttypes'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A fallback implementation of `Object.keys` which produces an array of the + * given object's own enumerable property names. + * + * @private + * @type Function + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + */ +var shimKeys = function(object) { + var index, iterable = object, result = []; + if (!iterable) return result; + if (!(objectTypes[typeof object])) return result; + for (index in iterable) { + if (hasOwnProperty.call(iterable, index)) { + result.push(index); + } + } + return result +}; + +module.exports = shimKeys; + +},{"lodash._objecttypes":22}],26:[function(require,module,exports){ +module.exports=require(17) +},{"lodash._objecttypes":22}],27:[function(require,module,exports){ +var d3 = require('d3') + +module.exports.d3 = d3 + +// Bar Chart +// Adapted mostly from http://bl.ocks.org/mbostock/3885705 +// options = {units: "string", labels: "string", m: [60, 150, 30, 150], w: 800, h: 300, div: "#dogBar", xaxis: "cuddlability", hiColor: "#EE0097"} + +module.exports.d3BarChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + // m = [t0, r1, b2, l3] + var m = options.m, + w = options.w - m[1] - m[3], + h = options.h - (m[0] + m[2]) + var format = d3.format(",.0f") + + var x = d3.scale.linear().range([0, w]), + y = d3.scale.ordinal().rangeRoundBands([0, h], .1) + + var xAxis = d3.svg.axis().scale(x).orient("top").tickSize(-h).tickFormat(d3.format("1s")), + yAxis = d3.svg.axis().scale(y).orient("left").tickSize(0) + + var svg = d3.select(options.div).append("svg") + .attr("width", w + m[1] + m[3]) + .attr("height", h + m[0] + m[2]) + .append("g") + .attr("transform", "translate(" + m[3] + "," + m[0] + ")") + + x.domain([0, d3.max(data, function(d) { return d.units })]) // 0 to max of units + y.domain(data.map(function(d) { return d.labels })) // makes array of labels + + var mouseOver = function() { + var rect = d3.select(this) + var indexValue = rect.attr("index_value") + + var barSelector = "." + "rect-" + indexValue + var selectedBar = d3.selectAll(barSelector) + selectedBar.style("fill", options.hiColor) + + var valueSelector = "." + "value-" + indexValue + var selectedValue = d3.selectAll(valueSelector) + selectedValue.style("fill", options.hiColor) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.style("fill", options.hiColor) + } + + var mouseOut = function() { + var rect = d3.select(this) + var indexValue = rect.attr("index_value") + + var barSelector = "." + "rect-" + indexValue + var selectedBar = d3.selectAll(barSelector) + selectedBar.style("fill", function(d) { return d.hexcolor}) + + var valueSelector = "." + "value-" + indexValue + var selectedValue = d3.selectAll(valueSelector) + selectedValue.style("fill", "#333333") + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.style("fill", "#333") + } + + var bar = svg.selectAll("g.bar") + .data(data) + .enter().append("g") + .attr("class", "bar") + .attr("transform", function(d) { return "translate(0," + y(d.labels) + ")" }) + + bar.append("text") + .attr("x", function(d) { return x(d.units) }) + .attr("y", y.rangeBand() / 2) + .attr("dx", 12) + .attr("dy", ".35em") + .attr("text-anchor", "end") + .attr("index_value", function(d, i) { return "index-" + i }) + .text(function(d) { return format(d.units) }) + .attr("class", function(d, i) { return "value-" + "index-" + i }) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + + bar.append("text") + .attr("x", -5) + .attr("y", y.rangeBand() / 2) + .attr("dx", 0) + .attr("dy", ".35em") + .attr("text-anchor", "end") + .attr("index_value", function(d, i) { return "index-" + i }) + .text(function(d) { return d.labels }) + .attr("class", function(d, i) { return "value-" + "index-" + i }) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + + bar.append("rect") + .attr("width", function(d) { return x(d.units)}) + .attr("height", y.rangeBand()) + .attr("index_value", function(d, i) { return "index-" + i }) + .style("fill", function(d) { return d.hexcolor}) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) + .attr("class", function(d, i) { return "rect-" + "index-" + i }) + + svg.append("g") + .attr("class", "x axis") + .call(xAxis) + .append("text") + // .attr("transform", "rotate(-90)") + .attr("y", -20) + .attr("x", m[1]) + .attr("class", "xLabel") + .style("text-anchor", "end") + .text(function() { + if (options.xaxis) return options.xaxis + return + }) +} + +// Pie Chart +// pieOptions = {units: "string", labels: "string", m: [80, 80, 80, 80], w: 800, h: 400, div: "#dogPie", hiColor: "#E4EB29"} +module.exports.d3PieChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + + var width = options.w, + height = options.h, + radius = Math.min(width, height) / 2.3 + + var arc = d3.svg.arc() + .outerRadius(radius - 10) + .innerRadius(0) + + var arcOver = d3.svg.arc() + .outerRadius(radius + .1) + + var pie = d3.layout.pie() + .sort(null) + .value(function(d) { return d.units }) + + var svg = d3.select(options.div).append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", "translate(" + width / 3 + "," + height / 2 + ")") + + var data = data + + data.forEach(function(d) { + d.units = +d.units + }) + function mouseOver(d) { + d3.select(this).select("path").transition() + .duration(500) + .attr("d", arcOver) + var slice = d3.select(this) + var indexValue = slice.attr("index_value") + + var pathSelector = "." + "path-" + indexValue + var selectedPath = d3.selectAll(pathSelector) + selectedPath.style("fill", options.hiColor) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.transition() + .duration(150) + .style("font-size", "12px").style("font-weight", "bold").style("fill", options.hiColor) + selectedText.attr("class", function(d, i) { return "labels-" + indexValue + " bigg" }) + } + function mouseOut(d) { + d3.select(this).select("path").transition() + .duration(150) + .attr("d", arc) + var slice = d3.select(this) + var indexValue = slice.attr("index_value") + + var pathSelector = "." + "path-" + indexValue + var selectedPath = d3.selectAll(pathSelector) + selectedPath.style("fill", function(d) { return d.data.hexcolor }) + + var textSelector = "." + "labels-" + indexValue + var selectedText = d3.selectAll(textSelector) + selectedText.transition() + .duration(200) + .style("font-size", "10px").style("font-weight", "normal").style("fill", function(d) { return d.hexcolor }) + } + + var g = svg.selectAll(".arc") + .data(pie(data)) + .enter().append("g") + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "slice-" + "index-" + i + " slice arc" }) + .on("mouseover", mouseOver) + .on("mouseout", mouseOut) + + var path = g.append("path") + .attr("d", arc) + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "path-" + "index-" + i }) + .style("fill", function(d) { return d.data.hexcolor}) + .attr("fill", function(d) { return d.data.hexcolor}) + + svg.selectAll("g.labels") + .data(data) + .enter().append("g") // Append legend elements + .append("text") + .attr("text-anchor", "start") + .attr("x", width / 2.5) + .attr("y", function(d, i) { return (height / 2) - i*(data.length * 20)}) + .attr("dx", 0) + .attr("dy", "-140px") // Controls padding to place text above bars + .text(function(d) { return d.labels + ", " + d.units}) + .style("fill", function(d) { return d.hexcolor }) + .attr("index_value", function(d, i) { return "index-" + i }) + .attr("class", function(d, i) { return "labels-" + "index-" + i + " aLabel "}) + .on('mouseover', mouseOver) + .on("mouseout", mouseOut) +} + +// Line Chart +// Adapted from http://bl.ocks.org/1166403 and +// http://www.d3noob.org/2013/01/adding-tooltips-to-d3js-graph.html +/// options = {units: "string", labels: "string", m: [80, 100, 120, 100], w: 800, h: 400, div: "#dogLine", yaxis: "cuddlability", hiColor: "#E4EB29"} +module.exports.d3LineChart = function(data, options) { + // format data into units and labels + var data = data.map(function(r) { + var labels = options.labels + var units = options.units + return {units: r[units], labels: r[labels], hexcolor: r.hexcolor} + }) + + var m = options.m + var w = options.w - m[1] - m[3] + var h = options.h - m[0] - m[2] + var data = data + + var x = d3.scale.ordinal().rangeRoundBands([0, w], 1) + x.domain(data.map(function(d) { return d.labels })) + var y = d3.scale.linear().range([0, h]) + y.domain([d3.max(data, function(d) { return d.units }) + 2, 0]) + + var line = d3.svg.line() + .x(function(d, i) { return x(i) }) + .y(function(d) { return y(d) }) + + var graph = d3.select(options.div).append("svg:svg") + .attr("width", w + m[1] + m[3]) + .attr("height", h + m[0] + m[2]) + .append("svg:g") + .attr("transform", "translate(" + m[3] + "," + m[0] + ")") + + var div = d3.select(options.div).append("div") + .attr("class", "tooltip") + .style("opacity", 0) + + // create yAxis + var xAxis = d3.svg.axis().scale(x).tickSize(-h).tickSubdivide(true) + // Add the x-axis. + graph.append("svg:g") + .attr("class", "x axis") + .attr("transform", "translate(0," + h + ")") + .call(xAxis) + .selectAll("text") + .style("text-anchor", "end") + .attr("dy", "-.5em") + .attr('dx', "-1em") + .attr("transform", "rotate(-80)") + .call(xAxis) + + // create left yAxis + var yAxisLeft = d3.svg.axis().scale(y).ticks(4).tickSize(-w).tickSubdivide(true).orient("left") + // Add the y-axis to the left + graph.append("svg:g") + .attr("class", "y axis") + .attr("dx", "25") + .attr("transform", "translate(0,0)") + .call(yAxisLeft) + .append("text") + .attr("transform", "rotate(-90)") + .attr("y", -40) + .attr("dy", 0) + .style("text-anchor", "end") + .text(function() { + if (options.yaxis) return options.yaxis + return + }) + +var lineData = data.map(function(d) { return d.units }) + graph.append("svg:path") + .attr("d", line(lineData)) + .attr("class", "chartLine") + .attr("index_value", function(d, i) { return i }) + // .attr("stroke", options.hiColor).attr("fill", "none") + + graph.selectAll("dot") + .data(data) + .enter().append("circle") + .attr("r", 3.5) + .attr("fill", options.hiColor) + .attr("cx", function(d) { return x(d.labels); }) + .attr("cy", function(d) { return y(d.units); }) + .on("mouseover", function(d) { + div.transition().duration(200).style("opacity", .9) + div .html(d.labels + ", " + d.units) + .style("left", (d3.event.pageX) + "px") + .style("top", (d3.event.pageY - 28) + "px") + }) + .on("mouseout", function(d) { + div.transition().duration(500).style("opacity", 0) + }) +} + + +},{"d3":29}],28:[function(require,module,exports){ +d3 = function() { + var d3 = { + version: "3.2.8" + }; + if (!Date.now) Date.now = function() { + return +new Date(); + }; + var d3_document = document, d3_documentElement = d3_document.documentElement, d3_window = window; + try { + d3_document.createElement("div").style.setProperty("opacity", 0, ""); + } catch (error) { + var d3_element_prototype = d3_window.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = d3_window.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; + d3_element_prototype.setAttribute = function(name, value) { + d3_element_setAttribute.call(this, name, value + ""); + }; + d3_element_prototype.setAttributeNS = function(space, local, value) { + d3_element_setAttributeNS.call(this, space, local, value + ""); + }; + d3_style_prototype.setProperty = function(name, value, priority) { + d3_style_setProperty.call(this, name, value + "", priority); + }; + } + d3.ascending = function(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + }; + d3.descending = function(a, b) { + return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; + }; + d3.min = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && a > b) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; + } + return a; + }; + d3.max = function(array, f) { + var i = -1, n = array.length, a, b; + if (arguments.length === 1) { + while (++i < n && !((a = array[i]) != null && a <= a)) a = undefined; + while (++i < n) if ((b = array[i]) != null && b > a) a = b; + } else { + while (++i < n && !((a = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; + } + return a; + }; + d3.extent = function(array, f) { + var i = -1, n = array.length, a, b, c; + if (arguments.length === 1) { + while (++i < n && !((a = c = array[i]) != null && a <= a)) a = c = undefined; + while (++i < n) if ((b = array[i]) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } else { + while (++i < n && !((a = c = f.call(array, array[i], i)) != null && a <= a)) a = undefined; + while (++i < n) if ((b = f.call(array, array[i], i)) != null) { + if (a > b) a = b; + if (c < b) c = b; + } + } + return [ a, c ]; + }; + d3.sum = function(array, f) { + var s = 0, n = array.length, a, i = -1; + if (arguments.length === 1) { + while (++i < n) if (!isNaN(a = +array[i])) s += a; + } else { + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; + } + return s; + }; + function d3_number(x) { + return x != null && !isNaN(x); + } + d3.mean = function(array, f) { + var n = array.length, a, m = 0, i = -1, j = 0; + if (arguments.length === 1) { + while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; + } else { + while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; + } + return j ? m : undefined; + }; + d3.quantile = function(values, p) { + var H = (values.length - 1) * p + 1, h = Math.floor(H), v = +values[h - 1], e = H - h; + return e ? v + e * (values[h] - v) : v; + }; + d3.median = function(array, f) { + if (arguments.length > 1) array = array.map(f); + array = array.filter(d3_number); + return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; + }; + d3.bisector = function(f) { + return { + left: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; + } + return lo; + }, + right: function(a, x, lo, hi) { + if (arguments.length < 3) lo = 0; + if (arguments.length < 4) hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; + } + return lo; + } + }; + }; + var d3_bisector = d3.bisector(function(d) { + return d; + }); + d3.bisectLeft = d3_bisector.left; + d3.bisect = d3.bisectRight = d3_bisector.right; + d3.shuffle = function(array) { + var m = array.length, t, i; + while (m) { + i = Math.random() * m-- | 0; + t = array[m], array[m] = array[i], array[i] = t; + } + return array; + }; + d3.permute = function(array, indexes) { + var i = indexes.length, permutes = new Array(i); + while (i--) permutes[i] = array[indexes[i]]; + return permutes; + }; + d3.zip = function() { + if (!(n = arguments.length)) return []; + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { + zip[j] = arguments[j][i]; + } + } + return zips; + }; + function d3_zipLength(d) { + return d.length; + } + d3.transpose = function(matrix) { + return d3.zip.apply(d3, matrix); + }; + d3.keys = function(map) { + var keys = []; + for (var key in map) keys.push(key); + return keys; + }; + d3.values = function(map) { + var values = []; + for (var key in map) values.push(map[key]); + return values; + }; + d3.entries = function(map) { + var entries = []; + for (var key in map) entries.push({ + key: key, + value: map[key] + }); + return entries; + }; + d3.merge = function(arrays) { + return Array.prototype.concat.apply([], arrays); + }; + d3.range = function(start, stop, step) { + if (arguments.length < 3) { + step = 1; + if (arguments.length < 2) { + stop = start; + start = 0; + } + } + if ((stop - start) / step === Infinity) throw new Error("infinite range"); + var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; + start *= k, stop *= k, step *= k; + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); + return range; + }; + function d3_range_integerScale(x) { + var k = 1; + while (x * k % 1) k *= 10; + return k; + } + function d3_class(ctor, properties) { + try { + for (var key in properties) { + Object.defineProperty(ctor.prototype, key, { + value: properties[key], + enumerable: false + }); + } + } catch (e) { + ctor.prototype = properties; + } + } + d3.map = function(object) { + var map = new d3_Map(); + if (object instanceof d3_Map) object.forEach(function(key, value) { + map.set(key, value); + }); else for (var key in object) map.set(key, object[key]); + return map; + }; + function d3_Map() {} + d3_class(d3_Map, { + has: function(key) { + return d3_map_prefix + key in this; + }, + get: function(key) { + return this[d3_map_prefix + key]; + }, + set: function(key, value) { + return this[d3_map_prefix + key] = value; + }, + remove: function(key) { + key = d3_map_prefix + key; + return key in this && delete this[key]; + }, + keys: function() { + var keys = []; + this.forEach(function(key) { + keys.push(key); + }); + return keys; + }, + values: function() { + var values = []; + this.forEach(function(key, value) { + values.push(value); + }); + return values; + }, + entries: function() { + var entries = []; + this.forEach(function(key, value) { + entries.push({ + key: key, + value: value + }); + }); + return entries; + }, + forEach: function(f) { + for (var key in this) { + if (key.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, key.substring(1), this[key]); + } + } + } + }); + var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); + d3.nest = function() { + var nest = {}, keys = [], sortKeys = [], sortValues, rollup; + function map(mapType, array, depth) { + if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; + var i = -1, n = array.length, key = keys[depth++], keyValue, object, setter, valuesByKey = new d3_Map(), values; + while (++i < n) { + if (values = valuesByKey.get(keyValue = key(object = array[i]))) { + values.push(object); + } else { + valuesByKey.set(keyValue, [ object ]); + } + } + if (mapType) { + object = mapType(); + setter = function(keyValue, values) { + object.set(keyValue, map(mapType, values, depth)); + }; + } else { + object = {}; + setter = function(keyValue, values) { + object[keyValue] = map(mapType, values, depth); + }; + } + valuesByKey.forEach(setter); + return object; + } + function entries(map, depth) { + if (depth >= keys.length) return map; + var array = [], sortKey = sortKeys[depth++]; + map.forEach(function(key, keyMap) { + array.push({ + key: key, + values: entries(keyMap, depth) + }); + }); + return sortKey ? array.sort(function(a, b) { + return sortKey(a.key, b.key); + }) : array; + } + nest.map = function(array, mapType) { + return map(mapType, array, 0); + }; + nest.entries = function(array) { + return entries(map(d3.map, array, 0), 0); + }; + nest.key = function(d) { + keys.push(d); + return nest; + }; + nest.sortKeys = function(order) { + sortKeys[keys.length - 1] = order; + return nest; + }; + nest.sortValues = function(order) { + sortValues = order; + return nest; + }; + nest.rollup = function(f) { + rollup = f; + return nest; + }; + return nest; + }; + d3.set = function(array) { + var set = new d3_Set(); + if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); + return set; + }; + function d3_Set() {} + d3_class(d3_Set, { + has: function(value) { + return d3_map_prefix + value in this; + }, + add: function(value) { + this[d3_map_prefix + value] = true; + return value; + }, + remove: function(value) { + value = d3_map_prefix + value; + return value in this && delete this[value]; + }, + values: function() { + var values = []; + this.forEach(function(value) { + values.push(value); + }); + return values; + }, + forEach: function(f) { + for (var value in this) { + if (value.charCodeAt(0) === d3_map_prefixCode) { + f.call(this, value.substring(1)); + } + } + } + }); + d3.behavior = {}; + d3.rebind = function(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; + }; + function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; + } + function d3_vendorSymbol(object, name) { + if (name in object) return name; + name = name.charAt(0).toUpperCase() + name.substring(1); + for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { + var prefixName = d3_vendorPrefixes[i] + name; + if (prefixName in object) return prefixName; + } + } + var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ]; + var d3_array = d3_arraySlice; + function d3_arrayCopy(pseudoarray) { + var i = pseudoarray.length, array = new Array(i); + while (i--) array[i] = pseudoarray[i]; + return array; + } + function d3_arraySlice(pseudoarray) { + return Array.prototype.slice.call(pseudoarray); + } + try { + d3_array(d3_documentElement.childNodes)[0].nodeType; + } catch (e) { + d3_array = d3_arrayCopy; + } + function d3_noop() {} + d3.dispatch = function() { + var dispatch = new d3_dispatch(), i = -1, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + return dispatch; + }; + function d3_dispatch() {} + d3_dispatch.prototype.on = function(type, listener) { + var i = type.indexOf("."), name = ""; + if (i >= 0) { + name = type.substring(i + 1); + type = type.substring(0, i); + } + if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); + if (arguments.length === 2) { + if (listener == null) for (type in this) { + if (this.hasOwnProperty(type)) this[type].on(name, null); + } + return this; + } + }; + function d3_dispatch_event(dispatch) { + var listeners = [], listenerByName = new d3_Map(); + function event() { + var z = listeners, i = -1, n = z.length, l; + while (++i < n) if (l = z[i].on) l.apply(this, arguments); + return dispatch; + } + event.on = function(name, listener) { + var l = listenerByName.get(name), i; + if (arguments.length < 2) return l && l.on; + if (l) { + l.on = null; + listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); + listenerByName.remove(name); + } + if (listener) listeners.push(listenerByName.set(name, { + on: listener + })); + return dispatch; + }; + return event; + } + d3.event = null; + function d3_eventPreventDefault() { + d3.event.preventDefault(); + } + function d3_eventSource() { + var e = d3.event, s; + while (s = e.sourceEvent) e = s; + return e; + } + function d3_eventDispatch(target) { + var dispatch = new d3_dispatch(), i = 0, n = arguments.length; + while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); + dispatch.of = function(thiz, argumentz) { + return function(e1) { + try { + var e0 = e1.sourceEvent = d3.event; + e1.target = target; + d3.event = e1; + dispatch[e1.type].apply(thiz, argumentz); + } finally { + d3.event = e0; + } + }; + }; + return dispatch; + } + d3.requote = function(s) { + return s.replace(d3_requote_re, "\\$&"); + }; + var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; + var d3_subclass = {}.__proto__ ? function(object, prototype) { + object.__proto__ = prototype; + } : function(object, prototype) { + for (var property in prototype) object[property] = prototype[property]; + }; + function d3_selection(groups) { + d3_subclass(groups, d3_selectionPrototype); + return groups; + } + var d3_select = function(s, n) { + return n.querySelector(s); + }, d3_selectAll = function(s, n) { + return n.querySelectorAll(s); + }, d3_selectMatcher = d3_documentElement[d3_vendorSymbol(d3_documentElement, "matchesSelector")], d3_selectMatches = function(n, s) { + return d3_selectMatcher.call(n, s); + }; + if (typeof Sizzle === "function") { + d3_select = function(s, n) { + return Sizzle(s, n)[0] || null; + }; + d3_selectAll = function(s, n) { + return Sizzle.uniqueSort(Sizzle(s, n)); + }; + d3_selectMatches = Sizzle.matchesSelector; + } + d3.selection = function() { + return d3_selectionRoot; + }; + var d3_selectionPrototype = d3.selection.prototype = []; + d3_selectionPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, group, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(subnode = selector.call(node, node.__data__, i, j)); + if (subnode && "__data__" in node) subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selector(selector) { + return typeof selector === "function" ? selector : function() { + return d3_select(selector, this); + }; + } + d3_selectionPrototype.selectAll = function(selector) { + var subgroups = [], subgroup, node; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); + subgroup.parentNode = node; + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_selectorAll(selector) { + return typeof selector === "function" ? selector : function() { + return d3_selectAll(selector, this); + }; + } + var d3_nsPrefix = { + svg: "http://www.w3.org/2000/svg", + xhtml: "http://www.w3.org/1999/xhtml", + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + d3.ns = { + prefix: d3_nsPrefix, + qualify: function(name) { + var i = name.indexOf(":"), prefix = name; + if (i >= 0) { + prefix = name.substring(0, i); + name = name.substring(i + 1); + } + return d3_nsPrefix.hasOwnProperty(prefix) ? { + space: d3_nsPrefix[prefix], + local: name + } : name; + } + }; + d3_selectionPrototype.attr = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(); + name = d3.ns.qualify(name); + return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); + } + for (value in name) this.each(d3_selection_attr(value, name[value])); + return this; + } + return this.each(d3_selection_attr(name, value)); + }; + function d3_selection_attr(name, value) { + name = d3.ns.qualify(name); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrConstant() { + this.setAttribute(name, value); + } + function attrConstantNS() { + this.setAttributeNS(name.space, name.local, value); + } + function attrFunction() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); + } + function attrFunctionNS() { + var x = value.apply(this, arguments); + if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); + } + return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; + } + function d3_collapse(s) { + return s.trim().replace(/\s+/g, " "); + } + d3_selectionPrototype.classed = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") { + var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; + if (value = node.classList) { + while (++i < n) if (!value.contains(name[i])) return false; + } else { + value = node.getAttribute("class"); + while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; + } + return true; + } + for (value in name) this.each(d3_selection_classed(value, name[value])); + return this; + } + return this.each(d3_selection_classed(name, value)); + }; + function d3_selection_classedRe(name) { + return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); + } + function d3_selection_classed(name, value) { + name = name.trim().split(/\s+/).map(d3_selection_classedName); + var n = name.length; + function classedConstant() { + var i = -1; + while (++i < n) name[i](this, value); + } + function classedFunction() { + var i = -1, x = value.apply(this, arguments); + while (++i < n) name[i](this, x); + } + return typeof value === "function" ? classedFunction : classedConstant; + } + function d3_selection_classedName(name) { + var re = d3_selection_classedRe(name); + return function(node, value) { + if (c = node.classList) return value ? c.add(name) : c.remove(name); + var c = node.getAttribute("class") || ""; + if (value) { + re.lastIndex = 0; + if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); + } else { + node.setAttribute("class", d3_collapse(c.replace(re, " "))); + } + }; + } + d3_selectionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); + return this; + } + if (n < 2) return d3_window.getComputedStyle(this.node(), null).getPropertyValue(name); + priority = ""; + } + return this.each(d3_selection_style(name, value, priority)); + }; + function d3_selection_style(name, value, priority) { + function styleNull() { + this.style.removeProperty(name); + } + function styleConstant() { + this.style.setProperty(name, value, priority); + } + function styleFunction() { + var x = value.apply(this, arguments); + if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); + } + return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; + } + d3_selectionPrototype.property = function(name, value) { + if (arguments.length < 2) { + if (typeof name === "string") return this.node()[name]; + for (value in name) this.each(d3_selection_property(value, name[value])); + return this; + } + return this.each(d3_selection_property(name, value)); + }; + function d3_selection_property(name, value) { + function propertyNull() { + delete this[name]; + } + function propertyConstant() { + this[name] = value; + } + function propertyFunction() { + var x = value.apply(this, arguments); + if (x == null) delete this[name]; else this[name] = x; + } + return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; + } + d3_selectionPrototype.text = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + } : value == null ? function() { + this.textContent = ""; + } : function() { + this.textContent = value; + }) : this.node().textContent; + }; + d3_selectionPrototype.html = function(value) { + return arguments.length ? this.each(typeof value === "function" ? function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + } : value == null ? function() { + this.innerHTML = ""; + } : function() { + this.innerHTML = value; + }) : this.node().innerHTML; + }; + d3_selectionPrototype.append = function(name) { + name = d3_selection_creator(name); + return this.select(function() { + return this.appendChild(name.apply(this, arguments)); + }); + }; + function d3_selection_creator(name) { + return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? function() { + return d3_document.createElementNS(name.space, name.local); + } : function() { + return d3_document.createElementNS(this.namespaceURI, name); + }; + } + d3_selectionPrototype.insert = function(name, before) { + name = d3_selection_creator(name); + before = d3_selection_selector(before); + return this.select(function() { + return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments)); + }); + }; + d3_selectionPrototype.remove = function() { + return this.each(function() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + }); + }; + d3_selectionPrototype.data = function(value, key) { + var i = -1, n = this.length, group, node; + if (!arguments.length) { + value = new Array(n = (group = this[0]).length); + while (++i < n) { + if (node = group[i]) { + value[i] = node.__data__; + } + } + return value; + } + function bind(group, groupData) { + var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData; + if (key) { + var nodeByKeyValue = new d3_Map(), dataByKeyValue = new d3_Map(), keyValues = [], keyValue; + for (i = -1; ++i < n; ) { + keyValue = key.call(node = group[i], node.__data__, i); + if (nodeByKeyValue.has(keyValue)) { + exitNodes[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + keyValues.push(keyValue); + } + for (i = -1; ++i < m; ) { + keyValue = key.call(groupData, nodeData = groupData[i], i); + if (node = nodeByKeyValue.get(keyValue)) { + updateNodes[i] = node; + node.__data__ = nodeData; + } else if (!dataByKeyValue.has(keyValue)) { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + dataByKeyValue.set(keyValue, nodeData); + nodeByKeyValue.remove(keyValue); + } + for (i = -1; ++i < n; ) { + if (nodeByKeyValue.has(keyValues[i])) { + exitNodes[i] = group[i]; + } + } + } else { + for (i = -1; ++i < n0; ) { + node = group[i]; + nodeData = groupData[i]; + if (node) { + node.__data__ = nodeData; + updateNodes[i] = node; + } else { + enterNodes[i] = d3_selection_dataNode(nodeData); + } + } + for (;i < m; ++i) { + enterNodes[i] = d3_selection_dataNode(groupData[i]); + } + for (;i < n; ++i) { + exitNodes[i] = group[i]; + } + } + enterNodes.update = updateNodes; + enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; + enter.push(enterNodes); + update.push(updateNodes); + exit.push(exitNodes); + } + var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); + if (typeof value === "function") { + while (++i < n) { + bind(group = this[i], value.call(group, group.parentNode.__data__, i)); + } + } else { + while (++i < n) { + bind(group = this[i], value); + } + } + update.enter = function() { + return enter; + }; + update.exit = function() { + return exit; + }; + return update; + }; + function d3_selection_dataNode(data) { + return { + __data__: data + }; + } + d3_selectionPrototype.datum = function(value) { + return arguments.length ? this.property("__data__", value) : this.property("__data__"); + }; + d3_selectionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + subgroup.parentNode = (group = this[j]).parentNode; + for (var i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_selection(subgroups); + }; + function d3_selection_filter(selector) { + return function() { + return d3_selectMatches(this, selector); + }; + } + d3_selectionPrototype.order = function() { + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { + if (node = group[i]) { + if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + return this; + }; + d3_selectionPrototype.sort = function(comparator) { + comparator = d3_selection_sortComparator.apply(this, arguments); + for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); + return this.order(); + }; + function d3_selection_sortComparator(comparator) { + if (!arguments.length) comparator = d3.ascending; + return function(a, b) { + return a && b ? comparator(a.__data__, b.__data__) : !a - !b; + }; + } + d3_selectionPrototype.each = function(callback) { + return d3_selection_each(this, function(node, i, j) { + callback.call(node, node.__data__, i, j); + }); + }; + function d3_selection_each(groups, callback) { + for (var j = 0, m = groups.length; j < m; j++) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { + if (node = group[i]) callback(node, i, j); + } + } + return groups; + } + d3_selectionPrototype.call = function(callback) { + var args = d3_array(arguments); + callback.apply(args[0] = this, args); + return this; + }; + d3_selectionPrototype.empty = function() { + return !this.node(); + }; + d3_selectionPrototype.node = function() { + for (var j = 0, m = this.length; j < m; j++) { + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + var node = group[i]; + if (node) return node; + } + } + return null; + }; + d3_selectionPrototype.size = function() { + var n = 0; + this.each(function() { + ++n; + }); + return n; + }; + function d3_selection_enter(selection) { + d3_subclass(selection, d3_selection_enterPrototype); + return selection; + } + var d3_selection_enterPrototype = []; + d3.selection.enter = d3_selection_enter; + d3.selection.enter.prototype = d3_selection_enterPrototype; + d3_selection_enterPrototype.append = d3_selectionPrototype.append; + d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; + d3_selection_enterPrototype.node = d3_selectionPrototype.node; + d3_selection_enterPrototype.call = d3_selectionPrototype.call; + d3_selection_enterPrototype.size = d3_selectionPrototype.size; + d3_selection_enterPrototype.select = function(selector) { + var subgroups = [], subgroup, subnode, upgroup, group, node; + for (var j = -1, m = this.length; ++j < m; ) { + upgroup = (group = this[j]).update; + subgroups.push(subgroup = []); + subgroup.parentNode = group.parentNode; + for (var i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); + subnode.__data__ = node.__data__; + } else { + subgroup.push(null); + } + } + } + return d3_selection(subgroups); + }; + d3_selection_enterPrototype.insert = function(name, before) { + if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); + return d3_selectionPrototype.insert.call(this, name, before); + }; + function d3_selection_enterInsertBefore(enter) { + var i0, j0; + return function(d, i, j) { + var group = enter[j].update, n = group.length, node; + if (j != j0) j0 = j, i0 = 0; + if (i >= i0) i0 = i + 1; + while (!(node = group[i0]) && ++i0 < n) ; + return node; + }; + } + d3_selectionPrototype.transition = function() { + var id = d3_transitionInheritId || ++d3_transitionId, subgroups = [], subgroup, node, transition = d3_transitionInherit || { + time: Date.now(), + ease: d3_ease_cubicInOut, + delay: 0, + duration: 250 + }; + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) d3_transitionNode(node, i, id, transition); + subgroup.push(node); + } + } + return d3_transition(subgroups, id); + }; + d3.select = function(node) { + var group = [ typeof node === "string" ? d3_select(node, d3_document) : node ]; + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + d3.selectAll = function(nodes) { + var group = d3_array(typeof nodes === "string" ? d3_selectAll(nodes, d3_document) : nodes); + group.parentNode = d3_documentElement; + return d3_selection([ group ]); + }; + var d3_selectionRoot = d3.select(d3_documentElement); + d3_selectionPrototype.on = function(type, listener, capture) { + var n = arguments.length; + if (n < 3) { + if (typeof type !== "string") { + if (n < 2) listener = false; + for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); + return this; + } + if (n < 2) return (n = this.node()["__on" + type]) && n._; + capture = false; + } + return this.each(d3_selection_on(type, listener, capture)); + }; + function d3_selection_on(type, listener, capture) { + var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener; + if (i > 0) type = type.substring(0, i); + var filter = d3_selection_onFilters.get(type); + if (filter) type = filter, wrap = d3_selection_onFilter; + function onRemove() { + var l = this[name]; + if (l) { + this.removeEventListener(type, l, l.$); + delete this[name]; + } + } + function onAdd() { + var l = wrap(listener, d3_array(arguments)); + onRemove.call(this); + this.addEventListener(type, this[name] = l, l.$ = capture); + l._ = listener; + } + function removeAll() { + var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match; + for (var name in this) { + if (match = name.match(re)) { + var l = this[name]; + this.removeEventListener(match[1], l, l.$); + delete this[name]; + } + } + } + return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll; + } + var d3_selection_onFilters = d3.map({ + mouseenter: "mouseover", + mouseleave: "mouseout" + }); + d3_selection_onFilters.forEach(function(k) { + if ("on" + k in d3_document) d3_selection_onFilters.remove(k); + }); + function d3_selection_onListener(listener, argumentz) { + return function(e) { + var o = d3.event; + d3.event = e; + argumentz[0] = this.__data__; + try { + listener.apply(this, argumentz); + } finally { + d3.event = o; + } + }; + } + function d3_selection_onFilter(listener, argumentz) { + var l = d3_selection_onListener(listener, argumentz); + return function(e) { + var target = this, related = e.relatedTarget; + if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) { + l.call(target, e); + } + }; + } + var d3_event_dragSelect = d3_vendorSymbol(d3_documentElement.style, "userSelect"), d3_event_dragId = 0; + function d3_event_dragSuppress() { + var name = ".dragsuppress-" + ++d3_event_dragId, touchmove = "touchmove" + name, selectstart = "selectstart" + name, dragstart = "dragstart" + name, click = "click" + name, w = d3.select(d3_window).on(touchmove, d3_eventPreventDefault).on(selectstart, d3_eventPreventDefault).on(dragstart, d3_eventPreventDefault), style = d3_documentElement.style, select = style[d3_event_dragSelect]; + style[d3_event_dragSelect] = "none"; + return function(suppressClick) { + w.on(name, null); + style[d3_event_dragSelect] = select; + if (suppressClick) { + function off() { + w.on(click, null); + } + w.on(click, function() { + d3_eventPreventDefault(); + off(); + }, true); + setTimeout(off, 0); + } + }; + } + d3.mouse = function(container) { + return d3_mousePoint(container, d3_eventSource()); + }; + var d3_mouse_bug44083 = /WebKit/.test(d3_window.navigator.userAgent) ? -1 : 0; + function d3_mousePoint(container, e) { + var svg = container.ownerSVGElement || container; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + if (d3_mouse_bug44083 < 0 && (d3_window.scrollX || d3_window.scrollY)) { + svg = d3.select("body").append("svg").style({ + position: "absolute", + top: 0, + left: 0, + margin: 0, + padding: 0, + border: "none" + }, "important"); + var ctm = svg[0][0].getScreenCTM(); + d3_mouse_bug44083 = !(ctm.f || ctm.e); + svg.remove(); + } + if (d3_mouse_bug44083) { + point.x = e.pageX; + point.y = e.pageY; + } else { + point.x = e.clientX; + point.y = e.clientY; + } + point = point.matrixTransform(container.getScreenCTM().inverse()); + return [ point.x, point.y ]; + } + var rect = container.getBoundingClientRect(); + return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; + } + d3.touches = function(container, touches) { + if (arguments.length < 2) touches = d3_eventSource().touches; + return touches ? d3_array(touches).map(function(touch) { + var point = d3_mousePoint(container, touch); + point.identifier = touch.identifier; + return point; + }) : []; + }; + d3.behavior.drag = function() { + var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); + function drag() { + this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart); + } + function touchid() { + return d3.event.changedTouches[0].identifier; + } + function touchposition(parent, id) { + return d3.touches(parent).filter(function(p) { + return p.identifier === id; + })[0]; + } + function dragstart(id, position, move, end) { + return function() { + var target = this, parent = target.parentNode, event_ = event.of(target, arguments), eventTarget = d3.event.target, eventId = id(), drag = eventId == null ? "drag" : "drag-" + eventId, origin_ = position(parent, eventId), dragged = 0, offset, w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragRestore = d3_event_dragSuppress(); + if (origin) { + offset = origin.apply(target, arguments); + offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; + } else { + offset = [ 0, 0 ]; + } + event_({ + type: "dragstart" + }); + function moved() { + if (!parent) return ended(); + var p = position(parent, eventId), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; + dragged |= dx | dy; + origin_ = p; + event_({ + type: "drag", + x: p[0] + offset[0], + y: p[1] + offset[1], + dx: dx, + dy: dy + }); + } + function ended() { + w.on(move + "." + drag, null).on(end + "." + drag, null); + dragRestore(dragged && d3.event.target === eventTarget); + event_({ + type: "dragend" + }); + } + }; + } + drag.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return drag; + }; + return d3.rebind(drag, event, "on"); + }; + d3.behavior.zoom = function() { + var translate = [ 0, 0 ], translate0, scale = 1, scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1; + function zoom() { + this.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted); + } + zoom.translate = function(x) { + if (!arguments.length) return translate; + translate = x.map(Number); + rescale(); + return zoom; + }; + zoom.scale = function(x) { + if (!arguments.length) return scale; + scale = +x; + rescale(); + return zoom; + }; + zoom.scaleExtent = function(x) { + if (!arguments.length) return scaleExtent; + scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); + return zoom; + }; + zoom.x = function(z) { + if (!arguments.length) return x1; + x1 = z; + x0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + zoom.y = function(z) { + if (!arguments.length) return y1; + y1 = z; + y0 = z.copy(); + translate = [ 0, 0 ]; + scale = 1; + return zoom; + }; + function location(p) { + return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; + } + function point(l) { + return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; + } + function scaleTo(s) { + scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); + } + function translateTo(p, l) { + l = point(l); + translate[0] += p[0] - l[0]; + translate[1] += p[1] - l[1]; + } + function rescale() { + if (x1) x1.domain(x0.range().map(function(x) { + return (x - translate[0]) / scale; + }).map(x0.invert)); + if (y1) y1.domain(y0.range().map(function(y) { + return (y - translate[1]) / scale; + }).map(y0.invert)); + } + function dispatch(event) { + rescale(); + event({ + type: "zoom", + scale: scale, + translate: translate + }); + } + function mousedowned() { + var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, dragged = 0, w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), l = location(d3.mouse(target)), dragRestore = d3_event_dragSuppress(); + function moved() { + dragged = 1; + translateTo(d3.mouse(target), l); + dispatch(event_); + } + function ended() { + w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); + dragRestore(dragged && d3.event.target === eventTarget); + } + } + function touchstarted() { + var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress(); + started(); + function relocate() { + var touches = d3.touches(target); + scale0 = scale; + locations0 = {}; + touches.forEach(function(t) { + locations0[t.identifier] = location(t); + }); + return touches; + } + function started() { + var now = Date.now(), touches = relocate(); + if (touches.length === 1) { + if (now - touchtime < 500) { + var p = touches[0], l = locations0[p.identifier]; + scaleTo(scale * 2); + translateTo(p, l); + d3_eventPreventDefault(); + dispatch(event_); + } + touchtime = now; + } else if (touches.length > 1) { + var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1]; + distance0 = dx * dx + dy * dy; + } + } + function moved() { + var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier]; + if (p1 = touches[1]) { + var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale; + if (scale1 == null) { + var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1; + scale1 = distance0 && Math.sqrt(distance1 / distance0); + } + p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; + l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; + scaleTo(scale1 * scale0); + } + touchtime = null; + translateTo(p0, l0); + dispatch(event_); + } + function ended() { + if (d3.event.touches.length) { + relocate(); + } else { + w.on(touchmove, null).on(touchend, null); + t.on(mousedown, mousedowned).on(touchstart, touchstarted); + dragRestore(); + } + } + } + function mousewheeled() { + d3_eventPreventDefault(); + if (!translate0) translate0 = location(d3.mouse(this)); + scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); + translateTo(d3.mouse(this), translate0); + dispatch(event.of(this, arguments)); + } + function mousewheelreset() { + translate0 = null; + } + function dblclicked() { + var p = d3.mouse(this), l = location(p), k = Math.log(scale) / Math.LN2; + scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); + translateTo(p, l); + dispatch(event.of(this, arguments)); + } + return d3.rebind(zoom, event, "on"); + }; + var d3_behavior_zoomInfinity = [ 0, Infinity ]; + var d3_behavior_zoomDelta, d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); + }, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { + return d3.event.wheelDelta; + }, "mousewheel") : (d3_behavior_zoomDelta = function() { + return -d3.event.detail; + }, "MozMousePixelScroll"); + function d3_Color() {} + d3_Color.prototype.toString = function() { + return this.rgb() + ""; + }; + d3.hsl = function(h, s, l) { + return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); + }; + function d3_hsl(h, s, l) { + return new d3_Hsl(h, s, l); + } + function d3_Hsl(h, s, l) { + this.h = h; + this.s = s; + this.l = l; + } + var d3_hslPrototype = d3_Hsl.prototype = new d3_Color(); + d3_hslPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, this.l / k); + }; + d3_hslPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_hsl(this.h, this.s, k * this.l); + }; + d3_hslPrototype.rgb = function() { + return d3_hsl_rgb(this.h, this.s, this.l); + }; + function d3_hsl_rgb(h, s, l) { + var m1, m2; + h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; + s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; + l = l < 0 ? 0 : l > 1 ? 1 : l; + m2 = l <= .5 ? l * (1 + s) : l + s - l * s; + m1 = 2 * l - m2; + function v(h) { + if (h > 360) h -= 360; else if (h < 0) h += 360; + if (h < 60) return m1 + (m2 - m1) * h / 60; + if (h < 180) return m2; + if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; + return m1; + } + function vv(h) { + return Math.round(v(h) * 255); + } + return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); + } + var π = Math.PI, ε = 1e-6, ε2 = ε * ε, d3_radians = π / 180, d3_degrees = 180 / π; + function d3_sgn(x) { + return x > 0 ? 1 : x < 0 ? -1 : 0; + } + function d3_acos(x) { + return x > 1 ? 0 : x < -1 ? π : Math.acos(x); + } + function d3_asin(x) { + return x > 1 ? π / 2 : x < -1 ? -π / 2 : Math.asin(x); + } + function d3_sinh(x) { + return (Math.exp(x) - Math.exp(-x)) / 2; + } + function d3_cosh(x) { + return (Math.exp(x) + Math.exp(-x)) / 2; + } + function d3_haversin(x) { + return (x = Math.sin(x / 2)) * x; + } + d3.hcl = function(h, c, l) { + return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); + }; + function d3_hcl(h, c, l) { + return new d3_Hcl(h, c, l); + } + function d3_Hcl(h, c, l) { + this.h = h; + this.c = c; + this.l = l; + } + var d3_hclPrototype = d3_Hcl.prototype = new d3_Color(); + d3_hclPrototype.brighter = function(k) { + return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.darker = function(k) { + return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); + }; + d3_hclPrototype.rgb = function() { + return d3_hcl_lab(this.h, this.c, this.l).rgb(); + }; + function d3_hcl_lab(h, c, l) { + if (isNaN(h)) h = 0; + if (isNaN(c)) c = 0; + return d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); + } + d3.lab = function(l, a, b) { + return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); + }; + function d3_lab(l, a, b) { + return new d3_Lab(l, a, b); + } + function d3_Lab(l, a, b) { + this.l = l; + this.a = a; + this.b = b; + } + var d3_lab_K = 18; + var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; + var d3_labPrototype = d3_Lab.prototype = new d3_Color(); + d3_labPrototype.brighter = function(k) { + return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.darker = function(k) { + return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); + }; + d3_labPrototype.rgb = function() { + return d3_lab_rgb(this.l, this.a, this.b); + }; + function d3_lab_rgb(l, a, b) { + var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; + x = d3_lab_xyz(x) * d3_lab_X; + y = d3_lab_xyz(y) * d3_lab_Y; + z = d3_lab_xyz(z) * d3_lab_Z; + return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); + } + function d3_lab_hcl(l, a, b) { + return l > 0 ? d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : d3_hcl(NaN, NaN, l); + } + function d3_lab_xyz(x) { + return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; + } + function d3_xyz_lab(x) { + return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; + } + function d3_xyz_rgb(r) { + return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); + } + d3.rgb = function(r, g, b) { + return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); + }; + function d3_rgbNumber(value) { + return d3_rgb(value >> 16, value >> 8 & 255, value & 255); + } + function d3_rgbString(value) { + return d3_rgbNumber(value) + ""; + } + function d3_rgb(r, g, b) { + return new d3_Rgb(r, g, b); + } + function d3_Rgb(r, g, b) { + this.r = r; + this.g = g; + this.b = b; + } + var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color(); + d3_rgbPrototype.brighter = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + var r = this.r, g = this.g, b = this.b, i = 30; + if (!r && !g && !b) return d3_rgb(i, i, i); + if (r && r < i) r = i; + if (g && g < i) g = i; + if (b && b < i) b = i; + return d3_rgb(Math.min(255, ~~(r / k)), Math.min(255, ~~(g / k)), Math.min(255, ~~(b / k))); + }; + d3_rgbPrototype.darker = function(k) { + k = Math.pow(.7, arguments.length ? k : 1); + return d3_rgb(~~(k * this.r), ~~(k * this.g), ~~(k * this.b)); + }; + d3_rgbPrototype.hsl = function() { + return d3_rgb_hsl(this.r, this.g, this.b); + }; + d3_rgbPrototype.toString = function() { + return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); + }; + function d3_rgb_hex(v) { + return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); + } + function d3_rgb_parse(format, rgb, hsl) { + var r = 0, g = 0, b = 0, m1, m2, name; + m1 = /([a-z]+)\((.*)\)/i.exec(format); + if (m1) { + m2 = m1[2].split(","); + switch (m1[1]) { + case "hsl": + { + return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); + } + + case "rgb": + { + return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); + } + } + } + if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); + if (format != null && format.charAt(0) === "#") { + if (format.length === 4) { + r = format.charAt(1); + r += r; + g = format.charAt(2); + g += g; + b = format.charAt(3); + b += b; + } else if (format.length === 7) { + r = format.substring(1, 3); + g = format.substring(3, 5); + b = format.substring(5, 7); + } + r = parseInt(r, 16); + g = parseInt(g, 16); + b = parseInt(b, 16); + } + return rgb(r, g, b); + } + function d3_rgb_hsl(r, g, b) { + var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; + if (d) { + s = l < .5 ? d / (max + min) : d / (2 - max - min); + if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; + h *= 60; + } else { + h = NaN; + s = l > 0 && l < 1 ? 0 : h; + } + return d3_hsl(h, s, l); + } + function d3_rgb_lab(r, g, b) { + r = d3_rgb_xyz(r); + g = d3_rgb_xyz(g); + b = d3_rgb_xyz(b); + var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); + return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); + } + function d3_rgb_xyz(r) { + return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); + } + function d3_rgb_parseNumber(c) { + var f = parseFloat(c); + return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; + } + var d3_rgb_names = d3.map({ + aliceblue: 15792383, + antiquewhite: 16444375, + aqua: 65535, + aquamarine: 8388564, + azure: 15794175, + beige: 16119260, + bisque: 16770244, + black: 0, + blanchedalmond: 16772045, + blue: 255, + blueviolet: 9055202, + brown: 10824234, + burlywood: 14596231, + cadetblue: 6266528, + chartreuse: 8388352, + chocolate: 13789470, + coral: 16744272, + cornflowerblue: 6591981, + cornsilk: 16775388, + crimson: 14423100, + cyan: 65535, + darkblue: 139, + darkcyan: 35723, + darkgoldenrod: 12092939, + darkgray: 11119017, + darkgreen: 25600, + darkgrey: 11119017, + darkkhaki: 12433259, + darkmagenta: 9109643, + darkolivegreen: 5597999, + darkorange: 16747520, + darkorchid: 10040012, + darkred: 9109504, + darksalmon: 15308410, + darkseagreen: 9419919, + darkslateblue: 4734347, + darkslategray: 3100495, + darkslategrey: 3100495, + darkturquoise: 52945, + darkviolet: 9699539, + deeppink: 16716947, + deepskyblue: 49151, + dimgray: 6908265, + dimgrey: 6908265, + dodgerblue: 2003199, + firebrick: 11674146, + floralwhite: 16775920, + forestgreen: 2263842, + fuchsia: 16711935, + gainsboro: 14474460, + ghostwhite: 16316671, + gold: 16766720, + goldenrod: 14329120, + gray: 8421504, + green: 32768, + greenyellow: 11403055, + grey: 8421504, + honeydew: 15794160, + hotpink: 16738740, + indianred: 13458524, + indigo: 4915330, + ivory: 16777200, + khaki: 15787660, + lavender: 15132410, + lavenderblush: 16773365, + lawngreen: 8190976, + lemonchiffon: 16775885, + lightblue: 11393254, + lightcoral: 15761536, + lightcyan: 14745599, + lightgoldenrodyellow: 16448210, + lightgray: 13882323, + lightgreen: 9498256, + lightgrey: 13882323, + lightpink: 16758465, + lightsalmon: 16752762, + lightseagreen: 2142890, + lightskyblue: 8900346, + lightslategray: 7833753, + lightslategrey: 7833753, + lightsteelblue: 11584734, + lightyellow: 16777184, + lime: 65280, + limegreen: 3329330, + linen: 16445670, + magenta: 16711935, + maroon: 8388608, + mediumaquamarine: 6737322, + mediumblue: 205, + mediumorchid: 12211667, + mediumpurple: 9662683, + mediumseagreen: 3978097, + mediumslateblue: 8087790, + mediumspringgreen: 64154, + mediumturquoise: 4772300, + mediumvioletred: 13047173, + midnightblue: 1644912, + mintcream: 16121850, + mistyrose: 16770273, + moccasin: 16770229, + navajowhite: 16768685, + navy: 128, + oldlace: 16643558, + olive: 8421376, + olivedrab: 7048739, + orange: 16753920, + orangered: 16729344, + orchid: 14315734, + palegoldenrod: 15657130, + palegreen: 10025880, + paleturquoise: 11529966, + palevioletred: 14381203, + papayawhip: 16773077, + peachpuff: 16767673, + peru: 13468991, + pink: 16761035, + plum: 14524637, + powderblue: 11591910, + purple: 8388736, + red: 16711680, + rosybrown: 12357519, + royalblue: 4286945, + saddlebrown: 9127187, + salmon: 16416882, + sandybrown: 16032864, + seagreen: 3050327, + seashell: 16774638, + sienna: 10506797, + silver: 12632256, + skyblue: 8900331, + slateblue: 6970061, + slategray: 7372944, + slategrey: 7372944, + snow: 16775930, + springgreen: 65407, + steelblue: 4620980, + tan: 13808780, + teal: 32896, + thistle: 14204888, + tomato: 16737095, + turquoise: 4251856, + violet: 15631086, + wheat: 16113331, + white: 16777215, + whitesmoke: 16119285, + yellow: 16776960, + yellowgreen: 10145074 + }); + d3_rgb_names.forEach(function(key, value) { + d3_rgb_names.set(key, d3_rgbNumber(value)); + }); + function d3_functor(v) { + return typeof v === "function" ? v : function() { + return v; + }; + } + d3.functor = d3_functor; + function d3_identity(d) { + return d; + } + d3.xhr = d3_xhrType(d3_identity); + function d3_xhrType(response) { + return function(url, mimeType, callback) { + if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, + mimeType = null; + return d3_xhr(url, mimeType, response, callback); + }; + } + function d3_xhr(url, mimeType, response, callback) { + var xhr = {}, dispatch = d3.dispatch("progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null; + if (d3_window.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest(); + "onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() { + request.readyState > 3 && respond(); + }; + function respond() { + var status = request.status, result; + if (!status && request.responseText || status >= 200 && status < 300 || status === 304) { + try { + result = response.call(xhr, request); + } catch (e) { + dispatch.error.call(xhr, e); + return; + } + dispatch.load.call(xhr, result); + } else { + dispatch.error.call(xhr, request); + } + } + request.onprogress = function(event) { + var o = d3.event; + d3.event = event; + try { + dispatch.progress.call(xhr, request); + } finally { + d3.event = o; + } + }; + xhr.header = function(name, value) { + name = (name + "").toLowerCase(); + if (arguments.length < 2) return headers[name]; + if (value == null) delete headers[name]; else headers[name] = value + ""; + return xhr; + }; + xhr.mimeType = function(value) { + if (!arguments.length) return mimeType; + mimeType = value == null ? null : value + ""; + return xhr; + }; + xhr.responseType = function(value) { + if (!arguments.length) return responseType; + responseType = value; + return xhr; + }; + xhr.response = function(value) { + response = value; + return xhr; + }; + [ "get", "post" ].forEach(function(method) { + xhr[method] = function() { + return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments))); + }; + }); + xhr.send = function(method, data, callback) { + if (arguments.length === 2 && typeof data === "function") callback = data, data = null; + request.open(method, url, true); + if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; + if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); + if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); + if (responseType != null) request.responseType = responseType; + if (callback != null) xhr.on("error", callback).on("load", function(request) { + callback(null, request); + }); + request.send(data == null ? null : data); + return xhr; + }; + xhr.abort = function() { + request.abort(); + return xhr; + }; + d3.rebind(xhr, dispatch, "on"); + return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); + } + function d3_xhr_fixCallback(callback) { + return callback.length === 1 ? function(error, request) { + callback(error == null ? request : null); + } : callback; + } + d3.dsv = function(delimiter, mimeType) { + var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); + function dsv(url, row, callback) { + if (arguments.length < 3) callback = row, row = null; + var xhr = d3.xhr(url, mimeType, callback); + xhr.row = function(_) { + return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row; + }; + return xhr.row(row); + } + function response(request) { + return dsv.parse(request.responseText); + } + function typedResponse(f) { + return function(request) { + return dsv.parse(request.responseText, f); + }; + } + dsv.parse = function(text, f) { + var o; + return dsv.parseRows(text, function(row, i) { + if (o) return o(row, i - 1); + var a = new Function("d", "return {" + row.map(function(name, i) { + return JSON.stringify(name) + ": d[" + i + "]"; + }).join(",") + "}"); + o = f ? function(row, i) { + return f(a(row), i); + } : a; + }); + }; + dsv.parseRows = function(text, f) { + var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol; + function token() { + if (I >= N) return EOF; + if (eol) return eol = false, EOL; + var j = I; + if (text.charCodeAt(j) === 34) { + var i = j; + while (i++ < N) { + if (text.charCodeAt(i) === 34) { + if (text.charCodeAt(i + 1) !== 34) break; + ++i; + } + } + I = i + 2; + var c = text.charCodeAt(i + 1); + if (c === 13) { + eol = true; + if (text.charCodeAt(i + 2) === 10) ++I; + } else if (c === 10) { + eol = true; + } + return text.substring(j + 1, i).replace(/""/g, '"'); + } + while (I < N) { + var c = text.charCodeAt(I++), k = 1; + if (c === 10) eol = true; else if (c === 13) { + eol = true; + if (text.charCodeAt(I) === 10) ++I, ++k; + } else if (c !== delimiterCode) continue; + return text.substring(j, I - k); + } + return text.substring(j); + } + while ((t = token()) !== EOF) { + var a = []; + while (t !== EOL && t !== EOF) { + a.push(t); + t = token(); + } + if (f && !(a = f(a, n++))) continue; + rows.push(a); + } + return rows; + }; + dsv.format = function(rows) { + if (Array.isArray(rows[0])) return dsv.formatRows(rows); + var fieldSet = new d3_Set(), fields = []; + rows.forEach(function(row) { + for (var field in row) { + if (!fieldSet.has(field)) { + fields.push(fieldSet.add(field)); + } + } + }); + return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) { + return fields.map(function(field) { + return formatValue(row[field]); + }).join(delimiter); + })).join("\n"); + }; + dsv.formatRows = function(rows) { + return rows.map(formatRow).join("\n"); + }; + function formatRow(row) { + return row.map(formatValue).join(delimiter); + } + function formatValue(text) { + return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; + } + return dsv; + }; + d3.csv = d3.dsv(",", "text/csv"); + d3.tsv = d3.dsv(" ", "text/tab-separated-values"); + var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_active, d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, "requestAnimationFrame")] || function(callback) { + setTimeout(callback, 17); + }; + d3.timer = function(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + var time = then + delay, timer = { + callback: callback, + time: time, + next: null + }; + if (d3_timer_queueTail) d3_timer_queueTail.next = timer; else d3_timer_queueHead = timer; + d3_timer_queueTail = timer; + if (!d3_timer_interval) { + d3_timer_timeout = clearTimeout(d3_timer_timeout); + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + }; + function d3_timer_step() { + var now = d3_timer_mark(), delay = d3_timer_sweep() - now; + if (delay > 24) { + if (isFinite(delay)) { + clearTimeout(d3_timer_timeout); + d3_timer_timeout = setTimeout(d3_timer_step, delay); + } + d3_timer_interval = 0; + } else { + d3_timer_interval = 1; + d3_timer_frame(d3_timer_step); + } + } + d3.timer.flush = function() { + d3_timer_mark(); + d3_timer_sweep(); + }; + function d3_timer_replace(callback, delay, then) { + var n = arguments.length; + if (n < 2) delay = 0; + if (n < 3) then = Date.now(); + d3_timer_active.callback = callback; + d3_timer_active.time = then + delay; + } + function d3_timer_mark() { + var now = Date.now(); + d3_timer_active = d3_timer_queueHead; + while (d3_timer_active) { + if (now >= d3_timer_active.time) d3_timer_active.flush = d3_timer_active.callback(now - d3_timer_active.time); + d3_timer_active = d3_timer_active.next; + } + return now; + } + function d3_timer_sweep() { + var t0, t1 = d3_timer_queueHead, time = Infinity; + while (t1) { + if (t1.flush) { + t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next; + } else { + if (t1.time < time) time = t1.time; + t1 = (t0 = t1).next; + } + } + d3_timer_queueTail = t0; + return time; + } + var d3_format_decimalPoint = ".", d3_format_thousandsSeparator = ",", d3_format_grouping = [ 3, 3 ], d3_format_currencySymbol = "$"; + var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); + d3.formatPrefix = function(value, precision) { + var i = 0; + if (value) { + if (value < 0) value *= -1; + if (precision) value = d3.round(value, d3_format_precision(value, precision)); + i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); + i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); + } + return d3_formatPrefixes[8 + i / 3]; + }; + function d3_formatPrefix(d, i) { + var k = Math.pow(10, Math.abs(8 - i) * 3); + return { + scale: i > 8 ? function(d) { + return d / k; + } : function(d) { + return d * k; + }, + symbol: d + }; + } + d3.round = function(x, n) { + return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); + }; + d3.format = function(specifier) { + var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; + if (precision) precision = +precision.substring(1); + if (zfill || fill === "0" && align === "=") { + zfill = fill = "0"; + align = "="; + if (comma) width -= Math.floor((width - 1) / 4); + } + switch (type) { + case "n": + comma = true; + type = "g"; + break; + + case "%": + scale = 100; + suffix = "%"; + type = "f"; + break; + + case "p": + scale = 100; + suffix = "%"; + type = "r"; + break; + + case "b": + case "o": + case "x": + case "X": + if (symbol === "#") symbol = "0" + type.toLowerCase(); + + case "c": + case "d": + integer = true; + precision = 0; + break; + + case "s": + scale = -1; + type = "r"; + break; + } + if (symbol === "#") symbol = ""; else if (symbol === "$") symbol = d3_format_currencySymbol; + if (type == "r" && !precision) type = "g"; + if (precision != null) { + if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision)); + } + type = d3_format_types.get(type) || d3_format_typeDefault; + var zcomma = zfill && comma; + return function(value) { + if (integer && value % 1) return ""; + var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign; + if (scale < 0) { + var prefix = d3.formatPrefix(value, precision); + value = prefix.scale(value); + suffix = prefix.symbol; + } else { + value *= scale; + } + value = type(value, precision); + var i = value.lastIndexOf("."), before = i < 0 ? value : value.substring(0, i), after = i < 0 ? "" : d3_format_decimalPoint + value.substring(i + 1); + if (!zfill && comma) before = d3_format_group(before); + var length = symbol.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : ""; + if (zcomma) before = d3_format_group(padding + before); + negative += symbol; + value = before + after; + return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + suffix; + }; + }; + var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i; + var d3_format_types = d3.map({ + b: function(x) { + return x.toString(2); + }, + c: function(x) { + return String.fromCharCode(x); + }, + o: function(x) { + return x.toString(8); + }, + x: function(x) { + return x.toString(16); + }, + X: function(x) { + return x.toString(16).toUpperCase(); + }, + g: function(x, p) { + return x.toPrecision(p); + }, + e: function(x, p) { + return x.toExponential(p); + }, + f: function(x, p) { + return x.toFixed(p); + }, + r: function(x, p) { + return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p)))); + } + }); + function d3_format_precision(x, p) { + return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1); + } + function d3_format_typeDefault(x) { + return x + ""; + } + var d3_format_group = d3_identity; + if (d3_format_grouping) { + var d3_format_groupingLength = d3_format_grouping.length; + d3_format_group = function(value) { + var i = value.length, t = [], j = 0, g = d3_format_grouping[0]; + while (i > 0 && g > 0) { + t.push(value.substring(i -= g, i + g)); + g = d3_format_grouping[j = (j + 1) % d3_format_groupingLength]; + } + return t.reverse().join(d3_format_thousandsSeparator); + }; + } + d3.geo = {}; + function d3_adder() {} + d3_adder.prototype = { + s: 0, + t: 0, + add: function(y) { + d3_adderSum(y, this.t, d3_adderTemp); + d3_adderSum(d3_adderTemp.s, this.s, this); + if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t; + }, + reset: function() { + this.s = this.t = 0; + }, + valueOf: function() { + return this.s; + } + }; + var d3_adderTemp = new d3_adder(); + function d3_adderSum(a, b, o) { + var x = o.s = a + b, bv = x - a, av = x - bv; + o.t = a - av + (b - bv); + } + d3.geo.stream = function(object, listener) { + if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { + d3_geo_streamObjectType[object.type](object, listener); + } else { + d3_geo_streamGeometry(object, listener); + } + }; + function d3_geo_streamGeometry(geometry, listener) { + if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { + d3_geo_streamGeometryType[geometry.type](geometry, listener); + } + } + var d3_geo_streamObjectType = { + Feature: function(feature, listener) { + d3_geo_streamGeometry(feature.geometry, listener); + }, + FeatureCollection: function(object, listener) { + var features = object.features, i = -1, n = features.length; + while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); + } + }; + var d3_geo_streamGeometryType = { + Sphere: function(object, listener) { + listener.sphere(); + }, + Point: function(object, listener) { + var coordinate = object.coordinates; + listener.point(coordinate[0], coordinate[1]); + }, + MultiPoint: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length, coordinate; + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + }, + LineString: function(object, listener) { + d3_geo_streamLine(object.coordinates, listener, 0); + }, + MultiLineString: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); + }, + Polygon: function(object, listener) { + d3_geo_streamPolygon(object.coordinates, listener); + }, + MultiPolygon: function(object, listener) { + var coordinates = object.coordinates, i = -1, n = coordinates.length; + while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); + }, + GeometryCollection: function(object, listener) { + var geometries = object.geometries, i = -1, n = geometries.length; + while (++i < n) d3_geo_streamGeometry(geometries[i], listener); + } + }; + function d3_geo_streamLine(coordinates, listener, closed) { + var i = -1, n = coordinates.length - closed, coordinate; + listener.lineStart(); + while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1]); + listener.lineEnd(); + } + function d3_geo_streamPolygon(coordinates, listener) { + var i = -1, n = coordinates.length; + listener.polygonStart(); + while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); + listener.polygonEnd(); + } + d3.geo.area = function(object) { + d3_geo_areaSum = 0; + d3.geo.stream(object, d3_geo_area); + return d3_geo_areaSum; + }; + var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder(); + var d3_geo_area = { + sphere: function() { + d3_geo_areaSum += 4 * π; + }, + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_areaRingSum.reset(); + d3_geo_area.lineStart = d3_geo_areaRingStart; + }, + polygonEnd: function() { + var area = 2 * d3_geo_areaRingSum; + d3_geo_areaSum += area < 0 ? 4 * π + area : area; + d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; + } + }; + function d3_geo_areaRingStart() { + var λ00, φ00, λ0, cosφ0, sinφ0; + d3_geo_area.point = function(λ, φ) { + d3_geo_area.point = nextPoint; + λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), + sinφ0 = Math.sin(φ); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + φ = φ * d3_radians / 2 + π / 4; + var dλ = λ - λ0, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(dλ), v = k * Math.sin(dλ); + d3_geo_areaRingSum.add(Math.atan2(v, u)); + λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; + } + d3_geo_area.lineEnd = function() { + nextPoint(λ00, φ00); + }; + } + function d3_geo_cartesian(spherical) { + var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ); + return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ]; + } + function d3_geo_cartesianDot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + function d3_geo_cartesianCross(a, b) { + return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ]; + } + function d3_geo_cartesianAdd(a, b) { + a[0] += b[0]; + a[1] += b[1]; + a[2] += b[2]; + } + function d3_geo_cartesianScale(vector, k) { + return [ vector[0] * k, vector[1] * k, vector[2] * k ]; + } + function d3_geo_cartesianNormalize(d) { + var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); + d[0] /= l; + d[1] /= l; + d[2] /= l; + } + function d3_geo_spherical(cartesian) { + return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ]; + } + function d3_geo_sphericalEqual(a, b) { + return Math.abs(a[0] - b[0]) < ε && Math.abs(a[1] - b[1]) < ε; + } + d3.geo.bounds = function() { + var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range; + var bound = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + bound.point = ringPoint; + bound.lineStart = ringStart; + bound.lineEnd = ringEnd; + dλSum = 0; + d3_geo_area.polygonStart(); + }, + polygonEnd: function() { + d3_geo_area.polygonEnd(); + bound.point = point; + bound.lineStart = lineStart; + bound.lineEnd = lineEnd; + if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90; + range[0] = λ0, range[1] = λ1; + } + }; + function point(λ, φ) { + ranges.push(range = [ λ0 = λ, λ1 = λ ]); + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + function linePoint(λ, φ) { + var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]); + if (p0) { + var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal); + d3_geo_cartesianNormalize(inflection); + inflection = d3_geo_spherical(inflection); + var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = Math.abs(dλ) > 180; + if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = inflection[1] * d3_degrees; + if (φi > φ1) φ1 = φi; + } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { + var φi = -inflection[1] * d3_degrees; + if (φi < φ0) φ0 = φi; + } else { + if (φ < φ0) φ0 = φ; + if (φ > φ1) φ1 = φ; + } + if (antimeridian) { + if (λ < λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } else { + if (λ1 >= λ0) { + if (λ < λ0) λ0 = λ; + if (λ > λ1) λ1 = λ; + } else { + if (λ > λ_) { + if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; + } else { + if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; + } + } + } + } else { + point(λ, φ); + } + p0 = p, λ_ = λ; + } + function lineStart() { + bound.point = linePoint; + } + function lineEnd() { + range[0] = λ0, range[1] = λ1; + bound.point = point; + p0 = null; + } + function ringPoint(λ, φ) { + if (p0) { + var dλ = λ - λ_; + dλSum += Math.abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; + } else λ__ = λ, φ__ = φ; + d3_geo_area.point(λ, φ); + linePoint(λ, φ); + } + function ringStart() { + d3_geo_area.lineStart(); + } + function ringEnd() { + ringPoint(λ__, φ__); + d3_geo_area.lineEnd(); + if (Math.abs(dλSum) > ε) λ0 = -(λ1 = 180); + range[0] = λ0, range[1] = λ1; + p0 = null; + } + function angle(λ0, λ1) { + return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; + } + function compareRanges(a, b) { + return a[0] - b[0]; + } + function withinRange(x, range) { + return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; + } + return function(feature) { + φ1 = λ1 = -(λ0 = φ0 = Infinity); + ranges = []; + d3.geo.stream(feature, bound); + var n = ranges.length; + if (n) { + ranges.sort(compareRanges); + for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) { + b = ranges[i]; + if (withinRange(b[0], a) || withinRange(b[1], a)) { + if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; + if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; + } else { + merged.push(a = b); + } + } + var best = -Infinity, dλ; + for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { + b = merged[i]; + if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; + } + } + ranges = range = null; + return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ]; + }; + }(); + d3.geo.centroid = function(object) { + d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, d3_geo_centroid); + var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z; + if (m < ε2) { + x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; + if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; + m = x * x + y * y + z * z; + if (m < ε2) return [ NaN, NaN ]; + } + return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ]; + }; + var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2; + var d3_geo_centroid = { + sphere: d3_noop, + point: d3_geo_centroidPoint, + lineStart: d3_geo_centroidLineStart, + lineEnd: d3_geo_centroidLineEnd, + polygonStart: function() { + d3_geo_centroid.lineStart = d3_geo_centroidRingStart; + }, + polygonEnd: function() { + d3_geo_centroid.lineStart = d3_geo_centroidLineStart; + } + }; + function d3_geo_centroidPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); + } + function d3_geo_centroidPointXYZ(x, y, z) { + ++d3_geo_centroidW0; + d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; + d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; + d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; + } + function d3_geo_centroidLineStart() { + var x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroid.point = nextPoint; + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z); + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_geo_centroidLineEnd() { + d3_geo_centroid.point = d3_geo_centroidPoint; + } + function d3_geo_centroidRingStart() { + var λ00, φ00, x0, y0, z0; + d3_geo_centroid.point = function(λ, φ) { + λ00 = λ, φ00 = φ; + d3_geo_centroid.point = nextPoint; + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians); + x0 = cosφ * Math.cos(λ); + y0 = cosφ * Math.sin(λ); + z0 = Math.sin(φ); + d3_geo_centroidPointXYZ(x0, y0, z0); + }; + d3_geo_centroid.lineEnd = function() { + nextPoint(λ00, φ00); + d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; + d3_geo_centroid.point = d3_geo_centroidPoint; + }; + function nextPoint(λ, φ) { + λ *= d3_radians; + var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u); + d3_geo_centroidX2 += v * cx; + d3_geo_centroidY2 += v * cy; + d3_geo_centroidZ2 += v * cz; + d3_geo_centroidW1 += w; + d3_geo_centroidX1 += w * (x0 + (x0 = x)); + d3_geo_centroidY1 += w * (y0 + (y0 = y)); + d3_geo_centroidZ1 += w * (z0 + (z0 = z)); + d3_geo_centroidPointXYZ(x0, y0, z0); + } + } + function d3_true() { + return true; + } + function d3_geo_clipPolygon(segments, compare, inside, interpolate, listener) { + var subject = [], clip = []; + segments.forEach(function(segment) { + if ((n = segment.length - 1) <= 0) return; + var n, p0 = segment[0], p1 = segment[n]; + if (d3_geo_sphericalEqual(p0, p1)) { + listener.lineStart(); + for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); + listener.lineEnd(); + return; + } + var a = { + point: p0, + points: segment, + other: null, + visited: false, + entry: true, + subject: true + }, b = { + point: p0, + points: [ p0 ], + other: a, + visited: false, + entry: false, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + a = { + point: p1, + points: [ p1 ], + other: null, + visited: false, + entry: false, + subject: true + }; + b = { + point: p1, + points: [ p1 ], + other: a, + visited: false, + entry: true, + subject: false + }; + a.other = b; + subject.push(a); + clip.push(b); + }); + clip.sort(compare); + d3_geo_clipPolygonLinkCircular(subject); + d3_geo_clipPolygonLinkCircular(clip); + if (!subject.length) return; + if (inside) for (var i = 1, e = !inside(clip[0].point), n = clip.length; i < n; ++i) { + clip[i].entry = e = !e; + } + var start = subject[0], current, points, point; + while (1) { + current = start; + while (current.visited) if ((current = current.next) === start) return; + points = current.points; + listener.lineStart(); + do { + current.visited = current.other.visited = true; + if (current.entry) { + if (current.subject) { + for (var i = 0; i < points.length; i++) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.next.point, 1, listener); + } + current = current.next; + } else { + if (current.subject) { + points = current.prev.points; + for (var i = points.length; --i >= 0; ) listener.point((point = points[i])[0], point[1]); + } else { + interpolate(current.point, current.prev.point, -1, listener); + } + current = current.prev; + } + current = current.other; + points = current.points; + } while (!current.visited); + listener.lineEnd(); + } + } + function d3_geo_clipPolygonLinkCircular(array) { + if (!(n = array.length)) return; + var n, i = 0, a = array[0], b; + while (++i < n) { + a.next = b = array[i]; + b.prev = a; + a = b; + } + a.next = b = array[0]; + b.prev = a; + } + function d3_geo_clip(pointVisible, clipLine, interpolate, polygonContains) { + return function(listener) { + var line = clipLine(listener); + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + clip.point = pointRing; + clip.lineStart = ringStart; + clip.lineEnd = ringEnd; + segments = []; + polygon = []; + listener.polygonStart(); + }, + polygonEnd: function() { + clip.point = point; + clip.lineStart = lineStart; + clip.lineEnd = lineEnd; + segments = d3.merge(segments); + if (segments.length) { + d3_geo_clipPolygon(segments, d3_geo_clipSort, null, interpolate, listener); + } else if (polygonContains(polygon)) { + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + } + listener.polygonEnd(); + segments = polygon = null; + }, + sphere: function() { + listener.polygonStart(); + listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(); + listener.polygonEnd(); + } + }; + function point(λ, φ) { + if (pointVisible(λ, φ)) listener.point(λ, φ); + } + function pointLine(λ, φ) { + line.point(λ, φ); + } + function lineStart() { + clip.point = pointLine; + line.lineStart(); + } + function lineEnd() { + clip.point = point; + line.lineEnd(); + } + var segments; + var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; + function pointRing(λ, φ) { + ringListener.point(λ, φ); + ring.push([ λ, φ ]); + } + function ringStart() { + ringListener.lineStart(); + ring = []; + } + function ringEnd() { + pointRing(ring[0][0], ring[0][1]); + ringListener.lineEnd(); + var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length; + ring.pop(); + polygon.push(ring); + ring = null; + if (!n) return; + if (clean & 1) { + segment = ringSegments[0]; + var n = segment.length - 1, i = -1, point; + listener.lineStart(); + while (++i < n) listener.point((point = segment[i])[0], point[1]); + listener.lineEnd(); + return; + } + if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); + segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); + } + return clip; + }; + } + function d3_geo_clipSegmentLength1(segment) { + return segment.length > 1; + } + function d3_geo_clipBufferListener() { + var lines = [], line; + return { + lineStart: function() { + lines.push(line = []); + }, + point: function(λ, φ) { + line.push([ λ, φ ]); + }, + lineEnd: d3_noop, + buffer: function() { + var buffer = lines; + lines = []; + line = null; + return buffer; + }, + rejoin: function() { + if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); + } + }; + } + function d3_geo_clipSort(a, b) { + return ((a = a.point)[0] < 0 ? a[1] - π / 2 - ε : π / 2 - a[1]) - ((b = b.point)[0] < 0 ? b[1] - π / 2 - ε : π / 2 - b[1]); + } + function d3_geo_pointInPolygon(point, polygon) { + var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, polar = false, southPole = false, winding = 0; + d3_geo_areaRingSum.reset(); + for (var i = 0, n = polygon.length; i < n; ++i) { + var ring = polygon[i], m = ring.length; + if (!m) continue; + var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1; + while (true) { + if (j === m) j = 0; + point = ring[j]; + var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, antimeridian = Math.abs(dλ) > π, k = sinφ0 * sinφ; + d3_geo_areaRingSum.add(Math.atan2(k * Math.sin(dλ), cosφ0 * cosφ + k * Math.cos(dλ))); + if (Math.abs(φ) < ε) southPole = true; + polarAngle += antimeridian ? dλ + (dλ >= 0 ? 2 : -2) * π : dλ; + if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { + var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); + d3_geo_cartesianNormalize(arc); + var intersection = d3_geo_cartesianCross(meridianNormal, arc); + d3_geo_cartesianNormalize(intersection); + var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); + if (parallel > φarc) { + winding += antimeridian ^ dλ >= 0 ? 1 : -1; + } + } + if (!j++) break; + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; + } + if (Math.abs(polarAngle) > ε) polar = true; + } + return (!southPole && !polar && d3_geo_areaRingSum < 0 || polarAngle < -ε) ^ winding & 1; + } + var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, d3_geo_clipAntimeridianPolygonContains); + function d3_geo_clipAntimeridianLine(listener) { + var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean; + return { + lineStart: function() { + listener.lineStart(); + clean = 1; + }, + point: function(λ1, φ1) { + var sλ1 = λ1 > 0 ? π : -π, dλ = Math.abs(λ1 - λ0); + if (Math.abs(dλ - π) < ε) { + listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? π / 2 : -π / 2); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + listener.point(λ1, φ0); + clean = 0; + } else if (sλ0 !== sλ1 && dλ >= π) { + if (Math.abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; + if (Math.abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; + φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); + listener.point(sλ0, φ0); + listener.lineEnd(); + listener.lineStart(); + listener.point(sλ1, φ0); + clean = 0; + } + listener.point(λ0 = λ1, φ0 = φ1); + sλ0 = sλ1; + }, + lineEnd: function() { + listener.lineEnd(); + λ0 = φ0 = NaN; + }, + clean: function() { + return 2 - clean; + } + }; + } + function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { + var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1); + return Math.abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2; + } + function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { + var φ; + if (from == null) { + φ = direction * π / 2; + listener.point(-π, φ); + listener.point(0, φ); + listener.point(π, φ); + listener.point(π, 0); + listener.point(π, -φ); + listener.point(0, -φ); + listener.point(-π, -φ); + listener.point(-π, 0); + listener.point(-π, φ); + } else if (Math.abs(from[0] - to[0]) > ε) { + var s = (from[0] < to[0] ? 1 : -1) * π; + φ = direction * s / 2; + listener.point(-s, φ); + listener.point(0, φ); + listener.point(s, φ); + } else { + listener.point(to[0], to[1]); + } + } + var d3_geo_clipAntimeridianPoint = [ -π, 0 ]; + function d3_geo_clipAntimeridianPolygonContains(polygon) { + return d3_geo_pointInPolygon(d3_geo_clipAntimeridianPoint, polygon); + } + function d3_geo_clipCircle(radius) { + var cr = Math.cos(radius), smallRadius = cr > 0, point = [ radius, 0 ], notHemisphere = Math.abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); + return d3_geo_clip(visible, clipLine, interpolate, polygonContains); + function visible(λ, φ) { + return Math.cos(λ) * Math.cos(φ) > cr; + } + function clipLine(listener) { + var point0, c0, v0, v00, clean; + return { + lineStart: function() { + v00 = v0 = false; + clean = 1; + }, + point: function(λ, φ) { + var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; + if (!point0 && (v00 = v0 = v)) listener.lineStart(); + if (v !== v0) { + point2 = intersect(point0, point1); + if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { + point1[0] += ε; + point1[1] += ε; + v = visible(point1[0], point1[1]); + } + } + if (v !== v0) { + clean = 0; + if (v) { + listener.lineStart(); + point2 = intersect(point1, point0); + listener.point(point2[0], point2[1]); + } else { + point2 = intersect(point0, point1); + listener.point(point2[0], point2[1]); + listener.lineEnd(); + } + point0 = point2; + } else if (notHemisphere && point0 && smallRadius ^ v) { + var t; + if (!(c & c0) && (t = intersect(point1, point0, true))) { + clean = 0; + if (smallRadius) { + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + } else { + listener.point(t[1][0], t[1][1]); + listener.lineEnd(); + listener.lineStart(); + listener.point(t[0][0], t[0][1]); + } + } + } + if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { + listener.point(point1[0], point1[1]); + } + point0 = point1, v0 = v, c0 = c; + }, + lineEnd: function() { + if (v0) listener.lineEnd(); + point0 = null; + }, + clean: function() { + return clean | (v00 && v0) << 1; + } + }; + } + function intersect(a, b, two) { + var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b); + var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2; + if (!determinant) return !two && a; + var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2); + d3_geo_cartesianAdd(A, B); + var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); + if (t2 < 0) return; + var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu); + d3_geo_cartesianAdd(q, A); + q = d3_geo_spherical(q); + if (!two) return q; + var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z; + if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; + var δλ = λ1 - λ0, polar = Math.abs(δλ - π) < ε, meridian = polar || δλ < ε; + if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; + if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (Math.abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { + var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); + d3_geo_cartesianAdd(q1, A); + return [ q, d3_geo_spherical(q1) ]; + } + } + function code(λ, φ) { + var r = smallRadius ? radius : π - radius, code = 0; + if (λ < -r) code |= 1; else if (λ > r) code |= 2; + if (φ < -r) code |= 4; else if (φ > r) code |= 8; + return code; + } + function polygonContains(polygon) { + return d3_geo_pointInPolygon(point, polygon); + } + } + var d3_geo_clipViewMAX = 1e9; + function d3_geo_clipView(x0, y0, x1, y1) { + return function(listener) { + var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), segments, polygon, ring; + var clip = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + listener = bufferListener; + segments = []; + polygon = []; + }, + polygonEnd: function() { + listener = listener_; + if ((segments = d3.merge(segments)).length) { + listener.polygonStart(); + d3_geo_clipPolygon(segments, compare, inside, interpolate, listener); + listener.polygonEnd(); + } else if (insidePolygon([ x0, y0 ])) { + listener.polygonStart(), listener.lineStart(); + interpolate(null, null, 1, listener); + listener.lineEnd(), listener.polygonEnd(); + } + segments = polygon = ring = null; + } + }; + function inside(point) { + var a = corner(point, -1), i = insidePolygon([ a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0 ]); + return i; + } + function insidePolygon(p) { + var wn = 0, n = polygon.length, y = p[1]; + for (var i = 0; i < n; ++i) { + for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { + b = v[j]; + if (a[1] <= y) { + if (b[1] > y && isLeft(a, b, p) > 0) ++wn; + } else { + if (b[1] <= y && isLeft(a, b, p) < 0) --wn; + } + a = b; + } + } + return wn !== 0; + } + function isLeft(a, b, c) { + return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]); + } + function interpolate(from, to, direction, listener) { + var a = 0, a1 = 0; + if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) { + do { + listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); + } while ((a = (a + direction + 4) % 4) !== a1); + } else { + listener.point(to[0], to[1]); + } + } + function visible(x, y) { + return x0 <= x && x <= x1 && y0 <= y && y <= y1; + } + function point(x, y) { + if (visible(x, y)) listener.point(x, y); + } + var x__, y__, v__, x_, y_, v_, first; + function lineStart() { + clip.point = linePoint; + if (polygon) polygon.push(ring = []); + first = true; + v_ = false; + x_ = y_ = NaN; + } + function lineEnd() { + if (segments) { + linePoint(x__, y__); + if (v__ && v_) bufferListener.rejoin(); + segments.push(bufferListener.buffer()); + } + clip.point = point; + if (v_) listener.lineEnd(); + } + function linePoint(x, y) { + x = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, x)); + y = Math.max(-d3_geo_clipViewMAX, Math.min(d3_geo_clipViewMAX, y)); + var v = visible(x, y); + if (polygon) ring.push([ x, y ]); + if (first) { + x__ = x, y__ = y, v__ = v; + first = false; + if (v) { + listener.lineStart(); + listener.point(x, y); + } + } else { + if (v && v_) listener.point(x, y); else { + var a = [ x_, y_ ], b = [ x, y ]; + if (clipLine(a, b)) { + if (!v_) { + listener.lineStart(); + listener.point(a[0], a[1]); + } + listener.point(b[0], b[1]); + if (!v) listener.lineEnd(); + } else if (v) { + listener.lineStart(); + listener.point(x, y); + } + } + } + x_ = x, y_ = y, v_ = v; + } + return clip; + }; + function corner(p, direction) { + return Math.abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : Math.abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : Math.abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; + } + function compare(a, b) { + return comparePoints(a.point, b.point); + } + function comparePoints(a, b) { + var ca = corner(a, 1), cb = corner(b, 1); + return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0]; + } + function clipLine(a, b) { + var dx = b[0] - a[0], dy = b[1] - a[1], t = [ 0, 1 ]; + if (Math.abs(dx) < ε && Math.abs(dy) < ε) return x0 <= a[0] && a[0] <= x1 && y0 <= a[1] && a[1] <= y1; + if (d3_geo_clipViewT(x0 - a[0], dx, t) && d3_geo_clipViewT(a[0] - x1, -dx, t) && d3_geo_clipViewT(y0 - a[1], dy, t) && d3_geo_clipViewT(a[1] - y1, -dy, t)) { + if (t[1] < 1) { + b[0] = a[0] + t[1] * dx; + b[1] = a[1] + t[1] * dy; + } + if (t[0] > 0) { + a[0] += t[0] * dx; + a[1] += t[0] * dy; + } + return true; + } + return false; + } + } + function d3_geo_clipViewT(num, denominator, t) { + if (Math.abs(denominator) < ε) return num <= 0; + var u = num / denominator; + if (denominator > 0) { + if (u > t[1]) return false; + if (u > t[0]) t[0] = u; + } else { + if (u < t[0]) return false; + if (u < t[1]) t[1] = u; + } + return true; + } + function d3_geo_compose(a, b) { + function compose(x, y) { + return x = a(x, y), b(x[0], x[1]); + } + if (a.invert && b.invert) compose.invert = function(x, y) { + return x = b.invert(x, y), x && a.invert(x[0], x[1]); + }; + return compose; + } + function d3_geo_conic(projectAt) { + var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1); + p.parallels = function(_) { + if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ]; + return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); + }; + return p; + } + function d3_geo_conicEqualArea(φ0, φ1) { + var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n; + function forward(λ, φ) { + var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; + return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = ρ0 - y; + return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ]; + }; + return forward; + } + (d3.geo.conicEqualArea = function() { + return d3_geo_conic(d3_geo_conicEqualArea); + }).raw = d3_geo_conicEqualArea; + d3.geo.albers = function() { + return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070); + }; + d3.geo.albersUsa = function() { + var lower48 = d3.geo.albers(); + var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]); + var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]); + var point, pointStream = { + point: function(x, y) { + point = [ x, y ]; + } + }, lower48Point, alaskaPoint, hawaiiPoint; + function albersUsa(coordinates) { + var x = coordinates[0], y = coordinates[1]; + point = null; + (lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y); + return point; + } + albersUsa.invert = function(coordinates) { + var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k; + return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates); + }; + albersUsa.stream = function(stream) { + var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream); + return { + point: function(x, y) { + lower48Stream.point(x, y); + alaskaStream.point(x, y); + hawaiiStream.point(x, y); + }, + sphere: function() { + lower48Stream.sphere(); + alaskaStream.sphere(); + hawaiiStream.sphere(); + }, + lineStart: function() { + lower48Stream.lineStart(); + alaskaStream.lineStart(); + hawaiiStream.lineStart(); + }, + lineEnd: function() { + lower48Stream.lineEnd(); + alaskaStream.lineEnd(); + hawaiiStream.lineEnd(); + }, + polygonStart: function() { + lower48Stream.polygonStart(); + alaskaStream.polygonStart(); + hawaiiStream.polygonStart(); + }, + polygonEnd: function() { + lower48Stream.polygonEnd(); + alaskaStream.polygonEnd(); + hawaiiStream.polygonEnd(); + } + }; + }; + albersUsa.precision = function(_) { + if (!arguments.length) return lower48.precision(); + lower48.precision(_); + alaska.precision(_); + hawaii.precision(_); + return albersUsa; + }; + albersUsa.scale = function(_) { + if (!arguments.length) return lower48.scale(); + lower48.scale(_); + alaska.scale(_ * .35); + hawaii.scale(_); + return albersUsa.translate(lower48.translate()); + }; + albersUsa.translate = function(_) { + if (!arguments.length) return lower48.translate(); + var k = lower48.scale(), x = +_[0], y = +_[1]; + lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point; + alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point; + return albersUsa; + }; + return albersUsa.scale(1070); + }; + var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { + point: d3_noop, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: function() { + d3_geo_pathAreaPolygon = 0; + d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; + }, + polygonEnd: function() { + d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; + d3_geo_pathAreaSum += Math.abs(d3_geo_pathAreaPolygon / 2); + } + }; + function d3_geo_pathAreaRingStart() { + var x00, y00, x0, y0; + d3_geo_pathArea.point = function(x, y) { + d3_geo_pathArea.point = nextPoint; + x00 = x0 = x, y00 = y0 = y; + }; + function nextPoint(x, y) { + d3_geo_pathAreaPolygon += y0 * x - x0 * y; + x0 = x, y0 = y; + } + d3_geo_pathArea.lineEnd = function() { + nextPoint(x00, y00); + }; + } + var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1; + var d3_geo_pathBounds = { + point: d3_geo_pathBoundsPoint, + lineStart: d3_noop, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_pathBoundsPoint(x, y) { + if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; + if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; + if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; + if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; + } + function d3_geo_pathBuffer() { + var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = []; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointCircle = d3_geo_pathBufferCircle(_); + return stream; + }, + result: function() { + if (buffer.length) { + var result = buffer.join(""); + buffer = []; + return result; + } + } + }; + function point(x, y) { + buffer.push("M", x, ",", y, pointCircle); + } + function pointLineStart(x, y) { + buffer.push("M", x, ",", y); + stream.point = pointLine; + } + function pointLine(x, y) { + buffer.push("L", x, ",", y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + buffer.push("Z"); + } + return stream; + } + function d3_geo_pathBufferCircle(radius) { + return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z"; + } + var d3_geo_pathCentroid = { + point: d3_geo_pathCentroidPoint, + lineStart: d3_geo_pathCentroidLineStart, + lineEnd: d3_geo_pathCentroidLineEnd, + polygonStart: function() { + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; + }, + polygonEnd: function() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; + d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; + } + }; + function d3_geo_pathCentroidPoint(x, y) { + d3_geo_centroidX0 += x; + d3_geo_centroidY0 += y; + ++d3_geo_centroidZ0; + } + function d3_geo_pathCentroidLineStart() { + var x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + } + function d3_geo_pathCentroidLineEnd() { + d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; + } + function d3_geo_pathCentroidRingStart() { + var x00, y00, x0, y0; + d3_geo_pathCentroid.point = function(x, y) { + d3_geo_pathCentroid.point = nextPoint; + d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); + }; + function nextPoint(x, y) { + var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); + d3_geo_centroidX1 += z * (x0 + x) / 2; + d3_geo_centroidY1 += z * (y0 + y) / 2; + d3_geo_centroidZ1 += z; + z = y0 * x - x0 * y; + d3_geo_centroidX2 += z * (x0 + x); + d3_geo_centroidY2 += z * (y0 + y); + d3_geo_centroidZ2 += z * 3; + d3_geo_pathCentroidPoint(x0 = x, y0 = y); + } + d3_geo_pathCentroid.lineEnd = function() { + nextPoint(x00, y00); + }; + } + function d3_geo_pathContext(context) { + var pointRadius = 4.5; + var stream = { + point: point, + lineStart: function() { + stream.point = pointLineStart; + }, + lineEnd: lineEnd, + polygonStart: function() { + stream.lineEnd = lineEndPolygon; + }, + polygonEnd: function() { + stream.lineEnd = lineEnd; + stream.point = point; + }, + pointRadius: function(_) { + pointRadius = _; + return stream; + }, + result: d3_noop + }; + function point(x, y) { + context.moveTo(x, y); + context.arc(x, y, pointRadius, 0, 2 * π); + } + function pointLineStart(x, y) { + context.moveTo(x, y); + stream.point = pointLine; + } + function pointLine(x, y) { + context.lineTo(x, y); + } + function lineEnd() { + stream.point = point; + } + function lineEndPolygon() { + context.closePath(); + } + return stream; + } + function d3_geo_resample(project) { + var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16; + function resample(stream) { + var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0; + var resample = { + point: point, + lineStart: lineStart, + lineEnd: lineEnd, + polygonStart: function() { + stream.polygonStart(); + resample.lineStart = ringStart; + }, + polygonEnd: function() { + stream.polygonEnd(); + resample.lineStart = lineStart; + } + }; + function point(x, y) { + x = project(x, y); + stream.point(x[0], x[1]); + } + function lineStart() { + x0 = NaN; + resample.point = linePoint; + stream.lineStart(); + } + function linePoint(λ, φ) { + var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ); + resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); + stream.point(x0, y0); + } + function lineEnd() { + resample.point = point; + stream.lineEnd(); + } + function ringStart() { + lineStart(); + resample.point = ringPoint; + resample.lineEnd = ringEnd; + } + function ringPoint(λ, φ) { + linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; + resample.point = linePoint; + } + function ringEnd() { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); + resample.lineEnd = lineEnd; + lineEnd(); + } + return resample; + } + function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { + var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy; + if (d2 > 4 * δ2 && depth--) { + var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = Math.abs(Math.abs(c) - 1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2; + if (dz * dz / d2 > δ2 || Math.abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { + resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); + stream.point(x2, y2); + resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); + } + } + } + resample.precision = function(_) { + if (!arguments.length) return Math.sqrt(δ2); + maxDepth = (δ2 = _ * _) > 0 && 16; + return resample; + }; + return resample; + } + d3.geo.path = function() { + var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream; + function path(object) { + if (object) { + if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); + if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); + d3.geo.stream(object, cacheStream); + } + return contextStream.result(); + } + path.area = function(object) { + d3_geo_pathAreaSum = 0; + d3.geo.stream(object, projectStream(d3_geo_pathArea)); + return d3_geo_pathAreaSum; + }; + path.centroid = function(object) { + d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; + d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); + return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ]; + }; + path.bounds = function(object) { + d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); + d3.geo.stream(object, projectStream(d3_geo_pathBounds)); + return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ]; + }; + path.projection = function(_) { + if (!arguments.length) return projection; + projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; + return reset(); + }; + path.context = function(_) { + if (!arguments.length) return context; + contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_); + if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); + return reset(); + }; + path.pointRadius = function(_) { + if (!arguments.length) return pointRadius; + pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); + return path; + }; + function reset() { + cacheStream = null; + return path; + } + return path.projection(d3.geo.albersUsa()).context(null); + }; + function d3_geo_pathProjectStream(project) { + var resample = d3_geo_resample(function(λ, φ) { + return project([ λ * d3_degrees, φ * d3_degrees ]); + }); + return function(stream) { + stream = resample(stream); + return { + point: function(λ, φ) { + stream.point(λ * d3_radians, φ * d3_radians); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + }; + } + d3.geo.projection = d3_geo_projection; + d3.geo.projectionMutator = d3_geo_projectionMutator; + function d3_geo_projection(project) { + return d3_geo_projectionMutator(function() { + return project; + })(); + } + function d3_geo_projectionMutator(projectAt) { + var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) { + x = project(x, y); + return [ x[0] * k + δx, δy - x[1] * k ]; + }), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream; + function projection(point) { + point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); + return [ point[0] * k + δx, δy - point[1] * k ]; + } + function invert(point) { + point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); + return point && [ point[0] * d3_degrees, point[1] * d3_degrees ]; + } + projection.stream = function(output) { + if (stream) stream.valid = false; + stream = d3_geo_projectionRadiansRotate(rotate, preclip(projectResample(postclip(output)))); + stream.valid = true; + return stream; + }; + projection.clipAngle = function(_) { + if (!arguments.length) return clipAngle; + preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); + return invalidate(); + }; + projection.clipExtent = function(_) { + if (!arguments.length) return clipExtent; + clipExtent = _; + postclip = _ == null ? d3_identity : d3_geo_clipView(_[0][0], _[0][1], _[1][0], _[1][1]); + return invalidate(); + }; + projection.scale = function(_) { + if (!arguments.length) return k; + k = +_; + return reset(); + }; + projection.translate = function(_) { + if (!arguments.length) return [ x, y ]; + x = +_[0]; + y = +_[1]; + return reset(); + }; + projection.center = function(_) { + if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ]; + λ = _[0] % 360 * d3_radians; + φ = _[1] % 360 * d3_radians; + return reset(); + }; + projection.rotate = function(_) { + if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ]; + δλ = _[0] % 360 * d3_radians; + δφ = _[1] % 360 * d3_radians; + δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; + return reset(); + }; + d3.rebind(projection, projectResample, "precision"); + function reset() { + projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); + var center = project(λ, φ); + δx = x - center[0] * k; + δy = y + center[1] * k; + return invalidate(); + } + function invalidate() { + if (stream) { + stream.valid = false; + stream = null; + } + return projection; + } + return function() { + project = projectAt.apply(this, arguments); + projection.invert = project.invert && invert; + return reset(); + }; + } + function d3_geo_projectionRadiansRotate(rotate, stream) { + return { + point: function(x, y) { + y = rotate(x * d3_radians, y * d3_radians), x = y[0]; + stream.point(x > π ? x - 2 * π : x < -π ? x + 2 * π : x, y[1]); + }, + sphere: function() { + stream.sphere(); + }, + lineStart: function() { + stream.lineStart(); + }, + lineEnd: function() { + stream.lineEnd(); + }, + polygonStart: function() { + stream.polygonStart(); + }, + polygonEnd: function() { + stream.polygonEnd(); + } + }; + } + function d3_geo_equirectangular(λ, φ) { + return [ λ, φ ]; + } + (d3.geo.equirectangular = function() { + return d3_geo_projection(d3_geo_equirectangular); + }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; + d3.geo.rotation = function(rotate) { + rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); + function forward(coordinates) { + coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + } + forward.invert = function(coordinates) { + coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); + return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; + }; + return forward; + }; + function d3_geo_rotation(δλ, δφ, δγ) { + return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_equirectangular; + } + function d3_geo_forwardRotationλ(δλ) { + return function(λ, φ) { + return λ += δλ, [ λ > π ? λ - 2 * π : λ < -π ? λ + 2 * π : λ, φ ]; + }; + } + function d3_geo_rotationλ(δλ) { + var rotation = d3_geo_forwardRotationλ(δλ); + rotation.invert = d3_geo_forwardRotationλ(-δλ); + return rotation; + } + function d3_geo_rotationφγ(δφ, δγ) { + var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ); + function rotation(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ; + return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ]; + } + rotation.invert = function(λ, φ) { + var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ; + return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ]; + }; + return rotation; + } + d3.geo.circle = function() { + var origin = [ 0, 0 ], angle, precision = 6, interpolate; + function circle() { + var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = []; + interpolate(null, null, 1, { + point: function(x, y) { + ring.push(x = rotate(x, y)); + x[0] *= d3_degrees, x[1] *= d3_degrees; + } + }); + return { + type: "Polygon", + coordinates: [ ring ] + }; + } + circle.origin = function(x) { + if (!arguments.length) return origin; + origin = x; + return circle; + }; + circle.angle = function(x) { + if (!arguments.length) return angle; + interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); + return circle; + }; + circle.precision = function(_) { + if (!arguments.length) return precision; + interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); + return circle; + }; + return circle.angle(90); + }; + function d3_geo_circleInterpolate(radius, precision) { + var cr = Math.cos(radius), sr = Math.sin(radius); + return function(from, to, direction, listener) { + if (from != null) { + from = d3_geo_circleAngle(cr, from); + to = d3_geo_circleAngle(cr, to); + if (direction > 0 ? from < to : from > to) from += direction * 2 * π; + } else { + from = radius + direction * 2 * π; + to = radius; + } + var point; + for (var step = direction * precision, t = from; direction > 0 ? t > to : t < to; t -= step) { + listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]); + } + }; + } + function d3_geo_circleAngle(cr, point) { + var a = d3_geo_cartesian(point); + a[0] -= cr; + d3_geo_cartesianNormalize(a); + var angle = d3_acos(-a[1]); + return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); + } + d3.geo.distance = function(a, b) { + var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t; + return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ); + }; + d3.geo.graticule = function() { + var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5; + function graticule() { + return { + type: "MultiLineString", + coordinates: lines() + }; + } + function lines() { + return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) { + return Math.abs(x % DX) > ε; + }).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) { + return Math.abs(y % DY) > ε; + }).map(y)); + } + graticule.lines = function() { + return lines().map(function(coordinates) { + return { + type: "LineString", + coordinates: coordinates + }; + }); + }; + graticule.outline = function() { + return { + type: "Polygon", + coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ] + }; + }; + graticule.extent = function(_) { + if (!arguments.length) return graticule.minorExtent(); + return graticule.majorExtent(_).minorExtent(_); + }; + graticule.majorExtent = function(_) { + if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ]; + X0 = +_[0][0], X1 = +_[1][0]; + Y0 = +_[0][1], Y1 = +_[1][1]; + if (X0 > X1) _ = X0, X0 = X1, X1 = _; + if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _; + return graticule.precision(precision); + }; + graticule.minorExtent = function(_) { + if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ]; + x0 = +_[0][0], x1 = +_[1][0]; + y0 = +_[0][1], y1 = +_[1][1]; + if (x0 > x1) _ = x0, x0 = x1, x1 = _; + if (y0 > y1) _ = y0, y0 = y1, y1 = _; + return graticule.precision(precision); + }; + graticule.step = function(_) { + if (!arguments.length) return graticule.minorStep(); + return graticule.majorStep(_).minorStep(_); + }; + graticule.majorStep = function(_) { + if (!arguments.length) return [ DX, DY ]; + DX = +_[0], DY = +_[1]; + return graticule; + }; + graticule.minorStep = function(_) { + if (!arguments.length) return [ dx, dy ]; + dx = +_[0], dy = +_[1]; + return graticule; + }; + graticule.precision = function(_) { + if (!arguments.length) return precision; + precision = +_; + x = d3_geo_graticuleX(y0, y1, 90); + y = d3_geo_graticuleY(x0, x1, precision); + X = d3_geo_graticuleX(Y0, Y1, 90); + Y = d3_geo_graticuleY(X0, X1, precision); + return graticule; + }; + return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]); + }; + function d3_geo_graticuleX(y0, y1, dy) { + var y = d3.range(y0, y1 - ε, dy).concat(y1); + return function(x) { + return y.map(function(y) { + return [ x, y ]; + }); + }; + } + function d3_geo_graticuleY(x0, x1, dx) { + var x = d3.range(x0, x1 - ε, dx).concat(x1); + return function(y) { + return x.map(function(x) { + return [ x, y ]; + }); + }; + } + function d3_source(d) { + return d.source; + } + function d3_target(d) { + return d.target; + } + d3.geo.greatArc = function() { + var source = d3_source, source_, target = d3_target, target_; + function greatArc() { + return { + type: "LineString", + coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ] + }; + } + greatArc.distance = function() { + return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments)); + }; + greatArc.source = function(_) { + if (!arguments.length) return source; + source = _, source_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.target = function(_) { + if (!arguments.length) return target; + target = _, target_ = typeof _ === "function" ? null : _; + return greatArc; + }; + greatArc.precision = function() { + return arguments.length ? greatArc : 0; + }; + return greatArc; + }; + d3.geo.interpolate = function(source, target) { + return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians); + }; + function d3_geo_interpolate(x0, y0, x1, y1) { + var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d); + var interpolate = d ? function(t) { + var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; + return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ]; + } : function() { + return [ x0 * d3_degrees, y0 * d3_degrees ]; + }; + interpolate.distance = d; + return interpolate; + } + d3.geo.length = function(object) { + d3_geo_lengthSum = 0; + d3.geo.stream(object, d3_geo_length); + return d3_geo_lengthSum; + }; + var d3_geo_lengthSum; + var d3_geo_length = { + sphere: d3_noop, + point: d3_noop, + lineStart: d3_geo_lengthLineStart, + lineEnd: d3_noop, + polygonStart: d3_noop, + polygonEnd: d3_noop + }; + function d3_geo_lengthLineStart() { + var λ0, sinφ0, cosφ0; + d3_geo_length.point = function(λ, φ) { + λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); + d3_geo_length.point = nextPoint; + }; + d3_geo_length.lineEnd = function() { + d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; + }; + function nextPoint(λ, φ) { + var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = Math.abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t); + d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); + λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; + } + } + function d3_geo_azimuthal(scale, angle) { + function azimuthal(λ, φ) { + var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ); + return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ]; + } + azimuthal.invert = function(x, y) { + var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c); + return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ]; + }; + return azimuthal; + } + var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) { + return Math.sqrt(2 / (1 + cosλcosφ)); + }, function(ρ) { + return 2 * Math.asin(ρ / 2); + }); + (d3.geo.azimuthalEqualArea = function() { + return d3_geo_projection(d3_geo_azimuthalEqualArea); + }).raw = d3_geo_azimuthalEqualArea; + var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) { + var c = Math.acos(cosλcosφ); + return c && c / Math.sin(c); + }, d3_identity); + (d3.geo.azimuthalEquidistant = function() { + return d3_geo_projection(d3_geo_azimuthalEquidistant); + }).raw = d3_geo_azimuthalEquidistant; + function d3_geo_conicConformal(φ0, φ1) { + var cosφ0 = Math.cos(φ0), t = function(φ) { + return Math.tan(π / 4 + φ / 2); + }, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n; + if (!n) return d3_geo_mercator; + function forward(λ, φ) { + var ρ = Math.abs(Math.abs(φ) - π / 2) < ε ? 0 : F / Math.pow(t(φ), n); + return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y); + return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - π / 2 ]; + }; + return forward; + } + (d3.geo.conicConformal = function() { + return d3_geo_conic(d3_geo_conicConformal); + }).raw = d3_geo_conicConformal; + function d3_geo_conicEquidistant(φ0, φ1) { + var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0; + if (Math.abs(n) < ε) return d3_geo_equirectangular; + function forward(λ, φ) { + var ρ = G - φ; + return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ]; + } + forward.invert = function(x, y) { + var ρ0_y = G - y; + return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ]; + }; + return forward; + } + (d3.geo.conicEquidistant = function() { + return d3_geo_conic(d3_geo_conicEquidistant); + }).raw = d3_geo_conicEquidistant; + var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / cosλcosφ; + }, Math.atan); + (d3.geo.gnomonic = function() { + return d3_geo_projection(d3_geo_gnomonic); + }).raw = d3_geo_gnomonic; + function d3_geo_mercator(λ, φ) { + return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ]; + } + d3_geo_mercator.invert = function(x, y) { + return [ x, 2 * Math.atan(Math.exp(y)) - π / 2 ]; + }; + function d3_geo_mercatorProjection(project) { + var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto; + m.scale = function() { + var v = scale.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.translate = function() { + var v = translate.apply(m, arguments); + return v === m ? clipAuto ? m.clipExtent(null) : m : v; + }; + m.clipExtent = function(_) { + var v = clipExtent.apply(m, arguments); + if (v === m) { + if (clipAuto = _ == null) { + var k = π * scale(), t = translate(); + clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]); + } + } else if (clipAuto) { + v = null; + } + return v; + }; + return m.clipExtent(null); + } + (d3.geo.mercator = function() { + return d3_geo_mercatorProjection(d3_geo_mercator); + }).raw = d3_geo_mercator; + var d3_geo_orthographic = d3_geo_azimuthal(function() { + return 1; + }, Math.asin); + (d3.geo.orthographic = function() { + return d3_geo_projection(d3_geo_orthographic); + }).raw = d3_geo_orthographic; + var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) { + return 1 / (1 + cosλcosφ); + }, function(ρ) { + return 2 * Math.atan(ρ); + }); + (d3.geo.stereographic = function() { + return d3_geo_projection(d3_geo_stereographic); + }).raw = d3_geo_stereographic; + function d3_geo_transverseMercator(λ, φ) { + var B = Math.cos(φ) * Math.sin(λ); + return [ Math.log((1 + B) / (1 - B)) / 2, Math.atan2(Math.tan(φ), Math.cos(λ)) ]; + } + d3_geo_transverseMercator.invert = function(x, y) { + return [ Math.atan2(d3_sinh(x), Math.cos(y)), d3_asin(Math.sin(y) / d3_cosh(x)) ]; + }; + (d3.geo.transverseMercator = function() { + return d3_geo_mercatorProjection(d3_geo_transverseMercator); + }).raw = d3_geo_transverseMercator; + d3.geom = {}; + d3.svg = {}; + function d3_svg_line(projection) { + var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; + function line(data) { + var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); + function segment() { + segments.push("M", interpolate(projection(points), tension)); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); + } else if (points.length) { + segment(); + points = []; + } + } + if (points.length) segment(); + return segments.length ? segments.join("") : null; + } + line.x = function(_) { + if (!arguments.length) return x; + x = _; + return line; + }; + line.y = function(_) { + if (!arguments.length) return y; + y = _; + return line; + }; + line.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return line; + }; + line.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + return line; + }; + line.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return line; + }; + return line; + } + d3.svg.line = function() { + return d3_svg_line(d3_identity); + }; + function d3_svg_lineX(d) { + return d[0]; + } + function d3_svg_lineY(d) { + return d[1]; + } + var d3_svg_lineInterpolators = d3.map({ + linear: d3_svg_lineLinear, + "linear-closed": d3_svg_lineLinearClosed, + step: d3_svg_lineStep, + "step-before": d3_svg_lineStepBefore, + "step-after": d3_svg_lineStepAfter, + basis: d3_svg_lineBasis, + "basis-open": d3_svg_lineBasisOpen, + "basis-closed": d3_svg_lineBasisClosed, + bundle: d3_svg_lineBundle, + cardinal: d3_svg_lineCardinal, + "cardinal-open": d3_svg_lineCardinalOpen, + "cardinal-closed": d3_svg_lineCardinalClosed, + monotone: d3_svg_lineMonotone + }); + d3_svg_lineInterpolators.forEach(function(key, value) { + value.key = key; + value.closed = /-closed$/.test(key); + }); + function d3_svg_lineLinear(points) { + return points.join("L"); + } + function d3_svg_lineLinearClosed(points) { + return d3_svg_lineLinear(points) + "Z"; + } + function d3_svg_lineStep(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]); + if (n > 1) path.push("H", p[0]); + return path.join(""); + } + function d3_svg_lineStepBefore(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); + return path.join(""); + } + function d3_svg_lineStepAfter(points) { + var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; + while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); + return path.join(""); + } + function d3_svg_lineCardinalOpen(points, tension) { + return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineCardinalClosed(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), + points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); + } + function d3_svg_lineCardinal(points, tension) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); + } + function d3_svg_lineHermite(points, tangents) { + if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { + return d3_svg_lineLinear(points); + } + var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; + if (quad) { + path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; + p0 = points[1]; + pi = 2; + } + if (tangents.length > 1) { + t = tangents[1]; + p = points[pi]; + pi++; + path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + for (var i = 2; i < tangents.length; i++, pi++) { + p = points[pi]; + t = tangents[i]; + path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; + } + } + if (quad) { + var lp = points[pi]; + path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; + } + return path; + } + function d3_svg_lineCardinalTangents(points, tension) { + var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; + while (++i < n) { + p0 = p1; + p1 = p2; + p2 = points[i]; + tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); + } + return tangents; + } + function d3_svg_lineBasis(points) { + if (points.length < 3) return d3_svg_lineLinear(points); + var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + points.push(points[n - 1]); + while (++i <= n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + points.pop(); + path.push("L", pi); + return path.join(""); + } + function d3_svg_lineBasisOpen(points) { + if (points.length < 4) return d3_svg_lineLinear(points); + var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; + while (++i < 3) { + pi = points[i]; + px.push(pi[0]); + py.push(pi[1]); + } + path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); + --i; + while (++i < n) { + pi = points[i]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBasisClosed(points) { + var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; + while (++i < 4) { + pi = points[i % n]; + px.push(pi[0]); + py.push(pi[1]); + } + path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; + --i; + while (++i < m) { + pi = points[i % n]; + px.shift(); + px.push(pi[0]); + py.shift(); + py.push(pi[1]); + d3_svg_lineBasisBezier(path, px, py); + } + return path.join(""); + } + function d3_svg_lineBundle(points, tension) { + var n = points.length - 1; + if (n) { + var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; + while (++i <= n) { + p = points[i]; + t = i / n; + p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); + p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); + } + } + return d3_svg_lineBasis(points); + } + function d3_svg_lineDot4(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; + function d3_svg_lineBasisBezier(path, x, y) { + path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); + } + function d3_svg_lineSlope(p0, p1) { + return (p1[1] - p0[1]) / (p1[0] - p0[0]); + } + function d3_svg_lineFiniteDifferences(points) { + var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); + while (++i < j) { + m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; + } + m[i] = d; + return m; + } + function d3_svg_lineMonotoneTangents(points) { + var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; + while (++i < j) { + d = d3_svg_lineSlope(points[i], points[i + 1]); + if (Math.abs(d) < 1e-6) { + m[i] = m[i + 1] = 0; + } else { + a = m[i] / d; + b = m[i + 1] / d; + s = a * a + b * b; + if (s > 9) { + s = d * 3 / Math.sqrt(s); + m[i] = s * a; + m[i + 1] = s * b; + } + } + } + i = -1; + while (++i <= j) { + s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); + tangents.push([ s || 0, m[i] * s || 0 ]); + } + return tangents; + } + function d3_svg_lineMonotone(points) { + return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); + } + d3.geom.hull = function(vertices) { + var x = d3_svg_lineX, y = d3_svg_lineY; + if (arguments.length) return hull(vertices); + function hull(data) { + if (data.length < 3) return []; + var fx = d3_functor(x), fy = d3_functor(y), n = data.length, vertices, plen = n - 1, points = [], stack = [], d, i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; + if (fx === d3_svg_lineX && y === d3_svg_lineY) vertices = data; else for (i = 0, + vertices = []; i < n; ++i) { + vertices.push([ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]); + } + for (i = 1; i < n; ++i) { + if (vertices[i][1] < vertices[h][1] || vertices[i][1] == vertices[h][1] && vertices[i][0] < vertices[h][0]) h = i; + } + for (i = 0; i < n; ++i) { + if (i === h) continue; + y1 = vertices[i][1] - vertices[h][1]; + x1 = vertices[i][0] - vertices[h][0]; + points.push({ + angle: Math.atan2(y1, x1), + index: i + }); + } + points.sort(function(a, b) { + return a.angle - b.angle; + }); + a = points[0].angle; + v = points[0].index; + u = 0; + for (i = 1; i < plen; ++i) { + j = points[i].index; + if (a == points[i].angle) { + x1 = vertices[v][0] - vertices[h][0]; + y1 = vertices[v][1] - vertices[h][1]; + x2 = vertices[j][0] - vertices[h][0]; + y2 = vertices[j][1] - vertices[h][1]; + if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { + points[i].index = -1; + continue; + } else { + points[u].index = -1; + } + } + a = points[i].angle; + u = i; + v = j; + } + stack.push(h); + for (i = 0, j = 0; i < 2; ++j) { + if (points[j].index > -1) { + stack.push(points[j].index); + i++; + } + } + sp = stack.length; + for (;j < plen; ++j) { + if (points[j].index < 0) continue; + while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { + --sp; + } + stack[sp++] = points[j].index; + } + var poly = []; + for (i = sp - 1; i >= 0; --i) poly.push(data[stack[i]]); + return poly; + } + hull.x = function(_) { + return arguments.length ? (x = _, hull) : x; + }; + hull.y = function(_) { + return arguments.length ? (y = _, hull) : y; + }; + return hull; + }; + function d3_geom_hullCCW(i1, i2, i3, v) { + var t, a, b, c, d, e, f; + t = v[i1]; + a = t[0]; + b = t[1]; + t = v[i2]; + c = t[0]; + d = t[1]; + t = v[i3]; + e = t[0]; + f = t[1]; + return (f - b) * (c - a) - (d - b) * (e - a) > 0; + } + d3.geom.polygon = function(coordinates) { + d3_subclass(coordinates, d3_geom_polygonPrototype); + return coordinates; + }; + var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; + d3_geom_polygonPrototype.area = function() { + var i = -1, n = this.length, a, b = this[n - 1], area = 0; + while (++i < n) { + a = b; + b = this[i]; + area += a[1] * b[0] - a[0] * b[1]; + } + return area * .5; + }; + d3_geom_polygonPrototype.centroid = function(k) { + var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c; + if (!arguments.length) k = -1 / (6 * this.area()); + while (++i < n) { + a = b; + b = this[i]; + c = a[0] * b[1] - b[0] * a[1]; + x += (a[0] + b[0]) * c; + y += (a[1] + b[1]) * c; + } + return [ x * k, y * k ]; + }; + d3_geom_polygonPrototype.clip = function(subject) { + var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d; + while (++i < n) { + input = subject.slice(); + subject.length = 0; + b = this[i]; + c = input[(m = input.length - closed) - 1]; + j = -1; + while (++j < m) { + d = input[j]; + if (d3_geom_polygonInside(d, a, b)) { + if (!d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + subject.push(d); + } else if (d3_geom_polygonInside(c, a, b)) { + subject.push(d3_geom_polygonIntersect(c, d, a, b)); + } + c = d; + } + if (closed) subject.push(subject[0]); + a = b; + } + return subject; + }; + function d3_geom_polygonInside(p, a, b) { + return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); + } + function d3_geom_polygonIntersect(c, d, a, b) { + var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); + return [ x1 + ua * x21, y1 + ua * y21 ]; + } + function d3_geom_polygonClosed(coordinates) { + var a = coordinates[0], b = coordinates[coordinates.length - 1]; + return !(a[0] - b[0] || a[1] - b[1]); + } + d3.geom.delaunay = function(vertices) { + var edges = vertices.map(function() { + return []; + }), triangles = []; + d3_geom_voronoiTessellate(vertices, function(e) { + edges[e.region.l.index].push(vertices[e.region.r.index]); + }); + edges.forEach(function(edge, i) { + var v = vertices[i], cx = v[0], cy = v[1]; + edge.forEach(function(v) { + v.angle = Math.atan2(v[0] - cx, v[1] - cy); + }); + edge.sort(function(a, b) { + return a.angle - b.angle; + }); + for (var j = 0, m = edge.length - 1; j < m; j++) { + triangles.push([ v, edge[j], edge[j + 1] ]); + } + }); + return triangles; + }; + d3.geom.voronoi = function(points) { + var x = d3_svg_lineX, y = d3_svg_lineY, clipPolygon = null; + if (arguments.length) return voronoi(points); + function voronoi(data) { + var points, polygons = data.map(function() { + return []; + }), fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length, Z = 1e6; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var s1, s2, x1, x2, y1, y2; + if (e.a === 1 && e.b >= 0) { + s1 = e.ep.r; + s2 = e.ep.l; + } else { + s1 = e.ep.l; + s2 = e.ep.r; + } + if (e.a === 1) { + y1 = s1 ? s1.y : -Z; + x1 = e.c - e.b * y1; + y2 = s2 ? s2.y : Z; + x2 = e.c - e.b * y2; + } else { + x1 = s1 ? s1.x : -Z; + y1 = e.c - e.a * x1; + x2 = s2 ? s2.x : Z; + y2 = e.c - e.a * x2; + } + var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; + polygons[e.region.l.index].push(v1, v2); + polygons[e.region.r.index].push(v1, v2); + }); + polygons = polygons.map(function(polygon, i) { + var cx = points[i][0], cy = points[i][1], angle = polygon.map(function(v) { + return Math.atan2(v[0] - cx, v[1] - cy); + }), order = d3.range(polygon.length).sort(function(a, b) { + return angle[a] - angle[b]; + }); + return order.filter(function(d, i) { + return !i || angle[d] - angle[order[i - 1]] > ε; + }).map(function(d) { + return polygon[d]; + }); + }); + polygons.forEach(function(polygon, i) { + var n = polygon.length; + if (!n) return polygon.push([ -Z, -Z ], [ -Z, Z ], [ Z, Z ], [ Z, -Z ]); + if (n > 2) return; + var p0 = points[i], p1 = polygon[0], p2 = polygon[1], x0 = p0[0], y0 = p0[1], x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1], dx = Math.abs(x2 - x1), dy = y2 - y1; + if (Math.abs(dy) < ε) { + var y = y0 < y1 ? -Z : Z; + polygon.push([ -Z, y ], [ Z, y ]); + } else if (dx < ε) { + var x = x0 < x1 ? -Z : Z; + polygon.push([ x, -Z ], [ x, Z ]); + } else { + var y = (x2 - x1) * (y1 - y0) < (x1 - x0) * (y2 - y1) ? Z : -Z, z = Math.abs(dy) - dx; + if (Math.abs(z) < ε) { + polygon.push([ dy < 0 ? y : -y, y ]); + } else { + if (z > 0) y *= -1; + polygon.push([ -Z, y ], [ Z, y ]); + } + } + }); + if (clipPolygon) for (i = 0; i < n; ++i) clipPolygon.clip(polygons[i]); + for (i = 0; i < n; ++i) polygons[i].point = data[i]; + return polygons; + } + voronoi.x = function(_) { + return arguments.length ? (x = _, voronoi) : x; + }; + voronoi.y = function(_) { + return arguments.length ? (y = _, voronoi) : y; + }; + voronoi.clipExtent = function(_) { + if (!arguments.length) return clipPolygon && [ clipPolygon[0], clipPolygon[2] ]; + if (_ == null) clipPolygon = null; else { + var x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], y2 = +_[1][1]; + clipPolygon = d3.geom.polygon([ [ x1, y1 ], [ x1, y2 ], [ x2, y2 ], [ x2, y1 ] ]); + } + return voronoi; + }; + voronoi.size = function(_) { + if (!arguments.length) return clipPolygon && clipPolygon[2]; + return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]); + }; + voronoi.links = function(data) { + var points, graph = data.map(function() { + return []; + }), links = [], fx = d3_functor(x), fy = d3_functor(y), d, i, n = data.length; + if (fx === d3_svg_lineX && fy === d3_svg_lineY) points = data; else for (points = new Array(n), + i = 0; i < n; ++i) { + points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]; + } + d3_geom_voronoiTessellate(points, function(e) { + var l = e.region.l.index, r = e.region.r.index; + if (graph[l][r]) return; + graph[l][r] = graph[r][l] = true; + links.push({ + source: data[l], + target: data[r] + }); + }); + return links; + }; + voronoi.triangles = function(data) { + if (x === d3_svg_lineX && y === d3_svg_lineY) return d3.geom.delaunay(data); + var points = new Array(n), fx = d3_functor(x), fy = d3_functor(y), d, i = -1, n = data.length; + while (++i < n) { + (points[i] = [ +fx.call(this, d = data[i], i), +fy.call(this, d, i) ]).data = d; + } + return d3.geom.delaunay(points).map(function(triangle) { + return triangle.map(function(point) { + return point.data; + }); + }); + }; + return voronoi; + }; + var d3_geom_voronoiOpposite = { + l: "r", + r: "l" + }; + function d3_geom_voronoiTessellate(points, callback) { + var Sites = { + list: points.map(function(v, i) { + return { + index: i, + x: v[0], + y: v[1] + }; + }).sort(function(a, b) { + return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; + }), + bottomSite: null + }; + var EdgeList = { + list: [], + leftEnd: null, + rightEnd: null, + init: function() { + EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); + EdgeList.leftEnd.r = EdgeList.rightEnd; + EdgeList.rightEnd.l = EdgeList.leftEnd; + EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); + }, + createHalfEdge: function(edge, side) { + return { + edge: edge, + side: side, + vertex: null, + l: null, + r: null + }; + }, + insert: function(lb, he) { + he.l = lb; + he.r = lb.r; + lb.r.l = he; + lb.r = he; + }, + leftBound: function(p) { + var he = EdgeList.leftEnd; + do { + he = he.r; + } while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); + he = he.l; + return he; + }, + del: function(he) { + he.l.r = he.r; + he.r.l = he.l; + he.edge = null; + }, + right: function(he) { + return he.r; + }, + left: function(he) { + return he.l; + }, + leftRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; + }, + rightRegion: function(he) { + return he.edge == null ? Sites.bottomSite : he.edge.region[d3_geom_voronoiOpposite[he.side]]; + } + }; + var Geom = { + bisect: function(s1, s2) { + var newEdge = { + region: { + l: s1, + r: s2 + }, + ep: { + l: null, + r: null + } + }; + var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; + newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; + if (adx > ady) { + newEdge.a = 1; + newEdge.b = dy / dx; + newEdge.c /= dx; + } else { + newEdge.b = 1; + newEdge.a = dx / dy; + newEdge.c /= dy; + } + return newEdge; + }, + intersect: function(el1, el2) { + var e1 = el1.edge, e2 = el2.edge; + if (!e1 || !e2 || e1.region.r == e2.region.r) { + return null; + } + var d = e1.a * e2.b - e1.b * e2.a; + if (Math.abs(d) < 1e-10) { + return null; + } + var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; + if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { + el = el1; + e = e1; + } else { + el = el2; + e = e2; + } + var rightOfSite = xint >= e.region.r.x; + if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { + return null; + } + return { + x: xint, + y: yint + }; + }, + rightOf: function(he, p) { + var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; + if (rightOfSite && he.side === "l") { + return 1; + } + if (!rightOfSite && he.side === "r") { + return 0; + } + if (e.a === 1) { + var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; + if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { + above = fast = dyp >= e.b * dxp; + } else { + above = p.x + p.y * e.b > e.c; + if (e.b < 0) { + above = !above; + } + if (!above) { + fast = 1; + } + } + if (!fast) { + var dxs = topsite.x - e.region.l.x; + above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); + if (e.b < 0) { + above = !above; + } + } + } else { + var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; + above = t1 * t1 > t2 * t2 + t3 * t3; + } + return he.side === "l" ? above : !above; + }, + endPoint: function(edge, side, site) { + edge.ep[side] = site; + if (!edge.ep[d3_geom_voronoiOpposite[side]]) return; + callback(edge); + }, + distance: function(s, t) { + var dx = s.x - t.x, dy = s.y - t.y; + return Math.sqrt(dx * dx + dy * dy); + } + }; + var EventQueue = { + list: [], + insert: function(he, site, offset) { + he.vertex = site; + he.ystar = site.y + offset; + for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { + var next = list[i]; + if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { + continue; + } else { + break; + } + } + list.splice(i, 0, he); + }, + del: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} + ls.splice(i, 1); + }, + empty: function() { + return EventQueue.list.length === 0; + }, + nextEvent: function(he) { + for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { + if (ls[i] == he) return ls[i + 1]; + } + return null; + }, + min: function() { + var elem = EventQueue.list[0]; + return { + x: elem.vertex.x, + y: elem.ystar + }; + }, + extractMin: function() { + return EventQueue.list.shift(); + } + }; + EdgeList.init(); + Sites.bottomSite = Sites.list.shift(); + var newSite = Sites.list.shift(), newIntStar; + var lbnd, rbnd, llbnd, rrbnd, bisector; + var bot, top, temp, p, v; + var e, pm; + while (true) { + if (!EventQueue.empty()) { + newIntStar = EventQueue.min(); + } + if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { + lbnd = EdgeList.leftBound(newSite); + rbnd = EdgeList.right(lbnd); + bot = EdgeList.rightRegion(lbnd); + e = Geom.bisect(bot, newSite); + bisector = EdgeList.createHalfEdge(e, "l"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(lbnd, bisector); + if (p) { + EventQueue.del(lbnd); + EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); + } + lbnd = bisector; + bisector = EdgeList.createHalfEdge(e, "r"); + EdgeList.insert(lbnd, bisector); + p = Geom.intersect(bisector, rbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, newSite)); + } + newSite = Sites.list.shift(); + } else if (!EventQueue.empty()) { + lbnd = EventQueue.extractMin(); + llbnd = EdgeList.left(lbnd); + rbnd = EdgeList.right(lbnd); + rrbnd = EdgeList.right(rbnd); + bot = EdgeList.leftRegion(lbnd); + top = EdgeList.rightRegion(rbnd); + v = lbnd.vertex; + Geom.endPoint(lbnd.edge, lbnd.side, v); + Geom.endPoint(rbnd.edge, rbnd.side, v); + EdgeList.del(lbnd); + EventQueue.del(rbnd); + EdgeList.del(rbnd); + pm = "l"; + if (bot.y > top.y) { + temp = bot; + bot = top; + top = temp; + pm = "r"; + } + e = Geom.bisect(bot, top); + bisector = EdgeList.createHalfEdge(e, pm); + EdgeList.insert(llbnd, bisector); + Geom.endPoint(e, d3_geom_voronoiOpposite[pm], v); + p = Geom.intersect(llbnd, bisector); + if (p) { + EventQueue.del(llbnd); + EventQueue.insert(llbnd, p, Geom.distance(p, bot)); + } + p = Geom.intersect(bisector, rrbnd); + if (p) { + EventQueue.insert(bisector, p, Geom.distance(p, bot)); + } + } else { + break; + } + } + for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { + callback(lbnd.edge); + } + } + d3.geom.quadtree = function(points, x1, y1, x2, y2) { + var x = d3_svg_lineX, y = d3_svg_lineY, compat; + if (compat = arguments.length) { + x = d3_geom_quadtreeCompatX; + y = d3_geom_quadtreeCompatY; + if (compat === 3) { + y2 = y1; + x2 = x1; + y1 = x1 = 0; + } + return quadtree(points); + } + function quadtree(data) { + var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_; + if (x1 != null) { + x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2; + } else { + x2_ = y2_ = -(x1_ = y1_ = Infinity); + xs = [], ys = []; + n = data.length; + if (compat) for (i = 0; i < n; ++i) { + d = data[i]; + if (d.x < x1_) x1_ = d.x; + if (d.y < y1_) y1_ = d.y; + if (d.x > x2_) x2_ = d.x; + if (d.y > y2_) y2_ = d.y; + xs.push(d.x); + ys.push(d.y); + } else for (i = 0; i < n; ++i) { + var x_ = +fx(d = data[i], i), y_ = +fy(d, i); + if (x_ < x1_) x1_ = x_; + if (y_ < y1_) y1_ = y_; + if (x_ > x2_) x2_ = x_; + if (y_ > y2_) y2_ = y_; + xs.push(x_); + ys.push(y_); + } + } + var dx = x2_ - x1_, dy = y2_ - y1_; + if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy; + function insert(n, d, x, y, x1, y1, x2, y2) { + if (isNaN(x) || isNaN(y)) return; + if (n.leaf) { + var nx = n.x, ny = n.y; + if (nx != null) { + if (Math.abs(nx - x) + Math.abs(ny - y) < .01) { + insertChild(n, d, x, y, x1, y1, x2, y2); + } else { + var nPoint = n.point; + n.x = n.y = n.point = null; + insertChild(n, nPoint, nx, ny, x1, y1, x2, y2); + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } else { + n.x = x, n.y = y, n.point = d; + } + } else { + insertChild(n, d, x, y, x1, y1, x2, y2); + } + } + function insertChild(n, d, x, y, x1, y1, x2, y2) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = x >= sx, bottom = y >= sy, i = (bottom << 1) + right; + n.leaf = false; + n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); + if (right) x1 = sx; else x2 = sx; + if (bottom) y1 = sy; else y2 = sy; + insert(n, d, x, y, x1, y1, x2, y2); + } + var root = d3_geom_quadtreeNode(); + root.add = function(d) { + insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_); + }; + root.visit = function(f) { + d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_); + }; + i = -1; + if (x1 == null) { + while (++i < n) { + insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_); + } + --i; + } else data.forEach(root.add); + xs = ys = data = d = null; + return root; + } + quadtree.x = function(_) { + return arguments.length ? (x = _, quadtree) : x; + }; + quadtree.y = function(_) { + return arguments.length ? (y = _, quadtree) : y; + }; + quadtree.extent = function(_) { + if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0], + y2 = +_[1][1]; + return quadtree; + }; + quadtree.size = function(_) { + if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ]; + if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1]; + return quadtree; + }; + return quadtree; + }; + function d3_geom_quadtreeCompatX(d) { + return d.x; + } + function d3_geom_quadtreeCompatY(d) { + return d.y; + } + function d3_geom_quadtreeNode() { + return { + leaf: true, + nodes: [], + point: null, + x: null, + y: null + }; + } + function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { + if (!f(node, x1, y1, x2, y2)) { + var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; + if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); + if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); + if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); + if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); + } + } + d3.interpolateRgb = d3_interpolateRgb; + function d3_interpolateRgb(a, b) { + a = d3.rgb(a); + b = d3.rgb(b); + var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; + return function(t) { + return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); + }; + } + d3.interpolateObject = d3_interpolateObject; + function d3_interpolateObject(a, b) { + var i = {}, c = {}, k; + for (k in a) { + if (k in b) { + i[k] = d3_interpolate(a[k], b[k]); + } else { + c[k] = a[k]; + } + } + for (k in b) { + if (!(k in a)) { + c[k] = b[k]; + } + } + return function(t) { + for (k in i) c[k] = i[k](t); + return c; + }; + } + d3.interpolateNumber = d3_interpolateNumber; + function d3_interpolateNumber(a, b) { + b -= a = +a; + return function(t) { + return a + b * t; + }; + } + d3.interpolateString = d3_interpolateString; + function d3_interpolateString(a, b) { + var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; + a = a + "", b = b + ""; + d3_interpolate_number.lastIndex = 0; + for (i = 0; m = d3_interpolate_number.exec(b); ++i) { + if (m.index) s.push(b.substring(s0, s1 = m.index)); + q.push({ + i: s.length, + x: m[0] + }); + s.push(null); + s0 = d3_interpolate_number.lastIndex; + } + if (s0 < b.length) s.push(b.substring(s0)); + for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { + o = q[i]; + if (o.x == m[0]) { + if (o.i) { + if (s[o.i + 1] == null) { + s[o.i - 1] += o.x; + s.splice(o.i, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } else { + s[o.i - 1] += o.x + s[o.i + 1]; + s.splice(o.i, 2); + for (j = i + 1; j < n; ++j) q[j].i -= 2; + } + } else { + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + for (j = i + 1; j < n; ++j) q[j].i--; + } + } + q.splice(i, 1); + n--; + i--; + } else { + o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); + } + } + while (i < n) { + o = q.pop(); + if (s[o.i + 1] == null) { + s[o.i] = o.x; + } else { + s[o.i] = o.x + s[o.i + 1]; + s.splice(o.i + 1, 1); + } + n--; + } + if (s.length === 1) { + return s[0] == null ? (o = q[0].x, function(t) { + return o(t) + ""; + }) : function() { + return b; + }; + } + return function(t) { + for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; + d3.interpolate = d3_interpolate; + function d3_interpolate(a, b) { + var i = d3.interpolators.length, f; + while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; + return f; + } + d3.interpolators = [ function(a, b) { + var t = typeof b; + return (t === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_Color ? d3_interpolateRgb : t === "object" ? Array.isArray(b) ? d3_interpolateArray : d3_interpolateObject : d3_interpolateNumber)(a, b); + } ]; + d3.interpolateArray = d3_interpolateArray; + function d3_interpolateArray(a, b) { + var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; + for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); + for (;i < na; ++i) c[i] = a[i]; + for (;i < nb; ++i) c[i] = b[i]; + return function(t) { + for (i = 0; i < n0; ++i) c[i] = x[i](t); + return c; + }; + } + var d3_ease_default = function() { + return d3_identity; + }; + var d3_ease = d3.map({ + linear: d3_ease_default, + poly: d3_ease_poly, + quad: function() { + return d3_ease_quad; + }, + cubic: function() { + return d3_ease_cubic; + }, + sin: function() { + return d3_ease_sin; + }, + exp: function() { + return d3_ease_exp; + }, + circle: function() { + return d3_ease_circle; + }, + elastic: d3_ease_elastic, + back: d3_ease_back, + bounce: function() { + return d3_ease_bounce; + } + }); + var d3_ease_mode = d3.map({ + "in": d3_identity, + out: d3_ease_reverse, + "in-out": d3_ease_reflect, + "out-in": function(f) { + return d3_ease_reflect(d3_ease_reverse(f)); + } + }); + d3.ease = function(name) { + var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; + t = d3_ease.get(t) || d3_ease_default; + m = d3_ease_mode.get(m) || d3_identity; + return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); + }; + function d3_ease_clamp(f) { + return function(t) { + return t <= 0 ? 0 : t >= 1 ? 1 : f(t); + }; + } + function d3_ease_reverse(f) { + return function(t) { + return 1 - f(1 - t); + }; + } + function d3_ease_reflect(f) { + return function(t) { + return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); + }; + } + function d3_ease_quad(t) { + return t * t; + } + function d3_ease_cubic(t) { + return t * t * t; + } + function d3_ease_cubicInOut(t) { + if (t <= 0) return 0; + if (t >= 1) return 1; + var t2 = t * t, t3 = t2 * t; + return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); + } + function d3_ease_poly(e) { + return function(t) { + return Math.pow(t, e); + }; + } + function d3_ease_sin(t) { + return 1 - Math.cos(t * π / 2); + } + function d3_ease_exp(t) { + return Math.pow(2, 10 * (t - 1)); + } + function d3_ease_circle(t) { + return 1 - Math.sqrt(1 - t * t); + } + function d3_ease_elastic(a, p) { + var s; + if (arguments.length < 2) p = .45; + if (arguments.length) s = p / (2 * π) * Math.asin(1 / a); else a = 1, s = p / 4; + return function(t) { + return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * π / p); + }; + } + function d3_ease_back(s) { + if (!s) s = 1.70158; + return function(t) { + return t * t * ((s + 1) * t - s); + }; + } + function d3_ease_bounce(t) { + return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + } + d3.interpolateHcl = d3_interpolateHcl; + function d3_interpolateHcl(a, b) { + a = d3.hcl(a); + b = d3.hcl(b); + var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; + if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; + }; + } + d3.interpolateHsl = d3_interpolateHsl; + function d3_interpolateHsl(a, b) { + a = d3.hsl(a); + b = d3.hsl(b); + var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; + if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as; + if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; + return function(t) { + return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + ""; + }; + } + d3.interpolateLab = d3_interpolateLab; + function d3_interpolateLab(a, b) { + a = d3.lab(a); + b = d3.lab(b); + var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; + return function(t) { + return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; + }; + } + d3.interpolateRound = d3_interpolateRound; + function d3_interpolateRound(a, b) { + b -= a; + return function(t) { + return Math.round(a + b * t); + }; + } + d3.transform = function(string) { + var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); + return (d3.transform = function(string) { + if (string != null) { + g.setAttribute("transform", string); + var t = g.transform.baseVal.consolidate(); + } + return new d3_transform(t ? t.matrix : d3_transformIdentity); + })(string); + }; + function d3_transform(m) { + var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; + if (r0[0] * r1[1] < r1[0] * r0[1]) { + r0[0] *= -1; + r0[1] *= -1; + kx *= -1; + kz *= -1; + } + this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; + this.translate = [ m.e, m.f ]; + this.scale = [ kx, ky ]; + this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; + } + d3_transform.prototype.toString = function() { + return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; + }; + function d3_transformDot(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + function d3_transformNormalize(a) { + var k = Math.sqrt(d3_transformDot(a, a)); + if (k) { + a[0] /= k; + a[1] /= k; + } + return k; + } + function d3_transformCombine(a, b, k) { + a[0] += k * b[0]; + a[1] += k * b[1]; + return a; + } + var d3_transformIdentity = { + a: 1, + b: 0, + c: 0, + d: 1, + e: 0, + f: 0 + }; + d3.interpolateTransform = d3_interpolateTransform; + function d3_interpolateTransform(a, b) { + var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; + if (ta[0] != tb[0] || ta[1] != tb[1]) { + s.push("translate(", null, ",", null, ")"); + q.push({ + i: 1, + x: d3_interpolateNumber(ta[0], tb[0]) + }, { + i: 3, + x: d3_interpolateNumber(ta[1], tb[1]) + }); + } else if (tb[0] || tb[1]) { + s.push("translate(" + tb + ")"); + } else { + s.push(""); + } + if (ra != rb) { + if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; + q.push({ + i: s.push(s.pop() + "rotate(", null, ")") - 2, + x: d3_interpolateNumber(ra, rb) + }); + } else if (rb) { + s.push(s.pop() + "rotate(" + rb + ")"); + } + if (wa != wb) { + q.push({ + i: s.push(s.pop() + "skewX(", null, ")") - 2, + x: d3_interpolateNumber(wa, wb) + }); + } else if (wb) { + s.push(s.pop() + "skewX(" + wb + ")"); + } + if (ka[0] != kb[0] || ka[1] != kb[1]) { + n = s.push(s.pop() + "scale(", null, ",", null, ")"); + q.push({ + i: n - 4, + x: d3_interpolateNumber(ka[0], kb[0]) + }, { + i: n - 2, + x: d3_interpolateNumber(ka[1], kb[1]) + }); + } else if (kb[0] != 1 || kb[1] != 1) { + s.push(s.pop() + "scale(" + kb + ")"); + } + n = q.length; + return function(t) { + var i = -1, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + } + function d3_uninterpolateNumber(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return (x - a) * b; + }; + } + function d3_uninterpolateClamp(a, b) { + b = b - (a = +a) ? 1 / (b - a) : 0; + return function(x) { + return Math.max(0, Math.min(1, (x - a) * b)); + }; + } + d3.layout = {}; + d3.layout.bundle = function() { + return function(links) { + var paths = [], i = -1, n = links.length; + while (++i < n) paths.push(d3_layout_bundlePath(links[i])); + return paths; + }; + }; + function d3_layout_bundlePath(link) { + var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; + while (start !== lca) { + start = start.parent; + points.push(start); + } + var k = points.length; + while (end !== lca) { + points.splice(k, 0, end); + end = end.parent; + } + return points; + } + function d3_layout_bundleAncestors(node) { + var ancestors = [], parent = node.parent; + while (parent != null) { + ancestors.push(node); + node = parent; + parent = parent.parent; + } + ancestors.push(node); + return ancestors; + } + function d3_layout_bundleLeastCommonAncestor(a, b) { + if (a === b) return a; + var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; + while (aNode === bNode) { + sharedNode = aNode; + aNode = aNodes.pop(); + bNode = bNodes.pop(); + } + return sharedNode; + } + d3.layout.chord = function() { + var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; + function relayout() { + var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; + chords = []; + groups = []; + k = 0, i = -1; + while (++i < n) { + x = 0, j = -1; + while (++j < n) { + x += matrix[i][j]; + } + groupSums.push(x); + subgroupIndex.push(d3.range(n)); + k += x; + } + if (sortGroups) { + groupIndex.sort(function(a, b) { + return sortGroups(groupSums[a], groupSums[b]); + }); + } + if (sortSubgroups) { + subgroupIndex.forEach(function(d, i) { + d.sort(function(a, b) { + return sortSubgroups(matrix[i][a], matrix[i][b]); + }); + }); + } + k = (2 * π - padding * n) / k; + x = 0, i = -1; + while (++i < n) { + x0 = x, j = -1; + while (++j < n) { + var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; + subgroups[di + "-" + dj] = { + index: di, + subindex: dj, + startAngle: a0, + endAngle: a1, + value: v + }; + } + groups[di] = { + index: di, + startAngle: x0, + endAngle: x, + value: (x - x0) / k + }; + x += padding; + } + i = -1; + while (++i < n) { + j = i - 1; + while (++j < n) { + var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; + if (source.value || target.value) { + chords.push(source.value < target.value ? { + source: target, + target: source + } : { + source: source, + target: target + }); + } + } + } + if (sortChords) resort(); + } + function resort() { + chords.sort(function(a, b) { + return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); + }); + } + chord.matrix = function(x) { + if (!arguments.length) return matrix; + n = (matrix = x) && matrix.length; + chords = groups = null; + return chord; + }; + chord.padding = function(x) { + if (!arguments.length) return padding; + padding = x; + chords = groups = null; + return chord; + }; + chord.sortGroups = function(x) { + if (!arguments.length) return sortGroups; + sortGroups = x; + chords = groups = null; + return chord; + }; + chord.sortSubgroups = function(x) { + if (!arguments.length) return sortSubgroups; + sortSubgroups = x; + chords = null; + return chord; + }; + chord.sortChords = function(x) { + if (!arguments.length) return sortChords; + sortChords = x; + if (chords) resort(); + return chord; + }; + chord.chords = function() { + if (!chords) relayout(); + return chords; + }; + chord.groups = function() { + if (!groups) relayout(); + return groups; + }; + return chord; + }; + d3.layout.force = function() { + var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, nodes = [], links = [], distances, strengths, charges; + function repulse(node) { + return function(quad, x1, _, x2) { + if (quad.point !== node) { + var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); + if ((x2 - x1) * dn < theta) { + var k = quad.charge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + return true; + } + if (quad.point && isFinite(dn)) { + var k = quad.pointCharge * dn * dn; + node.px -= dx * k; + node.py -= dy * k; + } + } + return !quad.charge; + }; + } + force.tick = function() { + if ((alpha *= .99) < .005) { + event.end({ + type: "end", + alpha: alpha = 0 + }); + return true; + } + var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; + for (i = 0; i < m; ++i) { + o = links[i]; + s = o.source; + t = o.target; + x = t.x - s.x; + y = t.y - s.y; + if (l = x * x + y * y) { + l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; + x *= l; + y *= l; + t.x -= x * (k = s.weight / (t.weight + s.weight)); + t.y -= y * k; + s.x += x * (k = 1 - k); + s.y += y * k; + } + } + if (k = alpha * gravity) { + x = size[0] / 2; + y = size[1] / 2; + i = -1; + if (k) while (++i < n) { + o = nodes[i]; + o.x += (x - o.x) * k; + o.y += (y - o.y) * k; + } + } + if (charge) { + d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); + i = -1; + while (++i < n) { + if (!(o = nodes[i]).fixed) { + q.visit(repulse(o)); + } + } + } + i = -1; + while (++i < n) { + o = nodes[i]; + if (o.fixed) { + o.x = o.px; + o.y = o.py; + } else { + o.x -= (o.px - (o.px = o.x)) * friction; + o.y -= (o.py - (o.py = o.y)) * friction; + } + } + event.tick({ + type: "tick", + alpha: alpha + }); + }; + force.nodes = function(x) { + if (!arguments.length) return nodes; + nodes = x; + return force; + }; + force.links = function(x) { + if (!arguments.length) return links; + links = x; + return force; + }; + force.size = function(x) { + if (!arguments.length) return size; + size = x; + return force; + }; + force.linkDistance = function(x) { + if (!arguments.length) return linkDistance; + linkDistance = typeof x === "function" ? x : +x; + return force; + }; + force.distance = force.linkDistance; + force.linkStrength = function(x) { + if (!arguments.length) return linkStrength; + linkStrength = typeof x === "function" ? x : +x; + return force; + }; + force.friction = function(x) { + if (!arguments.length) return friction; + friction = +x; + return force; + }; + force.charge = function(x) { + if (!arguments.length) return charge; + charge = typeof x === "function" ? x : +x; + return force; + }; + force.gravity = function(x) { + if (!arguments.length) return gravity; + gravity = +x; + return force; + }; + force.theta = function(x) { + if (!arguments.length) return theta; + theta = +x; + return force; + }; + force.alpha = function(x) { + if (!arguments.length) return alpha; + x = +x; + if (alpha) { + if (x > 0) alpha = x; else alpha = 0; + } else if (x > 0) { + event.start({ + type: "start", + alpha: alpha = x + }); + d3.timer(force.tick); + } + return force; + }; + force.start = function() { + var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; + for (i = 0; i < n; ++i) { + (o = nodes[i]).index = i; + o.weight = 0; + } + for (i = 0; i < m; ++i) { + o = links[i]; + if (typeof o.source == "number") o.source = nodes[o.source]; + if (typeof o.target == "number") o.target = nodes[o.target]; + ++o.source.weight; + ++o.target.weight; + } + for (i = 0; i < n; ++i) { + o = nodes[i]; + if (isNaN(o.x)) o.x = position("x", w); + if (isNaN(o.y)) o.y = position("y", h); + if (isNaN(o.px)) o.px = o.x; + if (isNaN(o.py)) o.py = o.y; + } + distances = []; + if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance; + strengths = []; + if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength; + charges = []; + if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge; + function position(dimension, size) { + var neighbors = neighbor(i), j = -1, m = neighbors.length, x; + while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; + return Math.random() * size; + } + function neighbor() { + if (!neighbors) { + neighbors = []; + for (j = 0; j < n; ++j) { + neighbors[j] = []; + } + for (j = 0; j < m; ++j) { + var o = links[j]; + neighbors[o.source.index].push(o.target); + neighbors[o.target.index].push(o.source); + } + } + return neighbors[i]; + } + return force.resume(); + }; + force.resume = function() { + return force.alpha(.1); + }; + force.stop = function() { + return force.alpha(0); + }; + force.drag = function() { + if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend); + if (!arguments.length) return drag; + this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); + }; + function dragmove(d) { + d.px = d3.event.x, d.py = d3.event.y; + force.resume(); + } + return d3.rebind(force, event, "on"); + }; + function d3_layout_forceDragstart(d) { + d.fixed |= 2; + } + function d3_layout_forceDragend(d) { + d.fixed &= ~6; + } + function d3_layout_forceMouseover(d) { + d.fixed |= 4; + d.px = d.x, d.py = d.y; + } + function d3_layout_forceMouseout(d) { + d.fixed &= ~4; + } + function d3_layout_forceAccumulate(quad, alpha, charges) { + var cx = 0, cy = 0; + quad.charge = 0; + if (!quad.leaf) { + var nodes = quad.nodes, n = nodes.length, i = -1, c; + while (++i < n) { + c = nodes[i]; + if (c == null) continue; + d3_layout_forceAccumulate(c, alpha, charges); + quad.charge += c.charge; + cx += c.charge * c.cx; + cy += c.charge * c.cy; + } + } + if (quad.point) { + if (!quad.leaf) { + quad.point.x += Math.random() - .5; + quad.point.y += Math.random() - .5; + } + var k = alpha * charges[quad.point.index]; + quad.charge += quad.pointCharge = k; + cx += k * quad.point.x; + cy += k * quad.point.y; + } + quad.cx = cx / quad.charge; + quad.cy = cy / quad.charge; + } + var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1; + d3.layout.hierarchy = function() { + var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; + function recurse(node, depth, nodes) { + var childs = children.call(hierarchy, node, depth); + node.depth = depth; + nodes.push(node); + if (childs && (n = childs.length)) { + var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; + while (++i < n) { + d = recurse(childs[i], j, nodes); + d.parent = node; + c.push(d); + v += d.value; + } + if (sort) c.sort(sort); + if (value) node.value = v; + } else if (value) { + node.value = +value.call(hierarchy, node, depth) || 0; + } + return node; + } + function revalue(node, depth) { + var children = node.children, v = 0; + if (children && (n = children.length)) { + var i = -1, n, j = depth + 1; + while (++i < n) v += revalue(children[i], j); + } else if (value) { + v = +value.call(hierarchy, node, depth) || 0; + } + if (value) node.value = v; + return v; + } + function hierarchy(d) { + var nodes = []; + recurse(d, 0, nodes); + return nodes; + } + hierarchy.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return hierarchy; + }; + hierarchy.children = function(x) { + if (!arguments.length) return children; + children = x; + return hierarchy; + }; + hierarchy.value = function(x) { + if (!arguments.length) return value; + value = x; + return hierarchy; + }; + hierarchy.revalue = function(root) { + revalue(root, 0); + return root; + }; + return hierarchy; + }; + function d3_layout_hierarchyRebind(object, hierarchy) { + d3.rebind(object, hierarchy, "sort", "children", "value"); + object.nodes = object; + object.links = d3_layout_hierarchyLinks; + return object; + } + function d3_layout_hierarchyChildren(d) { + return d.children; + } + function d3_layout_hierarchyValue(d) { + return d.value; + } + function d3_layout_hierarchySort(a, b) { + return b.value - a.value; + } + function d3_layout_hierarchyLinks(nodes) { + return d3.merge(nodes.map(function(parent) { + return (parent.children || []).map(function(child) { + return { + source: parent, + target: child + }; + }); + })); + } + d3.layout.partition = function() { + var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; + function position(node, x, dx, dy) { + var children = node.children; + node.x = x; + node.y = node.depth * dy; + node.dx = dx; + node.dy = dy; + if (children && (n = children.length)) { + var i = -1, n, c, d; + dx = node.value ? dx / node.value : 0; + while (++i < n) { + position(c = children[i], x, d = c.value * dx, dy); + x += d; + } + } + } + function depth(node) { + var children = node.children, d = 0; + if (children && (n = children.length)) { + var i = -1, n; + while (++i < n) d = Math.max(d, depth(children[i])); + } + return 1 + d; + } + function partition(d, i) { + var nodes = hierarchy.call(this, d, i); + position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); + return nodes; + } + partition.size = function(x) { + if (!arguments.length) return size; + size = x; + return partition; + }; + return d3_layout_hierarchyRebind(partition, hierarchy); + }; + d3.layout.pie = function() { + var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * π; + function pie(data) { + var values = data.map(function(d, i) { + return +value.call(pie, d, i); + }); + var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); + var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a) / d3.sum(values); + var index = d3.range(data.length); + if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { + return values[j] - values[i]; + } : function(i, j) { + return sort(data[i], data[j]); + }); + var arcs = []; + index.forEach(function(i) { + var d; + arcs[i] = { + data: data[i], + value: d = values[i], + startAngle: a, + endAngle: a += d * k + }; + }); + return arcs; + } + pie.value = function(x) { + if (!arguments.length) return value; + value = x; + return pie; + }; + pie.sort = function(x) { + if (!arguments.length) return sort; + sort = x; + return pie; + }; + pie.startAngle = function(x) { + if (!arguments.length) return startAngle; + startAngle = x; + return pie; + }; + pie.endAngle = function(x) { + if (!arguments.length) return endAngle; + endAngle = x; + return pie; + }; + return pie; + }; + var d3_layout_pieSortByValue = {}; + d3.layout.stack = function() { + var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; + function stack(data, index) { + var series = data.map(function(d, i) { + return values.call(stack, d, i); + }); + var points = series.map(function(d) { + return d.map(function(v, i) { + return [ x.call(stack, v, i), y.call(stack, v, i) ]; + }); + }); + var orders = order.call(stack, points, index); + series = d3.permute(series, orders); + points = d3.permute(points, orders); + var offsets = offset.call(stack, points, index); + var n = series.length, m = series[0].length, i, j, o; + for (j = 0; j < m; ++j) { + out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); + for (i = 1; i < n; ++i) { + out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); + } + } + return data; + } + stack.values = function(x) { + if (!arguments.length) return values; + values = x; + return stack; + }; + stack.order = function(x) { + if (!arguments.length) return order; + order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; + return stack; + }; + stack.offset = function(x) { + if (!arguments.length) return offset; + offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; + return stack; + }; + stack.x = function(z) { + if (!arguments.length) return x; + x = z; + return stack; + }; + stack.y = function(z) { + if (!arguments.length) return y; + y = z; + return stack; + }; + stack.out = function(z) { + if (!arguments.length) return out; + out = z; + return stack; + }; + return stack; + }; + function d3_layout_stackX(d) { + return d.x; + } + function d3_layout_stackY(d) { + return d.y; + } + function d3_layout_stackOut(d, y0, y) { + d.y0 = y0; + d.y = y; + } + var d3_layout_stackOrders = d3.map({ + "inside-out": function(data) { + var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { + return max[a] - max[b]; + }), top = 0, bottom = 0, tops = [], bottoms = []; + for (i = 0; i < n; ++i) { + j = index[i]; + if (top < bottom) { + top += sums[j]; + tops.push(j); + } else { + bottom += sums[j]; + bottoms.push(j); + } + } + return bottoms.reverse().concat(tops); + }, + reverse: function(data) { + return d3.range(data.length).reverse(); + }, + "default": d3_layout_stackOrderDefault + }); + var d3_layout_stackOffsets = d3.map({ + silhouette: function(data) { + var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o > max) max = o; + sums.push(o); + } + for (j = 0; j < m; ++j) { + y0[j] = (max - sums[j]) / 2; + } + return y0; + }, + wiggle: function(data) { + var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; + y0[0] = o = o0 = 0; + for (j = 1; j < m; ++j) { + for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; + for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { + for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { + s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; + } + s2 += s3 * data[i][j][1]; + } + y0[j] = o -= s1 ? s2 / s1 * dx : 0; + if (o < o0) o0 = o; + } + for (j = 0; j < m; ++j) y0[j] -= o0; + return y0; + }, + expand: function(data) { + var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; + for (j = 0; j < m; ++j) { + for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; + if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; + } + for (j = 0; j < m; ++j) y0[j] = 0; + return y0; + }, + zero: d3_layout_stackOffsetZero + }); + function d3_layout_stackOrderDefault(data) { + return d3.range(data.length); + } + function d3_layout_stackOffsetZero(data) { + var j = -1, m = data[0].length, y0 = []; + while (++j < m) y0[j] = 0; + return y0; + } + function d3_layout_stackMaxIndex(array) { + var i = 1, j = 0, v = array[0][1], k, n = array.length; + for (;i < n; ++i) { + if ((k = array[i][1]) > v) { + j = i; + v = k; + } + } + return j; + } + function d3_layout_stackReduceSum(d) { + return d.reduce(d3_layout_stackSum, 0); + } + function d3_layout_stackSum(p, d) { + return p + d[1]; + } + d3.layout.histogram = function() { + var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; + function histogram(data, i) { + var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; + while (++i < m) { + bin = bins[i] = []; + bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); + bin.y = 0; + } + if (m > 0) { + i = -1; + while (++i < n) { + x = values[i]; + if (x >= range[0] && x <= range[1]) { + bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; + bin.y += k; + bin.push(data[i]); + } + } + } + return bins; + } + histogram.value = function(x) { + if (!arguments.length) return valuer; + valuer = x; + return histogram; + }; + histogram.range = function(x) { + if (!arguments.length) return ranger; + ranger = d3_functor(x); + return histogram; + }; + histogram.bins = function(x) { + if (!arguments.length) return binner; + binner = typeof x === "number" ? function(range) { + return d3_layout_histogramBinFixed(range, x); + } : d3_functor(x); + return histogram; + }; + histogram.frequency = function(x) { + if (!arguments.length) return frequency; + frequency = !!x; + return histogram; + }; + return histogram; + }; + function d3_layout_histogramBinSturges(range, values) { + return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); + } + function d3_layout_histogramBinFixed(range, n) { + var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; + while (++x <= n) f[x] = m * x + b; + return f; + } + function d3_layout_histogramRange(values) { + return [ d3.min(values), d3.max(values) ]; + } + d3.layout.tree = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function tree(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0]; + function firstWalk(node, previousSibling) { + var children = node.children, layout = node._tree; + if (children && (n = children.length)) { + var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; + while (++i < n) { + child = children[i]; + firstWalk(child, previousChild); + ancestor = apportion(child, previousChild, ancestor); + previousChild = child; + } + d3_layout_treeShift(node); + var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + layout.mod = layout.prelim - midpoint; + } else { + layout.prelim = midpoint; + } + } else { + if (previousSibling) { + layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); + } + } + } + function secondWalk(node, x) { + node.x = node._tree.prelim + x; + var children = node.children; + if (children && (n = children.length)) { + var i = -1, n; + x += node._tree.mod; + while (++i < n) { + secondWalk(children[i], x); + } + } + } + function apportion(node, previousSibling, ancestor) { + if (previousSibling) { + var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; + while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { + vom = d3_layout_treeLeft(vom); + vop = d3_layout_treeRight(vop); + vop._tree.ancestor = node; + shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); + if (shift > 0) { + d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); + sip += shift; + sop += shift; + } + sim += vim._tree.mod; + sip += vip._tree.mod; + som += vom._tree.mod; + sop += vop._tree.mod; + } + if (vim && !d3_layout_treeRight(vop)) { + vop._tree.thread = vim; + vop._tree.mod += sim - sop; + } + if (vip && !d3_layout_treeLeft(vom)) { + vom._tree.thread = vip; + vom._tree.mod += sip - som; + ancestor = node; + } + } + return ancestor; + } + d3_layout_treeVisitAfter(root, function(node, previousSibling) { + node._tree = { + ancestor: node, + prelim: 0, + mod: 0, + change: 0, + shift: 0, + number: previousSibling ? previousSibling._tree.number + 1 : 0 + }; + }); + firstWalk(root); + secondWalk(root, -root._tree.prelim); + var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x *= size[0]; + node.y = node.depth * size[1]; + delete node._tree; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = node.depth / y1 * size[1]; + delete node._tree; + }); + return nodes; + } + tree.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return tree; + }; + tree.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return tree; + }; + tree.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return tree; + }; + return d3_layout_hierarchyRebind(tree, hierarchy); + }; + function d3_layout_treeSeparation(a, b) { + return a.parent == b.parent ? 1 : 2; + } + function d3_layout_treeLeft(node) { + var children = node.children; + return children && children.length ? children[0] : node._tree.thread; + } + function d3_layout_treeRight(node) { + var children = node.children, n; + return children && (n = children.length) ? children[n - 1] : node._tree.thread; + } + function d3_layout_treeSearch(node, compare) { + var children = node.children; + if (children && (n = children.length)) { + var child, n, i = -1; + while (++i < n) { + if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { + node = child; + } + } + } + return node; + } + function d3_layout_treeRightmost(a, b) { + return a.x - b.x; + } + function d3_layout_treeLeftmost(a, b) { + return b.x - a.x; + } + function d3_layout_treeDeepest(a, b) { + return a.depth - b.depth; + } + function d3_layout_treeVisitAfter(node, callback) { + function visit(node, previousSibling) { + var children = node.children; + if (children && (n = children.length)) { + var child, previousChild = null, i = -1, n; + while (++i < n) { + child = children[i]; + visit(child, previousChild); + previousChild = child; + } + } + callback(node, previousSibling); + } + visit(node, null); + } + function d3_layout_treeShift(node) { + var shift = 0, change = 0, children = node.children, i = children.length, child; + while (--i >= 0) { + child = children[i]._tree; + child.prelim += shift; + child.mod += shift; + shift += child.shift + (change += child.change); + } + } + function d3_layout_treeMove(ancestor, node, shift) { + ancestor = ancestor._tree; + node = node._tree; + var change = shift / (node.number - ancestor.number); + ancestor.change += change; + node.change -= change; + node.shift += shift; + node.prelim += shift; + node.mod += shift; + } + function d3_layout_treeAncestor(vim, node, ancestor) { + return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; + } + d3.layout.pack = function() { + var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius; + function pack(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() { + return radius; + }; + root.x = root.y = 0; + d3_layout_treeVisitAfter(root, function(d) { + d.r = +r(d.value); + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + if (padding) { + var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2; + d3_layout_treeVisitAfter(root, function(d) { + d.r += dr; + }); + d3_layout_treeVisitAfter(root, d3_layout_packSiblings); + d3_layout_treeVisitAfter(root, function(d) { + d.r -= dr; + }); + } + d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h)); + return nodes; + } + pack.size = function(_) { + if (!arguments.length) return size; + size = _; + return pack; + }; + pack.radius = function(_) { + if (!arguments.length) return radius; + radius = _ == null || typeof _ === "function" ? _ : +_; + return pack; + }; + pack.padding = function(_) { + if (!arguments.length) return padding; + padding = +_; + return pack; + }; + return d3_layout_hierarchyRebind(pack, hierarchy); + }; + function d3_layout_packSort(a, b) { + return a.value - b.value; + } + function d3_layout_packInsert(a, b) { + var c = a._pack_next; + a._pack_next = b; + b._pack_prev = a; + b._pack_next = c; + c._pack_prev = b; + } + function d3_layout_packSplice(a, b) { + a._pack_next = b; + b._pack_prev = a; + } + function d3_layout_packIntersects(a, b) { + var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; + return .999 * dr * dr > dx * dx + dy * dy; + } + function d3_layout_packSiblings(node) { + if (!(nodes = node.children) || !(n = nodes.length)) return; + var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; + function bound(node) { + xMin = Math.min(node.x - node.r, xMin); + xMax = Math.max(node.x + node.r, xMax); + yMin = Math.min(node.y - node.r, yMin); + yMax = Math.max(node.y + node.r, yMax); + } + nodes.forEach(d3_layout_packLink); + a = nodes[0]; + a.x = -a.r; + a.y = 0; + bound(a); + if (n > 1) { + b = nodes[1]; + b.x = b.r; + b.y = 0; + bound(b); + if (n > 2) { + c = nodes[2]; + d3_layout_packPlace(a, b, c); + bound(c); + d3_layout_packInsert(a, c); + a._pack_prev = c; + d3_layout_packInsert(c, b); + b = a._pack_next; + for (i = 3; i < n; i++) { + d3_layout_packPlace(a, b, c = nodes[i]); + var isect = 0, s1 = 1, s2 = 1; + for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { + if (d3_layout_packIntersects(j, c)) { + isect = 1; + break; + } + } + if (isect == 1) { + for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { + if (d3_layout_packIntersects(k, c)) { + break; + } + } + } + if (isect) { + if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); + i--; + } else { + d3_layout_packInsert(a, c); + b = c; + bound(c); + } + } + } + } + var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; + for (i = 0; i < n; i++) { + c = nodes[i]; + c.x -= cx; + c.y -= cy; + cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); + } + node.r = cr; + nodes.forEach(d3_layout_packUnlink); + } + function d3_layout_packLink(node) { + node._pack_next = node._pack_prev = node; + } + function d3_layout_packUnlink(node) { + delete node._pack_next; + delete node._pack_prev; + } + function d3_layout_packTransform(node, x, y, k) { + var children = node.children; + node.x = x += k * node.x; + node.y = y += k * node.y; + node.r *= k; + if (children) { + var i = -1, n = children.length; + while (++i < n) d3_layout_packTransform(children[i], x, y, k); + } + } + function d3_layout_packPlace(a, b, c) { + var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; + if (db && (dx || dy)) { + var da = b.r + c.r, dc = dx * dx + dy * dy; + da *= da; + db *= db; + var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); + c.x = a.x + x * dx + y * dy; + c.y = a.y + x * dy - y * dx; + } else { + c.x = a.x + db; + c.y = a.y; + } + } + d3.layout.cluster = function() { + var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false; + function cluster(d, i) { + var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0; + d3_layout_treeVisitAfter(root, function(node) { + var children = node.children; + if (children && children.length) { + node.x = d3_layout_clusterX(children); + node.y = d3_layout_clusterY(children); + } else { + node.x = previousNode ? x += separation(node, previousNode) : 0; + node.y = 0; + previousNode = node; + } + }); + var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; + d3_layout_treeVisitAfter(root, nodeSize ? function(node) { + node.x = (node.x - root.x) * size[0]; + node.y = (root.y - node.y) * size[1]; + } : function(node) { + node.x = (node.x - x0) / (x1 - x0) * size[0]; + node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; + }); + return nodes; + } + cluster.separation = function(x) { + if (!arguments.length) return separation; + separation = x; + return cluster; + }; + cluster.size = function(x) { + if (!arguments.length) return nodeSize ? null : size; + nodeSize = (size = x) == null; + return cluster; + }; + cluster.nodeSize = function(x) { + if (!arguments.length) return nodeSize ? size : null; + nodeSize = (size = x) != null; + return cluster; + }; + return d3_layout_hierarchyRebind(cluster, hierarchy); + }; + function d3_layout_clusterY(children) { + return 1 + d3.max(children, function(child) { + return child.y; + }); + } + function d3_layout_clusterX(children) { + return children.reduce(function(x, child) { + return x + child.x; + }, 0) / children.length; + } + function d3_layout_clusterLeft(node) { + var children = node.children; + return children && children.length ? d3_layout_clusterLeft(children[0]) : node; + } + function d3_layout_clusterRight(node) { + var children = node.children, n; + return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; + } + d3.layout.treemap = function() { + var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); + function scale(children, k) { + var i = -1, n = children.length, child, area; + while (++i < n) { + area = (child = children[i]).value * (k < 0 ? 0 : k); + child.area = isNaN(area) || area <= 0 ? 0 : area; + } + } + function squarify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while ((n = remaining.length) > 0) { + row.push(child = remaining[n - 1]); + row.area += child.area; + if (mode !== "squarify" || (score = worst(row, u)) <= best) { + remaining.pop(); + best = score; + } else { + row.area -= row.pop().area; + position(row, u, rect, false); + u = Math.min(rect.dx, rect.dy); + row.length = row.area = 0; + best = Infinity; + } + } + if (row.length) { + position(row, u, rect, true); + row.length = row.area = 0; + } + children.forEach(squarify); + } + } + function stickify(node) { + var children = node.children; + if (children && children.length) { + var rect = pad(node), remaining = children.slice(), child, row = []; + scale(remaining, rect.dx * rect.dy / node.value); + row.area = 0; + while (child = remaining.pop()) { + row.push(child); + row.area += child.area; + if (child.z != null) { + position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); + row.length = row.area = 0; + } + } + children.forEach(stickify); + } + } + function worst(row, u) { + var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; + while (++i < n) { + if (!(r = row[i].area)) continue; + if (r < rmin) rmin = r; + if (r > rmax) rmax = r; + } + s *= s; + u *= u; + return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; + } + function position(row, u, rect, flush) { + var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; + if (u == rect.dx) { + if (flush || v > rect.dy) v = rect.dy; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dy = v; + x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); + } + o.z = true; + o.dx += rect.x + rect.dx - x; + rect.y += v; + rect.dy -= v; + } else { + if (flush || v > rect.dx) v = rect.dx; + while (++i < n) { + o = row[i]; + o.x = x; + o.y = y; + o.dx = v; + y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); + } + o.z = false; + o.dy += rect.y + rect.dy - y; + rect.x += v; + rect.dx -= v; + } + } + function treemap(d) { + var nodes = stickies || hierarchy(d), root = nodes[0]; + root.x = 0; + root.y = 0; + root.dx = size[0]; + root.dy = size[1]; + if (stickies) hierarchy.revalue(root); + scale([ root ], root.dx * root.dy / root.value); + (stickies ? stickify : squarify)(root); + if (sticky) stickies = nodes; + return nodes; + } + treemap.size = function(x) { + if (!arguments.length) return size; + size = x; + return treemap; + }; + treemap.padding = function(x) { + if (!arguments.length) return padding; + function padFunction(node) { + var p = x.call(treemap, node, node.depth); + return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); + } + function padConstant(node) { + return d3_layout_treemapPad(node, x); + } + var type; + pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], + padConstant) : padConstant; + return treemap; + }; + treemap.round = function(x) { + if (!arguments.length) return round != Number; + round = x ? Math.round : Number; + return treemap; + }; + treemap.sticky = function(x) { + if (!arguments.length) return sticky; + sticky = x; + stickies = null; + return treemap; + }; + treemap.ratio = function(x) { + if (!arguments.length) return ratio; + ratio = x; + return treemap; + }; + treemap.mode = function(x) { + if (!arguments.length) return mode; + mode = x + ""; + return treemap; + }; + return d3_layout_hierarchyRebind(treemap, hierarchy); + }; + function d3_layout_treemapPadNull(node) { + return { + x: node.x, + y: node.y, + dx: node.dx, + dy: node.dy + }; + } + function d3_layout_treemapPad(node, padding) { + var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; + if (dx < 0) { + x += dx / 2; + dx = 0; + } + if (dy < 0) { + y += dy / 2; + dy = 0; + } + return { + x: x, + y: y, + dx: dx, + dy: dy + }; + } + d3.random = { + normal: function(µ, σ) { + var n = arguments.length; + if (n < 2) σ = 1; + if (n < 1) µ = 0; + return function() { + var x, y, r; + do { + x = Math.random() * 2 - 1; + y = Math.random() * 2 - 1; + r = x * x + y * y; + } while (!r || r > 1); + return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); + }; + }, + logNormal: function() { + var random = d3.random.normal.apply(d3, arguments); + return function() { + return Math.exp(random()); + }; + }, + irwinHall: function(m) { + return function() { + for (var s = 0, j = 0; j < m; j++) s += Math.random(); + return s / m; + }; + } + }; + d3.scale = {}; + function d3_scaleExtent(domain) { + var start = domain[0], stop = domain[domain.length - 1]; + return start < stop ? [ start, stop ] : [ stop, start ]; + } + function d3_scaleRange(scale) { + return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); + } + function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { + var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); + return function(x) { + return i(u(x)); + }; + } + function d3_scale_nice(domain, nice) { + var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; + if (x1 < x0) { + dx = i0, i0 = i1, i1 = dx; + dx = x0, x0 = x1, x1 = dx; + } + domain[i0] = nice.floor(x0); + domain[i1] = nice.ceil(x1); + return domain; + } + function d3_scale_niceStep(step) { + return step ? { + floor: function(x) { + return Math.floor(x / step) * step; + }, + ceil: function(x) { + return Math.ceil(x / step) * step; + } + } : d3_scale_niceIdentity; + } + var d3_scale_niceIdentity = { + floor: d3_identity, + ceil: d3_identity + }; + function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { + var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; + if (domain[k] < domain[0]) { + domain = domain.slice().reverse(); + range = range.slice().reverse(); + } + while (++j <= k) { + u.push(uninterpolate(domain[j - 1], domain[j])); + i.push(interpolate(range[j - 1], range[j])); + } + return function(x) { + var j = d3.bisect(domain, x, 1, k) - 1; + return i[j](u[j](x)); + }; + } + d3.scale.linear = function() { + return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false); + }; + function d3_scale_linear(domain, range, interpolate, clamp) { + var output, input; + function rescale() { + var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; + output = linear(domain, range, uninterpolate, interpolate); + input = linear(range, domain, uninterpolate, d3_interpolate); + return scale; + } + function scale(x) { + return output(x); + } + scale.invert = function(y) { + return input(y); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.map(Number); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.rangeRound = function(x) { + return scale.range(x).interpolate(d3_interpolateRound); + }; + scale.clamp = function(x) { + if (!arguments.length) return clamp; + clamp = x; + return rescale(); + }; + scale.interpolate = function(x) { + if (!arguments.length) return interpolate; + interpolate = x; + return rescale(); + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + d3_scale_linearNice(domain, m); + return rescale(); + }; + scale.copy = function() { + return d3_scale_linear(domain, range, interpolate, clamp); + }; + return rescale(); + } + function d3_scale_linearRebind(scale, linear) { + return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); + } + function d3_scale_linearNice(domain, m) { + return d3_scale_nice(domain, d3_scale_niceStep(m ? d3_scale_linearTickRange(domain, m)[2] : d3_scale_linearNiceStep(domain))); + } + function d3_scale_linearNiceStep(domain) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0]; + return Math.pow(10, Math.round(Math.log(span) / Math.LN10) - 1); + } + function d3_scale_linearTickRange(domain, m) { + var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; + if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; + extent[0] = Math.ceil(extent[0] / step) * step; + extent[1] = Math.floor(extent[1] / step) * step + step * .5; + extent[2] = step; + return extent; + } + function d3_scale_linearTicks(domain, m) { + return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); + } + function d3_scale_linearTickFormat(domain, m, format) { + var precision = -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01); + return d3.format(format ? format.replace(d3_format_re, function(a, b, c, d, e, f, g, h, i, j) { + return [ b, c, d, e, f, g, h, i || "." + (precision - (j === "%") * 2), j ].join(""); + }) : ",." + precision + "f"); + } + d3.scale.log = function() { + return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]); + }; + function d3_scale_log(linear, base, positive, domain) { + function log(x) { + return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base); + } + function pow(x) { + return positive ? Math.pow(base, x) : -Math.pow(base, -x); + } + function scale(x) { + return linear(log(x)); + } + scale.invert = function(x) { + return pow(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + positive = x[0] >= 0; + linear.domain((domain = x.map(Number)).map(log)); + return scale; + }; + scale.base = function(_) { + if (!arguments.length) return base; + base = +_; + linear.domain(domain.map(log)); + return scale; + }; + scale.nice = function() { + var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative); + linear.domain(niced); + domain = niced.map(pow); + return scale; + }; + scale.ticks = function() { + var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base; + if (isFinite(j - i)) { + if (positive) { + for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k); + ticks.push(pow(i)); + } else { + ticks.push(pow(i)); + for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k); + } + for (i = 0; ticks[i] < u; i++) {} + for (j = ticks.length; ticks[j - 1] > v; j--) {} + ticks = ticks.slice(i, j); + } + return ticks; + }; + scale.tickFormat = function(n, format) { + if (!arguments.length) return d3_scale_logFormat; + if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format); + var k = Math.max(.1, n / scale.ticks().length), f = positive ? (e = 1e-12, Math.ceil) : (e = -1e-12, + Math.floor), e; + return function(d) { + return d / pow(f(log(d) + e)) <= k ? format(d) : ""; + }; + }; + scale.copy = function() { + return d3_scale_log(linear.copy(), base, positive, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = { + floor: function(x) { + return -Math.ceil(-x); + }, + ceil: function(x) { + return -Math.floor(-x); + } + }; + d3.scale.pow = function() { + return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]); + }; + function d3_scale_pow(linear, exponent, domain) { + var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); + function scale(x) { + return linear(powp(x)); + } + scale.invert = function(x) { + return powb(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return domain; + linear.domain((domain = x.map(Number)).map(powp)); + return scale; + }; + scale.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + scale.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + scale.nice = function(m) { + return scale.domain(d3_scale_linearNice(domain, m)); + }; + scale.exponent = function(x) { + if (!arguments.length) return exponent; + powp = d3_scale_powPow(exponent = x); + powb = d3_scale_powPow(1 / exponent); + linear.domain(domain.map(powp)); + return scale; + }; + scale.copy = function() { + return d3_scale_pow(linear.copy(), exponent, domain); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_scale_powPow(e) { + return function(x) { + return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); + }; + } + d3.scale.sqrt = function() { + return d3.scale.pow().exponent(.5); + }; + d3.scale.ordinal = function() { + return d3_scale_ordinal([], { + t: "range", + a: [ [] ] + }); + }; + function d3_scale_ordinal(domain, ranger) { + var index, range, rangeBand; + function scale(x) { + return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; + } + function steps(start, step) { + return d3.range(domain.length).map(function(i) { + return start + step * i; + }); + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = []; + index = new d3_Map(); + var i = -1, n = x.length, xi; + while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); + return scale[ranger.t].apply(scale, ranger.a); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + rangeBand = 0; + ranger = { + t: "range", + a: arguments + }; + return scale; + }; + scale.rangePoints = function(x, padding) { + if (arguments.length < 2) padding = 0; + var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); + range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); + rangeBand = 0; + ranger = { + t: "rangePoints", + a: arguments + }; + return scale; + }; + scale.rangeBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); + range = steps(start + step * outerPadding, step); + if (reverse) range.reverse(); + rangeBand = step * (1 - padding); + ranger = { + t: "rangeBands", + a: arguments + }; + return scale; + }; + scale.rangeRoundBands = function(x, padding, outerPadding) { + if (arguments.length < 2) padding = 0; + if (arguments.length < 3) outerPadding = padding; + var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; + range = steps(start + Math.round(error / 2), step); + if (reverse) range.reverse(); + rangeBand = Math.round(step * (1 - padding)); + ranger = { + t: "rangeRoundBands", + a: arguments + }; + return scale; + }; + scale.rangeBand = function() { + return rangeBand; + }; + scale.rangeExtent = function() { + return d3_scaleExtent(ranger.a[0]); + }; + scale.copy = function() { + return d3_scale_ordinal(domain, ranger); + }; + return scale.domain(domain); + } + d3.scale.category10 = function() { + return d3.scale.ordinal().range(d3_category10); + }; + d3.scale.category20 = function() { + return d3.scale.ordinal().range(d3_category20); + }; + d3.scale.category20b = function() { + return d3.scale.ordinal().range(d3_category20b); + }; + d3.scale.category20c = function() { + return d3.scale.ordinal().range(d3_category20c); + }; + var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString); + var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString); + var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString); + var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString); + d3.scale.quantile = function() { + return d3_scale_quantile([], []); + }; + function d3_scale_quantile(domain, range) { + var thresholds; + function rescale() { + var k = 0, q = range.length; + thresholds = []; + while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); + return scale; + } + function scale(x) { + if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)]; + } + scale.domain = function(x) { + if (!arguments.length) return domain; + domain = x.filter(function(d) { + return !isNaN(d); + }).sort(d3.ascending); + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.quantiles = function() { + return thresholds; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ]; + }; + scale.copy = function() { + return d3_scale_quantile(domain, range); + }; + return rescale(); + } + d3.scale.quantize = function() { + return d3_scale_quantize(0, 1, [ 0, 1 ]); + }; + function d3_scale_quantize(x0, x1, range) { + var kx, i; + function scale(x) { + return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; + } + function rescale() { + kx = range.length / (x1 - x0); + i = range.length - 1; + return scale; + } + scale.domain = function(x) { + if (!arguments.length) return [ x0, x1 ]; + x0 = +x[0]; + x1 = +x[x.length - 1]; + return rescale(); + }; + scale.range = function(x) { + if (!arguments.length) return range; + range = x; + return rescale(); + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + y = y < 0 ? NaN : y / kx + x0; + return [ y, y + 1 / kx ]; + }; + scale.copy = function() { + return d3_scale_quantize(x0, x1, range); + }; + return rescale(); + } + d3.scale.threshold = function() { + return d3_scale_threshold([ .5 ], [ 0, 1 ]); + }; + function d3_scale_threshold(domain, range) { + function scale(x) { + if (x <= x) return range[d3.bisect(domain, x)]; + } + scale.domain = function(_) { + if (!arguments.length) return domain; + domain = _; + return scale; + }; + scale.range = function(_) { + if (!arguments.length) return range; + range = _; + return scale; + }; + scale.invertExtent = function(y) { + y = range.indexOf(y); + return [ domain[y - 1], domain[y] ]; + }; + scale.copy = function() { + return d3_scale_threshold(domain, range); + }; + return scale; + } + d3.scale.identity = function() { + return d3_scale_identity([ 0, 1 ]); + }; + function d3_scale_identity(domain) { + function identity(x) { + return +x; + } + identity.invert = identity; + identity.domain = identity.range = function(x) { + if (!arguments.length) return domain; + domain = x.map(identity); + return identity; + }; + identity.ticks = function(m) { + return d3_scale_linearTicks(domain, m); + }; + identity.tickFormat = function(m, format) { + return d3_scale_linearTickFormat(domain, m, format); + }; + identity.copy = function() { + return d3_scale_identity(domain); + }; + return identity; + } + d3.svg.arc = function() { + var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function arc() { + var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, + a0 = a1, a1 = da), a1 - a0), df = da < π ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); + return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; + } + arc.innerRadius = function(v) { + if (!arguments.length) return innerRadius; + innerRadius = d3_functor(v); + return arc; + }; + arc.outerRadius = function(v) { + if (!arguments.length) return outerRadius; + outerRadius = d3_functor(v); + return arc; + }; + arc.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return arc; + }; + arc.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return arc; + }; + arc.centroid = function() { + var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; + return [ Math.cos(a) * r, Math.sin(a) * r ]; + }; + return arc; + }; + var d3_svg_arcOffset = -π / 2, d3_svg_arcMax = 2 * π - 1e-6; + function d3_svg_arcInnerRadius(d) { + return d.innerRadius; + } + function d3_svg_arcOuterRadius(d) { + return d.outerRadius; + } + function d3_svg_arcStartAngle(d) { + return d.startAngle; + } + function d3_svg_arcEndAngle(d) { + return d.endAngle; + } + d3.svg.line.radial = function() { + var line = d3_svg_line(d3_svg_lineRadial); + line.radius = line.x, delete line.x; + line.angle = line.y, delete line.y; + return line; + }; + function d3_svg_lineRadial(points) { + var point, i = -1, n = points.length, r, a; + while (++i < n) { + point = points[i]; + r = point[0]; + a = point[1] + d3_svg_arcOffset; + point[0] = r * Math.cos(a); + point[1] = r * Math.sin(a); + } + return points; + } + function d3_svg_area(projection) { + var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; + function area(data) { + var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { + return x; + } : d3_functor(x1), fy1 = y0 === y1 ? function() { + return y; + } : d3_functor(y1), x, y; + function segment() { + segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); + } + while (++i < n) { + if (defined.call(this, d = data[i], i)) { + points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); + points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); + } else if (points0.length) { + segment(); + points0 = []; + points1 = []; + } + } + if (points0.length) segment(); + return segments.length ? segments.join("") : null; + } + area.x = function(_) { + if (!arguments.length) return x1; + x0 = x1 = _; + return area; + }; + area.x0 = function(_) { + if (!arguments.length) return x0; + x0 = _; + return area; + }; + area.x1 = function(_) { + if (!arguments.length) return x1; + x1 = _; + return area; + }; + area.y = function(_) { + if (!arguments.length) return y1; + y0 = y1 = _; + return area; + }; + area.y0 = function(_) { + if (!arguments.length) return y0; + y0 = _; + return area; + }; + area.y1 = function(_) { + if (!arguments.length) return y1; + y1 = _; + return area; + }; + area.defined = function(_) { + if (!arguments.length) return defined; + defined = _; + return area; + }; + area.interpolate = function(_) { + if (!arguments.length) return interpolateKey; + if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; + interpolateReverse = interpolate.reverse || interpolate; + L = interpolate.closed ? "M" : "L"; + return area; + }; + area.tension = function(_) { + if (!arguments.length) return tension; + tension = _; + return area; + }; + return area; + } + d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; + d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; + d3.svg.area = function() { + return d3_svg_area(d3_identity); + }; + d3.svg.area.radial = function() { + var area = d3_svg_area(d3_svg_lineRadial); + area.radius = area.x, delete area.x; + area.innerRadius = area.x0, delete area.x0; + area.outerRadius = area.x1, delete area.x1; + area.angle = area.y, delete area.y; + area.startAngle = area.y0, delete area.y0; + area.endAngle = area.y1, delete area.y1; + return area; + }; + d3.svg.chord = function() { + var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; + function chord(d, i) { + var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); + return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; + } + function subgroup(self, f, d, i) { + var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; + return { + r: r, + a0: a0, + a1: a1, + p0: [ r * Math.cos(a0), r * Math.sin(a0) ], + p1: [ r * Math.cos(a1), r * Math.sin(a1) ] + }; + } + function equals(a, b) { + return a.a0 == b.a0 && a.a1 == b.a1; + } + function arc(r, p, a) { + return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p; + } + function curve(r0, p0, r1, p1) { + return "Q 0,0 " + p1; + } + chord.radius = function(v) { + if (!arguments.length) return radius; + radius = d3_functor(v); + return chord; + }; + chord.source = function(v) { + if (!arguments.length) return source; + source = d3_functor(v); + return chord; + }; + chord.target = function(v) { + if (!arguments.length) return target; + target = d3_functor(v); + return chord; + }; + chord.startAngle = function(v) { + if (!arguments.length) return startAngle; + startAngle = d3_functor(v); + return chord; + }; + chord.endAngle = function(v) { + if (!arguments.length) return endAngle; + endAngle = d3_functor(v); + return chord; + }; + return chord; + }; + function d3_svg_chordRadius(d) { + return d.radius; + } + d3.svg.diagonal = function() { + var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection; + function diagonal(d, i) { + var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { + x: p0.x, + y: m + }, { + x: p3.x, + y: m + }, p3 ]; + p = p.map(projection); + return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; + } + diagonal.source = function(x) { + if (!arguments.length) return source; + source = d3_functor(x); + return diagonal; + }; + diagonal.target = function(x) { + if (!arguments.length) return target; + target = d3_functor(x); + return diagonal; + }; + diagonal.projection = function(x) { + if (!arguments.length) return projection; + projection = x; + return diagonal; + }; + return diagonal; + }; + function d3_svg_diagonalProjection(d) { + return [ d.x, d.y ]; + } + d3.svg.diagonal.radial = function() { + var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; + diagonal.projection = function(x) { + return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; + }; + return diagonal; + }; + function d3_svg_diagonalRadialProjection(projection) { + return function() { + var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; + return [ r * Math.cos(a), r * Math.sin(a) ]; + }; + } + d3.svg.symbol = function() { + var type = d3_svg_symbolType, size = d3_svg_symbolSize; + function symbol(d, i) { + return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); + } + symbol.type = function(x) { + if (!arguments.length) return type; + type = d3_functor(x); + return symbol; + }; + symbol.size = function(x) { + if (!arguments.length) return size; + size = d3_functor(x); + return symbol; + }; + return symbol; + }; + function d3_svg_symbolSize() { + return 64; + } + function d3_svg_symbolType() { + return "circle"; + } + function d3_svg_symbolCircle(size) { + var r = Math.sqrt(size / π); + return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; + } + var d3_svg_symbols = d3.map({ + circle: d3_svg_symbolCircle, + cross: function(size) { + var r = Math.sqrt(size / 5) / 2; + return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; + }, + diamond: function(size) { + var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; + return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; + }, + square: function(size) { + var r = Math.sqrt(size) / 2; + return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; + }, + "triangle-down": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; + }, + "triangle-up": function(size) { + var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; + return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; + } + }); + d3.svg.symbolTypes = d3_svg_symbols.keys(); + var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians); + function d3_transition(groups, id) { + d3_subclass(groups, d3_transitionPrototype); + groups.id = id; + return groups; + } + var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit; + d3_transitionPrototype.call = d3_selectionPrototype.call; + d3_transitionPrototype.empty = d3_selectionPrototype.empty; + d3_transitionPrototype.node = d3_selectionPrototype.node; + d3_transitionPrototype.size = d3_selectionPrototype.size; + d3.transition = function(selection) { + return arguments.length ? d3_transitionInheritId ? selection.transition() : selection : d3_selectionRoot.transition(); + }; + d3.transition.prototype = d3_transitionPrototype; + d3_transitionPrototype.select = function(selector) { + var id = this.id, subgroups = [], subgroup, subnode, node; + selector = d3_selection_selector(selector); + for (var j = -1, m = this.length; ++j < m; ) { + subgroups.push(subgroup = []); + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + d3_transitionNode(subnode, i, id, node.__transition__[id]); + subgroup.push(subnode); + } else { + subgroup.push(null); + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.selectAll = function(selector) { + var id = this.id, subgroups = [], subgroup, subnodes, node, subnode, transition; + selector = d3_selection_selectorAll(selector); + for (var j = -1, m = this.length; ++j < m; ) { + for (var group = this[j], i = -1, n = group.length; ++i < n; ) { + if (node = group[i]) { + transition = node.__transition__[id]; + subnodes = selector.call(node, node.__data__, i, j); + subgroups.push(subgroup = []); + for (var k = -1, o = subnodes.length; ++k < o; ) { + if (subnode = subnodes[k]) d3_transitionNode(subnode, k, id, transition); + subgroup.push(subnode); + } + } + } + } + return d3_transition(subgroups, id); + }; + d3_transitionPrototype.filter = function(filter) { + var subgroups = [], subgroup, group, node; + if (typeof filter !== "function") filter = d3_selection_filter(filter); + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if ((node = group[i]) && filter.call(node, node.__data__, i)) { + subgroup.push(node); + } + } + } + return d3_transition(subgroups, this.id); + }; + d3_transitionPrototype.tween = function(name, tween) { + var id = this.id; + if (arguments.length < 2) return this.node().__transition__[id].tween.get(name); + return d3_selection_each(this, tween == null ? function(node) { + node.__transition__[id].tween.remove(name); + } : function(node) { + node.__transition__[id].tween.set(name, tween); + }); + }; + function d3_transition_tween(groups, name, value, tween) { + var id = groups.id; + return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].tween.set(name, tween(value.call(node, node.__data__, i, j))); + } : (value = tween(value), function(node) { + node.__transition__[id].tween.set(name, value); + })); + } + d3_transitionPrototype.attr = function(nameNS, value) { + if (arguments.length < 2) { + for (value in nameNS) this.attr(value, nameNS[value]); + return this; + } + var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS); + function attrNull() { + this.removeAttribute(name); + } + function attrNullNS() { + this.removeAttributeNS(name.space, name.local); + } + function attrTween(b) { + return b == null ? attrNull : (b += "", function() { + var a = this.getAttribute(name), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttribute(name, i(t)); + }); + }); + } + function attrTweenNS(b) { + return b == null ? attrNullNS : (b += "", function() { + var a = this.getAttributeNS(name.space, name.local), i; + return a !== b && (i = interpolate(a, b), function(t) { + this.setAttributeNS(name.space, name.local, i(t)); + }); + }); + } + return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.attrTween = function(nameNS, tween) { + var name = d3.ns.qualify(nameNS); + function attrTween(d, i) { + var f = tween.call(this, d, i, this.getAttribute(name)); + return f && function(t) { + this.setAttribute(name, f(t)); + }; + } + function attrTweenNS(d, i) { + var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); + return f && function(t) { + this.setAttributeNS(name.space, name.local, f(t)); + }; + } + return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); + }; + d3_transitionPrototype.style = function(name, value, priority) { + var n = arguments.length; + if (n < 3) { + if (typeof name !== "string") { + if (n < 2) value = ""; + for (priority in name) this.style(priority, name[priority], value); + return this; + } + priority = ""; + } + function styleNull() { + this.style.removeProperty(name); + } + function styleString(b) { + return b == null ? styleNull : (b += "", function() { + var a = d3_window.getComputedStyle(this, null).getPropertyValue(name), i; + return a !== b && (i = d3_interpolate(a, b), function(t) { + this.style.setProperty(name, i(t), priority); + }); + }); + } + return d3_transition_tween(this, "style." + name, value, styleString); + }; + d3_transitionPrototype.styleTween = function(name, tween, priority) { + if (arguments.length < 3) priority = ""; + function styleTween(d, i) { + var f = tween.call(this, d, i, d3_window.getComputedStyle(this, null).getPropertyValue(name)); + return f && function(t) { + this.style.setProperty(name, f(t), priority); + }; + } + return this.tween("style." + name, styleTween); + }; + d3_transitionPrototype.text = function(value) { + return d3_transition_tween(this, "text", value, d3_transition_text); + }; + function d3_transition_text(b) { + if (b == null) b = ""; + return function() { + this.textContent = b; + }; + } + d3_transitionPrototype.remove = function() { + return this.each("end.transition", function() { + var p; + if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); + }); + }; + d3_transitionPrototype.ease = function(value) { + var id = this.id; + if (arguments.length < 1) return this.node().__transition__[id].ease; + if (typeof value !== "function") value = d3.ease.apply(d3, arguments); + return d3_selection_each(this, function(node) { + node.__transition__[id].ease = value; + }); + }; + d3_transitionPrototype.delay = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].delay = value.call(node, node.__data__, i, j) | 0; + } : (value |= 0, function(node) { + node.__transition__[id].delay = value; + })); + }; + d3_transitionPrototype.duration = function(value) { + var id = this.id; + return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { + node.__transition__[id].duration = Math.max(1, value.call(node, node.__data__, i, j) | 0); + } : (value = Math.max(1, value | 0), function(node) { + node.__transition__[id].duration = value; + })); + }; + d3_transitionPrototype.each = function(type, listener) { + var id = this.id; + if (arguments.length < 2) { + var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId; + d3_transitionInheritId = id; + d3_selection_each(this, function(node, i, j) { + d3_transitionInherit = node.__transition__[id]; + type.call(node, node.__data__, i, j); + }); + d3_transitionInherit = inherit; + d3_transitionInheritId = inheritId; + } else { + d3_selection_each(this, function(node) { + var transition = node.__transition__[id]; + (transition.event || (transition.event = d3.dispatch("start", "end"))).on(type, listener); + }); + } + return this; + }; + d3_transitionPrototype.transition = function() { + var id0 = this.id, id1 = ++d3_transitionId, subgroups = [], subgroup, group, node, transition; + for (var j = 0, m = this.length; j < m; j++) { + subgroups.push(subgroup = []); + for (var group = this[j], i = 0, n = group.length; i < n; i++) { + if (node = group[i]) { + transition = Object.create(node.__transition__[id0]); + transition.delay += transition.duration; + d3_transitionNode(node, i, id1, transition); + } + subgroup.push(node); + } + } + return d3_transition(subgroups, id1); + }; + function d3_transitionNode(node, i, id, inherit) { + var lock = node.__transition__ || (node.__transition__ = { + active: 0, + count: 0 + }), transition = lock[id]; + if (!transition) { + var time = inherit.time; + transition = lock[id] = { + tween: new d3_Map(), + time: time, + ease: inherit.ease, + delay: inherit.delay, + duration: inherit.duration + }; + ++lock.count; + d3.timer(function(elapsed) { + var d = node.__data__, ease = transition.ease, delay = transition.delay, duration = transition.duration, tweened = []; + if (delay <= elapsed) return start(elapsed); + d3_timer_replace(start, delay, time); + function start(elapsed) { + if (lock.active > id) return stop(); + lock.active = id; + transition.event && transition.event.start.call(node, d, i); + transition.tween.forEach(function(key, value) { + if (value = value.call(node, d, i)) { + tweened.push(value); + } + }); + if (tick(elapsed)) return 1; + d3_timer_replace(tick, 0, time); + } + function tick(elapsed) { + if (lock.active !== id) return stop(); + var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; + while (n > 0) { + tweened[--n].call(node, e); + } + if (t >= 1) { + stop(); + transition.event && transition.event.end.call(node, d, i); + return 1; + } + } + function stop() { + if (--lock.count) delete lock[id]; else delete node.__transition__; + return 1; + } + }, 0, time); + } + } + d3.svg.axis = function() { + var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; + function axis(g) { + g.each(function() { + var g = d3.select(this); + var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; + var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".tick.minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", ".tick").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); + var tick = g.selectAll(".tick.major").data(ticks, String), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick major").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; + var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"), + d3.transition(path)); + var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; + this.__chart__ = scale1; + tickEnter.append("line"); + tickEnter.append("text"); + var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); + switch (orient) { + case "bottom": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); + lineEnter.attr("y2", tickMajorSize); + textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); + textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); + text.attr("dy", ".71em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); + break; + } + + case "top": + { + tickTransform = d3_svg_axisX; + subtickEnter.attr("y2", -tickMinorSize); + subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); + lineEnter.attr("y2", -tickMajorSize); + textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); + textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); + text.attr("dy", "0em").style("text-anchor", "middle"); + pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); + break; + } + + case "left": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", -tickMinorSize); + subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", -tickMajorSize); + textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); + lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); + textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "end"); + pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); + break; + } + + case "right": + { + tickTransform = d3_svg_axisY; + subtickEnter.attr("x2", tickMinorSize); + subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); + lineEnter.attr("x2", tickMajorSize); + textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); + lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); + textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); + text.attr("dy", ".32em").style("text-anchor", "start"); + pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); + break; + } + } + if (scale.rangeBand) { + var dx = scale1.rangeBand() / 2, x = function(d) { + return scale1(d) + dx; + }; + tickEnter.call(tickTransform, x); + tickUpdate.call(tickTransform, x); + } else { + tickEnter.call(tickTransform, scale0); + tickUpdate.call(tickTransform, scale1); + tickExit.call(tickTransform, scale1); + subtickEnter.call(tickTransform, scale0); + subtickUpdate.call(tickTransform, scale1); + subtickExit.call(tickTransform, scale1); + } + }); + } + axis.scale = function(x) { + if (!arguments.length) return scale; + scale = x; + return axis; + }; + axis.orient = function(x) { + if (!arguments.length) return orient; + orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient; + return axis; + }; + axis.ticks = function() { + if (!arguments.length) return tickArguments_; + tickArguments_ = arguments; + return axis; + }; + axis.tickValues = function(x) { + if (!arguments.length) return tickValues; + tickValues = x; + return axis; + }; + axis.tickFormat = function(x) { + if (!arguments.length) return tickFormat_; + tickFormat_ = x; + return axis; + }; + axis.tickSize = function(x, y) { + if (!arguments.length) return tickMajorSize; + var n = arguments.length - 1; + tickMajorSize = +x; + tickMinorSize = n > 1 ? +y : tickMajorSize; + tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; + return axis; + }; + axis.tickPadding = function(x) { + if (!arguments.length) return tickPadding; + tickPadding = +x; + return axis; + }; + axis.tickSubdivide = function(x) { + if (!arguments.length) return tickSubdivide; + tickSubdivide = +x; + return axis; + }; + return axis; + }; + var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = { + top: 1, + right: 1, + bottom: 1, + left: 1 + }; + function d3_svg_axisX(selection, x) { + selection.attr("transform", function(d) { + return "translate(" + x(d) + ",0)"; + }); + } + function d3_svg_axisY(selection, y) { + selection.attr("transform", function(d) { + return "translate(0," + y(d) + ")"; + }); + } + function d3_svg_axisSubdivide(scale, ticks, m) { + subticks = []; + if (m && ticks.length > 1) { + var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; + while (++i < n) { + for (j = m; --j > 0; ) { + if ((v = +ticks[i] - j * d) >= extent[0]) { + subticks.push(v); + } + } + } + for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { + subticks.push(v); + } + } + return subticks; + } + d3.svg.brush = function() { + var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], clamp = [ true, true ], extentDomain; + function brush(g) { + g.each(function() { + var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; + g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); + bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); + fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); + tz.enter().append("g").attr("class", function(d) { + return "resize " + d; + }).style("cursor", function(d) { + return d3_svg_brushCursor[d]; + }).append("rect").attr("x", function(d) { + return /[ew]$/.test(d) ? -3 : null; + }).attr("y", function(d) { + return /^[ns]/.test(d) ? -3 : null; + }).attr("width", 6).attr("height", 6).style("visibility", "hidden"); + tz.style("display", brush.empty() ? "none" : null); + tz.exit().remove(); + if (x) { + e = d3_scaleRange(x); + bg.attr("x", e[0]).attr("width", e[1] - e[0]); + redrawX(g); + } + if (y) { + e = d3_scaleRange(y); + bg.attr("y", e[0]).attr("height", e[1] - e[0]); + redrawY(g); + } + redraw(g); + }); + } + function redraw(g) { + g.selectAll(".resize").attr("transform", function(d) { + return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; + }); + } + function redrawX(g) { + g.select(".extent").attr("x", extent[0][0]); + g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); + } + function redrawY(g) { + g.select(".extent").attr("y", extent[0][1]); + g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); + } + function brushstart() { + var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), dragRestore = d3_event_dragSuppress(), center, origin = mouse(), offset; + var w = d3.select(d3_window).on("keydown.brush", keydown).on("keyup.brush", keyup); + if (d3.event.changedTouches) { + w.on("touchmove.brush", brushmove).on("touchend.brush", brushend); + } else { + w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend); + } + if (dragging) { + origin[0] = extent[0][0] - origin[0]; + origin[1] = extent[0][1] - origin[1]; + } else if (resizing) { + var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); + offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; + origin[0] = extent[ex][0]; + origin[1] = extent[ey][1]; + } else if (d3.event.altKey) center = origin.slice(); + g.style("pointer-events", "none").selectAll(".resize").style("display", null); + d3.select("body").style("cursor", eventTarget.style("cursor")); + event_({ + type: "brushstart" + }); + brushmove(); + function mouse() { + var touches = d3.event.changedTouches; + return touches ? d3.touches(target, touches)[0] : d3.mouse(target); + } + function keydown() { + if (d3.event.keyCode == 32) { + if (!dragging) { + center = null; + origin[0] -= extent[1][0]; + origin[1] -= extent[1][1]; + dragging = 2; + } + d3_eventPreventDefault(); + } + } + function keyup() { + if (d3.event.keyCode == 32 && dragging == 2) { + origin[0] += extent[1][0]; + origin[1] += extent[1][1]; + dragging = 0; + d3_eventPreventDefault(); + } + } + function brushmove() { + var point = mouse(), moved = false; + if (offset) { + point[0] += offset[0]; + point[1] += offset[1]; + } + if (!dragging) { + if (d3.event.altKey) { + if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; + origin[0] = extent[+(point[0] < center[0])][0]; + origin[1] = extent[+(point[1] < center[1])][1]; + } else center = null; + } + if (resizingX && move1(point, x, 0)) { + redrawX(g); + moved = true; + } + if (resizingY && move1(point, y, 1)) { + redrawY(g); + moved = true; + } + if (moved) { + redraw(g); + event_({ + type: "brush", + mode: dragging ? "move" : "resize" + }); + } + } + function move1(point, scale, i) { + var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; + if (dragging) { + r0 -= position; + r1 -= size + position; + } + min = clamp[i] ? Math.max(r0, Math.min(r1, point[i])) : point[i]; + if (dragging) { + max = (min += position) + size; + } else { + if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); + if (position < min) { + max = min; + min = position; + } else { + max = position; + } + } + if (extent[0][i] !== min || extent[1][i] !== max) { + extentDomain = null; + extent[0][i] = min; + extent[1][i] = max; + return true; + } + } + function brushend() { + brushmove(); + g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); + d3.select("body").style("cursor", null); + w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); + dragRestore(); + event_({ + type: "brushend" + }); + } + } + brush.x = function(z) { + if (!arguments.length) return x; + x = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.y = function(z) { + if (!arguments.length) return y; + y = z; + resizes = d3_svg_brushResizes[!x << 1 | !y]; + return brush; + }; + brush.clamp = function(z) { + if (!arguments.length) return x && y ? clamp : x || y ? clamp[+!x] : null; + if (x && y) clamp = [ !!z[0], !!z[1] ]; else if (x || y) clamp[+!x] = !!z; + return brush; + }; + brush.extent = function(z) { + var x0, x1, y0, y1, t; + if (!arguments.length) { + z = extentDomain || extent; + if (x) { + x0 = z[0][0], x1 = z[1][0]; + if (!extentDomain) { + x0 = extent[0][0], x1 = extent[1][0]; + if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + } + } + if (y) { + y0 = z[0][1], y1 = z[1][1]; + if (!extentDomain) { + y0 = extent[0][1], y1 = extent[1][1]; + if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + } + } + return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; + } + extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; + if (x) { + x0 = z[0], x1 = z[1]; + if (y) x0 = x0[0], x1 = x1[0]; + extentDomain[0][0] = x0, extentDomain[1][0] = x1; + if (x.invert) x0 = x(x0), x1 = x(x1); + if (x1 < x0) t = x0, x0 = x1, x1 = t; + extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; + } + if (y) { + y0 = z[0], y1 = z[1]; + if (x) y0 = y0[1], y1 = y1[1]; + extentDomain[0][1] = y0, extentDomain[1][1] = y1; + if (y.invert) y0 = y(y0), y1 = y(y1); + if (y1 < y0) t = y0, y0 = y1, y1 = t; + extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; + } + return brush; + }; + brush.clear = function() { + extentDomain = null; + extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; + return brush; + }; + brush.empty = function() { + return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; + }; + return d3.rebind(brush, event, "on"); + }; + var d3_svg_brushCursor = { + n: "ns-resize", + e: "ew-resize", + s: "ns-resize", + w: "ew-resize", + nw: "nwse-resize", + ne: "nesw-resize", + se: "nwse-resize", + sw: "nesw-resize" + }; + var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; + d3.time = {}; + var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; + function d3_time_utc() { + this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); + } + d3_time_utc.prototype = { + getDate: function() { + return this._.getUTCDate(); + }, + getDay: function() { + return this._.getUTCDay(); + }, + getFullYear: function() { + return this._.getUTCFullYear(); + }, + getHours: function() { + return this._.getUTCHours(); + }, + getMilliseconds: function() { + return this._.getUTCMilliseconds(); + }, + getMinutes: function() { + return this._.getUTCMinutes(); + }, + getMonth: function() { + return this._.getUTCMonth(); + }, + getSeconds: function() { + return this._.getUTCSeconds(); + }, + getTime: function() { + return this._.getTime(); + }, + getTimezoneOffset: function() { + return 0; + }, + valueOf: function() { + return this._.valueOf(); + }, + setDate: function() { + d3_time_prototype.setUTCDate.apply(this._, arguments); + }, + setDay: function() { + d3_time_prototype.setUTCDay.apply(this._, arguments); + }, + setFullYear: function() { + d3_time_prototype.setUTCFullYear.apply(this._, arguments); + }, + setHours: function() { + d3_time_prototype.setUTCHours.apply(this._, arguments); + }, + setMilliseconds: function() { + d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); + }, + setMinutes: function() { + d3_time_prototype.setUTCMinutes.apply(this._, arguments); + }, + setMonth: function() { + d3_time_prototype.setUTCMonth.apply(this._, arguments); + }, + setSeconds: function() { + d3_time_prototype.setUTCSeconds.apply(this._, arguments); + }, + setTime: function() { + d3_time_prototype.setTime.apply(this._, arguments); + } + }; + var d3_time_prototype = Date.prototype; + var d3_time_formatDateTime = "%a %b %e %X %Y", d3_time_formatDate = "%m/%d/%Y", d3_time_formatTime = "%H:%M:%S"; + var d3_time_days = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], d3_time_dayAbbreviations = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + function d3_time_interval(local, step, number) { + function round(date) { + var d0 = local(date), d1 = offset(d0, 1); + return date - d0 < d1 - date ? d0 : d1; + } + function ceil(date) { + step(date = local(new d3_time(date - 1)), 1); + return date; + } + function offset(date, k) { + step(date = new d3_time(+date), k); + return date; + } + function range(t0, t1, dt) { + var time = ceil(t0), times = []; + if (dt > 1) { + while (time < t1) { + if (!(number(time) % dt)) times.push(new Date(+time)); + step(time, 1); + } + } else { + while (time < t1) times.push(new Date(+time)), step(time, 1); + } + return times; + } + function range_utc(t0, t1, dt) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = t0; + return range(utc, t1, dt); + } finally { + d3_time = Date; + } + } + local.floor = local; + local.round = round; + local.ceil = ceil; + local.offset = offset; + local.range = range; + var utc = local.utc = d3_time_interval_utc(local); + utc.floor = utc; + utc.round = d3_time_interval_utc(round); + utc.ceil = d3_time_interval_utc(ceil); + utc.offset = d3_time_interval_utc(offset); + utc.range = range_utc; + return local; + } + function d3_time_interval_utc(method) { + return function(date, k) { + try { + d3_time = d3_time_utc; + var utc = new d3_time_utc(); + utc._ = date; + return method(utc, k)._; + } finally { + d3_time = Date; + } + }; + } + d3.time.year = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setMonth(0, 1); + return date; + }, function(date, offset) { + date.setFullYear(date.getFullYear() + offset); + }, function(date) { + return date.getFullYear(); + }); + d3.time.years = d3.time.year.range; + d3.time.years.utc = d3.time.year.utc.range; + d3.time.day = d3_time_interval(function(date) { + var day = new d3_time(2e3, 0); + day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); + return day; + }, function(date, offset) { + date.setDate(date.getDate() + offset); + }, function(date) { + return date.getDate() - 1; + }); + d3.time.days = d3.time.day.range; + d3.time.days.utc = d3.time.day.utc.range; + d3.time.dayOfYear = function(date) { + var year = d3.time.year(date); + return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); + }; + d3_time_daySymbols.forEach(function(day, i) { + day = day.toLowerCase(); + i = 7 - i; + var interval = d3.time[day] = d3_time_interval(function(date) { + (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); + return date; + }, function(date, offset) { + date.setDate(date.getDate() + Math.floor(offset) * 7); + }, function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); + }); + d3.time[day + "s"] = interval.range; + d3.time[day + "s"].utc = interval.utc.range; + d3.time[day + "OfYear"] = function(date) { + var day = d3.time.year(date).getDay(); + return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); + }; + }); + d3.time.week = d3.time.sunday; + d3.time.weeks = d3.time.sunday.range; + d3.time.weeks.utc = d3.time.sunday.utc.range; + d3.time.weekOfYear = d3.time.sundayOfYear; + d3.time.format = function(template) { + var n = template.length; + function format(date) { + var string = [], i = -1, j = 0, c, p, f; + while (++i < n) { + if (template.charCodeAt(i) === 37) { + string.push(template.substring(j, i)); + if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i); + if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p); + string.push(c); + j = i + 1; + } + } + string.push(template.substring(j, i)); + return string.join(""); + } + format.parse = function(string) { + var d = { + y: 1900, + m: 0, + d: 1, + H: 0, + M: 0, + S: 0, + L: 0 + }, i = d3_time_parse(d, template, string, 0); + if (i != string.length) return null; + if ("p" in d) d.H = d.H % 12 + d.p * 12; + var date = new d3_time(); + if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("w" in d && ("W" in d || "U" in d)) { + date.setFullYear(d.y, 0, 1); + date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7); + } else date.setFullYear(d.y, d.m, d.d); + date.setHours(d.H, d.M, d.S, d.L); + return date; + }; + format.toString = function() { + return template; + }; + return format; + }; + function d3_time_parse(date, template, string, j) { + var c, p, i = 0, n = template.length, m = string.length; + while (i < n) { + if (j >= m) return -1; + c = template.charCodeAt(i++); + if (c === 37) { + p = d3_time_parsers[template.charAt(i++)]; + if (!p || (j = p(date, string, j)) < 0) return -1; + } else if (c != string.charCodeAt(j++)) { + return -1; + } + } + return j; + } + function d3_time_formatRe(names) { + return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); + } + function d3_time_formatLookup(names) { + var map = new d3_Map(), i = -1, n = names.length; + while (++i < n) map.set(names[i].toLowerCase(), i); + return map; + } + function d3_time_formatPad(value, fill, width) { + var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length; + return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string); + } + var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayLookup = d3_time_formatLookup(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_dayAbbrevLookup = d3_time_formatLookup(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations), d3_time_percentRe = /^%/; + var d3_time_formatPads = { + "-": "", + _: " ", + "0": "0" + }; + var d3_time_formats = { + a: function(d) { + return d3_time_dayAbbreviations[d.getDay()]; + }, + A: function(d) { + return d3_time_days[d.getDay()]; + }, + b: function(d) { + return d3_time_monthAbbreviations[d.getMonth()]; + }, + B: function(d) { + return d3_time_months[d.getMonth()]; + }, + c: d3.time.format(d3_time_formatDateTime), + d: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + e: function(d, p) { + return d3_time_formatPad(d.getDate(), p, 2); + }, + H: function(d, p) { + return d3_time_formatPad(d.getHours(), p, 2); + }, + I: function(d, p) { + return d3_time_formatPad(d.getHours() % 12 || 12, p, 2); + }, + j: function(d, p) { + return d3_time_formatPad(1 + d3.time.dayOfYear(d), p, 3); + }, + L: function(d, p) { + return d3_time_formatPad(d.getMilliseconds(), p, 3); + }, + m: function(d, p) { + return d3_time_formatPad(d.getMonth() + 1, p, 2); + }, + M: function(d, p) { + return d3_time_formatPad(d.getMinutes(), p, 2); + }, + p: function(d) { + return d.getHours() >= 12 ? "PM" : "AM"; + }, + S: function(d, p) { + return d3_time_formatPad(d.getSeconds(), p, 2); + }, + U: function(d, p) { + return d3_time_formatPad(d3.time.sundayOfYear(d), p, 2); + }, + w: function(d) { + return d.getDay(); + }, + W: function(d, p) { + return d3_time_formatPad(d3.time.mondayOfYear(d), p, 2); + }, + x: d3.time.format(d3_time_formatDate), + X: d3.time.format(d3_time_formatTime), + y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 100, p, 2); + }, + Y: function(d, p) { + return d3_time_formatPad(d.getFullYear() % 1e4, p, 4); + }, + Z: d3_time_zone, + "%": function() { + return "%"; + } + }; + var d3_time_parsers = { + a: d3_time_parseWeekdayAbbrev, + A: d3_time_parseWeekday, + b: d3_time_parseMonthAbbrev, + B: d3_time_parseMonth, + c: d3_time_parseLocaleFull, + d: d3_time_parseDay, + e: d3_time_parseDay, + H: d3_time_parseHour24, + I: d3_time_parseHour24, + j: d3_time_parseDayOfYear, + L: d3_time_parseMilliseconds, + m: d3_time_parseMonthNumber, + M: d3_time_parseMinutes, + p: d3_time_parseAmPm, + S: d3_time_parseSeconds, + U: d3_time_parseWeekNumberSunday, + w: d3_time_parseWeekdayNumber, + W: d3_time_parseWeekNumberMonday, + x: d3_time_parseLocaleDate, + X: d3_time_parseLocaleTime, + y: d3_time_parseYear, + Y: d3_time_parseFullYear, + "%": d3_time_parseLiteralPercent + }; + function d3_time_parseWeekdayAbbrev(date, string, i) { + d3_time_dayAbbrevRe.lastIndex = 0; + var n = d3_time_dayAbbrevRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekday(date, string, i) { + d3_time_dayRe.lastIndex = 0; + var n = d3_time_dayRe.exec(string.substring(i)); + return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseWeekdayNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 1)); + return n ? (date.w = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberSunday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.U = +n[0], i + n[0].length) : -1; + } + function d3_time_parseWeekNumberMonday(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i)); + return n ? (date.W = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMonthAbbrev(date, string, i) { + d3_time_monthAbbrevRe.lastIndex = 0; + var n = d3_time_monthAbbrevRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseMonth(date, string, i) { + d3_time_monthRe.lastIndex = 0; + var n = d3_time_monthRe.exec(string.substring(i)); + return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1; + } + function d3_time_parseLocaleFull(date, string, i) { + return d3_time_parse(date, d3_time_formats.c.toString(), string, i); + } + function d3_time_parseLocaleDate(date, string, i) { + return d3_time_parse(date, d3_time_formats.x.toString(), string, i); + } + function d3_time_parseLocaleTime(date, string, i) { + return d3_time_parse(date, d3_time_formats.X.toString(), string, i); + } + function d3_time_parseFullYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 4)); + return n ? (date.y = +n[0], i + n[0].length) : -1; + } + function d3_time_parseYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1; + } + function d3_time_expandYear(d) { + return d + (d > 68 ? 1900 : 2e3); + } + function d3_time_parseMonthNumber(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.m = n[0] - 1, i + n[0].length) : -1; + } + function d3_time_parseDay(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.d = +n[0], i + n[0].length) : -1; + } + function d3_time_parseDayOfYear(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.j = +n[0], i + n[0].length) : -1; + } + function d3_time_parseHour24(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.H = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMinutes(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.M = +n[0], i + n[0].length) : -1; + } + function d3_time_parseSeconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 2)); + return n ? (date.S = +n[0], i + n[0].length) : -1; + } + function d3_time_parseMilliseconds(date, string, i) { + d3_time_numberRe.lastIndex = 0; + var n = d3_time_numberRe.exec(string.substring(i, i + 3)); + return n ? (date.L = +n[0], i + n[0].length) : -1; + } + var d3_time_numberRe = /^\s*\d+/; + function d3_time_parseAmPm(date, string, i) { + var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); + return n == null ? -1 : (date.p = n, i); + } + var d3_time_amPmLookup = d3.map({ + am: 0, + pm: 1 + }); + function d3_time_zone(d) { + var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; + return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2); + } + function d3_time_parseLiteralPercent(date, string, i) { + d3_time_percentRe.lastIndex = 0; + var n = d3_time_percentRe.exec(string.substring(i, i + 1)); + return n ? i + n[0].length : -1; + } + d3.time.format.utc = function(template) { + var local = d3.time.format(template); + function format(date) { + try { + d3_time = d3_time_utc; + var utc = new d3_time(); + utc._ = date; + return local(utc); + } finally { + d3_time = Date; + } + } + format.parse = function(string) { + try { + d3_time = d3_time_utc; + var date = local.parse(string); + return date && date._; + } finally { + d3_time = Date; + } + }; + format.toString = local.toString; + return format; + }; + var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); + d3.time.format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso; + function d3_time_formatIsoNative(date) { + return date.toISOString(); + } + d3_time_formatIsoNative.parse = function(string) { + var date = new Date(string); + return isNaN(date) ? null : date; + }; + d3_time_formatIsoNative.toString = d3_time_formatIso.toString; + d3.time.second = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 1e3) * 1e3); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 1e3); + }, function(date) { + return date.getSeconds(); + }); + d3.time.seconds = d3.time.second.range; + d3.time.seconds.utc = d3.time.second.utc.range; + d3.time.minute = d3_time_interval(function(date) { + return new d3_time(Math.floor(date / 6e4) * 6e4); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 6e4); + }, function(date) { + return date.getMinutes(); + }); + d3.time.minutes = d3.time.minute.range; + d3.time.minutes.utc = d3.time.minute.utc.range; + d3.time.hour = d3_time_interval(function(date) { + var timezone = date.getTimezoneOffset() / 60; + return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); + }, function(date, offset) { + date.setTime(date.getTime() + Math.floor(offset) * 36e5); + }, function(date) { + return date.getHours(); + }); + d3.time.hours = d3.time.hour.range; + d3.time.hours.utc = d3.time.hour.utc.range; + d3.time.month = d3_time_interval(function(date) { + date = d3.time.day(date); + date.setDate(1); + return date; + }, function(date, offset) { + date.setMonth(date.getMonth() + offset); + }, function(date) { + return date.getMonth(); + }); + d3.time.months = d3.time.month.range; + d3.time.months.utc = d3.time.month.utc.range; + function d3_time_scale(linear, methods, format) { + function scale(x) { + return linear(x); + } + scale.invert = function(x) { + return d3_time_scaleDate(linear.invert(x)); + }; + scale.domain = function(x) { + if (!arguments.length) return linear.domain().map(d3_time_scaleDate); + linear.domain(x); + return scale; + }; + scale.nice = function(m) { + return scale.domain(d3_scale_nice(scale.domain(), m)); + }; + scale.ticks = function(m, k) { + var extent = d3_scaleExtent(scale.domain()); + if (typeof m !== "function") { + var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); + if (i == d3_time_scaleSteps.length) return methods.year(extent, m); + if (!i) return linear.ticks(m).map(d3_time_scaleDate); + if (target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target) --i; + m = methods[i]; + k = m[1]; + m = m[0].range; + } + return m(extent[0], new Date(+extent[1] + 1), k); + }; + scale.tickFormat = function() { + return format; + }; + scale.copy = function() { + return d3_time_scale(linear.copy(), methods, format); + }; + return d3_scale_linearRebind(scale, linear); + } + function d3_time_scaleDate(t) { + return new Date(t); + } + function d3_time_scaleFormat(formats) { + return function(date) { + var i = formats.length - 1, f = formats[i]; + while (!f[1](date)) f = formats[--i]; + return f[0](date); + }; + } + function d3_time_scaleSetYear(y) { + var d = new Date(y, 0, 1); + d.setFullYear(y); + return d; + } + function d3_time_scaleGetYear(d) { + var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; + var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; + var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), d3_true ], [ d3.time.format("%B"), function(d) { + return d.getMonth(); + } ], [ d3.time.format("%b %d"), function(d) { + return d.getDate() != 1; + } ], [ d3.time.format("%a %d"), function(d) { + return d.getDay() && d.getDate() != 1; + } ], [ d3.time.format("%I %p"), function(d) { + return d.getHours(); + } ], [ d3.time.format("%I:%M"), function(d) { + return d.getMinutes(); + } ], [ d3.time.format(":%S"), function(d) { + return d.getSeconds(); + } ], [ d3.time.format(".%L"), function(d) { + return d.getMilliseconds(); + } ] ]; + var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); + d3_time_scaleLocalMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); + }; + d3.time.scale = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); + }; + var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { + return [ m[0].utc, m[1] ]; + }); + var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), d3_true ], [ d3.time.format.utc("%B"), function(d) { + return d.getUTCMonth(); + } ], [ d3.time.format.utc("%b %d"), function(d) { + return d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%a %d"), function(d) { + return d.getUTCDay() && d.getUTCDate() != 1; + } ], [ d3.time.format.utc("%I %p"), function(d) { + return d.getUTCHours(); + } ], [ d3.time.format.utc("%I:%M"), function(d) { + return d.getUTCMinutes(); + } ], [ d3.time.format.utc(":%S"), function(d) { + return d.getUTCSeconds(); + } ], [ d3.time.format.utc(".%L"), function(d) { + return d.getUTCMilliseconds(); + } ] ]; + var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); + function d3_time_scaleUTCSetYear(y) { + var d = new Date(Date.UTC(y, 0, 1)); + d.setUTCFullYear(y); + return d; + } + function d3_time_scaleUTCGetYear(d) { + var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); + return y + (d - d0) / (d1 - d0); + } + d3_time_scaleUTCMethods.year = function(extent, m) { + return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); + }; + d3.time.scale.utc = function() { + return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); + }; + d3.text = d3_xhrType(function(request) { + return request.responseText; + }); + d3.json = function(url, callback) { + return d3_xhr(url, "application/json", d3_json, callback); + }; + function d3_json(request) { + return JSON.parse(request.responseText); + } + d3.html = function(url, callback) { + return d3_xhr(url, "text/html", d3_html, callback); + }; + function d3_html(request) { + var range = d3_document.createRange(); + range.selectNode(d3_document.body); + return range.createContextualFragment(request.responseText); + } + d3.xml = d3_xhrType(function(request) { + return request.responseXML; + }); + return d3; +}(); +},{}],29:[function(require,module,exports){ +require("./d3"); +module.exports = d3; +(function () { delete this.d3; })(); // unset global + +},{"./d3":28}],30:[function(require,module,exports){ +var ich = require('icanhaz') + +module.exports.ich = ich + +module.exports.getKeywordCount = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group.length + if (group = []) return "0" +} + +module.exports.getKeyword = function(data, keyword) { + var group = [] + data.forEach(function (d) { + for(var key in d) { + var value = d[key].toString().toLowerCase() + if (value.match(keyword.toLowerCase())) group.push(d) + } + }) + return group + if (group = []) return "no matches" +} + +module.exports.getColumnTotal = function(data, column) { + var total = [] + data.forEach(function (d) { + if (d[column] === "") return + total.push(+d[column]) + }) + return total.reduce(function(a,b) { + return a + b + }) +} + +module.exports.getColumnAverage = function(data, column) { + var total = getColumnTotal(data, column) + var average = total / data.length + return average +} + +module.exports.getMax = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() > result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +module.exports.getMin = function(data, column) { + var result = [] + data.forEach(function (element){ + if (result.length === 0) return result.push(element) + else { + if (element[column].valueOf() < result[0][column].valueOf()) { + result.length = 0 + return result.push(element) + } + if (element[column].valueOf() === result[0][column].valueOf()) { + return result.push(element) + } + } + }) + return result +} + +// out of the data, filter something from a category +module.exports.getMatches = function (data, filter, category) { + var matches = [] + data.forEach(function (element) { + var projectType = element[category].toString().toLowerCase() + if (projectType === filter.toLowerCase()) matches.push(element) + }) + return matches +} + +module.exports.mostFrequent = function(data, category) { + var count = {} + for (var i = 0; i < data.length; i++) { + if (!count[data[i][category]]) { + count[data[i][category]] = 0 + } + count[data[i][category]]++ + } + var sortable = [] + for (var category in count) { + sortable.push([category, count[category]]) + } + sortable.sort(function(a, b) {return b[1] - a[1]}) + return sortable + // returns array of arrays, in order +} + +// thank you! http://james.padolsey.com/javascript/deep-copying-of-objects-and-arrays/ +module.exports.deepCopy = function(obj) { + if (Object.prototype.toString.call(obj) === '[object Array]') { + var out = [], i = 0, len = obj.length; + for ( ; i < len; i++ ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + if (typeof obj === 'object') { + var out = {}, i; + for ( i in obj ) { + out[i] = arguments.callee(obj[i]); + } + return out; + } + return obj; +} + +module.exports.getOccurance = function(data, category) { + var occuranceCount = {} + for (var i = 0; i < data.length; i++) { + if (!occuranceCount[data[i][category]]) { + occuranceCount[data[i][category]] = 0 + } + occuranceCount[data[i][category]]++ + } + return occuranceCount + // returns object, keys alphabetical +} + +module.exports.makeColorArrayOfObject = function(data, colors, category) { + var category = category + var keys = Object.keys(data) + var counter = 1 + var colorIndex + return keys.map(function(key){ + if (keys.length > colors.length || keys.length <= colors.length ) { + colorIndex = counter % colors.length + } + var h = {units: data[key], hexcolor: colors[colorIndex]} + h[category] = key + counter++ + colorIndex = counter + return h + }) +} + +module.exports.makeArrayOfObject = function(data) { + var keys = Object.keys(data) + return keys.map(function(key){ + // var h = {label: key, units: data[key], hexcolor: "#FDBDBD"} + var h = {label: key, units: data[key]} + return h + }) +} + +},{"icanhaz":31}],31:[function(require,module,exports){ +/*! +ICanHaz.js version 0.10.2 -- by @HenrikJoreteg +More info at: http://icanhazjs.com +*/ +(function () { +/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.4.0", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +/*! + ICanHaz.js -- by @HenrikJoreteg +*/ +/*global */ +(function () { + function trim(stuff) { + if (''.trim) return stuff.trim(); + else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + // Establish the root object, `window` in the browser, or `global` on the server. + var root = this; + + var ich = { + VERSION: "0.10.2", + templates: {}, + + // grab jquery or zepto if it's there + $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, + + // public function for adding templates + // can take a name and template string arguments + // or can take an object with name/template pairs + // We're enforcing uniqueness to avoid accidental template overwrites. + // If you want a different template, it should have a different name. + addTemplate: function (name, templateString) { + if (typeof name === 'object') { + for (var template in name) { + this.addTemplate(template, name[template]); + } + return; + } + if (ich[name]) { + console.error("Invalid name: " + name + "."); + } else if (ich.templates[name]) { + console.error("Template \"" + name + " \" exists"); + } else { + ich.templates[name] = templateString; + ich[name] = function (data, raw) { + data = data || {}; + var result = Mustache.to_html(ich.templates[name], data, ich.templates); + return (ich.$ && !raw) ? ich.$(trim(result)) : result; + }; + } + }, + + // clears all retrieval functions and empties cache + clearAll: function () { + for (var key in ich.templates) { + delete ich[key]; + } + ich.templates = {}; + }, + + // clears/grabs + refresh: function () { + ich.clearAll(); + ich.grabTemplates(); + }, + + // grabs templates from the DOM and caches them. + // Loop through and add templates. + // Whitespace at beginning and end of all templates inside From 58c35df6dcad1f920ee779be1c25c32a3bbd5b13 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 14 Feb 2014 13:50:17 -0800 Subject: [PATCH 050/157] fix links, fixes #37 --- readme.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/readme.md b/readme.md index 3173752e..cba28b00 100644 --- a/readme.md +++ b/readme.md @@ -5,19 +5,19 @@ **Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. -Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](/docs/basics.md). +Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](./docs/basics.md). ## Modules -Each of **sheetsee.js**'s features are divided into modules. Use just the parts you need; see docs on [building](/docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). +Each of **sheetsee.js**'s features are divided into modules. Use just the parts you need; see docs on [building](./docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). | Module | Contains | Docs | | ------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------- | -| **sheetsee-core** | **Included in any build**. Gets you started and has the working-with-your-data functions. | [Doc](/docs/sheetsee-core.md) | -| **sheetsee-tables** | Contains everything you'll need to create a table including sortable columns, pagination and search.| [Doc](/docs/sheetsee-tables.md) | -| **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js. | [Doc](/docs/sheetsee-maps.md) | -| **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](/docs/sheetsee-charts.md) | +| **sheetsee-core** | **Included in any build**. Gets you started and has the working-with-your-data functions. | [Doc](./docs/sheetsee-core.md) | +| **sheetsee-tables** | Contains everything you'll need to create a table including sortable columns, pagination and search.| [Doc](./docs/sheetsee-tables.md) | +| **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js. | [Doc](./docs/sheetsee-maps.md) | +| **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](./docs/sheetsee-charts.md) | ## Making Things @@ -33,10 +33,10 @@ What can you make with **Sheetsee.js**? Lost of things, here are some examples: Demos pages for the documentation. -- [Table Demo](/demos/demo-table.html) -- [Map Demo](/demos/demo-map.html) -- [Chart Demo](/demos/demo-chart.html) -- [Basic Template](/demos/template.html) +- [Table Demo](./demos/demo-table.html) +- [Map Demo](./demos/demo-map.html) +- [Chart Demo](./demos/demo-chart.html) +- [Basic Template](./demos/template.html) ## Documentation @@ -44,19 +44,19 @@ More resources on using Sheetsee.js: #### Getting Started -- [About Sheetsee.js](docs/about.md) -- [Building Sheetsee](docs/building.md) -- [Basics](docs/basics.md) +- [About Sheetsee.js](./docs/about.md) +- [Building Sheetsee](./docs/building.md) +- [Basics](./docs/basics.md) #### Ideas -- [Fork-n-Go](docs/fork-n-go.md) -- [Tips!](docs/tips.md) -- [Custom charts](docs/custom-charts.md) +- [Fork-n-Go](./docs/fork-n-go.md) +- [Tips!](./docs/tips.md) +- [Custom charts](./docs/custom-charts.md) #### Use -- [Sheetsee-core](docs/sheetsee-core.md) -- [Sheetsee-tables](docs/sheetsee-tables.md) -- [Sheetsee-maps](docs/sheetsee-maps.md) -- [Sheetsee-charts](docs/sheetsee-charts.md) +- [Sheetsee-core](./docs/sheetsee-core.md) +- [Sheetsee-tables](./docs/sheetsee-tables.md) +- [Sheetsee-maps](./docs/sheetsee-maps.md) +- [Sheetsee-charts](./docs/sheetsee-charts.md) From 5203c92722a7096910c3e1608f06bbcbd09fa5b3 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 14 Feb 2014 13:51:52 -0800 Subject: [PATCH 051/157] rebuild site --- site/demos/demo-chart.html | 2 +- site/demos/demo-map.html | 2 +- site/demos/demo-table.html | 2 +- site/docs/about.html | 2 +- site/docs/basics.html | 2 +- site/docs/building.html | 2 +- site/docs/changelog.html | 2 +- site/docs/custom-charts.html | 2 +- site/docs/fork-n-go.html | 2 +- site/docs/sheetsee-charts.html | 2 +- site/docs/sheetsee-core.html | 2 +- site/docs/sheetsee-maps.html | 2 +- site/docs/sheetsee-tables.html | 2 +- site/docs/tips.html | 2 +- site/index.html | 42 +++++++++++++++++----------------- 15 files changed, 35 insertions(+), 35 deletions(-) diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index cc94c234..8ec2501b 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -62,7 +62,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home

    +

    Home Page

    diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index b5489c66..c0c258b8 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -55,7 +55,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home

    +

    Home Page

    diff --git a/site/docs/basics.html b/site/docs/basics.html index aa2fe35d..5ae26762 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -116,7 +116,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/building.html b/site/docs/building.html index b1eb3099..4bd15b12 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -74,7 +74,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/changelog.html b/site/docs/changelog.html index f31fe2a6..98d60727 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -66,7 +66,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 2a8a27e2..363f42d7 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -102,7 +102,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 01bbef36..41063615 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -71,7 +71,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 37d8bd5a..f663c2b9 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -143,7 +143,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index c511a187..2affba30 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -121,7 +121,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index c8d4e6e3..fc1cccbe 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -113,7 +113,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 3dbb2c98..ec3db3c1 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -135,7 +135,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/docs/tips.html b/site/docs/tips.html index 08295f71..5ff27e20 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -102,7 +102,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    diff --git a/site/index.html b/site/index.html index 9494b23a..c1fee176 100644 --- a/site/index.html +++ b/site/index.html @@ -18,9 +18,9 @@

    sheetseeimg

    Sheetsee.js

    Sheetsee.js is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts.

    -

    Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

    +

    Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

    Modules

    -

    Each of sheetsee.js's features are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    +

    Each of sheetsee.js's features are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    @@ -33,22 +33,22 @@

    Modules

    - + - + - + - +
    sheetsee-core Included in any build. Gets you started and has the working-with-your-data functions.DocDoc
    sheetsee-tables Contains everything you'll need to create a table including sortable columns, pagination and search.DocDoc
    sheetsee-maps For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js.DocDoc
    sheetsee-charts Includes 3 basic d3 charts: bar, line and pie. You can also use your own.DocDoc
    @@ -62,31 +62,31 @@

    Making Things

    Demos

    Demos pages for the documentation.

    Documentation

    More resources on using Sheetsee.js:

    Getting Started

    Ideas

    Use

    @@ -121,7 +121,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home Page

    From fb83f8400c20df1ee5bfff9544f63925d349e7c2 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Fri, 14 Feb 2014 15:05:18 -0800 Subject: [PATCH 052/157] remove tempalte line --- readme.md | 1 - site/index.html | 1 - 2 files changed, 2 deletions(-) diff --git a/readme.md b/readme.md index cba28b00..976f83ba 100644 --- a/readme.md +++ b/readme.md @@ -36,7 +36,6 @@ Demos pages for the documentation. - [Table Demo](./demos/demo-table.html) - [Map Demo](./demos/demo-map.html) - [Chart Demo](./demos/demo-chart.html) -- [Basic Template](./demos/template.html) ## Documentation diff --git a/site/index.html b/site/index.html index c1fee176..e1a58d6e 100644 --- a/site/index.html +++ b/site/index.html @@ -65,7 +65,6 @@

    Demos

  • Table Demo
  • Map Demo
  • Chart Demo
  • -
  • Basic Template
  • Documentation

    More resources on using Sheetsee.js:

    From e5f1c7d79836fb28b9c26dc5461472ab5a0fc764 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 23 Feb 2014 19:20:58 -0800 Subject: [PATCH 053/157] change to new tabletop in demos --- demos/demo-chart.html | 8 +- demos/demo-map.html | 8 +- demos/demo-table.html | 10 +- js/tabletop1.3.3.js | 471 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 484 insertions(+), 13 deletions(-) create mode 100644 js/tabletop1.3.3.js diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 8ec2501b..acb4db18 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -5,7 +5,7 @@ Sheetsee Chart Demo - + @@ -46,9 +46,9 @@

    Ideas

    Demos

    Use

      diff --git a/demos/demo-map.html b/demos/demo-map.html index c0c258b8..f18d5884 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -5,7 +5,7 @@ Sheetsee Maps Demo - + @@ -39,9 +39,9 @@

      Ideas

    Demos

    Use

      diff --git a/demos/demo-table.html b/demos/demo-table.html index 625272df..32dad8de 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -4,9 +4,9 @@ Sheetsee Table Demo - - + + +#Pagination {background: #eee;} +.pagination-next, .pagination-pre {cursor: hand;} +.no-pag {color: #acacac;} ``` ## Table Filter/Search @@ -127,9 +84,77 @@ Sheetsee.initiateTableFilter(tableOptions) It will connect that input to your data as well as inject this HTML for a button, which you can style yourself in your CSS: + ```HTML Clear no matches ``` +## Example + +_HTML_ + +```HTML +
      + +``` + +_Template_ + +```JavaScript + +``` + +_JavaScript_ + +```javascript + +``` + +To create another table, simply repeat the steps above (abreviated here below). + +_HTML_ +```HTML +
      + +``` +_Template_ + +```JavaScript + +``` + +_JavaScript_ + +```JavaScript + +``` + +Learn more about the things you can do with [ICanHaz.js](http://icanhazjs.com). + _[View Demo](/demos/demo-table.html)_ From 545d917f165351bd726456c4c38770b8b971e268 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 11 May 2014 11:54:38 +0200 Subject: [PATCH 068/157] update documentation, changelong re: new tables, spreadsheets --- docs/basics.md | 4 ++-- docs/changelog.md | 20 ++++++++++++++++++++ readme.md | 32 +++++++------------------------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index b4e3ee93..e227170a 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -31,8 +31,8 @@ Ignoring some HTML things to conserve space, you get the point. This is a basic - - + + diff --git a/docs/changelog.md b/docs/changelog.md index 78495125..25a8b313 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,25 @@ ### Sheetsee v3 +## May 10, 2014 +### Better Table Template Options + +Updated `sheetsee-tables` to allow you to re-use a template (rather than duplicating it for each different table you wanted to create). Previously it assumed your HTML table `div` id matched your script template `id`. This means that you can pass in an extra key/value pair in your table options into `Sheetsee.maketable()`. The new pair it takes is: `"templateID" : "yourtemplateid"`. Example below, full `sheetsee-tables` documentation [here](docs/sheetsee-tables.html). + +```JavaScript +var tableOptions = { + "data": gData, + "pagination": 10, + "tableDiv": "#fullTable", + "filterDiv": "#fullTableFilter", + "templateID": "tableTemplte" + } +Sheetsee.makeTable(tableOptions) +``` + +## May 2014 +### Important Google Spreadsheets & Tabletop News + +Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. **Be sure to include at least version 1.3.4 in your project.** ## August 13, 2013 ### Charting Intake diff --git a/readme.md b/readme.md index c11ce512..298a9835 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,7 @@ Each of **sheetsee.js**'s features are divided into modules. Use just the parts | **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](./docs/sheetsee-charts.md) | -## Making Things +## In the Wild What can you make with **Sheetsee.js**? Lots of things, here are some examples: @@ -29,33 +29,15 @@ What can you make with **Sheetsee.js**? Lots of things, here are some examples: **List your sheetsee project here: file an [issue or pull request](http://www.github.com/jlord/sheetsee.js).** -## Demos - -Demos pages for the documentation. - -- [Table Demo](./demos/demo-table.html) -- [Map Demo](./demos/demo-map.html) -- [Chart Demo](./demos/demo-chart.html) - -## Documentation +# Resources & Documentation More resources on using Sheetsee.js: -#### Getting Started - -- [About Sheetsee.js](./docs/about.md) -- [Building Sheetsee](./docs/building.md) -- [Basics](./docs/basics.md) - -#### Ideas +| Getting Started | Ideas | Use | Demos | +| --- | --- | --- | --- | +| [About Sheetsee.js](./docs/about.md)
      [Building Sheetsee](./docs/building.md)
      [Basics](./docs/basics.md) | [Fork-n-Go](./docs/fork-n-go.md)
      [Tips!](./docs/tips.md)
      [Custom charts](./docs/custom-charts.md) | [Sheetsee-core](./docs/sheetsee-core.md)
      [Sheetsee-tables](./docs/sheetsee-tables.md)
      [Sheetsee-maps](./docs/sheetsee-maps.md)
      [Sheetsee-charts](./docs/sheetsee-charts.md) | [Table Demo](./demos/demo-table.html)
      [Map Demo](./demos/demo-map.html)
      [Chart Demo](./demos/demo-chart.html) | -- [Fork-n-Go](./docs/fork-n-go.md) -- [Tips!](./docs/tips.md) -- [Custom charts](./docs/custom-charts.md) +## Note on New Google Spreadsheets -#### Use +Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. **Be sure to include at least version 1.3.4 in your project.** -- [Sheetsee-core](./docs/sheetsee-core.md) -- [Sheetsee-tables](./docs/sheetsee-tables.md) -- [Sheetsee-maps](./docs/sheetsee-maps.md) -- [Sheetsee-charts](./docs/sheetsee-charts.md) From 60d5e2f7f088af33cafd2d6db6d9ce1b12beae2f Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 11 May 2014 11:56:20 +0200 Subject: [PATCH 069/157] fresh site files --- site/docs/basics.html | 4 +- site/docs/changelog.html | 15 +++++ site/docs/sheetsee-tables.html | 103 +++++++++++++++++++-------------- site/index.html | 50 +++++++--------- 4 files changed, 98 insertions(+), 74 deletions(-) diff --git a/site/docs/basics.html b/site/docs/basics.html index 8fd27a32..5d4e461e 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -41,8 +41,8 @@

      Bare Minimum Setup

      <html>
         <head>
           <meta charset="utf-8">
      -    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
      -    <script src="//cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.1.0/tabletop.min.js"></script>
      +    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
      +    <script type="text/javascript" src="js/tabletop.js"></script>
           <script type="text/javascript" src='js/sheetsee.js'></script>
           <link rel="stylesheet" type="text/css" href="css/sss.css">
         </head>
      diff --git a/site/docs/changelog.html b/site/docs/changelog.html
      index 98d60727..bf21db57 100644
      --- a/site/docs/changelog.html
      +++ b/site/docs/changelog.html
      @@ -16,6 +16,21 @@
         
           

      Sheetsee v3

      +

      May 10, 2014

      +

      Better Table Template Options

      +

      Updated sheetsee-tables to allow you to re-use a template (rather than duplicating it for each different table you wanted to create). Previously it assumed your HTML table div id matched your script template id. This means that you can pass in an extra key/value pair in your table options into Sheetsee.maketable(). The new pair it takes is: "templateID" : "yourtemplateid". Example below, full sheetsee-tables documentation here.

      +
      var tableOptions = {
      +                    "data": gData,
      +                    "pagination": 10,
      +                    "tableDiv": "#fullTable",
      +                    "filterDiv": "#fullTableFilter",
      +                    "templateID": "tableTemplte"
      +                    }
      +Sheetsee.makeTable(tableOptions)
      +
      +

      May 2014

      +

      Important Google Spreadsheets & Tabletop News

      +

      Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. Be sure to include at least version 1.3.4 in your project.

      August 13, 2013

      Charting Intake

      D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart.

      diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 294cb828..de194bd2 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -16,48 +16,18 @@

      Sheetsee-tables

      -

      see: jlord.github.io/sheetsee.js

      With this module you can create tables of your data that are sortable, searchable and paginate-able.

      You'll need a placeholder <div> in your html, a <script> mustache template and a <script> that initiates the table.

      -

      Your HTML Placeholder <div>

      -

      This is as simple as an empty <div> with an id. This id should match the script template id in the next section.

      -
      <div id="siteTable"></div>
      -
      -

      Your <script> Template

      -

      Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you!

      +

      Your HTML Placeholder

      +

      This is as simple as an empty <div> with an id.

      +

      Your Template

      +

      Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you! It is an HTML template inside of <script> tags.

      Sorting

      If you want users to be able to click on headers and sort that column, your template must include table headers with the class tHeader.

      -

      Example

      -

      The variables inside the {{}} must match the column headers in your spreadsheet. They should be lowercase and remember spaces are omitted, so "Place Name" will become "placename".

      -
      <script id="siteTable" type="text/html">
      -    <table>
      -    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
      -      {{#rows}}
      -        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
      -      {{/rows}}
      -  </table>
      -</script>
      -
      -

      Your <script> Execution

      -
      <script type="text/javascript">
      -    document.addEventListener('DOMContentLoaded', function() {
      -      var tableOptions = {
      -                          "data": gData,
      -                          "pagination": 10,
      -                          "tableDiv": "#fullTable",
      -                          "filterDiv": "#fullTableFilter"
      -                          }
      -      Sheetsee.makeTable(tableOptions)
      -      Sheetsee.initiateTableFilter(tableOptions)
      -    })
      -</script>
      -
      -

      To create another table, simply repeat the steps except for initiateTableFilter()

      -
      <div id="secondTable"></div>
      -<script id="secondTable"> // your table template here </script>
      -<script>Sheetsee.makeTable(otherData, "#secondTable", 10)</script>
      -
      -

      Learn more about the things you can do with ICanHaz.js.

      +

      You can then style .tHeader in your CSS to make them look how you want.

      +

      Your Script

      +

      You'll want to set your table options and pass them into Sheetsee.makeTable(). If you want to add a search/filter, pass your options into Sheetsee.initiateTableFilter()

      +

      Funtions

      Sheetsee.makeTable(tableOptions)

      You pass in an object containing:

        @@ -73,7 +43,6 @@

        Sheetsee.makeTable(tableOptions)

        "tableDiv": "#fullTable", "filterDiv": "#fullTableFilter", "templateID": "fullTable" - } Sheetsee.makeTable(tableOptions)
      @@ -86,11 +55,9 @@

      Pagination

      </div>

      CSS

      -
      <style>
      -  #Pagination {background: #eee;}
      -  .pagination-next, .pagination-pre {cursor: hand;}
      -  .no-pag {color: #acacac;}
      -</style>
      +
      #Pagination {background: #eee;}
      +.pagination-next, .pagination-pre {cursor: hand;}
      +.no-pag {color: #acacac;}
       

      If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want, placeholder text:

      @@ -104,6 +71,54 @@

      Sheetsee.initiateTableFilter
      <span class="clear button">Clear</span>
       <span class="noMatches">no matches</span>
       
      +

      Example

      +

      HTML

      +
      <div id="siteTable"></div>
      +<input id="siteTableFilter" type="text"></input>
      +
      +

      Template

      +
      <script id="tableTemplate" type="text/html">
      +    <table>
      +    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
      +      {{#rows}}
      +        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
      +      {{/rows}}
      +  </table>
      +</script>
      +
      +

      JavaScript

      +
      <script type="text/javascript">
      +    document.addEventListener('DOMContentLoaded', function() {
      +      var tableOptions = {
      +                          "data": gData,
      +                          "pagination": 10,
      +                          "tableDiv": "#siteTable",
      +                          "filterDiv": "#siteTableFilter",
      +                          "templateID": "tableTemplate"
      +                          }
      +      Sheetsee.makeTable(tableOptions)
      +      Sheetsee.initiateTableFilter(tableOptions)
      +    })
      +</script>
      +
      +

      To create another table, simply repeat the steps above (abreviated here below).

      +

      HTML

      +
      <div id="secondTable"></div>
      +<input id="secondFilter" type="text"></input>
      +
      +

      Template

      +
      <script text="text/javascript" id="secondTable">
      +  // Template here
      +</script>
      +
      +

      JavaScript

      +
      <script>
      +  var secondTableOpts = {} // the options
      +  Sheetsee.makeTable(secondTableOpts)
      +  Sheetsee.initiateTableFilter(secondTableOpts)
      +</script>
      +
      +

      Learn more about the things you can do with ICanHaz.js.

      View Demo

      diff --git a/site/index.html b/site/index.html index bd2b1a83..bc40b955 100644 --- a/site/index.html +++ b/site/index.html @@ -52,41 +52,35 @@

      Modules

      -

      Making Things

      +

      In the Wild

      What can you make with Sheetsee.js? Lots of things, here are some examples:

      List your sheetsee project here: file an issue or pull request.

      -

      Demos

      -

      Demos pages for the documentation.

      - -

      Documentation

      +

      Resources & Documentation

      More resources on using Sheetsee.js:

      -

      Getting Started

      - -

      Ideas

      - -

      Use

      - + + + + + + + + + + + + + + + + + +
      Getting StartedIdeasUseDemos
      About Sheetsee.js
      Building Sheetsee
      Basics
      Fork-n-Go
      Tips!
      Custom charts
      Sheetsee-core
      Sheetsee-tables
      Sheetsee-maps
      Sheetsee-charts
      Table Demo
      Map Demo
      Chart Demo
      +

      Note on New Google Spreadsheets

      +

      Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. Be sure to include at least version 1.3.4 in your project.

      From 33ebbf393a23751e377ea7e4a19ee0372cf9ddf7 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sat, 24 May 2014 13:21:00 +0200 Subject: [PATCH 070/157] add polygon info to doc --- docs/sheetsee-maps.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/sheetsee-maps.md b/docs/sheetsee-maps.md index ec170de1..ace03121 100644 --- a/docs/sheetsee-maps.md +++ b/docs/sheetsee-maps.md @@ -4,6 +4,30 @@ _[View Demo](../demos/demo-map.html)_ Sheetsee.js uses [Mapbox.js](http://mapbox.com/mapbox.js) and [Leaflet.js](http://leafletjs.com/) to make maps of your **points**, **polygons**, **lines** or **multipolygons** (all coordinate based). Details on what that actually looks like [here](http://leafletjs.com/examples/geojson.html). +### Maps: Polygons and Lines + +Sheetsee-maps now supports polygons and lines. So long as you have the correct coordinate structure in your cells, Sheetsee will add them to the geoJSON it creates for your maps. More details for coordinates of lines and polygons in geoJSON are [here](http://leafletjs.com/examples/geojson.html), but briefly: + +A linestring: + +``` +[-122.41722106933594, 37.7663045891584], [-122.40477561950684, 37.77695634643178] +``` + +A polygon: + +``` +[-122.41790771484375, 37.740381166384914], [-122.41790771484375, 37.74520008134973], [-122.40966796874999, 37.74520008134973],[-122.40966796874999, 37.740381166384914], [-122.41790771484375, 37.740381166384914] +``` + +A Multipolygon: + +``` +[[-122.431640625, 37.79106586542567], [-122.431640625, 37.797441398913286], [-122.42666244506835, 37.797441398913286],[-122.42666244506835, 37.79106586542567], [-122.431640625, 37.79106586542567]], +[[-122.43352890014648, 37.78197638783258], [-122.43352890014648, 37.789031004883654], [-122.42443084716797, 37.789031004883654], [-122.42443084716797, 37.78197638783258], [-122.43352890014648, 37.78197638783258]] + +### The Parts + You'll create a placeholder `
      ` in your HTML, CSS giving it a size and fire up a map from within ` - + diff --git a/demos/demo-map.html b/demos/demo-map.html index dd04957d..0be42924 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -6,13 +6,13 @@ - + diff --git a/readme.md b/readme.md index 389e38b5..ae9f82c0 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,8 @@ ![sheetseeimg](https://raw.github.com/jlord/sheetsee-cache/master/img/sheetsee-03.png) -# Sheetsee.js - **Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. -Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](./docs/basics.md). - ## Modules Each of **sheetsee.js**'s features are divided into modules. Use just the parts you need; see docs on [building](./docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). @@ -19,6 +15,9 @@ Each of **sheetsee.js**'s features are divided into modules. Use just the parts | **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js. | [Doc](./docs/sheetsee-maps.md) | | **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](./docs/sheetsee-charts.md) | +## Spreadsheets!? + +Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](./docs/basics.md). ## In the Wild @@ -36,7 +35,10 @@ More resources on using Sheetsee.js: | Getting Started | Ideas | Use | Demos | | --- | --- | --- | --- | -| [About Sheetsee.js](./docs/about.md)
      [Building Sheetsee](./docs/building.md)
      [Basics](./docs/basics.md) | [Fork-n-Go](./docs/fork-n-go.md)
      [Tips!](./docs/tips.md)
      [Custom charts](./docs/custom-charts.md) | [Sheetsee-core](./docs/sheetsee-core.md)
      [Sheetsee-tables](./docs/sheetsee-tables.md)
      [Sheetsee-maps](./docs/sheetsee-maps.md)
      [Sheetsee-charts](./docs/sheetsee-charts.md) | [Table Demo](./demos/demo-table.html)
      [Map Demo](./demos/demo-map.html)
      [Chart Demo](./demos/demo-chart.html) | +| [About Sheetsee.js](./docs/about.md) | [Fork-n-Go](./docs/fork-n-go.md) | [Sheetsee-core](./docs/sheetsee-core.md) | [Table Demo](./demos/demo-table.html) | +| [Building Sheetsee](./docs/building.md) | [Tips!](./docs/tips.md) | [Sheetsee-tables](./docs/sheetsee-tables.md) | [Table Demo](./demos/demo-table.html) | +| [Basics](./docs/basics.md) | [Custom charts](./docs/custom-charts.md) | [Sheetsee-maps](./docs/sheetsee-maps.md) | [Map Demo](./demos/demo-map.html) | +| | | [Sheetsee-charts](./docs/sheetsee-charts.md) | [Chart Demo](./demos/demo-chart.html) | ## Note on New Google Spreadsheets diff --git a/site/assets/style.css b/site/assets/style.css index 17f14e90..5e531298 100644 --- a/site/assets/style.css +++ b/site/assets/style.css @@ -33,11 +33,12 @@ img {width: 100%;} p a, a {color: #535353; text-decoration: none; padding-bottom: 0px; border-bottom: 2px #CCF4FF solid;} a:hover {color: #47CCFC;} a:active {color: #47CCFC;} -/*a:visited {color: #333;}*/ small {padding: 10px 0px;} p, ol {line-height: 1.4;} text {font-size: 12px;} +body.index p:nth-of-type(2) {font-size: 30px;} +body.index table {border: 4px solid #CCF4FF; padding: 18px;} .home-link {color: #47CCFC;} pre {word-wrap: break-word; padding: 10px; background: #F8F8F8;} diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index df86dd31..6094a844 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -16,7 +16,7 @@ .no-pag {color: #acacac; border: none;} .no-pag:hover {color: #acacac;} input {border: none; border-bottom: 1px solid #333;margin: 10px 0px; width: 200px; font-size: 16px; padding-bottom: 6px;} - .tHeader {padding: 8px; font-family: Helvetica Neue; Helvetica, Arial, sans-serif; cursor: hand;} + .tHeader {padding: 8px; cursor: pointer; text-align: left;} .photo {display: inline-block; float: left; width: 100px;} #photogrid {overflow: auto;} diff --git a/site/docs/about.html b/site/docs/about.html index 5a53252c..8ebef202 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -13,7 +13,7 @@ - +

      About

      Sheetsee.js began as a part of my Code for America 2012 Fellowship project, See Penny Work. The idea and original code was to enable cities to easily publish and maintain themselves their budget data. The original sheetsee.js was built into Wordpress templates so that with the See Penny Work template, you could create pages that you only had to name and they would be populated with maps, charts and tables based on the page name corelating with a project in the spreadsheet.

      diff --git a/site/docs/basics.html b/site/docs/basics.html index 05cc20ee..9cb52a98 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -13,7 +13,7 @@ - +

      Spreadsheets as Databases

      Spreadsheets are a great lightweight databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information -- the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet!

      diff --git a/site/docs/building.html b/site/docs/building.html index cb3d4166..2c614004 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -13,7 +13,7 @@ - +

      Right-sizing

      You can customize your sheetsee.js build with just the parts you want to use. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

      diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 1cdb498a..b92c550d 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -13,7 +13,7 @@ - +

      Sheetsee v3

      May 10, 2014

      diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 22a1e00e..3aa49fe2 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -13,7 +13,7 @@ - +

      Custom Charts

      It's easy to take a D3.js chart of your own and use it with Sheetsee.js. If you make it into a module, anyone can use your chart, too!

      diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 661d6853..de4189af 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -13,7 +13,7 @@ - +

      Fork-n-Go

      A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

      diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index dea26407..25f873a0 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -13,7 +13,7 @@ - +

      Sheetsee-charts

      View Demo

      diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index a8f8aa6e..101aa4cf 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -13,7 +13,7 @@ - +

      Sheetsee-core

      This is the core module in sheetsee and is included in all builds. It contains the functions for building your custom file as well as the basic data manipulation functions.

      diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index fe9e643c..fe9e58fe 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -13,7 +13,7 @@ - +

      Sheetsee-maps

      View Demo

      diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index e90a83ae..94a65574 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -13,7 +13,7 @@ - +

      Sheetsee-tables

      With this module you can create tables of your data that are sortable, searchable and paginate-able.

      diff --git a/site/docs/tips.html b/site/docs/tips.html index d9bc10f8..e05f05c4 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -13,7 +13,7 @@ - +

      Tips

      A few things to think about beyond charts, maps and tables.

      diff --git a/site/index.html b/site/index.html index 856237ab..340cc5b8 100644 --- a/site/index.html +++ b/site/index.html @@ -13,12 +13,10 @@ - +

      sheetseeimg

      -

      Sheetsee.js

      Sheetsee.js is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts.

      -

      Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

      Modules

      Each of sheetsee.js's features are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

      @@ -52,6 +50,8 @@

      Modules

      +

      Spreadsheets!?

      +

      Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases here.

      In the Wild

      What can you make with Sheetsee.js? Lots of things, here are some examples:

        @@ -73,10 +73,28 @@

        Resources & Documentation

        -About Sheetsee.js
        Building Sheetsee
        Basics -Fork-n-Go
        Tips!
        Custom charts -Sheetsee-core
        Sheetsee-tables
        Sheetsee-maps
        Sheetsee-charts -Table Demo
        Map Demo
        Chart Demo +About Sheetsee.js +Fork-n-Go +Sheetsee-core +Table Demo + + +Building Sheetsee +Tips! +Sheetsee-tables +Table Demo + + +Basics +Custom charts +Sheetsee-maps +Map Demo + + + + +Sheetsee-charts +Chart Demo diff --git a/template.hbs b/template.hbs index db08907c..93d59f5f 100644 --- a/template.hbs +++ b/template.hbs @@ -13,7 +13,7 @@ - +
        {{{content}}} From ac07a0e637ed860336a707f3335d614157462b06 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 20:46:11 -0700 Subject: [PATCH 090/157] edit about page --- docs/about.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/about.md b/docs/about.md index 55ff664a..08cb80e4 100644 --- a/docs/about.md +++ b/docs/about.md @@ -7,16 +7,20 @@ In early 2013, after the CfA Fellowship, I recieved a grant from [Mozilla Open N The present version makes the project modular, customizable and with more maping and table features. ## Built on top of Tabletop.js -Sheetsee would not exist were it not for [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js. +Sheetsee pairs with [tabletop.js](https://github.com/jsoma/tabletop) a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js. Well, actually, if you have some data on hand already in JSON format, you can use Sheetsee too :) ### Sheetsee.js + Mapbox.js + d3.js -Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, **sheetsee-tables**, comes with sorting, filtering and pagination. **Sheetsee-maps** is built ontop of [Leaflet.js](http://leafletjs.com/) and [Mapbox.js](https://www.mapbox.com/mapbox.js/) and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, **Sheetee-charts** comes with three basic [d3.js](http://d3js.org) charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is [here](docs/custom-chart.md). +Once you've got the data, you're ready to Sheetsee. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, **sheetsee-tables**, comes with sorting, filtering and pagination. Tables use [icanhaz.js](http://www.icanhazjs.com) for very mustache.js-like templating. + +**Sheetsee-maps** is built ontop of [Leaflet.js](http://leafletjs.com/) and [Mapbox.js](https://www.mapbox.com/mapbox.js/) and allows you to customize colors and popups of points, lines, polygons or multipolygons. + +Finally, **Sheetee-charts** comes with three basic [d3.js](http://d3js.org) charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is [here](docs/custom-chart.md). ## Hacked on Openly - Sheetsee.js is open source software with a [BSD license](docs/license.md). - Sheetsee.js is a labor of love by [jlord](http://www.github.com/jlord) ([twitter](http://www.twitter.com/jllord)) with support from [contributors](https://github.com/jlord/sheetsee.js/graphs/contributors). -## Contact +## Contact & Contribute - File a [new issue](https://github.com/jlord/sheetsee.js/issues/new) for ideas and bug reports. - If your issue falls specifically with one of the modules, you can file it on its particular repo: - [sheetsee](http://www.github.com/jlord/sheetsee/issues/new) From 3225e6b3644d8579b280de57c508ff699d8f8ce5 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 20:57:33 -0700 Subject: [PATCH 091/157] edit forkngo page --- docs/fork-n-go.md | 21 +++++++++++---------- site/assets/style.css | 1 + site/docs/about.html | 8 +++++--- site/docs/fork-n-go.html | 22 ++++++++++------------ 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/docs/fork-n-go.md b/docs/fork-n-go.md index 9440d5d5..50ec3cf9 100644 --- a/docs/fork-n-go.md +++ b/docs/fork-n-go.md @@ -1,22 +1,23 @@ # Fork-n-Go -A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database. + -To awesome things that make this possible: **Forking** and [**GitHub Pages**](http://pages.github.com). +A Fork-n-Go project is a project on GitHub that in a few clicks, starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database. -On GitHub, a **fork** is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button. +Two awesome things that make this possible: **Forking**, the tool on GitHub that allows you to copy a public repository onto your account, and [**GitHub Pages**](http://pages.github.com), GitHub's free web hosting service for ever repository, account and organization. -**GitHub Pages** is the hosting service that GitHub provides free to all users, organizations _and_ repositories. This means everyone of these entities or project can have it's own website at a predictable domain: +I've built a whole other website on the idea with lots of examples: [jlord.github.io/forkngo](http://jlord.github.io/forkngo/) -- **organizations**: orgname.github.io -- **users**: username.github.io -- **repositories**: username.github.io/repositoryname +--- +## How -To have a website for a repository all you need is a branch named `gh-pages`. GitHub will then look in that branch for web files and serve them up at the address. +To have a website for a repository hosted by GitHub Pages all you need is a branch named `gh-pages`. GitHub will then look in that branch for web files and serve them up at the address. -What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily. +So Sheetsee.js projects, hosted on `gh-pages` branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own—with data they control—really easily. -A Fork-n-Go example from my [blog post](http://jlord.us/fork-n-go/) on the topic: +## Example + +A Fork-n-Go example from my [blog post](http://jlord.github.io/blog/fork-n-go) on the topic: ### Hack Spots Fork-n-Go diff --git a/site/assets/style.css b/site/assets/style.css index 5e531298..55de85b7 100644 --- a/site/assets/style.css +++ b/site/assets/style.css @@ -29,6 +29,7 @@ h1, h2, h3, h4, h5, h6 {font-family: Source Sans Pro, Arial, sans-serif;} h2 {margin-top: 40px;} img {width: 100%;} +hr {border: 2px solid #CCF4FF;} p a, a {color: #535353; text-decoration: none; padding-bottom: 0px; border-bottom: 2px #CCF4FF solid;} a:hover {color: #47CCFC;} diff --git a/site/docs/about.html b/site/docs/about.html index 8ebef202..e63f8621 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -20,15 +20,17 @@

        About

        In early 2013, after the CfA Fellowship, I recieved a grant from Mozilla Open News to pull out the sheetsee.js bits and make it a standalone open source library. That brought us to version 2.

        The present version makes the project modular, customizable and with more maping and table features.

        Built on top of Tabletop.js

        -

        Sheetsee would not exist were it not for tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js.

        +

        Sheetsee pairs with tabletop.js a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. Every instance of Sheetsee begins with running tabletop.js. Well, actually, if you have some data on hand already in JSON format, you can use Sheetsee too :)

        Sheetsee.js + Mapbox.js + d3.js

        -

        Once you've got the data, the meat of Sheetsee comes into play. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons. Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

        +

        Once you've got the data, you're ready to Sheetsee. You can now decide if you want to map, chart or display your data in a table. Sheetsee's table module, sheetsee-tables, comes with sorting, filtering and pagination. Tables use icanhaz.js for very mustache.js-like templating.

        +

        Sheetsee-maps is built ontop of Leaflet.js and Mapbox.js and allows you to customize colors and popups of points, lines, polygons or multipolygons.

        +

        Finally, Sheetee-charts comes with three basic d3.js charts: bar, circle and line. It is difficult to make a chart that can suit many types of data, but it is easy to choose your own d3 chart and plug it in to sheetsee. Documentation for creating a d3 module is here.

        Hacked on Openly

        -

        Contact

        +

        Contact & Contribute

        • File a new issue for ideas and bug reports.
        • If your issue falls specifically with one of the modules, you can file it on its particular repo:
            diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index de4189af..5bc635b2 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -16,18 +16,16 @@

            Fork-n-Go

            -

            A Fork-n-Go project is a project on GitHub that in a few clicks and starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

            -

            To awesome things that make this possible: Forking and GitHub Pages.

            -

            On GitHub, a fork is a full copy of a repository, on your account, that you can manage and edit. It's done with the click of a button.

            -

            GitHub Pages is the hosting service that GitHub provides free to all users, organizations and repositories. This means everyone of these entities or project can have it's own website at a predictable domain:

            -
              -
            • organizations: orgname.github.io
            • -
            • users: username.github.io
            • -
            • repositories: username.github.io/repositoryname
            • -
            -

            To have a website for a repository all you need is a branch named gh-pages. GitHub will then look in that branch for web files and serve them up at the address.

            -

            What all of this means is that Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own really easily.

            -

            A Fork-n-Go example from my blog post on the topic:

            +

            +

            A Fork-n-Go project is a project on GitHub that in a few clicks, starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

            +

            Two awesome things that make this possible: Forking, the tool on GitHub that allows you to copy a public repository onto your account, and GitHub Pages, GitHub's free web hosting service for ever repository, account and organization.

            +

            I've built a whole other website on the idea with lots of examples: jlord.github.io/forkngo

            +
            +

            How

            +

            To have a website for a repository hosted by GitHub Pages all you need is a branch named gh-pages. GitHub will then look in that branch for web files and serve them up at the address.

            +

            So Sheetsee.js projects, hosted on gh-pages branches on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own—with data they control—really easily.

            +

            Example

            +

            A Fork-n-Go example from my blog post on the topic:

            Hack Spots Fork-n-Go

            I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do:

              From 6d154e095c93e36bf1b6ec7945f6dff4a7496683 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 21:00:09 -0700 Subject: [PATCH 092/157] update font link --- demos/demo-chart.html | 2 +- demos/demo-map.html | 2 +- demos/demo-table.html | 2 +- site/demos/demo-chart.html | 2 +- site/demos/demo-map.html | 2 +- site/demos/demo-table.html | 2 +- site/docs/about.html | 2 +- site/docs/basics.html | 2 +- site/docs/building.html | 2 +- site/docs/changelog.html | 2 +- site/docs/custom-charts.html | 2 +- site/docs/fork-n-go.html | 2 +- site/docs/sheetsee-charts.html | 2 +- site/docs/sheetsee-core.html | 2 +- site/docs/sheetsee-maps.html | 2 +- site/docs/sheetsee-tables.html | 2 +- site/docs/tips.html | 2 +- site/index.html | 2 +- template.hbs | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/demos/demo-chart.html b/demos/demo-chart.html index aa45f156..b7ec0d63 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -5,7 +5,7 @@ Sheetsee Chart Demo - + diff --git a/demos/demo-map.html b/demos/demo-map.html index 01b6ce00..f5f757c9 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -5,7 +5,7 @@ Sheetsee Maps Demo - + diff --git a/demos/demo-table.html b/demos/demo-table.html index 6094a844..d5fa1116 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -5,7 +5,7 @@ Sheetsee Table Demo - + diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index aa45f156..b7ec0d63 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -5,7 +5,7 @@ Sheetsee Chart Demo - + diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index 01b6ce00..f5f757c9 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -5,7 +5,7 @@ Sheetsee Maps Demo - + diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index 6094a844..d5fa1116 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -5,7 +5,7 @@ Sheetsee Table Demo - + diff --git a/site/docs/about.html b/site/docs/about.html index e63f8621..f93caf85 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/basics.html b/site/docs/basics.html index 9cb52a98..ba385a34 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/building.html b/site/docs/building.html index 2c614004..e748bf0e 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/changelog.html b/site/docs/changelog.html index b92c550d..08144236 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index 3aa49fe2..c8a9a421 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 5bc635b2..2f9b2ad4 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 25f873a0..698b4f1b 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 101aa4cf..b838c46e 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index fe9e58fe..6993fb77 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 94a65574..25d9deaf 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -8,7 +8,7 @@ - + diff --git a/site/docs/tips.html b/site/docs/tips.html index e05f05c4..5c3e0946 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -8,7 +8,7 @@ - + diff --git a/site/index.html b/site/index.html index 340cc5b8..438d937e 100644 --- a/site/index.html +++ b/site/index.html @@ -8,7 +8,7 @@ - + diff --git a/template.hbs b/template.hbs index 93d59f5f..29923b9f 100644 --- a/template.hbs +++ b/template.hbs @@ -8,7 +8,7 @@ - + From bbe1e1e84ff378f6396428584e31e45b7f1c1176 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 21:32:48 -0700 Subject: [PATCH 093/157] fix highlighting --- demos/demo-chart.html | 2 +- demos/demo-map.html | 2 +- demos/demo-table.html | 2 +- js/highlight.pack.js | 1 + site/assets/style.css | 3 +- site/assets/styles/highlight.css | 94 ++++++++++++++++++++++++++++++++ site/demos/demo-chart.html | 2 +- site/demos/demo-map.html | 2 +- site/demos/demo-table.html | 2 +- site/docs/about.html | 7 +-- site/docs/basics.html | 7 +-- site/docs/building.html | 7 +-- site/docs/changelog.html | 7 +-- site/docs/custom-charts.html | 7 +-- site/docs/fork-n-go.html | 7 +-- site/docs/sheetsee-charts.html | 7 +-- site/docs/sheetsee-core.html | 7 +-- site/docs/sheetsee-maps.html | 7 +-- site/docs/sheetsee-tables.html | 7 +-- site/docs/tips.html | 7 +-- site/index.html | 7 +-- site/js/highlight.js | 1 + template.hbs | 7 +-- 23 files changed, 143 insertions(+), 59 deletions(-) create mode 100644 js/highlight.pack.js create mode 100644 site/assets/styles/highlight.css create mode 100644 site/js/highlight.js diff --git a/demos/demo-chart.html b/demos/demo-chart.html index b7ec0d63..7b00c614 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -5,7 +5,7 @@ Sheetsee Chart Demo - + diff --git a/demos/demo-map.html b/demos/demo-map.html index f5f757c9..5b452a4d 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -5,7 +5,7 @@ Sheetsee Maps Demo - + diff --git a/demos/demo-table.html b/demos/demo-table.html index d5fa1116..b7f11a4d 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -5,7 +5,7 @@ Sheetsee Table Demo - + diff --git a/js/highlight.pack.js b/js/highlight.pack.js new file mode 100644 index 00000000..5807522f --- /dev/null +++ b/js/highlight.pack.js @@ -0,0 +1 @@ +var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
              ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/site/assets/style.css b/site/assets/style.css index 55de85b7..58034575 100644 --- a/site/assets/style.css +++ b/site/assets/style.css @@ -44,7 +44,8 @@ body.index table {border: 4px solid #CCF4FF; padding: 18px;} pre {word-wrap: break-word; padding: 10px; background: #F8F8F8;} pre code {padding: 0;} -code {font-family: "Source Code Pro", monospace; font-size: 14px; line-height: 1; background: #F8F8F8; color: #636363; font-weight: normal; padding: 2px 6px; border-radius: 2px;} +code {font-family: "Source Code Pro", monospace; font-size: 14px; line-height: 1; background: #F8F8F8; color: #636363; font-weight: 400; padding: 2px 6px; border-radius: 2px;} +.hljs { background: #F8F8F8; color: #494949; line-height: 1.4em; } /* funsies */ ::selection {background: #44FFB4;} diff --git a/site/assets/styles/highlight.css b/site/assets/styles/highlight.css new file mode 100644 index 00000000..b71b008d --- /dev/null +++ b/site/assets/styles/highlight.css @@ -0,0 +1,94 @@ +/* Base16 Atelier Forest Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ +/* https://github.com/jmblog/color-themes-for-highlightjs */ + +/* Atelier Forest Light Comment */ +.hljs-comment, +.hljs-title { + color: #acacac; +} + +/* Atelier Forest Light Red */ +.hljs-variable, +.hljs-attribute, +.hljs-tag, +.hljs-regexp, +.ruby .hljs-constant, +.xml .hljs-tag .hljs-title, +.xml .hljs-pi, +.xml .hljs-doctype, +.html .hljs-doctype, +.css .hljs-id, +.css .hljs-class, +.css .hljs-pseudo { + color: #0091FF; +} + +/* Atelier Forest Light Orange */ +.hljs-number, +.hljs-preprocessor, +.hljs-pragma, +.hljs-built_in, +.hljs-literal, +.hljs-params, +.hljs-constant { + color: #085896; +} + +/* Atelier Forest Light Yellow */ +.hljs-ruby .hljs-class .hljs-title, +.css .hljs-rules .hljs-attribute { + color: #d5911a; +} + +/* Atelier Forest Light Green */ +.hljs-string, +.hljs-value, +.hljs-inheritance, +.hljs-header, +.ruby .hljs-symbol, +.xml .hljs-cdata { + color: #09cc40; +} + +/* Atelier Forest Light Aqua */ +.css .hljs-hexcolor { + color: #00ad9c; +} + +/* Atelier Forest Light Blue */ +.hljs-function, +.python .hljs-decorator, +.python .hljs-title, +.ruby .hljs-function .hljs-title, +.ruby .hljs-title .hljs-keyword, +.perl .hljs-sub, +.javascript .hljs-title, +.coffeescript .hljs-title { + color: #407ee7; + font-weight: bold; +} + +/* Atelier Forest Light Purple */ +.hljs-keyword, +.javascript .hljs-function { + color: #6666ea; +} + +.hljs { + display: block; + /*background: #f1efee;*/ + color: #68615e; + /*padding: 0.5em;*/ +} + +/*.coffeescript .javascript, +.javascript .xml, +.tex .hljs-formula, +.xml .javascript, +.xml .vbscript, +.xml .css, +.xml .hljs-cdata { + opacity: 0.5; +}*/ diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index b7ec0d63..7b00c614 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -5,7 +5,7 @@ Sheetsee Chart Demo - + diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index f5f757c9..5b452a4d 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -5,7 +5,7 @@ Sheetsee Maps Demo - + diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index d5fa1116..b7f11a4d 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -5,7 +5,7 @@ Sheetsee Table Demo - + diff --git a/site/docs/about.html b/site/docs/about.html index f93caf85..9439e955 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -6,13 +6,12 @@ - - - + + + -

              About

              diff --git a/site/docs/basics.html b/site/docs/basics.html index ba385a34..e8e5478a 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -6,13 +6,12 @@ - - - + + + -

              Spreadsheets as Databases

              diff --git a/site/docs/building.html b/site/docs/building.html index e748bf0e..7137747b 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -6,13 +6,12 @@ - - - + + + -

              Right-sizing

              diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 08144236..214609d5 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -6,13 +6,12 @@ - - - + + + -

              Sheetsee v3

              diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index c8a9a421..c27778ff 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -6,13 +6,12 @@ - - - + + + -

              Custom Charts

              diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 2f9b2ad4..062e157a 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -6,13 +6,12 @@ - - - + + + -

              Fork-n-Go

              diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 698b4f1b..6a3f0ea7 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -6,13 +6,12 @@ - - - + + + -

              Sheetsee-charts

              diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index b838c46e..2763fc51 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -6,13 +6,12 @@ - - - + + + -

              Sheetsee-core

              diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 6993fb77..06c9e14e 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -6,13 +6,12 @@ - - - + + + -

              Sheetsee-maps

              diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 25d9deaf..c73e47d0 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -6,13 +6,12 @@ - - - + + + -

              Sheetsee-tables

              diff --git a/site/docs/tips.html b/site/docs/tips.html index 5c3e0946..730cae11 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -6,13 +6,12 @@ - - - + + + -

              Tips

              diff --git a/site/index.html b/site/index.html index 438d937e..737376ac 100644 --- a/site/index.html +++ b/site/index.html @@ -6,13 +6,12 @@ - - - + + + -

              sheetseeimg

              diff --git a/site/js/highlight.js b/site/js/highlight.js new file mode 100644 index 00000000..5807522f --- /dev/null +++ b/site/js/highlight.js @@ -0,0 +1 @@ +var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
              ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/template.hbs b/template.hbs index 29923b9f..737cfd88 100644 --- a/template.hbs +++ b/template.hbs @@ -6,13 +6,12 @@ - - - + + + -
              {{{content}}} From 4c860b823990ae349cbc88950ee8cbe09855cb36 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 21:39:40 -0700 Subject: [PATCH 094/157] favicon --- favicon.png | Bin 0 -> 2420 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 favicon.png diff --git a/favicon.png b/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..09e9688767f7b12539a55cba85bdfbbc6e86d0a8 GIT binary patch literal 2420 zcmaJ@dpwi-A0KiFJ0dwDnkh+kc?>%nBQ~N;!{qK*^O%`kY{Mp{B-L5ep(Av2D5Vr3 zh2+-7ppZXLdA{Gz_w|0iKi5CLM=74$py~$d5C{b7 z?nd&Kt@iRyO-1&{FFfVT7JZ?MztD#pA&jT-L5Nd0cQ*)gXVVyA;f@Y4dl6nHzy^ghn1~(C5#U7x_!nKgY%f1X!C_w@LKXr3Pf-43 z3XI6*gD@MU4T6rg0$^Ai60otx0e~gU3JqXT02*b5LjVBY8jA;PVP7A(%o{&E0`E<7 z{pw3*5#W(RArFs2#mC1Z<1t7spMe5!I2;OXg|f0j$PfsDm?NZ#5FCN&vH}Sd(D_WB zkjdr1t647`l0Ew2TvmsmQR;8F2YpqiiaoiL7I@ur*gT`%T=UAa)n$$B$o#x5@F_K8lB0J z+nc`-$Yi`bMdvJfQz*=#s){ix;o)(WiJVh zTjr9u^jJ2?5iWDXzj3kX?{ej{z~;$3lR!Q*4h(nYbJ?&jIpdk%kA?JIy|3Kx@5W;5 z@?9=U77R+>+5hSE@{w$OJ@LKFE=cJ6|@}do4@yAQ0tIcajrT)H@zT_6YXX zb(n-Am@e1z#Q5h^Thw9vz`qQ zJ(g{4^SU&H8ktXWTfML{&3ctt3#Isw_}paeeD+|>WhBHj5nKVI)pSlq%)twkkN~$HDjogL7%9 zgDuroA$U>iHD}$8U32ynSqsn3=_oDv#^>uRjtAL4%35W4l+msppk6==T|jI3kti0M z4Cuz;?EZdCy=LXFsvjTgTkOo;{g&R*Dprap-6Xobc{&oedRl}%7^(^NkBlo*tdBVO zcDkz~r-`x2Ld|kzz^0V(UawEv_2-M%pVcl?Rkdu~>*$Mof7LtdcXNvq3@tCPOJ%0~ z#Sp1*u+svvL$T>{iMyot_Ngm}6O;>|n;|?2T`u-&x)R>Nk?Kpuxy9JF5v9t}n9RUA z|NhP}ir`xL@ghXN-5Wh}Nq}`u#aO%QuFa5J8qqN&sdXcR8=pVfy$zZ$bGr)q=kcK} z%XfCmp|N_W@CzfF)y+ zg8B?s+o|tpUSV}-X~er)w?RXTO*)zWD$XI7HL|o6W>RaaLzJjdr`9ks(Iup?5LUVZ zj~X8_<5X2Mf6>S&PuU~J3&QC-d$aIe-Jo9PBIb@tke1=>+s)!%4(<`I1EP(8dK*1( zbK`_=cSI^~veC~scW$BT2;sHP{={jI4HSp?m(3%WZW0%nZhu{{+j6(~MSz+nIq69# zU9~a~l6t`9a zcA)$E`*4QR*<bh$D2nh z)>(~zK=M86S&92zIhg~QkcGf(w`*{<>879c_LfI=I{84?E!9>|`E$O*0M2LjhO=@}>ox5f{It?_3w!F5-0@lEcV+M<1lA_f zVE^i&u?xO4aPW4C!n&k_=b2|+VVY5NeX&I4Rs~gIYwRu6hfOJcLsj>iW*X8{)5GTC zEc0x-skJQU@^_4Gbpv?1ix{gUU22(loOgU-%60UB=Pee_SeJKdn}pVEcrr}+DXTFm zc~~$ELJitEQ^$_F`sHQlJn`*Ogg9B&cq^9XsU8dYT)TE{=|*%ax69e|NCqJ-0+vQB zIDaDoe7^nBL%ct#InbY2j;bstZ-IO`A+U3;(Kvc{ji*(pPl{f2s8-gwXE)Du`4mRR z)EI^K|CJZ2a_6dc9qMk>(>DE~^`_Ll)){;E?EHHXeH}+_#UAO_k3N4Z_SMB5!-+Y; zuPRJRPoTo4(&i{@AjTOXWUAR#+X>WV{-k)IW$J1fb|KyH;P5lvRqI@xvMud{!v!OY z0)YGxV;1-06?Y1x^m*0WAgR5Rq(%|~a$fj2mrJS~)?Nl-aTCQs`%eY!PmXrt{3)HK z9s2oYYTrZZr Date: Sun, 7 Sep 2014 21:42:47 -0700 Subject: [PATCH 095/157] add favicon to pages: --- site/docs/about.html | 1 + site/docs/basics.html | 1 + site/docs/building.html | 1 + site/docs/changelog.html | 1 + site/docs/custom-charts.html | 1 + site/docs/fork-n-go.html | 1 + site/docs/sheetsee-charts.html | 1 + site/docs/sheetsee-core.html | 1 + site/docs/sheetsee-maps.html | 1 + site/docs/sheetsee-tables.html | 1 + site/docs/tips.html | 1 + site/index.html | 1 + template.hbs | 1 + 13 files changed, 13 insertions(+) diff --git a/site/docs/about.html b/site/docs/about.html index 9439e955..6204a6f4 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/basics.html b/site/docs/basics.html index e8e5478a..5357b4ff 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/building.html b/site/docs/building.html index 7137747b..0d567aac 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 214609d5..0df5536f 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index c27778ff..dc821745 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 062e157a..5009f815 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 6a3f0ea7..6cbd5a02 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index 2763fc51..b3c94326 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 06c9e14e..5f92d8d4 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index c73e47d0..67726f4c 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/tips.html b/site/docs/tips.html index 730cae11..f9d0bc61 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -6,6 +6,7 @@ + diff --git a/site/index.html b/site/index.html index 737376ac..850fa519 100644 --- a/site/index.html +++ b/site/index.html @@ -6,6 +6,7 @@ + diff --git a/template.hbs b/template.hbs index 737cfd88..720ec4a7 100644 --- a/template.hbs +++ b/template.hbs @@ -6,6 +6,7 @@ + From 34b5c3258bdd4239a1f32ab8d8341ad263b8f13d Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 21:45:12 -0700 Subject: [PATCH 096/157] add favicon link --- demos/demo-chart.html | 1 + demos/demo-map.html | 1 + demos/demo-table.html | 1 + site/demos/demo-chart.html | 1 + site/demos/demo-map.html | 1 + site/demos/demo-table.html | 1 + site/docs/about.html | 2 +- site/docs/basics.html | 2 +- site/docs/building.html | 2 +- site/docs/changelog.html | 2 +- site/docs/custom-charts.html | 2 +- site/docs/fork-n-go.html | 2 +- site/docs/sheetsee-charts.html | 2 +- site/docs/sheetsee-core.html | 2 +- site/docs/sheetsee-maps.html | 2 +- site/docs/sheetsee-tables.html | 2 +- site/docs/tips.html | 2 +- site/index.html | 2 +- site/js/highlight.pack.js | 1 + template.hbs | 2 +- 20 files changed, 20 insertions(+), 13 deletions(-) create mode 100644 site/js/highlight.pack.js diff --git a/demos/demo-chart.html b/demos/demo-chart.html index 7b00c614..69fcb5cd 100644 --- a/demos/demo-chart.html +++ b/demos/demo-chart.html @@ -5,6 +5,7 @@ Sheetsee Chart Demo + diff --git a/demos/demo-map.html b/demos/demo-map.html index 5b452a4d..51c292b2 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -6,6 +6,7 @@ + diff --git a/demos/demo-table.html b/demos/demo-table.html index b7f11a4d..4efffd6a 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -6,6 +6,7 @@ + diff --git a/site/demos/demo-chart.html b/site/demos/demo-chart.html index 7b00c614..69fcb5cd 100644 --- a/site/demos/demo-chart.html +++ b/site/demos/demo-chart.html @@ -5,6 +5,7 @@ Sheetsee Chart Demo + diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index 5b452a4d..51c292b2 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -6,6 +6,7 @@ + diff --git a/site/demos/demo-table.html b/site/demos/demo-table.html index b7f11a4d..4efffd6a 100644 --- a/site/demos/demo-table.html +++ b/site/demos/demo-table.html @@ -6,6 +6,7 @@ + diff --git a/site/docs/about.html b/site/docs/about.html index 6204a6f4..232df3ce 100644 --- a/site/docs/about.html +++ b/site/docs/about.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/basics.html b/site/docs/basics.html index 5357b4ff..b734dc16 100644 --- a/site/docs/basics.html +++ b/site/docs/basics.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/building.html b/site/docs/building.html index 0d567aac..0d8fca73 100644 --- a/site/docs/building.html +++ b/site/docs/building.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/changelog.html b/site/docs/changelog.html index 0df5536f..0186e5d0 100644 --- a/site/docs/changelog.html +++ b/site/docs/changelog.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/custom-charts.html b/site/docs/custom-charts.html index dc821745..7200c88d 100644 --- a/site/docs/custom-charts.html +++ b/site/docs/custom-charts.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/fork-n-go.html b/site/docs/fork-n-go.html index 5009f815..6eaa8853 100644 --- a/site/docs/fork-n-go.html +++ b/site/docs/fork-n-go.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/sheetsee-charts.html b/site/docs/sheetsee-charts.html index 6cbd5a02..06b35401 100644 --- a/site/docs/sheetsee-charts.html +++ b/site/docs/sheetsee-charts.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/sheetsee-core.html b/site/docs/sheetsee-core.html index b3c94326..f85b111d 100644 --- a/site/docs/sheetsee-core.html +++ b/site/docs/sheetsee-core.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index 5f92d8d4..fe5a9391 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/sheetsee-tables.html b/site/docs/sheetsee-tables.html index 67726f4c..2dc83088 100644 --- a/site/docs/sheetsee-tables.html +++ b/site/docs/sheetsee-tables.html @@ -6,7 +6,7 @@ - + diff --git a/site/docs/tips.html b/site/docs/tips.html index f9d0bc61..66270837 100644 --- a/site/docs/tips.html +++ b/site/docs/tips.html @@ -6,7 +6,7 @@ - + diff --git a/site/index.html b/site/index.html index 850fa519..cd3c4f9a 100644 --- a/site/index.html +++ b/site/index.html @@ -6,7 +6,7 @@ - + diff --git a/site/js/highlight.pack.js b/site/js/highlight.pack.js new file mode 100644 index 00000000..5807522f --- /dev/null +++ b/site/js/highlight.pack.js @@ -0,0 +1 @@ +var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
              ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/template.hbs b/template.hbs index 720ec4a7..bec28583 100644 --- a/template.hbs +++ b/template.hbs @@ -6,7 +6,7 @@ - + From 5d8ab8a60278f4ae24ab479371cb2fffe320f84b Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 7 Sep 2014 21:49:44 -0700 Subject: [PATCH 097/157] deleted --- js/highlight.pack.js | 1 - site/js/highlight.pack.js | 1 - 2 files changed, 2 deletions(-) delete mode 100644 js/highlight.pack.js delete mode 100644 site/js/highlight.pack.js diff --git a/js/highlight.pack.js b/js/highlight.pack.js deleted file mode 100644 index 5807522f..00000000 --- a/js/highlight.pack.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
              ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file diff --git a/site/js/highlight.pack.js b/site/js/highlight.pack.js deleted file mode 100644 index 5807522f..00000000 --- a/site/js/highlight.pack.js +++ /dev/null @@ -1 +0,0 @@ -var hljs=new function(){function k(v){return v.replace(/&/gm,"&").replace(//gm,">")}function t(v){return v.nodeName.toLowerCase()}function i(w,x){var v=w&&w.exec(x);return v&&v.index==0}function d(v){return Array.prototype.map.call(v.childNodes,function(w){if(w.nodeType==3){return b.useBR?w.nodeValue.replace(/\n/g,""):w.nodeValue}if(t(w)=="br"){return"\n"}return d(w)}).join("")}function r(w){var v=(w.className+" "+(w.parentNode?w.parentNode.className:"")).split(/\s+/);v=v.map(function(x){return x.replace(/^language-/,"")});return v.filter(function(x){return j(x)||x=="no-highlight"})[0]}function o(x,y){var v={};for(var w in x){v[w]=x[w]}if(y){for(var w in y){v[w]=y[w]}}return v}function u(x){var v=[];(function w(y,z){for(var A=y.firstChild;A;A=A.nextSibling){if(A.nodeType==3){z+=A.nodeValue.length}else{if(t(A)=="br"){z+=1}else{if(A.nodeType==1){v.push({event:"start",offset:z,node:A});z=w(A,z);v.push({event:"stop",offset:z,node:A})}}}}return z})(x,0);return v}function q(w,y,C){var x=0;var F="";var z=[];function B(){if(!w.length||!y.length){return w.length?w:y}if(w[0].offset!=y[0].offset){return(w[0].offset"}function E(G){F+=""}function v(G){(G.event=="start"?A:E)(G.node)}while(w.length||y.length){var D=B();F+=k(C.substr(x,D[0].offset-x));x=D[0].offset;if(D==w){z.reverse().forEach(E);do{v(D.splice(0,1)[0]);D=B()}while(D==w&&D.length&&D[0].offset==x);z.reverse().forEach(A)}else{if(D[0].event=="start"){z.push(D[0].node)}else{z.pop()}v(D.splice(0,1)[0])}}return F+k(C.substr(x))}function m(y){function v(z){return(z&&z.source)||z}function w(A,z){return RegExp(v(A),"m"+(y.cI?"i":"")+(z?"g":""))}function x(D,C){if(D.compiled){return}D.compiled=true;D.k=D.k||D.bK;if(D.k){var z={};function E(G,F){if(y.cI){F=F.toLowerCase()}F.split(" ").forEach(function(H){var I=H.split("|");z[I[0]]=[G,I[1]?Number(I[1]):1]})}if(typeof D.k=="string"){E("keyword",D.k)}else{Object.keys(D.k).forEach(function(F){E(F,D.k[F])})}D.k=z}D.lR=w(D.l||/\b[A-Za-z0-9_]+\b/,true);if(C){if(D.bK){D.b=D.bK.split(" ").join("|")}if(!D.b){D.b=/\B|\b/}D.bR=w(D.b);if(!D.e&&!D.eW){D.e=/\B|\b/}if(D.e){D.eR=w(D.e)}D.tE=v(D.e)||"";if(D.eW&&C.tE){D.tE+=(D.e?"|":"")+C.tE}}if(D.i){D.iR=w(D.i)}if(D.r===undefined){D.r=1}if(!D.c){D.c=[]}var B=[];D.c.forEach(function(F){if(F.v){F.v.forEach(function(G){B.push(o(F,G))})}else{B.push(F=="self"?D:F)}});D.c=B;D.c.forEach(function(F){x(F,D)});if(D.starts){x(D.starts,C)}var A=D.c.map(function(F){return F.bK?"\\.?\\b("+F.b+")\\b\\.?":F.b}).concat([D.tE]).concat([D.i]).map(v).filter(Boolean);D.t=A.length?w(A.join("|"),true):{exec:function(F){return null}};D.continuation={}}x(y)}function c(S,L,J,R){function v(U,V){for(var T=0;T";U+=Z+'">';return U+X+Y}function N(){var U=k(C);if(!I.k){return U}var T="";var X=0;I.lR.lastIndex=0;var V=I.lR.exec(U);while(V){T+=U.substr(X,V.index-X);var W=E(I,V);if(W){H+=W[1];T+=w(W[0],V[0])}else{T+=V[0]}X=I.lR.lastIndex;V=I.lR.exec(U)}return T+U.substr(X)}function F(){if(I.sL&&!f[I.sL]){return k(C)}var T=I.sL?c(I.sL,C,true,I.continuation.top):g(C);if(I.r>0){H+=T.r}if(I.subLanguageMode=="continuous"){I.continuation.top=T.top}return w(T.language,T.value,false,true)}function Q(){return I.sL!==undefined?F():N()}function P(V,U){var T=V.cN?w(V.cN,"",true):"";if(V.rB){D+=T;C=""}else{if(V.eB){D+=k(U)+T;C=""}else{D+=T;C=U}}I=Object.create(V,{parent:{value:I}})}function G(T,X){C+=T;if(X===undefined){D+=Q();return 0}var V=v(X,I);if(V){D+=Q();P(V,X);return V.rB?0:X.length}var W=z(I,X);if(W){var U=I;if(!(U.rE||U.eE)){C+=X}D+=Q();do{if(I.cN){D+=""}H+=I.r;I=I.parent}while(I!=W.parent);if(U.eE){D+=k(X)}C="";if(W.starts){P(W.starts,"")}return U.rE?0:X.length}if(A(X,I)){throw new Error('Illegal lexeme "'+X+'" for mode "'+(I.cN||"")+'"')}C+=X;return X.length||1}var M=j(S);if(!M){throw new Error('Unknown language: "'+S+'"')}m(M);var I=R||M;var D="";for(var K=I;K!=M;K=K.parent){if(K.cN){D=w(K.cN,D,true)}}var C="";var H=0;try{var B,y,x=0;while(true){I.t.lastIndex=x;B=I.t.exec(L);if(!B){break}y=G(L.substr(x,B.index-x),B[0]);x=B.index+y}G(L.substr(x));for(var K=I;K.parent;K=K.parent){if(K.cN){D+=""}}return{r:H,value:D,language:S,top:I}}catch(O){if(O.message.indexOf("Illegal")!=-1){return{r:0,value:k(L)}}else{throw O}}}function g(y,x){x=x||b.languages||Object.keys(f);var v={r:0,value:k(y)};var w=v;x.forEach(function(z){if(!j(z)){return}var A=c(z,y,false);A.language=z;if(A.r>w.r){w=A}if(A.r>v.r){w=v;v=A}});if(w.language){v.second_best=w}return v}function h(v){if(b.tabReplace){v=v.replace(/^((<[^>]+>|\t)+)/gm,function(w,z,y,x){return z.replace(/\t/g,b.tabReplace)})}if(b.useBR){v=v.replace(/\n/g,"
              ")}return v}function p(z){var y=d(z);var A=r(z);if(A=="no-highlight"){return}var v=A?c(A,y,true):g(y);var w=u(z);if(w.length){var x=document.createElementNS("http://www.w3.org/1999/xhtml","pre");x.innerHTML=v.value;v.value=q(w,u(x),y)}v.value=h(v.value);z.innerHTML=v.value;z.className+=" hljs "+(!A&&v.language||"");z.result={language:v.language,re:v.r};if(v.second_best){z.second_best={language:v.second_best.language,re:v.second_best.r}}}var b={classPrefix:"hljs-",tabReplace:null,useBR:false,languages:undefined};function s(v){b=o(b,v)}function l(){if(l.called){return}l.called=true;var v=document.querySelectorAll("pre code");Array.prototype.forEach.call(v,p)}function a(){addEventListener("DOMContentLoaded",l,false);addEventListener("load",l,false)}var f={};var n={};function e(v,x){var w=f[v]=x(this);if(w.aliases){w.aliases.forEach(function(y){n[y]=v})}}function j(v){return f[v]||f[n[v]]}this.highlight=c;this.highlightAuto=g;this.fixMarkup=h;this.highlightBlock=p;this.configure=s;this.initHighlighting=l;this.initHighlightingOnLoad=a;this.registerLanguage=e;this.getLanguage=j;this.inherit=o;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE]};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE]};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gim]*/,i:/\n/,c:[this.BE,{b:/\[/,e:/\]/,r:0,c:[this.BE]}]};this.TM={cN:"title",b:this.IR,r:0};this.UTM={cN:"title",b:this.UIR,r:0}}();hljs.registerLanguage("bash",function(b){var a={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)\}/}]};var d={cN:"string",b:/"/,e:/"/,c:[b.BE,a,{cN:"variable",b:/\$\(/,e:/\)/,c:[b.BE]}]};var c={cN:"string",b:/'/,e:/'/};return{l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for break continue while in do done exit return set declare case esac export exec",literal:"true false",built_in:"printf echo read cd pwd pushd popd dirs let eval unset typeset readonly getopts source shopt caller type hash bind help sudo",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:true,c:[b.inherit(b.TM,{b:/\w[\w\d_]*/})],r:0},b.HCM,b.NM,d,c,a]}});hljs.registerLanguage("diff",function(a){return{c:[{cN:"chunk",r:10,v:[{b:/^\@\@ +\-\d+,\d+ +\+\d+,\d+ +\@\@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}});hljs.registerLanguage("javascript",function(a){return{aliases:["js"],k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:10},a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,a.REGEXP_MODE,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,c:[a.inherit(a.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[a.CLCM,a.CBLCLM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+a.IR,r:0}]}});hljs.registerLanguage("xml",function(a){var c="[A-Za-z0-9\\._:-]+";var d={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"};var b={eW:true,i:/]+/}]}]}]};return{aliases:["html"],cI:true,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},d,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:"[^ /><]+",r:0},b]}]}});hljs.registerLanguage("markdown",function(a){return{c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}|\t)",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].+?[\\)\\]]",rB:true,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:true,rE:true,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:true,eE:true},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:true,eE:true,}],r:10},{b:"^\\[.+\\]:",e:"$",rB:true,c:[{cN:"link_reference",b:"\\[",e:"\\]",eB:true,eE:true},{cN:"link_url",b:"\\s",e:"$"}]}]}});hljs.registerLanguage("css",function(a){var b="[a-zA-Z-][a-zA-Z0-9_-]*";var c={cN:"function",b:b+"\\(",e:"\\)",c:["self",a.NM,a.ASM,a.QSM]};return{cI:true,i:"[=/|']",c:[a.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:true,eE:true,r:0,c:[c,a.ASM,a.QSM,a.NM]}]},{cN:"tag",b:b,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[a.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[c,a.NM,a.QSM,a.ASM,a.CBLCLM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}});hljs.registerLanguage("http",function(a){return{i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:true,e:"$",c:[{cN:"string",b:" ",e:" ",eB:true,eE:true}]},{cN:"attribute",b:"^\\w",e:": ",eE:true,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:true}}]}});hljs.registerLanguage("ini",function(a){return{cI:true,i:/\S/,c:[{cN:"comment",b:";",e:"$"},{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:true,k:"on off true false yes no",c:[a.QSM,a.NM],r:0}]}]}});hljs.registerLanguage("json",function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}); \ No newline at end of file From 37babb3188dd8e1c4bd6f8b8f6760ebb810c0d40 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Mon, 8 Sep 2014 16:49:40 -0700 Subject: [PATCH 098/157] gahh --- js/sheetsee.js | 2 +- site/js/sheetsee.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/sheetsee.js b/js/sheetsee.js index dcdddef3..ff3f52d8 100644 --- a/js/sheetsee.js +++ b/js/sheetsee.js @@ -25372,7 +25372,7 @@ function table(data, opts) { templateID = opts.tableDiv.replace("#", "") + "_template" } var template = $(templateID) - var tableContents = ich.fullTable_template({rows: data}) + var tableContents = ich[templateID]({rows: data}) $(opts.tableDiv).html(tableContents) } },{"icanhaz":2}]},{},[1]) diff --git a/site/js/sheetsee.js b/site/js/sheetsee.js index dcdddef3..ff3f52d8 100644 --- a/site/js/sheetsee.js +++ b/site/js/sheetsee.js @@ -25372,7 +25372,7 @@ function table(data, opts) { templateID = opts.tableDiv.replace("#", "") + "_template" } var template = $(templateID) - var tableContents = ich.fullTable_template({rows: data}) + var tableContents = ich[templateID]({rows: data}) $(opts.tableDiv).html(tableContents) } },{"icanhaz":2}]},{},[1]) From 21710227a4794a623d92661cc8ceb6fb606305f4 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Wed, 1 Oct 2014 23:40:15 -0700 Subject: [PATCH 099/157] fix id pattern, fixes #61 the tables now use _template to identify the templates from the divs --- demos/demo-table.html | 2 +- site/demos/demo-table.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demos/demo-table.html b/demos/demo-table.html index 4efffd6a..da9ad7a3 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -78,7 +78,7 @@

              Home Page - - diff --git a/site/demos/demo-map.html b/site/demos/demo-map.html index 51c292b2..e8df0411 100644 --- a/site/demos/demo-map.html +++ b/site/demos/demo-map.html @@ -78,7 +78,7 @@

              Home Page + "
            • {{placename}}

            " var geoJSON = Sheetsee.createGeoJSON(data, optionsJSON) var map = Sheetsee.loadMap("map") - Sheetsee.addTileLayer(map, 'examples.map-20v6611k') + Sheetsee.addTileLayer(map, 'jllord.n7aml2bc') Sheetsee.addMarkerLayer(geoJSON, map, template) } @@ -87,7 +87,7 @@

            Home Page var geojson = Sheetsee.createGeoJSON(data, opts) var plytemplate = "

            {{description}}

            " var shapesmap = Sheetsee.loadMap("shapesmap") - Sheetsee.addTileLayer(shapesmap, 'examples.map-20v6611k') + Sheetsee.addTileLayer(shapesmap, 'jllord.n7aml2bc') Sheetsee.addMarkerLayer(geojson, shapesmap, plytemplate) } diff --git a/site/docs/sheetsee-maps.html b/site/docs/sheetsee-maps.html index fe5a9391..895eb895 100644 --- a/site/docs/sheetsee-maps.html +++ b/site/docs/sheetsee-maps.html @@ -64,9 +64,9 @@

            Sheetsee.loadMap(mapDiv)

      Sheetsee.addTileLayer(map, tileLayer)

      To add a tile layer (aka a custom map scheme/design/background) you'll use this function which takes in your map and the source of the tileLayer. This source can be a Mapbox id, a URL to a TileJSON or your own generated TileJSON. See Mapbox's Documentation for more information.

      -
      Sheetsee.addTileLayer(map, 'examples.map-20v6611k')
      +
      Sheetsee.addTileLayer(map, 'jllord.n7aml2bc')
       
      -

      You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

      +

      You can add tiles from awesome mapmakers like Stamen or create your own in Mapbox's Tilemill or online.

      Sheetsee.addMarkerLayer(geoJSON, map)

      To add makers, lines or shapes to your map, use this function and pass in your geoJSON so that it can get the coordinates and your map so that it places the markers there. You can customize what the content in your marker's popup looks like with a popupTemplate, which is an ICanHaz.js template in HTML and can reference the column headers you included in your optionsJSON.

      var markerLayer = Sheetsee.addMarkerLayer(geoJSON, map, popupTemplate)
      @@ -90,7 +90,7 @@ 
       </script>
       

      Learn more about the things you can do with ICanHaz.js.

      -

      View Demo

      +

      View Demo

    From 0d1dd3abab82c132e1686e5ed8b3d248603ecd44 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 19:13:12 -0400 Subject: [PATCH 139/157] Update raw files --- docs/basics.md | 12 +++++------- docs/building.md | 16 +++++++--------- docs/index.md | 22 +++++++++------------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/docs/basics.md b/docs/basics.md index 47cf5eb6..2d70e025 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -9,18 +9,16 @@ Spreadsheets are a great _lightweight_ databases. Google Spreadsheets in particu 3. Create a place holder `
    `, with `id`, in your HTML the map or table you want. 4. Create templates for tables in ` diff --git a/docs/building.md b/docs/building.md index 0d93df90..84c15cf1 100644 --- a/docs/building.md +++ b/docs/building.md @@ -2,20 +2,18 @@ You can customize your Sheetsee build with just the parts you want to use, for example to only include the mapping module or only the tables module. If you want to just use the full version, you can grab it here at [github.com/jlord/sheetsee.js](https://github.com/jlord/sheetsee.js/blob/master/js/sheetsee.js). -All bundle comes with [Mustache.js](https://mustache.github.io) and [Leaflet.js](http://leafletjs.com). Additionally, you'll need to also include [Tabletop.js](https://github.com/jsoma/tabletop) your HTML head like so: +All builds come with [Mustache.js](https://mustache.github.io) and [Leaflet.js](http://leafletjs.com). Additionally, you'll need to link to [Tabletop.js](https://github.com/jsoma/tabletop) your HTML head like so: ```HTML - - + + ``` **To build a custom Sheetsee you'll need [Node.js](http://www.nodejs.org) on your computer familiarity with the command line.** -#### Get Node/NPM +Download Node.js from [nodejs.org/download](http://nodejs.org/download). For most users you can just download the Mac _.pkg_ or Windows _.msi_. Follow the install instructions; both include npm. Then install `sheetsee`. -Download Node.js from [nodejs.org/download](http://nodejs.org/download). For most users you can just download the Mac _.pkg_ or Windows _.msi_. Follow the install instructions, both include NPM. Once they're installed, proceed: - -## Install `sheetsee` from NPM +## Install `sheetsee` from npm The `sheetsee` (with no '.js') module is the tool for building custom Sheetsee builds. Install `sheetsee` globally and then run it within the folder of your soon-to-be Sheetsee project. _Install globally_ @@ -36,6 +34,6 @@ Here are the options for the different modules. If you want save the generated f - `-t` or `-tables` for tables - `--save` to write out the file* -_* otherwise, defaults to standardout on your console which you can_ `| pbcopy` +_* otherwise, defaults to standard out on your console which you can_ `| pbcopy` -So for instance, `sheetsee -m -t --save` will build you a Sheetsee.js with the basic **data** functions, the **map** and **tables** sections built in and save it as a file named **sheetsee.js**. Running `sheetsee -m -t | pbcopy` will save the output to your clipboard. +So for instance, `sheetsee -m --save` will build you a Sheetsee with the basic **data** functions and the **map** section, leaving out the tables section. It will save it as a file named '**sheetsee.js**'. Running `sheetsee -m | pbcopy` will save the output to your clipboard. diff --git a/docs/index.md b/docs/index.md index f6f4a26c..9f997dc4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,27 +1,27 @@ ![sheetseeimg](https://raw.github.com/jlord/sheetsee-cache/master/img/sheetsee-03.png) -**Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables, maps and charts. +**Sheetsee.js** is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables and maps. ## Modules -Each of **sheetsee.js**'s features are divided into modules. Use just the parts you need; see docs on [building](./docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). +Each of Sheetsee's functions are divided into modules. Use just the parts you need; see docs on [building](./docs/building.md). If you don't want to build your own, you can just use the full library which includes all modules, it's [here on GitHub](http://www.github.com/jlord/sheetsee.js). | Module | Contains | Docs | | ------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------- | -| **sheetsee-core** | **Included in any build**. Gets you started and has the working-with-your-data functions. | [Doc](./docs/sheetsee-core.md) | +| **sheetsee** | Command line module for make a custom build of Sheetsee. | [Doc](./docs/building.md) | +| **sheetsee-core** | **Included in all builds**. Has helpful working-with-your-data functions. | [Doc](./docs/sheetsee-core.md) | | **sheetsee-tables** | Contains everything you'll need to create a table including sortable columns, pagination and search.| [Doc](./docs/sheetsee-tables.md) | -| **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built on Mapbox.js. | [Doc](./docs/sheetsee-maps.md) | -| **sheetsee-charts** | Includes 3 basic d3 charts: bar, line and pie. You can also [use your own](docs/custom-charts.md). | [Doc](./docs/sheetsee-charts.md) | +| **sheetsee-maps** | For making maps with your point, line or polygon spreadsheet data. Built with Leaflet.js. | [Doc](./docs/sheetsee-maps.md) | ## Spreadsheets!? -Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases [here](./docs/basics.md). +Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. [Read more](./docs/basics.md) about using spreadsheets for databases. ## In the Wild -What can you make with **Sheetsee.js**? Lots of things, here are some examples: +What can you make with Sheetsee? Lots of things, here are some examples: - [Hack-Spots](http://jlord.github.io/hack-spots) - [Combine with IFTTT](http://jlord.us/instagram/) @@ -29,9 +29,9 @@ What can you make with **Sheetsee.js**? Lots of things, here are some examples: **List your sheetsee project here: file an [issue or pull request](http://www.github.com/jlord/sheetsee.js).** -# Resources & Documentation +## Resources & Documentation -More resources on using Sheetsee.js: +More resources on using Sheetsee: | Getting Started | Ideas | Use | Demos | | --- | --- | --- | --- | @@ -39,7 +39,3 @@ More resources on using Sheetsee.js: | [Building Sheetsee](./docs/building.md) | [Tips!](./docs/tips.md) | [Sheetsee-tables](./docs/sheetsee-tables.md) | [Table Demo](./demos/demo-table.html) | | [Basics](./docs/basics.md) | [Custom charts](./docs/custom-charts.md) | [Sheetsee-maps](./docs/sheetsee-maps.md) | [Map Demo](./demos/demo-map.html) | | | | [Sheetsee-charts](./docs/sheetsee-charts.md) | [Chart Demo](./demos/demo-chart.html) | - -## Note on New Google Spreadsheets - -Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. **Be sure to include at least version 1.3.4 in your project.** From 7ec395f49b7b61d80de767e46210af1d30b993e3 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 19:13:16 -0400 Subject: [PATCH 140/157] Build --- docs/about.html | 82 +++++++++++++++++++++ docs/basics.html | 121 ++++++++++++++++++++++++++++++ docs/building.html | 78 ++++++++++++++++++++ docs/changelog.html | 93 +++++++++++++++++++++++ docs/fork-n-go.html | 75 +++++++++++++++++++ docs/sheetsee-core.html | 150 ++++++++++++++++++++++++++++++++++++++ docs/sheetsee-maps.html | 112 ++++++++++++++++++++++++++++ docs/sheetsee-tables.html | 141 +++++++++++++++++++++++++++++++++++ docs/tips.html | 114 +++++++++++++++++++++++++++++ index.html | 137 ++++++++++++++++++++++++++++++++++ 10 files changed, 1103 insertions(+) create mode 100644 docs/about.html create mode 100644 docs/basics.html create mode 100644 docs/building.html create mode 100644 docs/changelog.html create mode 100644 docs/fork-n-go.html create mode 100644 docs/sheetsee-core.html create mode 100644 docs/sheetsee-maps.html create mode 100644 docs/sheetsee-tables.html create mode 100644 docs/tips.html create mode 100644 index.html diff --git a/docs/about.html b/docs/about.html new file mode 100644 index 00000000..4cf5e863 --- /dev/null +++ b/docs/about.html @@ -0,0 +1,82 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    About

    +

    Sheetsee.js began as a part of a Code for America 2012 Fellowship project. The original idea was to make a way for cities to easily publish and maintain budget data themselves. Originally, the JavaScript was part of a WordPress theme that could be connected to a spreadsheet, allowing new pages to be created with charts, maps and tables automatically generated from the data.

    +

    In early 2013, after the CfA Fellowship and through a grant from Mozilla Open News, the JavaScript bits were pulled out to make it a standalone open source library: sheetsee.js.

    +

    Since then there have been a few updates to the library but it was not until 2017 when Sheetsee got it's next major upgrade.

    +

    In Spring of 2017 Sheetsee was cleaned up and downsized. Charting support and some dependencies were removed to make maintenance and overall size better.

    +

    Dependencies

    +

    Sheetsee comes into play after you use Tabletop.js, a library that handles the messy interactions with the Google Spreadsheets API for you and returns a lovely array of your data. At the end of the day, however, Sheetsee just wants an array of JSON data, if you have some on hand already, you can use Sheetsee too :)

    +

    Mustache, Leaflet

    +

    Sheetsee uses the Mustache.js library for templates in sheetsee-tables and map popups in sheetsee-maps. The maps are generated using the Leaflet.js library.

    +

    Hacked on Openly

    + +

    Contact & Contribute

    +

    Issues with this website can be opened on the sheetsee.js repository. Otherwise, if your issue falls specifically with one of the modules, you can file it on its particular repo:

    + +

    Thanks, y'all

    +

    Thanks to Code for America for providing the platform me to build the first version of sheetsee.js for Macon, Georgia.

    +

    Thanks to Dan Sinker at Open News for having faith and getting things together to make this Code Sprint happen and thanks to Matt Green at WBEZ for being a willing partner.

    +

    Thanks to Max Ogden for emotional support, teaching me JavaScript and answering lots of questions.

    +

    Thanks to all the authors and contributors to Tabletop.js, Leaflet.js and Mustache.js. Thanks to Google and the Internet for existing and to all those who've written tutorials or asked or answered a question on StackOverflow.

    +

    Thanks to Mom and Dad for getting a computer in 1996 and the mIRC scripts I started writing that I suppose would eventually lead me here.

    + + + +
    + + + diff --git a/docs/basics.html b/docs/basics.html new file mode 100644 index 00000000..feee8bc8 --- /dev/null +++ b/docs/basics.html @@ -0,0 +1,121 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Spreadsheets as Databases

    +

    Spreadsheets are a great lightweight databases. Google Spreadsheets in particular are easy to work with and share, making this unlike most traditional database setups. That being said, traditional databases are great for bigger, more secure jobs. If you're storing lots and lots and lots of information, or storing sensitive or complex information—the spreadsheet is not for you. But if you're working on small to medium sized personal or community projects, try a spreadsheet!

    +

    The Short & Sweet

    +
      +
    1. Link to Sheetsee.js and Tabletop.js in your HTML head.
    2. +
    3. Link to sheetsee's default stylesheet, sss.css.
    4. +
    5. Create a place holder <div>, with id, in your HTML the map or table you want.
    6. +
    7. Create templates for tables in <script> tags with an id matching the <div> plus _template.
    8. +
    9. Inside of another <script> tag initialize Tabletop.js. Once it fetches your spreadsheet data, pass it onto Sheetsee.
      document.addEventListener('DOMContentLoaded', function() {
      +var URL = 'YOURSPREADSHEETSKEYHERE'
      +Tabletop.init({key: URL, callback: callback, simpleSheet: true})
      +})
      +
      +
    10. +
    11. Define the function that Tabletop.js calls when it returns with the data. This function will contain all the Sheetsee.js methods you want to use.
      function callback (data) {
      +// All the Sheetsee things you want to do!
      +}
      +
      +
    12. +
    13. Set it and forget. Now all you need to do is edit the spreadsheet and visitors will get the latest information every time they load the page.
    14. +
    +

    Bare Minimum Setup

    +

    Ignoring some HTML things to conserve space, you get the point. This is a basic setup:

    +
    <html>
    +  <head>
    +    <meta charset="utf-8">
    +    <script type="text/javascript" src="js/tabletop.js"></script>
    +    <script type="text/javascript" src='js/sheetsee.js'></script>
    +    <link rel="stylesheet" type="text/css" href="css/sss.css">
    +  </head>
    +  <body>
    +  <div id="placeholder"></div>
    +
    +  <script id="placeholder" type="text/html">
    +    // template if you so desire!
    +  </script>
    +
    +  <script type="text/javascript">
    +    document.addEventListener('DOMContentLoaded', function () {
    +        var URL = 'YOURSPREADSHEETSKEYHERE'
    +        Tabletop.init( { key: URL, callback: myData, simpleSheet: true } )
    +    })
    +    function myData (data) {
    +      // All the sheetsee things you want to do!
    +    }
    +  </script>
    +  </body>
    +</html>
    +
    +

    Your Data

    +

    sheetsee

    +

    Your Google Spreadsheet should be set up with row one as your column headers. Row two and beyond should be your data. Each header and row becomes an object in the final array that Tabletop.js delivers of your data.

    +

    sheetsee

    +

    There shouldn't be any breaks or horizontal organization in the spreadsheet. But, feel free to format the style of your spreadsheet as you wish; borders, fonts and colors and such do not transfer or affect your data exporting.

    +
    [{"name":"Coco","breed":"Teacup Maltese","kind":"Dog","cuddlability":"5","lat":"37.74832","long":"-122.402158","picurl":"http://distilleryimage8.s3.amazonaws.com/98580826813011e2bbe622000a9f1270_7.jpg","hexcolor":"#ECECEC","rowNumber":1}...]
    +

    Hexcolor

    +

    sheetsee

    +

    You can add a column to your spreadsheet with the heading hexcolor (case insensitive) and add colors to be used in maps. The color scheme is up to you, all you need to do is fill the column with hexidecimal color values. This color picker by Devin Hunt is really nice. #Funtip: Coloring the background of the cell it's hexcolor brings delight!

    +

    Geocoding

    +

    If you intend to map your data and only have addresses you'll need to geocode the addresses into lat/long coordinates. Mapbox built a plugin that does this for you in Google Docs. You can also use websites like latlong.net to get the coordinates and paste them into rows with column headers lat and long.

    +

    Publishing Your Spreadsheet

    +

    sheetsee

    +

    You need to do this in order to generate a unique key for your spreadsheet, which Tabletop.js will use to get your spreadsheet data. In your Google Spreadsheet, click File > Publish to the Web. Then in the next window click Start Publishing; it will then turn into a Stop Publishing button.

    +

    sheetsee

    +

    You should have an address in a box at the bottom, your key is the portion between the = and the &. You'll retrieve this later when you hook up your site to the spreadsheet. Actually, you technically can use the whole URL, but it's so long...

    +

    CSS

    +

    Sheetsee.js comes with a bare minimum stylesheet, sss.css, which contains elements you'll want to style when using the feature they correspond to. Use it if you want, or as a starting off point to create your own styles.

    + + + +
    + + + diff --git a/docs/building.html b/docs/building.html new file mode 100644 index 00000000..7ff9710e --- /dev/null +++ b/docs/building.html @@ -0,0 +1,78 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Right-sizing

    +

    You can customize your Sheetsee build with just the parts you want to use, for example to only include the mapping module or only the tables module. If you want to just use the full version, you can grab it here at github.com/jlord/sheetsee.js.

    +

    All builds come with Mustache.js and Leaflet.js. Additionally, you'll need to link to Tabletop.js your HTML head like so:

    +
    <script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.5.1/tabletop.min.js"></script>
    +<script src="js/sheetsee.js"></script>
    +
    +

    To build a custom Sheetsee you'll need Node.js on your computer familiarity with the command line.

    +

    Download Node.js from nodejs.org/download. For most users you can just download the Mac .pkg or Windows .msi. Follow the install instructions; both include npm. Then install sheetsee.

    +

    Install sheetsee from npm

    +

    The sheetsee (with no '.js') module is the tool for building custom Sheetsee builds. Install sheetsee globally and then run it within the folder of your soon-to-be Sheetsee project.

    +

    Install globally

    +
    npm install -g sheetsee
    +
    +

    Run from within a project folder

    +
    sheetsee [options]
    +
    +

    Here are the options for the different modules. If you want save the generated file as sheetsee.js then add the --save option.

    +
      +
    • -m or -maps for maps
    • +
    • -t or -tables for tables
    • +
    • --save to write out the file*
    • +
    +

    * otherwise, defaults to standard out on your console which you can | pbcopy

    +

    So for instance, sheetsee -m --save will build you a Sheetsee with the basic data functions and the map section, leaving out the tables section. It will save it as a file named 'sheetsee.js'. Running sheetsee -m | pbcopy will save the output to your clipboard.

    + + + +
    + + + diff --git a/docs/changelog.html b/docs/changelog.html new file mode 100644 index 00000000..51e25760 --- /dev/null +++ b/docs/changelog.html @@ -0,0 +1,93 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    March 2017 Sheetsee v4

    +

    sheetsee-core changes

    +

    Methods for charts have been removed:

    +
      +
    • Sheetsee.makeColorArrayOfObject(data, colors)
    • +
    • Sheetsee.addUnitsLabels(arrayObj, oldLabel, oldUnits)
    • +
    +

    May 10, 2014, Sheetsee v3

    +

    Better Table Template Options

    +

    Updated sheetsee-tables to allow you to re-use a template (rather than duplicating it for each different table you wanted to create). Previously it assumed your HTML table div id matched your script template id. This means that you can pass in an extra key/value pair in your table options into Sheetsee.maketable(). The new pair it takes is: "templateID" : "yourtemplateid". Example below, full sheetsee-tables documentation here.

    +
    var tableOptions = {
    +                    "data": gData,
    +                    "pagination": 10,
    +                    "tableDiv": "#fullTable",
    +                    "filterDiv": "#fullTableFilter",
    +                    "templateID": "tableTemplte"
    +                    }
    +Sheetsee.makeTable(tableOptions)
    +
    +

    May 2014

    +

    Important Google Spreadsheets & Tabletop News

    +

    Google recently updated their Google Spreadsheets and the API. For a bit this was breaking things using the old API, including Tabletop. This has been fixed and the latest version of tabletop.js works on both old and new spreadsheets. Be sure to include at least version 1.3.4 in your project.

    +

    August 13, 2013

    +

    Charting Intake

    +

    D3 charts need an array of objects, and something to chart: the thing itself (aka labels) and the corresponding value (aka units). Your data usually contains more than D3 needs to make the chart, so you have to tell it what to chart from your data to chart.

    +

    Previously Sheetsee required you pass your data through a function, addUnitsAndLabels() which took in your data and the things you wanted to chart, reformatted your data for you so that you could pass it into one of the d3 charts. This is one more step than actually needs to happen.

    +

    Now Sheetsee just asks for what you want your labels and units to be in the options you give it when calling the chart function. It then sorts the data correctly on the inside of the chart function. Yay, easier!

    +
    var options = {
    +  labels: "name",
    +  units: "cuddleability",
    +  m: [60, 60, 30, 150],
    +  w: 600, h: 400,
    +  div: "#barChart",
    +  xaxis: "no. of pennies",
    +  hiColor: "#FF317D"
    +}
    +
    +

    Thanks @maxogden for the help with this.

    +

    Started doing this changelong pretty late in the game.

    + + + +
    + + + diff --git a/docs/fork-n-go.html b/docs/fork-n-go.html new file mode 100644 index 00000000..e6213146 --- /dev/null +++ b/docs/fork-n-go.html @@ -0,0 +1,75 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Fork-n-Go

    +

    +

    A Fork-n-Go project is a project on GitHub that in a few clicks, starting with a fork, gives another user a live website that they control with an easy to swap-for-your-own Google Spreadsheet database.

    +

    Two awesome things that make this possible: Forking, the tool on GitHub that allows you to copy a public repository onto your account, and GitHub Pages, GitHub's free web hosting service for every repository, account and organization.

    +

    I've built a whole other website on the idea with lots of examples: jlord.github.io/forkngo

    +
    +

    How

    +

    To have a website for a repository hosted by GitHub Pages all you need is to have webfiles uploaded and to tell GitHub the name of the branch you want it to host (in your repository's settings).

    +

    So Sheetsee.js projects, hosted on GitHub, can easily be forked and connected to another spreadsheet giving another user a live website of their own—with data they control—really easily.

    +

    Example

    +

    A Fork-n-Go example from my blog post on the topic:

    +

    Hack Spots Fork-n-Go

    +

    I made this website to collect hack spots all over the world from friends and friends of friends (the spreadsheet is wide open, so you can add some, too!). It’s using sheetsee to power the table, map and other elements of the page. Its source is in this repo, with just a gh-pages branch. To create an instance of this site for yourself all you need to do:

    +
      +
    • Create a Google spreadsheet with the same headers (just copy and paste header row from the original). Click File > Publish to Web, then Start Publishing.
    • +
    • Fork the original repository.
    • +
    • Edit the HTML file directly on GitHub.com to replace the original spreadsheet’s unique key with your spreadsheet’s key (found in your spreadsheet’s URL). +Commit your change.
    • +
    +

    Now you have the same site connected to a spreadsheet that you manage — it’s live and can be found at yourGitHubName.github.io/theReposName.

    +

    forkcommit

    + + + +
    + + + diff --git a/docs/sheetsee-core.html b/docs/sheetsee-core.html new file mode 100644 index 00000000..b97718b1 --- /dev/null +++ b/docs/sheetsee-core.html @@ -0,0 +1,150 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    sheetsee-core

    +

    This module is included in every Sheetsee build. It contains methods for basic data manipulation you might want to do.

    +

    Working With Your Data

    +

    Sheetsee pairs with Tabletop.js which will fetch the data from your spreadsheet and return it as an array of objects. You'll use these methods from Sheetsee after you have that data.

    +

    Methods

    +

    Here are the functions you can use!

    +

    Sheetsee.getKeywordCount(data, keyword)

    +
      +
    • data array of objects
    • +
    • keyword string
    • +
    • Returns number
    • +
    +

    Given your data and keyword to search by, this function returns the number of times it occurs throughout all of the data.

    +
    getGroupCount(data, 'cat')
    +// returns a number
    +
    +

    Sheetsee.getKeyword(data, keyword)

    +
      +
    • data array of objects
    • +
    • keyword string
    • +
    • Returns number
    • +
    +

    Given your data and a keyword to search by, this function returns every row which contains a match to the keyword.

    +
    getKeyword(data, 'cat')
    +// returns array of objects
    +
    +

    Sheetsee.getColumnTotal(data, column)

    +
      +
    • data array of objects
    • +
    • column string
    • +
    • Returns number
    • +
    +

    Use only with columns of numbers

    +

    Given your data and column header, this function sums each cell in that column and returns the value.

    +
    getColumnTotal(data, 'cuddlability')
    +// returns number
    +
    +

    Sheetsee.getColumnAverage(data, column)

    +
      +
    • data array of objects
    • +
    • column string
    • +
    • Returns number
    • +
    +

    Given your data and column header, this function returns the average value of every cell in the column.

    +
    getColumnAverage(data, 'cuddlability')
    +// returns number
    +
    +

    Sheetsee.getMin(data, column)

    +
      +
    • data array of objects
    • +
    • column string
    • +
    • Returns array
    • +
    +

    Given your data and column header, this function returns an array of the rows with the lowest values within the specified column.

    +
    getMin(data, 'cuddlability')
    +// returns array
    +
    +

    Sheetsee.getMax(data, column)

    +
      +
    • data array of objects
    • +
    • column string
    • +
    • Returns array
    • +
    +

    Given your data and column header, this function returns an array of the rows with the highest values within the specified column.

    +
    getMin(data, 'cuddlability')
    +// returns array of objects
    +
    +

    Sheetsee.getMatches(data, filter, column)

    +
      +
    • data array of objects
    • +
    • filter string
    • +
    • column string
    • +
    • Returns array
    • +
    +

    Takes data, a filter term to search by within a column and returns every row that matches,

    +
    getMatches(data, 'dog', 'kind')
    +// returns array of objects
    +// [{'name': 'coco', 'kind': 'dog'...}, {'name': 'wolfgang', 'kind': 'dog'...},{'name': 'cooc', 'kind': 'dog'...} ]
    +
    +

    Sheetsee.getOccurance(data, column)

    +
      +
    • data array of objects
    • +
    • column string
    • +
    • Returns object
    • +
    +

    Takes data column header and returns an object with key/value pairs of how often an item occurs in the column.

    +
    getOccurance(data, 'kind')
    +// Returns an object
    +// {'dog': 3, 'cat': 3}
    +
    +

    Math

    +

    Don't Forget JavaScript Math! Create variables that are the sums, differences, multiples and so forth of others. Lots of info on that here on MDN.

    +
    var profit09 = Sheetsee.getColumnTotal(data, '2009')
    +var profit10 = Sheetsee.getColumnTotal(data, '2010')
    +var difference = profit09 - profit10
    +
    + + + +
    + + + diff --git a/docs/sheetsee-maps.html b/docs/sheetsee-maps.html new file mode 100644 index 00000000..c25a4e2d --- /dev/null +++ b/docs/sheetsee-maps.html @@ -0,0 +1,112 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    sheetsee-maps

    +

    see: jlord.github.io/sheetsee.js +demo: maps

    +

    Sheetsee uses this module to handle maps in your projects. This module uses (and includes) Leaflet.js to make maps of your points, polygons, lines or multipolygons (all coordinate based). Details on what that actually looks like here. It uses (and includes) Mustache.js templates for marker popups.

    +

    Maps: Polygons and Lines

    +

    Sheetsee-maps supports polygons and lines; so long as you have the correct coordinate structure in your cells. More details for coordinates of lines and polygons in geoJSON are here, but briefly:

    +

    A linestring:

    +
    [-122.41722106933594, 37.7663045891584], [-122.40477561950684, 37.77695634643178]
    +
    +

    A polygon:

    +
    [-122.41790771484375, 37.740381166384914], [-122.41790771484375, 37.74520008134973], [-122.40966796874999, 37.74520008134973],[-122.40966796874999, 37.740381166384914], [-122.41790771484375, 37.740381166384914]
    +
    +

    A Multipolygon:

    +
    [[-122.431640625, 37.79106586542567], [-122.431640625, 37.797441398913286], [-122.42666244506835, 37.797441398913286],[-122.42666244506835, 37.79106586542567], [-122.431640625, 37.79106586542567]],
    +[[-122.43352890014648, 37.78197638783258], [-122.43352890014648, 37.789031004883654], [-122.42443084716797, 37.789031004883654], [-122.42443084716797, 37.78197638783258], [-122.43352890014648, 37.78197638783258]]
    +
    +

    To Use

    +

    This module is used as a part of Sheetsee.js. You can download the full version or build your own with a command line tool.

    +

    You'll create a little bit of HTML and then some JavaScript in your HTML to use this. You can customize marker color, popup content and enable/disable clustering in your map.

    +

    Methods

    +

    Here are the functions you can use!

    +

    Sheetsee.createGeoJSON(data, optionsJSON)

    +
      +
    • data JSON array of data
    • +
    • optionsJSON array of strings, spreadsheet column title
    • +
    +

    If you'd like to just generate geoJSON from a spreadsheet you can use this method.

    +

    This takes in your spreadsheet data in JSON format (which you can get with Tabletop.js)and the parts of your data, optionsJSON, that you plan on including in your map's popups. These will be column headers in your spreadsheet in an array of strings.

    +

    If you're not going to have popups on your markers, don't worry about it then and just pass in your data (by default it will use all the row's information).

    +
    var optionsJSON = ['name', 'breed', 'cuddlability']
    +var geoJSON = Sheetsee.createGeoJSON(data, optionsJSON)
    +
    +

    It will return an array in the special geoJSON format that map making things love.

    +

    Sheetsee.loadMap(mapOptions)

    +
      +
    • object required object
        +
      • data your spreadsheet data array required
      • +
      • mapDiv the id of the div in your HTML to contain the map required
      • +
      • geoJSONincludes array of strings of column headers to include in popups
      • +
      • template HTML/Mustache template for popups
      • +
      • cluster a true/false boolean, do you want your markers clustered
      • +
      • hexcolor pick one color for your markers
      • +
      +
    • +
    +
    var mapOptions = {
    +  data: data, // required
    +  mapDiv: 'map', //required
    +  geoJSONincludes: ['Name', 'Animal', 'Rating'], // optional
    +  template: '<p>{{Name}}—{{Animal}}—{{Rating}}</p>', // optional
    +  cluster: true, // optional
    +  hexcolor: '#e91e63' // optional
    +}
    +
    +var map = Sheetsee.loadMap("map")
    +
    +

    Marker colors

    +

    If you create a column title hexcolor in your spreadsheet and fill each cell with hex color codes, those will be used to color your markers. If you define a color in hexcolors in the options you pass to your map it will override colors in the spreadsheet data.

    + + + +
    + + + diff --git a/docs/sheetsee-tables.html b/docs/sheetsee-tables.html new file mode 100644 index 00000000..aede1fa1 --- /dev/null +++ b/docs/sheetsee-tables.html @@ -0,0 +1,141 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    sheetsee-tables

    +

    Sheetsee uses this module to make tables. With this module you can create tables of your spreadsheet data that are sortable, searchable and paginate-able.

    +

    You'll need a placeholder <div> in your html, a <script> mustache template and a <script> that initiates the table.

    +

    Your HTML Placeholder

    +

    This is as simple as an empty <div> with an id.

    +

    Your Template

    +

    Your template is the mockup of what you'd like your table to look like and what content it should show. The style is up to you! It is a mustache template inside of <script> tags.

    +

    The id of the template should be the same as the HTML placeholder it corresponds to but with "_template" on the end.

    +

    Sorting

    +

    If you want users to be able to click on headers and sort that column, your template must include table headers with the class tHeader.

    +

    You can then style .tHeader in your CSS to make them look how you want.

    +

    Your Script

    +

    You'll want to set your table options and pass them into Sheetsee.makeTable(). If you want to add a search/filter, pass your options into Sheetsee.initiateTableFilter().

    +

    Methods

    +

    Functions for you to use! There are just two :tada:

    +

    Sheetsee.makeTable(tableOptions)

    +

    You pass in an object containing:

    +
      +
    • data array your data from Tabletop.js
    • +
    • pagination number how many rows displayed at one time, defaults to all
    • +
    • tableDiv string the <div> id placeholder in your HTML, includes the hash #
    • +
    • filterDiv string the <div> id containing your <input> filter if using search, includes the hash #
    • +
    • templateID string the id of your <script> tag with the template, defaults to assume it's the same as tableDiv + _template.
    • +
    +
    var tableOptions = {
    +  "data": data,
    +  "pagination": 10,
    +  "tableDiv": "#fullTable",
    +  "filterDiv": "#fullTableFilter",
    +  "templateID": "fullTable"
    +}
    +Sheetsee.makeTable(tableOptions)
    +
    +

    Pagination

    +

    If you do not put in a number for pagination, by default it will show all of the data at once. With pagination, HTML will be added at the bottom of your table for navigation, which you can style in your CSS:

    +

    HTML

    +
    <div id='Pagination' currentPage class='table-pagination'>
    +  Showing page {{currentPage}} of {{totalPages}}
    +  <a class='pagination-pre'>Previous</a><a class='pagination-next'>Next</a>
    +</div>
    +
    +

    CSS

    +
    #Pagination {}
    +.pagination-next {}
    +.pagination-pre {}
    +.no-pag {}
    +
    +

    Sheetsee.initiateTableFilter(tableOptions)

    +

    If you want to have an input to allow users to search/filter the data in the table, you'll add an input to your HTML. Give it an id and if you want add placeholder text:

    +
    <input id="tableFilter" type="text" placeholder="filter by.."></input>
    +
    +

    Then you'll pass your tableOptions object into this method:

    +
    Sheetsee.initiateTableFilter(tableOptions)
    +
    +

    You should also add a 'clear' button using the .clear CSS class.

    +
    <a href="#" class=".clear">Clear</a>
    +
    +

    Example

    +

    HTML

    +
    <input id="siteTableFilter" type="text"></input><a href="#" class=".clear">Clear</a>
    +<div id="siteTable"></div>
    +
    +

    Template

    +
    <script id="tableTemplate" type="text/html">
    +    <table>
    +    <tr><th class="tHeader">City</th><th class="tHeader">Place Name</th><th class="tHeader">Year</th><th class="tHeader">Image</th></tr>
    +      {{#rows}}
    +        <tr><td>{{city}}</td><td>{{placename}}</td><td>{{year}}</td><td>{{image}}</td></tr>
    +      {{/rows}}
    +  </table>
    +</script>
    +
    +

    JavaScript

    +
    <script type="text/javascript">
    +  document.addEventListener('DOMContentLoaded', function() {
    +    var tableOptions = {
    +      "data": data,
    +      "pagination": 10,
    +      "tableDiv": "#siteTable",
    +      "filterDiv": "#siteTableFilter",
    +      "templateID": "tableTemplate"
    +    }
    +    Sheetsee.makeTable(tableOptions)
    +    Sheetsee.initiateTableFilter(tableOptions)
    +  })
    +</script>
    +
    + + + +
    + + + diff --git a/docs/tips.html b/docs/tips.html new file mode 100644 index 00000000..2eb9f40a --- /dev/null +++ b/docs/tips.html @@ -0,0 +1,114 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    Tips

    +

    A few things to think about beyond maps and tables.

    +

    Mustache

    +

    You can use templates for more than just tables. Use them to create lists ol, ul; array of images... You'll need a placeholder <div> in your HTML, a <script> for your template. In your Tabletop.js callback use Mustache to pass your data into the template and add it to the DOM.

    +

    HTML

    +
    <div id="divID"></div>
    +
    +

    Template

    +
    <script id="divID_template" type="text/html">
    +  {{#rows}}
    +    <div><img class="photo" src="{{some-variable}}"></div>
    +  {{/rows}}
    +</script>
    +
    +

    Script

    +
    <script type="text/html">
    +  document.addEventListener('DOMContentLoaded', function() {
    +    var URL = 'YOURSPREADSHEETSKEYHERE'
    +    Tabletop.init({key: URL, callback: showData, simpleSheet: true})
    +  })
    +
    +  function showData (data) {
    +    var template = document.querySelector('divID_template').innerHTML
    +    var html = Sheetsee.Mustache.render(template, {'rows': data})
    +    document.getElementByID('divID').innerHTML = html
    +  }
    +</script>
    +
    +

    non-table example

    +

    lib

    +

    Query Strings

    +

    If your spreadsheet contains address information, using templates (Sheetsee uses Mustache.js), you can embed those elements into a query string (aka a search URL) like Google Maps URL or Yelp. If you search for a location in Google Maps, you'll notice it creates a URL for that search.

    +

    So, if you have information in your spreadsheet that would go inside a query string, make a template for inserting them into a link on your page.

    +

    The basic elements are: a spreadsheet with address info + HTML template to create the query string.

    +

    The Sheetsee Hack-Spots is an example that does such a thing. Here is the spreadsheet, with address information:

    +

    img

    +

    In the HTML template for the table on the Hack-Spots page, the button’s links look like this:

    +
    <a class="button" href="https://maps.google.com/maps?q={{address}},{{city}},{{state}}" target="_blank">View in Google Maps</a>
    +<a class="button" href="http://www.yelp.com/search?find_desc={{name}}&find_loc={{city}},{{state}}" target="_blank">Find on Yelp</a>
    +
    +

    Above we're inserting the address, city, and state details from the spreadsheet into the structure of a query string for Google maps and Yelp. You can figure out the query string of a service by just using it (type in an address in Google Maps) and looking at the resulting URL.

    +

    With a some CSS and such, the resulting website has a table with the hack spots and a button for viewing in Google Maps or Yelp:

    +

    img

    +

    When the page builds, it creates the correct link for each row. When someone clicks on the buttons it takes them directly to the Google Map search result for that address. BAM!

    +

    IFTTT

    +

    Ifttt.com offers lots of options sending data from your actions (Twitter, Instagram, GitHub, Pocket...) to Google Spreadsheets.

    +

    Row Numbers

    +

    When Tabletop.js returns your spreadsheet data, it adds a key/value of rownumber. This is great to use when you need to uniquely match or find a row in your data.

    +

    Images

    +

    Your spreadsheet can contain URLs to images which you can use to display the images on the page you build. Your template would look something like this:

    +
    <img src='{{imgurl}}'/>
    +
    +

    Data as Classes

    +

    You can use your data as classes to style with CSS. For instance, if you had data about recipes and a column called 'Taste' that contained either 'savory' or 'sweet'. In a table of the recipes you could do something like:

    +
    <tr><td class="{{taste}}"></tr>
    +
    +

    Then in your CSS:

    +
    td .savory {}
    +td .sweet {}
    +
    + + + +
    + + + diff --git a/index.html b/index.html new file mode 100644 index 00000000..62bf4b2e --- /dev/null +++ b/index.html @@ -0,0 +1,137 @@ + + + + + Sheetsee.js + + + + + + + + + + + +
    +

    sheetseeimg

    +

    Sheetsee.js is a client-side library for connecting Google Spreadsheets to a website and visualizing the information in tables and maps.

    +

    Modules

    +

    Each of Sheetsee's functions are divided into modules. Use just the parts you need; see docs on building. If you don't want to build your own, you can just use the full library which includes all modules, it's here on GitHub.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ModuleContainsDocs
    sheetseeCommand line module for make a custom build of Sheetsee.Doc
    sheetsee-coreIncluded in all builds. Has helpful working-with-your-data functions.Doc
    sheetsee-tablesContains everything you'll need to create a table including sortable columns, pagination and search.Doc
    sheetsee-mapsFor making maps with your point, line or polygon spreadsheet data. Built with Leaflet.js.Doc
    +

    Spreadsheets!?

    +

    Google Spreadsheets can be used as simple and collaborative databases, they make getting a data driven site going much easier than traditional databases. Read more about using spreadsheets for databases.

    +

    In the Wild

    +

    What can you make with Sheetsee? Lots of things, here are some examples:

    + +

    List your sheetsee project here: file an issue or pull request.

    +

    Resources & Documentation

    +

    More resources on using Sheetsee:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Getting StartedIdeasUseDemos
    About Sheetsee.jsFork-n-GoSheetsee-coreTable Demo
    Building SheetseeTips!Sheetsee-tablesTable Demo
    BasicsCustom chartsSheetsee-mapsMap Demo
    Sheetsee-chartsChart Demo
    + + + +
    + + + From 7bd7072c3790c7aaa95e13bcaa88cb9f511638bd Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 19:15:57 -0400 Subject: [PATCH 141/157] Remove footer link --- scripts/template.hbs | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/template.hbs b/scripts/template.hbs index ad005e86..4c31cce2 100644 --- a/scripts/template.hbs +++ b/scripts/template.hbs @@ -33,7 +33,6 @@

    Use

      From 291bf98d221922328b962d30f24dd36ff6cd07fa Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 19:16:07 -0400 Subject: [PATCH 142/157] Remove local dep --- assets/tabletop1.3.4.js | 474 ---------------------------------------- 1 file changed, 474 deletions(-) delete mode 100644 assets/tabletop1.3.4.js diff --git a/assets/tabletop1.3.4.js b/assets/tabletop1.3.4.js deleted file mode 100644 index 0e5612be..00000000 --- a/assets/tabletop1.3.4.js +++ /dev/null @@ -1,474 +0,0 @@ -(function(global) { - "use strict"; - - var inNodeJS = false; - if (typeof module !== 'undefined' && module.exports) { - inNodeJS = true; - var request = require('request'); - } - - var supportsCORS = false; - var inLegacyIE = false; - try { - var testXHR = new XMLHttpRequest(); - if (typeof testXHR.withCredentials !== 'undefined') { - supportsCORS = true; - } else { - if ("XDomainRequest" in window) { - supportsCORS = true; - inLegacyIE = true; - } - } - } catch (e) { } - - // Create a simple indexOf function for support - // of older browsers. Uses native indexOf if - // available. Code similar to underscores. - // By making a separate function, instead of adding - // to the prototype, we will not break bad for loops - // in older browsers - var indexOfProto = Array.prototype.indexOf; - var ttIndexOf = function(array, item) { - var i = 0, l = array.length; - - if (indexOfProto && array.indexOf === indexOfProto) return array.indexOf(item); - for (; i < l; i++) if (array[i] === item) return i; - return -1; - }; - - /* - Initialize with Tabletop.init( { key: '0AjAPaAU9MeLFdHUxTlJiVVRYNGRJQnRmSnQwTlpoUXc' } ) - OR! - Initialize with Tabletop.init( { key: 'https://docs.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AjAPaAU9MeLFdHUxTlJiVVRYNGRJQnRmSnQwTlpoUXc&output=html&widget=true' } ) - OR! - Initialize with Tabletop.init('0AjAPaAU9MeLFdHUxTlJiVVRYNGRJQnRmSnQwTlpoUXc') - */ - - var Tabletop = function(options) { - // Make sure Tabletop is being used as a constructor no matter what. - if(!this || !(this instanceof Tabletop)) { - return new Tabletop(options); - } - - if(typeof(options) === 'string') { - options = { key : options }; - } - - this.callback = options.callback; - this.wanted = options.wanted || []; - this.key = options.key; - this.simpleSheet = !!options.simpleSheet; - this.parseNumbers = !!options.parseNumbers; - this.wait = !!options.wait; - this.reverse = !!options.reverse; - this.postProcess = options.postProcess; - this.debug = !!options.debug; - this.query = options.query || ''; - this.orderby = options.orderby; - this.endpoint = options.endpoint || "https://spreadsheets.google.com"; - this.singleton = !!options.singleton; - this.simple_url = !!options.simple_url; - this.callbackContext = options.callbackContext; - - if(typeof(options.proxy) !== 'undefined') { - // Remove trailing slash, it will break the app - this.endpoint = options.proxy.replace(/\/$/,''); - this.simple_url = true; - this.singleton = true; - // Let's only use CORS (straight JSON request) when - // fetching straight from Google - supportsCORS = false - } - - this.parameterize = options.parameterize || false; - - if(this.singleton) { - if(typeof(Tabletop.singleton) !== 'undefined') { - this.log("WARNING! Tabletop singleton already defined"); - } - Tabletop.singleton = this; - } - - /* Be friendly about what you accept */ - if(/key=/.test(this.key)) { - this.log("You passed an old Google Docs url as the key! Attempting to parse."); - this.key = this.key.match("key=(.*?)&")[1]; - } - - if(/pubhtml/.test(this.key)) { - this.log("You passed a new Google Spreadsheets url as the key! Attempting to parse."); - this.key = this.key.match("d\\/(.*?)\\/pubhtml")[1]; - } - - if(!this.key) { - this.log("You need to pass Tabletop a key!"); - return; - } - - this.log("Initializing with key " + this.key); - - this.models = {}; - this.model_names = []; - - this.base_json_path = "/feeds/worksheets/" + this.key + "/public/basic?alt="; - - if (inNodeJS || supportsCORS) { - this.base_json_path += 'json'; - } else { - this.base_json_path += 'json-in-script'; - } - - if(!this.wait) { - this.fetch(); - } - }; - - // A global storage for callbacks. - Tabletop.callbacks = {}; - - // Backwards compatibility. - Tabletop.init = function(options) { - return new Tabletop(options); - }; - - Tabletop.sheets = function() { - this.log("Times have changed! You'll want to use var tabletop = Tabletop.init(...); tabletop.sheets(...); instead of Tabletop.sheets(...)"); - }; - - Tabletop.prototype = { - - fetch: function(callback) { - if(typeof(callback) !== "undefined") { - this.callback = callback; - } - this.requestData(this.base_json_path, this.loadSheets); - }, - - /* - This will call the environment appropriate request method. - - In browser it will use JSON-P, in node it will use request() - */ - requestData: function(path, callback) { - if (inNodeJS) { - this.serverSideFetch(path, callback); - } else { - //CORS only works in IE8/9 across the same protocol - //You must have your server on HTTPS to talk to Google, or it'll fall back on injection - var protocol = this.endpoint.split("//").shift() || "http"; - if (supportsCORS && (!inLegacyIE || protocol === location.protocol)) { - this.xhrFetch(path, callback); - } else { - this.injectScript(path, callback); - } - } - }, - - /* - Use Cross-Origin XMLHttpRequest to get the data in browsers that support it. - */ - xhrFetch: function(path, callback) { - //support IE8's separate cross-domain object - var xhr = inLegacyIE ? new XDomainRequest() : new XMLHttpRequest(); - xhr.open("GET", this.endpoint + path); - var self = this; - xhr.onload = function() { - try { - var json = JSON.parse(xhr.responseText); - } catch (e) { - console.error(e); - } - callback.call(self, json); - }; - xhr.send(); - }, - - /* - Insert the URL into the page as a script tag. Once it's loaded the spreadsheet data - it triggers the callback. This helps you avoid cross-domain errors - http://code.google.com/apis/gdata/samples/spreadsheet_sample.html - - Let's be plain-Jane and not use jQuery or anything. - */ - injectScript: function(path, callback) { - var script = document.createElement('script'); - var callbackName; - - if(this.singleton) { - if(callback === this.loadSheets) { - callbackName = 'Tabletop.singleton.loadSheets'; - } else if (callback === this.loadSheet) { - callbackName = 'Tabletop.singleton.loadSheet'; - } - } else { - var self = this; - callbackName = 'tt' + (+new Date()) + (Math.floor(Math.random()*100000)); - // Create a temp callback which will get removed once it has executed, - // this allows multiple instances of Tabletop to coexist. - Tabletop.callbacks[ callbackName ] = function () { - var args = Array.prototype.slice.call( arguments, 0 ); - callback.apply(self, args); - script.parentNode.removeChild(script); - delete Tabletop.callbacks[callbackName]; - }; - callbackName = 'Tabletop.callbacks.' + callbackName; - } - - var url = path + "&callback=" + callbackName; - - if(this.simple_url) { - // We've gone down a rabbit hole of passing injectScript the path, so let's - // just pull the sheet_id out of the path like the least efficient worker bees - if(path.indexOf("/list/") !== -1) { - script.src = this.endpoint + "/" + this.key + "-" + path.split("/")[4]; - } else { - script.src = this.endpoint + "/" + this.key; - } - } else { - script.src = this.endpoint + url; - } - - if (this.parameterize) { - script.src = this.parameterize + encodeURIComponent(script.src); - } - - document.getElementsByTagName('script')[0].parentNode.appendChild(script); - }, - - /* - This will only run if tabletop is being run in node.js - */ - serverSideFetch: function(path, callback) { - var self = this - request({url: this.endpoint + path, json: true}, function(err, resp, body) { - if (err) { - return console.error(err); - } - callback.call(self, body); - }); - }, - - /* - Is this a sheet you want to pull? - If { wanted: ["Sheet1"] } has been specified, only Sheet1 is imported - Pulls all sheets if none are specified - */ - isWanted: function(sheetName) { - if(this.wanted.length === 0) { - return true; - } else { - return (ttIndexOf(this.wanted, sheetName) !== -1); - } - }, - - /* - What gets send to the callback - if simpleSheet === true, then don't return an array of Tabletop.this.models, - only return the first one's elements - */ - data: function() { - // If the instance is being queried before the data's been fetched - // then return undefined. - if(this.model_names.length === 0) { - return undefined; - } - if(this.simpleSheet) { - if(this.model_names.length > 1 && this.debug) { - this.log("WARNING You have more than one sheet but are using simple sheet mode! Don't blame me when something goes wrong."); - } - return this.models[ this.model_names[0] ].all(); - } else { - return this.models; - } - }, - - /* - Add another sheet to the wanted list - */ - addWanted: function(sheet) { - if(ttIndexOf(this.wanted, sheet) === -1) { - this.wanted.push(sheet); - } - }, - - /* - Load all worksheets of the spreadsheet, turning each into a Tabletop Model. - Need to use injectScript because the worksheet view that you're working from - doesn't actually include the data. The list-based feed (/feeds/list/key..) does, though. - Calls back to loadSheet in order to get the real work done. - - Used as a callback for the worksheet-based JSON - */ - loadSheets: function(data) { - var i, ilen; - var toLoad = []; - this.foundSheetNames = []; - - for(i = 0, ilen = data.feed.entry.length; i < ilen ; i++) { - this.foundSheetNames.push(data.feed.entry[i].title.$t); - // Only pull in desired sheets to reduce loading - if( this.isWanted(data.feed.entry[i].content.$t) ) { - var linkIdx = data.feed.entry[i].link.length-1; - var sheet_id = data.feed.entry[i].link[linkIdx].href.split('/').pop(); - var json_path = "/feeds/list/" + this.key + "/" + sheet_id + "/public/values?alt=" - if (inNodeJS || supportsCORS) { - json_path += 'json'; - } else { - json_path += 'json-in-script'; - } - if(this.query) { - json_path += "&sq=" + this.query; - } - if(this.orderby) { - json_path += "&orderby=column:" + this.orderby.toLowerCase(); - } - if(this.reverse) { - json_path += "&reverse=true"; - } - toLoad.push(json_path); - } - } - - this.sheetsToLoad = toLoad.length; - for(i = 0, ilen = toLoad.length; i < ilen; i++) { - this.requestData(toLoad[i], this.loadSheet); - } - }, - - /* - Access layer for the this.models - .sheets() gets you all of the sheets - .sheets('Sheet1') gets you the sheet named Sheet1 - */ - sheets: function(sheetName) { - if(typeof sheetName === "undefined") { - return this.models; - } else { - if(typeof(this.models[ sheetName ]) === "undefined") { - // alert( "Can't find " + sheetName ); - return; - } else { - return this.models[ sheetName ]; - } - } - }, - - /* - Parse a single list-based worksheet, turning it into a Tabletop Model - - Used as a callback for the list-based JSON - */ - loadSheet: function(data) { - var model = new Tabletop.Model( { data: data, - parseNumbers: this.parseNumbers, - postProcess: this.postProcess, - tabletop: this } ); - this.models[ model.name ] = model; - if(ttIndexOf(this.model_names, model.name) === -1) { - this.model_names.push(model.name); - } - this.sheetsToLoad--; - if(this.sheetsToLoad === 0) - this.doCallback(); - }, - - /* - Execute the callback upon loading! Rely on this.data() because you might - only request certain pieces of data (i.e. simpleSheet mode) - Tests this.sheetsToLoad just in case a race condition happens to show up - */ - doCallback: function() { - if(this.sheetsToLoad === 0) { - this.callback.apply(this.callbackContext || this, [this.data(), this]); - } - }, - - log: function(msg) { - if(this.debug) { - if(typeof console !== "undefined" && typeof console.log !== "undefined") { - Function.prototype.apply.apply(console.log, [console, arguments]); - } - } - } - - }; - - /* - Tabletop.Model stores the attribute names and parses the worksheet data - to turn it into something worthwhile - - Options should be in the format { data: XXX }, with XXX being the list-based worksheet - */ - Tabletop.Model = function(options) { - var i, j, ilen, jlen; - this.column_names = []; - this.name = options.data.feed.title.$t; - this.elements = []; - this.raw = options.data; // A copy of the sheet's raw data, for accessing minutiae - - if(typeof(options.data.feed.entry) === 'undefined') { - options.tabletop.log("Missing data for " + this.name + ", make sure you didn't forget column headers"); - this.elements = []; - return; - } - - for(var key in options.data.feed.entry[0]){ - if(/^gsx/.test(key)) - this.column_names.push( key.replace("gsx$","") ); - } - - for(i = 0, ilen = options.data.feed.entry.length ; i < ilen; i++) { - var source = options.data.feed.entry[i]; - var element = {}; - for(var j = 0, jlen = this.column_names.length; j < jlen ; j++) { - var cell = source[ "gsx$" + this.column_names[j] ]; - if (typeof(cell) !== 'undefined') { - if(options.parseNumbers && cell.$t !== '' && !isNaN(cell.$t)) - element[ this.column_names[j] ] = +cell.$t; - else - element[ this.column_names[j] ] = cell.$t; - } else { - element[ this.column_names[j] ] = ''; - } - } - if(element.rowNumber === undefined) - element.rowNumber = i + 1; - if( options.postProcess ) - options.postProcess(element); - this.elements.push(element); - } - - }; - - Tabletop.Model.prototype = { - /* - Returns all of the elements (rows) of the worksheet as objects - */ - all: function() { - return this.elements; - }, - - /* - Return the elements as an array of arrays, instead of an array of objects - */ - toArray: function() { - var array = [], - i, j, ilen, jlen; - for(i = 0, ilen = this.elements.length; i < ilen; i++) { - var row = []; - for(j = 0, jlen = this.column_names.length; j < jlen ; j++) { - row.push( this.elements[i][ this.column_names[j] ] ); - } - array.push(row); - } - return array; - } - }; - - if(inNodeJS) { - module.exports = Tabletop; - } else { - global.Tabletop = Tabletop; - } - -})(this); From 21da950cba9a4e080c8d56d2bc01879ff323fb20 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 19:21:12 -0400 Subject: [PATCH 143/157] Build --- docs/about.html | 1 - docs/basics.html | 1 - docs/building.html | 1 - docs/changelog.html | 1 - docs/fork-n-go.html | 1 - docs/sheetsee-core.html | 1 - docs/sheetsee-maps.html | 1 - docs/sheetsee-tables.html | 1 - docs/tips.html | 1 - index.html | 1 - 10 files changed, 10 deletions(-) diff --git a/docs/about.html b/docs/about.html index 4cf5e863..4cff139c 100644 --- a/docs/about.html +++ b/docs/about.html @@ -61,7 +61,6 @@

      Demos

      Use

        diff --git a/docs/basics.html b/docs/basics.html index feee8bc8..31ca641f 100644 --- a/docs/basics.html +++ b/docs/basics.html @@ -100,7 +100,6 @@

        Demos

        Use

          diff --git a/docs/building.html b/docs/building.html index 7ff9710e..42ebc0c4 100644 --- a/docs/building.html +++ b/docs/building.html @@ -57,7 +57,6 @@

          Demos

          Use

            diff --git a/docs/changelog.html b/docs/changelog.html index 51e25760..1c09ca7d 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -72,7 +72,6 @@

            Demos

            Use

              diff --git a/docs/fork-n-go.html b/docs/fork-n-go.html index e6213146..275b497b 100644 --- a/docs/fork-n-go.html +++ b/docs/fork-n-go.html @@ -54,7 +54,6 @@

              Demos

              Use

                diff --git a/docs/sheetsee-core.html b/docs/sheetsee-core.html index b97718b1..3e7bcc4a 100644 --- a/docs/sheetsee-core.html +++ b/docs/sheetsee-core.html @@ -129,7 +129,6 @@

                Demos

                Use

                  diff --git a/docs/sheetsee-maps.html b/docs/sheetsee-maps.html index c25a4e2d..2c99a3ee 100644 --- a/docs/sheetsee-maps.html +++ b/docs/sheetsee-maps.html @@ -91,7 +91,6 @@

                  Demos

                  Use

                    diff --git a/docs/sheetsee-tables.html b/docs/sheetsee-tables.html index aede1fa1..337561fd 100644 --- a/docs/sheetsee-tables.html +++ b/docs/sheetsee-tables.html @@ -120,7 +120,6 @@

                    Demos

                    Use

                      diff --git a/docs/tips.html b/docs/tips.html index 2eb9f40a..7c4227fa 100644 --- a/docs/tips.html +++ b/docs/tips.html @@ -93,7 +93,6 @@

                      Demos

                      Use

                        diff --git a/index.html b/index.html index 62bf4b2e..3149b7b4 100644 --- a/index.html +++ b/index.html @@ -116,7 +116,6 @@

                        Demos

                        Use

                          From aa6cc64228227215aef1742de5793db69b3f7455 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 21:08:08 -0400 Subject: [PATCH 144/157] Update demos --- demos/demo-map.html | 53 +++++-------- demos/demo-table.html | 169 +++++++++++++++++------------------------- 2 files changed, 85 insertions(+), 137 deletions(-) diff --git a/demos/demo-map.html b/demos/demo-map.html index e8df0411..e49c5136 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -4,20 +4,17 @@ Sheetsee Maps Demo - - - - + + +
                          @@ -25,9 +22,6 @@

                          All Pennies Map

                          spreadsheet

                          View Source // View Documentation

                          -

                          Using linestrings, polygons and multipolygons

                          -
                          -

                          View Source // View Spreadsheet

                          +
                          diff --git a/demos/demo-table.html b/demos/demo-table.html index 7ff8116b..22e70075 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -4,11 +4,10 @@ Sheetsee Table Demo - - - + + - -
                          -

                          All Pennies

                          -

                          spreadsheet

                          - -

                          -

                          California Pennies

                          - -
                          -

                          Pretty Pennies

                          -
                          -

                          View Source // View Documentation

                          + +
                          +

                          All Pennies

                          +

                          spreadsheet

                          + + Clear +

                          +

                          View Source // View Documentation

                          - -
                          + +
                          - + - + - - - - + function showInfo (data) { + var tableOptions = { + "data": data, + "pagination": 10, + "tableDiv": "#fullTable", + "filterDiv": "#fullTableFilter" + } + Sheetsee.makeTable(tableOptions) + Sheetsee.initiateTableFilter(tableOptions) + } + + From 35931a260f9e3ac0a994335a5f6a4586eeba2802 Mon Sep 17 00:00:00 2001 From: Jessica Lord Date: Sun, 19 Mar 2017 21:22:41 -0400 Subject: [PATCH 145/157] Change footer --- demos/demo-map.html | 2 +- demos/demo-table.html | 2 +- docs/about.html | 2 +- docs/basics.html | 2 +- docs/building.html | 2 +- docs/changelog.html | 2 +- docs/fork-n-go.html | 2 +- docs/sheetsee-core.html | 2 +- docs/sheetsee-maps.html | 2 +- docs/sheetsee-tables.html | 2 +- docs/tips.html | 2 +- index.html | 2 +- scripts/template.hbs | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demos/demo-map.html b/demos/demo-map.html index e49c5136..8f7bf514 100644 --- a/demos/demo-map.html +++ b/demos/demo-map.html @@ -52,7 +52,7 @@

                          Contact

                        • @jllord
                        • File an issue
                        -

                        Home Page

                        +

                        Home

    diff --git a/demos/demo-table.html b/demos/demo-table.html index 22e70075..2b614605 100644 --- a/demos/demo-table.html +++ b/demos/demo-table.html @@ -56,7 +56,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home

    diff --git a/docs/about.html b/docs/about.html index 4cff139c..315bbfa3 100644 --- a/docs/about.html +++ b/docs/about.html @@ -73,7 +73,7 @@

    Contact

  • @jllord
  • File an issue
  • -

    Home Page

    +

    Home