From 4cb37f5fd87c71bd9fc14fa614250a9fa6879e01 Mon Sep 17 00:00:00 2001 From: Mark Daggett Date: Fri, 26 Feb 2016 07:50:59 -0600 Subject: [PATCH] update the d3 dependency, get rid of a error in bush feature. --- README.md | 2 +- bower.json | 6 +- d4.js | 5 +- d4.min.js | 1423 ++++++++++++++++++++++++++++++++++++++++- package.json | 4 +- src/features/brush.js | 1 - test/lib/d4.js | 5 +- 7 files changed, 1429 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 71a63311..f922dad3 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ open the `examples/` folder in your favorite web browser. You can find a hosted version of the example site here: http://visible.io/ -You can find a quickstart presentation on d4 [here](http://www.slideshare.net/heavysixer/d4-and-friendly-charting-dsl-for-d3). +You can find a quick-start presentation on d4 [here](http://www.slideshare.net/heavysixer/d4-and-friendly-charting-dsl-for-d3). ### Philosophy * * * diff --git a/bower.json b/bower.json index b1179a18..3f05efb5 100644 --- a/bower.json +++ b/bower.json @@ -2,11 +2,11 @@ "name": "d4", "description": "A friendly charting DSL for D3", "main": "d4.js", - "version": "0.9.4", + "version": "0.9.5", "dependencies": { - "d3": "~3.4.4" + "d3": "~3.5.16" }, "devDependencies": { - "d3": "~3.4.4" + "d3": "~3.5.16" } } diff --git a/d4.js b/d4.js index 90c9c7eb..885f42e8 100644 --- a/d4.js +++ b/d4.js @@ -1,6 +1,6 @@ -/*! d4 - v0.9.4 +/*! d4 - v0.9.5 * License: MIT Expat - * Date: 2015-04-14 + * Date: 2016-02-26 * Copyright: Mark Daggett, D4 Team */ /*! @@ -2903,7 +2903,6 @@ .call(brush); scope.accessors.selection.bind(this)(selection.select('.brush')); - scope.accessors.brush.bind(this)(brush); return brush; } }; diff --git a/d4.min.js b/d4.min.js index cb03608d..2a436efc 100644 --- a/d4.min.js +++ b/d4.min.js @@ -1,6 +1,6 @@ -/*! d4 - v0.9.4 +/*! d4 - v0.9.5 * License: MIT Expat - * Date: 2015-04-14 + * Date: 2016-02-26 * Copyright: Mark Daggett, D4 Team */ /*! @@ -9,5 +9,1420 @@ (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Underscore may be freely distributed under the MIT license. */ -(function(){"use strict";var t=this,e={},n=function(t){return t instanceof n?t:this instanceof n?(this.d4Wrapped=t,void 0):new n(t)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports.d4=n):t.d4=n,n.charts={},n.features={},n.parsers={},n.builders={};var r=n.each=n.forEach=function(t,n,r){var s,i,a=Array.prototype.forEach;if(null!==t)if(a&&t.forEach===a)t.forEach(n,r);else if(t.length===+t.length){for(s=0,i=t.length;i>s;s++)if(n.call(r,t[s],s,t)===e)return}else{var c=d3.keys(t);for(s=0,i=c.length;i>s;s++)if(n.call(r,t[c[s]],c[s],t)===e)return}},s=function(t){return t.charAt(0).toUpperCase()+t.slice(1)},i=function(t,e,r,s){Object.defineProperty(t,e,{configurable:!0,get:function(){return n.functor(s)()},set:function(){a(" You cannot directly assign values to the {0} property. Instead use the {1}() function.",e,r)}})},a=n.err=function(){var t,e=Array.prototype.slice.call(arguments),n=e.shift();throw r(e,function(e,r){t=RegExp("\\{"+r+"\\}","gi"),n=n.replace(t,e)}),Error("[d4] "+n)},c=function(t){return r(["link"],function(e){(!t[e]||n.isNotFunction(t[e]))&&a("The supplied builder does not have a {0} function",e)}),t},u=function(t){return this.builder||(this.builder=c(t.bind(this)())),this},o=function(t,e,r){if(n.isNotFunction(r)){var s="$"+e;i(t,s,e,r)}},d=function(t,e,r,i){var a=r;n.isDefined(i)&&(a=i+s(r)),t[a]=function(n){return arguments.length?(o(t,r,n),e[r]=n,t):e[r]},o(t,r,e[r])},f=function(t,e,n,s){r(n,function(n){d(t,e,n,s)})},h=function(t){var e=t.accessors;e&&f(t,t.accessors,d3.keys(e))},l=function(t,e){r(d3.keys(e.axes),function(n){t[n]=function(r){return P.bind(e)(n,r),t},r(d3.keys(e.axes[n].accessors),function(r){t[n][r]=e.axes[n][r]})})},y=function(t){var e=d3.keys(d3.scale);e.push("time"),e.push("time.utc"),0>e.indexOf(t)&&a('The scale type: "{0}" is unrecognized. D4 only supports these scale types: {1}',t,e.sort().join(", "))},x=function(t,e,r){n.createAccessorProxy(e,t),e.scale=function(t){return arguments.length?(e.accessors.scale=t,r(),e):e.accessors.scale}},b=function(t,e,n){var s;switch(y(n.accessors.scale),!0){case"time"===n.accessors.scale:s=d3.time.scale();break;case"time.utc"===n.accessors.scale:s=d3.time.scale.utc();break;default:s=d3.scale[n.accessors.scale]()}h(n),e[t]=s,x(s,e.axes[t],function(){b(t,e,n)}),r(d3.keys(e.axes[t].accessors),function(n){i(e[t],"$"+n,e.axes[t][n],e.axes[t][n])})},v=function(t,e,r){e.axes[t]={accessors:n.extend({key:t,min:void 0,max:void 0},r)},b(t,e,e.axes[t])},p=function(t){r(d3.keys(t.axes),function(e){v(e,t,t.axes[e])}),n.isUndefined(t.axes.x)&&v("x",t,{scale:"ordinal"}),n.isUndefined(t.axes.y)&&v("y",t,{scale:"linear"})},m=function(t,e){var r=n.functor({link:function(t,e){n.builders[t.x.$scale+"ScaleForNestedData"](t,e,"x"),n.builders[t.y.$scale+"ScaleForNestedData"](t,e,"y"),t.groups&&n.builders[t.groups.$scale+"ScaleForNestedData"](t,e,"groups")}}),s=n.merge({},t.accessors);delete t.accessors;var i=n.merge({axes:{},features:{},height:400,margin:{top:20,right:20,bottom:40,left:40},mixins:[],outerHeight:460,outerWidth:460,width:400},t);return i=n.merge(i,s),p(i),u.bind(i)(e||r),i.accessors=["width","height","valueKey"].concat(d3.keys(s)||[]),i},g=function(t,e){e&&r(d3.keys(t._proxiedFunctions),function(n){r(t._proxiedFunctions[n],function(t){e[n].apply(e,t)})})},k=function(t,e,r){var s=t.features[e].accessors.beforeRender.bind(t)(r);return n.isDefined(s)&&(r=s),r},$=function(t,e){var n,r;t.mixins.forEach(function(s){n=k(t,s,e),r=t.features[s].render.bind(t)(t.features[s],n,t.chartArea),t.features[s].accessors.afterRender.bind(t)(t.features[s],n,t.chartArea,r),g(t.features[s],r)})},S=function(t,e){t.builder?(t.builder.link(t,e),$(t,e)):a("No builder defined")},A=function(t){this.container="svg"===t.tagName?d3.select(t).classed("d4",!0).classed("chart",!0).attr("width",Math.max(0,this.width+this.margin.left+this.margin.right)).attr("height",Math.max(0,this.height+this.margin.top+this.margin.bottom)):"g"===t.tagName?d3.select(t).classed("d4",!0).classed("chart",!0):n.appendOnce(d3.select(t),"svg.d4.chart").attr("width",Math.max(0,this.width+this.margin.left+this.margin.right)).attr("height",Math.max(0,this.height+this.margin.top+this.margin.bottom)),n.appendOnce(this.container,"defs"),n.appendOnce(this.container,"g.margins").attr("transform","translate("+this.margin.left+","+this.margin.top+")"),this.chartArea=n.appendOnce(this.container.select("g.margins"),"g.chartArea")},O=function(t,e){var r=n.parsers.nestedGroup().x(t.x.$key).y(t.y.$key).nestKey(t.x.$key).value(t.valueKey)(e);return r.data},w=function(t,e){var r,s,i=!1;return n.isUndefined(t.valueKey)&&(t.valueKey=t.y.$key),e.length>0&&(s=e[0],n.isArray(s)?i=!0:(r=d3.keys(s),0>=r.indexOf("key")+r.indexOf("values")&&(i=!0))),i?O(t,e):e},L=function(t){return function(e){e.each(function(e){e=w(t,e),A.bind(t,this)(),S(t,e)})}},M=function(t,e){return t.overrides?t.overrides(e):{}},C=function(t,e,r){n.isDefined(r)?(r=Math.max(Math.min(r,t.length),0),t.splice(r,0,e)):t.push(e)},B=function(t){t._proxiedFunctions={on:[]},t.on=function(){return t._proxiedFunctions.on.push(Array.prototype.slice.call(arguments)),t}},K=function(t){h(t)},z=function(t){B(t),n.each(t.proxies,function(e){n.isUndefined(e.target)&&a("You included a feature which has a malformed proxy target.",t.name),n.createAccessorProxy(t,e.target,e.prefix)})},N=function(t){t||a("You need to supply an object or array of objects to mixin to the chart.");var e=n.flatten([t]);n.each(e,function(t){var e=t.name,r=M.bind(this)(t,e),s={accessors:{afterRender:function(){},beforeRender:function(){}},proxies:[]};t[e]=n.merge(n.merge(s,t.feature(e)),r),n.extend(this.features,t),C(this.mixins,e,t.index),z(this.features[e]),K(this.features[e])}.bind(this))},D=function(t){var e=[];n.isUndefined(t)&&a("A string or array of names is required in order to mixout a chart feature."),e.push(t),n.each(n.flatten(e),function(t){delete this.features[t],this.mixins=this.mixins.filter(function(e){return e!==t})}.bind(this))},R=function(t,e){var r=this.features[t];n.isNotFunction(e)&&a("You must supply a continuation function in order to use a chart feature."),r?e.bind(this)(r):a('Could not find feature: "{0}", maybe you forgot to mix it in?',t)},P=function(t,e){var r=this.axes[t];n.isNotFunction(e)&&a("You must supply a continuation function in order to use a chart axis."),r?e.bind(this)(r):a('Could not find axis: "{0}", maybe you forgot to define it?',t)},T=function(t){var e,r,s=t,i="[\\x20\\t\\r\\n\\f]",a="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",c=a.replace("w","w#"),u="\\["+i+"*("+a+")"+i+"*(?:([*^$|!~]?=)"+i+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+c+")|)|)"+i+"*\\]",o=["TAG","ID","CLASS"],d={ID:RegExp("#("+a+")"),CLASS:RegExp("\\.("+a+")"),TAG:RegExp("^("+a.replace("w","w*")+")"),ATTR:RegExp(""+u)},f=function(t){for(e=!1,h[t]=[],r=!0;r;)r=d[t].exec(s),null!==r&&(e=r.shift(),h[t].push(r[0]),s=s.slice(e.length))},h={};return n.each(o,f),n.each(o,function(t){for(;s&&(h[t]=h[t].join(" "),e););}),h},F=function(t){var e=L(t);return f(e,t.margin,d3.keys(t.margin),"margin"),f(e,t,t.accessors),l(e,t),e.axes=function(n){return arguments.length?(n(t.axes),e):t.axes},e.builder=function(n){return t.builder=c(n.bind(t)()),e},e.clone=function(){var e=n.extend({},t);return F(e)},e.features=function(){return t.mixins},e.margin=function(r){return arguments.length?(t.margin=n.merge(t.margin,n.functor(r)()),e.height(e.outerHeight()-t.margin.top-t.margin.bottom),e.width(e.outerWidth()-t.margin.left-t.margin.right),e):t.margin},e.mixin=function(n){return N.bind(t)(n),e},e.mixout=function(n,r){return D.bind(t)(n,r),e},e.outerHeight=function(r){var s=n.functor(r)();return arguments.length?(t.outerHeight=s,e.height(s-t.margin.top-t.margin.bottom),e):t.outerHeight},e.outerWidth=function(r){var s=n.functor(r)();return arguments.length?(t.outerWidth=s,e.width(s-t.margin.left-t.margin.right),e):t.outerWidth},e.using=function(n,r){return R.bind(t)(n,r),e},e};n.appendOnce=function(t,e){var n,r=t.selectAll(e);return r.empty()&&(n=T(e),r=t.append(n.TAG).attr("class",n.CLASS.join(" ")),n.ID&&r.attr("id",n.ID.pop())),r},n.baseChart=function(t){var e=m(t&&t.config||{},t&&t.builder||void 0);return F(e)},n.builder=function(t,e){return n.builders[t]=e,n.builders[t]},n.chart=function(t,e){return n.charts[t]=e,n.charts[t]},n.createAccessorProxy=function(t,e,i){r(d3.keys(e),function(r){var a=r;n.isDefined(i)&&(a=i+s(r)),t[a]=function(){return arguments.length?(e[r].$dirty=!0,t[a].$dirty=!0,e[r].apply(e,arguments),t):e[r]()},e[r].$dirty=!1,t[a].$dirty=!1})},n.defaultKey=function(t,e){return(t.key||0)+"_"+e},n.extend=function(t){return r(Array.prototype.slice.call(arguments,1),function(e){var r=function(t){var e=[];return n.each(t,function(t){var r=t;n.isObject(t)&&(r=n.extend({},t)),e.push(r)}),e};if(e)for(var s in e)if(e[s]&&e[s].constructor&&e[s].constructor===Object)t[s]=t[s]||{},n.extend(t[s],e[s]);else if(n.isArray(e[s])){var i=r(e[s].slice());t[s]=n.isArray(t[s])?t[s].concat(i):i}else t[s]=e[s]}),t},n.feature=function(t,e){return n.features[t]=e,n.features[t]},n.flatten=function(t){var e=t.reduce(function(t,e){return t=n.isArray(t)?t:[t],e=n.isArray(e)?e:[e],t.concat(e)});return n.isArray(e)?e:[e]},n.functor=function(t){return n.isFunction(t)?t:function(){return t}},n.isArray=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)},n.isContinuousScale=function(t){return n.isDefined(t.rangeRound)},n.isDate=function(t){return"[object Date]"===Object.prototype.toString.call(t)},n.isDefined=function(t){return!n.isUndefined(t)},n.isFunction=function(t){return!!(t&&t.constructor&&t.call&&t.apply)},n.isObject=function(t){return null!==t&&"object"==typeof t},n.isOrdinalScale=function(t){return n.isUndefined(t.rangeRound)},n.isNotFunction=function(t){return!n.isFunction(t)},n.isNotNull=function(t){return!n.isNull(t)},n.isNull=function(t){return null===t},n.isUndefined=function(t){return t===void 0},n.merge=function(t,e){return n.extend(n.extend({},t),e)},n.parser=function(t,e){return n.parsers[t]=e,n.parsers[t]}}).call(this),function(){"use strict";d4.helpers={};var t=function(t,e){var n=5,r=0,s=function(t,e){return!(t.righte.right||t.bottome.bottom)},i=function(t){var a,c,u,o=!1,d=0;t.each(function(){d>0&&(a=this.getBoundingClientRect(),c=u.getBoundingClientRect(),s(a,c)&&(e.bind(this)(c,a),o=!0)),d++,u=this}),o&&n>r&&(r++,i.bind(this)(t))};i.bind(this)(t)};d4.helpers.staggerTextVertically=function(e,n){var r=function(t,e){var r=d3.select(this),s=r.attr("data-last-vertical-offset")||1,i=t.top-e.top,a=(e.height-i+s)*n;r.attr("transform","translate(0,"+a+")"),r.attr("data-last-vertical-offset",Math.abs(a))};t.bind(this)(e,r)},d4.helpers.rotateText=function(t){return function(e){e.each(function(){var n=d3.transform(d3.functor(t).apply(this,arguments));e.attr("alignment-baseline","central"),e.style("dominant-baseline","central"),90>=n.rotate&&n.rotate>=-90?(e.attr("text-anchor","begin"),e.attr("transform",""+n)):(e.attr("text-anchor","end"),n.rotate=(n.rotate>0?-1:1)*(180-Math.abs(n.rotate)),e.attr("transform",""+n))})}},d4.helpers.staggerTextHorizontally=function(e,n){var r=function(t,e){var r=d3.select(this),s=+(r.attr("data-last-horizontal-offset")||1),i=t.left-e.left,a=(e.width-i+s)*n;r.attr("transform","translate("+a+", 0)"),r.attr("data-last-horizontal-offset",Math.abs(a))};t.bind(this)(e,r)},d4.helpers.textSize=function(t,e){var n={height:0,width:0,x:0,y:0};if(d4.isDefined(t)){var r=d3.select("body").append("svg").attr("class",""+e);r.append("text").attr("x",-5e3).text(t),n=r.node().getBBox(),r.remove()}return n},d4.helpers.wrapText=function(t,e){t.each(function(){var t,n=d3.select(this),r=n.text().split(/\s+/).reverse(),s=[],i=0,a=1.1,c=n.attr("x"),u=n.attr("y"),o=parseFloat(n.attr("dy")),d=n.text(null).append("tspan").attr("x",c).attr("y",u).attr("dy",o+"em");for(t=r.pop();t;)s.push(t),d.text(s.join(" ")),d.node().getComputedTextLength()>e-Math.abs(c)&&(s.pop(),d.text(s.join(" ")),s=[t],d=n.append("tspan").attr("x",c).attr("y",u).attr("dy",++i*a+o+"em").text(t)),t=r.pop()})}}.call(this),function(){"use strict";d4.chart("column",function(t){var e=t||{};return d4.baseChart(e).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.chart("donut",function(t){var e=t||{};return d4.baseChart(d4.extend({config:{accessors:{radius:function(){return Math.min(this.width,this.height)/2},arcWidth:function(t){return t/3}}}},e)).mixin([{name:"arcs",feature:d4.features.arcSeries},{name:"arcLabels",feature:d4.features.arcLabels}])})}.call(this),function(){"use strict";d4.chart("groupedColumn",function(t){var e=t||{},n=function(){return{accessors:{x:function(t){var e=this.x(t[this.x.$key]),n=this.groups(t[this.groups.$key]),r=this.groups.rangeBand()/2;return e+n+r}}}};return d4.baseChart(d4.extend({config:{axes:{groups:{scale:"ordinal",dimension:"x",roundBands:.1}},accessors:{groupsOf:1}}},e)).mixin([{name:"bars",feature:d4.features.groupedColumnSeries},{name:"barLabels",feature:d4.features.stackedLabels,overrides:n},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.chart("groupedRow",function(t){var e=t||{},n=function(){return{accessors:{y:function(t){var e=this.y(t[this.y.$key]),n=this.groups(t[this.groups.$key]),r=this.groups.rangeBand()/3;return e+n+r}}}};return d4.baseChart(d4.extend({config:{accessors:{groupsOf:1},margin:{top:20,right:40,bottom:20,left:40},axes:{x:{scale:"linear"},y:{scale:"ordinal"},groups:{scale:"ordinal",dimension:"y",roundBands:.1}}}},e)).mixin([{name:"bars",feature:d4.features.groupedColumnSeries},{name:"barLabels",feature:d4.features.stackedLabels,overrides:n},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.chart("line",function(t){var e=t||{};return d4.baseChart(e).mixin([{name:"lineSeries",feature:d4.features.lineSeries},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis},{name:"lineSeriesLabels",feature:d4.features.lineSeriesLabels}])})}.call(this),function(){"use strict";d4.chart("row",function(t){var e=t||{};return d4.baseChart(d4.extend({config:{margin:{top:20,right:40,bottom:20,left:40},valueKey:"x",axes:{x:{scale:"linear"},y:{scale:"ordinal"}}}},e)).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";var t=function(){var t=function(t,e){d4.builders[t.x.$scale+"ScaleForNestedData"](t,e,"x"),d4.builders[t.y.$scale+"ScaleForNestedData"](t,e,"y"),d4.builders[t.z.$scale+"ScaleForNestedData"](t,e,"z");var n=5,r=Math.max(n+1,(t.height-t.margin.top-t.margin.bottom)/10);t.z.range([n,r])},e={link:function(e,n){t.bind(this)(e,n)}};return e},e=function(t,e){var n=this[t];return n(e[n.$key])+n.rangeBand()/2},n=function(t,e){var n,r=this[t],s=Math.abs(r(e.y0)-r(e.y0+e.y))/2,i=10;return"x"===t&&(s*=-1,i*=-1),d4.isDefined(e.y0)?(n=e.y0+e.y,r(n)+s):r(e[r.$key])-i},r=function(){return{accessors:{x:function(t){return d4.isOrdinalScale(this.x)?e.bind(this)("x",t):n.bind(this)("x",t)},y:function(t){return d4.isOrdinalScale(this.y)?e.bind(this)("y",t):n.bind(this)("y",t)}}}},s=function(){return{accessors:{cx:function(t){return this.x(t[this.x.$key])},cy:function(t){return this.y(t[this.y.$key])},r:function(t){return this.z(t[this.z.$key])}}}};d4.chart("scatterPlot",function(e){var n=e||{};return d4.baseChart(d4.extend({builder:t,config:{axes:{x:{scale:"linear"},z:{scale:"linear"}}}},n)).mixin([{name:"circles",feature:d4.features.circleSeries,overrides:s},{name:"circleLabels",feature:d4.features.stackedLabels,overrides:r},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.chart("stackedColumn",function(t){var e=t||{},n=function(){var t=function(t){var e=[];return t.map(function(t){t.values.map(function(t){e.push(t)})}),e},e=function(t){return d3.nest().key(function(t){return t[this.x.$key]}.bind(this)).rollup(function(t){var e=d3.sum(t,function(t){return t[this.valueKey]}.bind(this)),n=d3.sum(t,function(t){return Math.max(0,t[this.valueKey])}.bind(this));return{text:e,size:n}}.bind(this)).entries(t)},n=function(n){return e.bind(this)(t(n)).map(function(t){var e={};return e[this.x.$key]=t.key,e.size=t.values.size,e[this.valueKey]=t.values.text,e}.bind(this))};return{accessors:{beforeRender:function(t){return n.bind(this)(t)},y:function(t,e){var n=this[t],r=5;return n(e.size)-r}}}};return d4.baseChart(e).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"connectors",feature:d4.features.stackedColumnConnectors},{name:"columnTotals",feature:d4.features.columnLabels,overrides:n},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.chart("stackedRow",function(t){var e=t||{},n=function(){var t=function(t){var e=[];return t.map(function(t){t.values.map(function(t){e.push(t)})}),e},e=function(t){return d3.nest().key(function(t){return t[this.y.$key]}.bind(this)).rollup(function(t){var e=d3.sum(t,function(t){return t[this.valueKey]}.bind(this)),n=d3.sum(t,function(t){return Math.max(0,t[this.valueKey])}.bind(this));return{text:e,size:n}}.bind(this)).entries(t)},n=function(n){return e.bind(this)(t(n)).map(function(t){var e={};return e[this.y.$key]=t.key,e.size=t.values.size,e[this.valueKey]=t.values.text,e}.bind(this))};return{accessors:{beforeRender:function(t){return n.bind(this)(t)},x:function(t){var e=5;return this.x(t.size)+e}}}};return d4.baseChart(d4.extend({config:{margin:{top:20,right:40,bottom:20,left:40},axes:{x:{scale:"linear"},y:{scale:"ordinal"}}}},e)).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"connectors",feature:d4.features.stackedColumnConnectors},{name:"columnTotals",feature:d4.features.columnLabels,overrides:n},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";var t=function(){return{accessors:{y:function(t){if(d4.isContinuousScale(this.y)){var e=t.y0+t.y-Math.min(0,t.y);return this.y(e)}return this.y(t[this.y.$key])},x:function(t){if(d4.isOrdinalScale(this.x))return this.x(t[this.x.$key]);var e=t.y0+t.y-Math.max(0,t.y);return this.x(e)},width:function(t,e){return d4.isOrdinalScale(this.x)?this.x.rangeBand():Math.abs(this.x(e.y0)-this.x(e.y0+e.y))},height:function(t,e){return d4.isContinuousScale(this.y)?Math.abs(this.y(e.y0)-this.y(e.y0+e.y)):this.y.rangeBand()},classes:function(t,e,n){var r=t.y>0?"positive":"negative";return n>0&&0===t.y0&&(r="subtotal"),"bar fill item"+e+" "+r+" "+t[this.y.$key]}}}},e=function(){return{accessors:{y:function(t){if(d4.isContinuousScale(this.y)){var e=Math.abs(this.y(t.y0)-this.y(t.y0+t.y)),n=t.y0+t.y-Math.max(0,t.y);return this.y(n)-10-e}return this.y(t[this.y.$key])+this.y.rangeBand()/2},x:function(t){if(d4.isOrdinalScale(this.x))return this.x(t[this.x.$key])+this.x.rangeBand()/2;var e=t.y0+t.y-Math.max(0,t.y),n=Math.abs(this.x(t.y0)-this.x(t.y0+t.y));return this.x(e)+10+n},text:function(t){return t[this.valueKey]}}}},n=function(){var t=function(t,e){var n;return"x"===e?[0,t.width]:(n=[0,t.height],d4.isOrdinalScale(t.x)?n.reverse():n)},e=function(e,n,r){var s=r.map(function(t){return t.key}.bind(this));e[n].domain(s).rangeRoundBands(t.bind(this)(e,n),e.xRoundBands||.3)},n=function(e,n,r){var s=d3.extent(d3.merge(r.map(function(t){return d3.extent(t.values,function(t){return t.y+t.y0})})));s[0]=d4.isDefined(e[n].$min)?e[n].$min:Math.min(0,s[0]),d4.isDefined(e[n].$max)&&(s[1]=e[n].$max),e[n].domain(s),e[n].range(t.bind(this)(e,n)).clamp(!0).nice()},r=function(t,r){d4.isOrdinalScale(t.x)?(e.bind(this)(t,"x",r),n.bind(this)(t,"y",r)):(e.bind(this)(t,"y",r),n.bind(this)(t,"x",r))},s={link:function(t,e){r.bind(this)(t,e)}};return s};d4.chart("waterfall",function(r){var s=r||{};return d4.baseChart(d4.extend({builder:n},s)).mixin([{name:"bars",feature:d4.features.rectSeries,overrides:t},{name:"connectors",feature:d4.features.waterfallConnectors},{name:"columnLabels",feature:d4.features.stackedLabels,overrides:e},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";d4.feature("arcLabels",function(t){var e=d3.svg.arc();return{accessors:{classes:function(t,e){return"arc stroke fill series"+e},duration:750,key:d4.functor(d4.defaultKey),text:function(t){return t.value},x:function(){return this.width/2},y:function(){return this.height/2}},proxies:[{target:e}],render:function(n,r,s){var i=function(t){return 180/Math.PI*(t.startAngle+t.endAngle)/2-90},a=function(t){var n=d3.interpolate(this._current,t);return this._current=n(0),function(r){return"translate("+e.centroid(n(r))+") rotate("+i(t)+")"}},c=d4.functor(this.radius).bind(this)(),u=d4.functor(n.accessors.x).bind(this)(),o=d4.functor(n.accessors.y).bind(this)();e.innerRadius(c).outerRadius(c+10);var d=s.selectAll("g."+t).data(r);d.enter().append("g").attr("class",t).attr("transform","translate("+u+","+o+")");var f=d.selectAll("text").data(function(t){return t.values},d4.functor(n.accessors.key).bind(this));return f.transition().duration(d4.functor(n.accessors.duration).bind(this)()).attrTween("transform",a),f.enter().append("text").attr("dy",5).attr("transform",function(t){return"translate("+e.centroid(t)+") rotate("+i(t)+")"}).style("text-anchor","start").text(d4.functor(n.accessors.text).bind(this)).attr("class",d4.functor(n.accessors.classes).bind(this)).attr("data-key",d4.functor(n.accessors.key).bind(this)).attr("d",e).each(function(t){this._current=t}),f.exit().remove(),d.exit().remove(),e}}})}.call(this),function(){"use strict";d4.feature("arcSeries",function(t){var e=d3.svg.arc();return{accessors:{classes:function(t,e){return"arc stroke fill series"+e},duration:750,key:d4.functor(d4.defaultKey),x:function(){return this.width/2},y:function(){return this.height/2}},proxies:[{target:e}],render:function(n,r,s){var i=function(t){var n=d3.interpolate(this._current,t);return this._current=n(0),function(t){return e(n(t))}},a=d4.functor(this.radius).bind(this)(),c=d4.functor(n.accessors.x).bind(this)(),u=d4.functor(n.accessors.y).bind(this)(),o=d4.functor(this.arcWidth).bind(this)(a);e.innerRadius(a).outerRadius(a-o);var d=d4.appendOnce(s,"g."+t),f=d.selectAll("g."+t+"-group").data(r);f.enter().append("g"),f.attr("class",t+"-group").attr("transform","translate("+c+","+u+")");var h=f.selectAll("path").data(function(t){return t.values},d4.functor(n.accessors.key).bind(this));return h.enter().append("path").each(function(t){this._current=t}),h.transition().duration(d4.functor(n.accessors.duration).bind(this)()).attrTween("d",i),h.attr("class",d4.functor(n.accessors.classes).bind(this)).attr("data-key",d4.functor(n.accessors.key).bind(this)).attr("d",e),h.exit().remove(),f.exit().remove(),e}}})}.call(this),function(){"use strict";d4.feature("arrow",function(t){return{accessors:{classes:"line",tipSize:6,x1:function(){return this.x(0)},x2:function(){return this.x(this.width)},y1:function(){return this.y(0)},y2:function(){return this.y(this.height)}},render:function(e,n,r){var s=this.container.select("defs");d4.appendOnce(s,"marker#"+t+"-end").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(e.accessors.tipSize).bind(this)).attr("markerHeight",d4.functor(e.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(s,"marker#"+t+"-start").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(e.accessors.tipSize).bind(this)()).attr("markerHeight",d4.functor(e.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(r,"g."+t);var i=d4.appendOnce(this.container.select("."+t),"line").attr("class",d4.functor(e.accessors.classes).bind(this)).attr("x1",d4.functor(e.accessors.x1).bind(this)).attr("x2",d4.functor(e.accessors.x2).bind(this)).attr("y1",d4.functor(e.accessors.y1).bind(this)).attr("y2",d4.functor(e.accessors.y2).bind(this)).attr("marker-end","url(#"+t+"-end)");return i}}})}.call(this),function(){"use strict";d4.feature("brush",function(t){var e=d3.svg.brush(),n=function(t){return d4.isDefined(t.$scale)?t:d4.functor(t).bind(this)()},r=function(t){return d4.isNull(e.y())?function(e){var n=e[this.x.$key],r=n>=t[0]&&t[1]>=n;return r}.bind(this):d4.isNull(e.x())?function(e){var n=e[this.y.$key],r=n>=t[0]&&t[1]>=n;return r}.bind(this):d4.isNotNull(e.x())&&d4.isNotNull(e.y())?function(e){var n=t[0][0]<=e[this.x.$key]&&e[this.x.$key]<=t[1][0]&&t[0][1]<=e[this.y.$key]&&e[this.y.$key]<=t[1][1];return n}.bind(this):void 0},s={accessors:{brushable:function(){return d3.selectAll(".brushable")},brushend:function(){this.container.classed("selecting",!d3.event.target.empty())},brushmove:function(){var e=d3.event.target.extent(),n=r.bind(this)(e);this.features[t].accessors.brushable().classed("selected",n)},brushstart:function(){this.container.classed("selecting",!0)},clamp:e.clamp,clear:e.clear,extent:e.extent,empty:e.empty,event:e.event,selection:function(t){return t},x:function(){return null},y:function(){return null}},render:function(r,s,i){var a=n.bind(this)(r.accessors.x),c=n.bind(this)(r.accessors.y);return null!==typeof a&&e.x(a),null!==typeof c&&e.y(c),e.on("brushstart",d4.functor(r.accessors.brushstart).bind(this)).on("brush",d4.functor(r.accessors.brushmove).bind(this)).on("brushend",d4.functor(r.accessors.brushend).bind(this)),d4.appendOnce(i,"g."+t).call(e),r.accessors.selection.bind(this)(i.select(".brush")),r.accessors.brush.bind(this)(e),e}};return s})}.call(this),function(){"use strict";d4.feature("columnLabels",function(t){var e=5,n=function(){return d4.isContinuousScale(this.y)?"middle":"start"};return{accessors:{key:d4.functor(d4.defaultKey),x:function(t,e){var n=this[t];if(d4.isOrdinalScale(n))return n(e[n.$key])+n.rangeBand()/2;var r=Math.abs(n(e[n.$key])-n(0));return n(e[n.$key])-r/2},y:function(t,n){var r=this[t];if(d4.isOrdinalScale(r))return r(n[r.$key])+r.rangeBand()/2+e;var s=Math.abs(r(n[r.$key])-r(0));return(0>n[r.$key]?r(n[r.$key])-s:r(n[r.$key]))-e},text:function(t){return t[this.valueKey]},xScaleId:function(){return"x"},yScaleId:function(){return"y"}},render:function(e,r,s){var i=d4.functor(e.accessors.xScaleId)(),a=d4.functor(e.accessors.yScaleId)(),c=d4.appendOnce(s,"g."+t),u=c.selectAll("text").data(r,d4.functor(e.accessors.key).bind(this));return u.enter().append("text"),u.exit().remove(),u.attr("class","column-label "+t).text(d4.functor(e.accessors.text).bind(this)).attr("text-anchor",n.bind(this)).attr("x",d4.functor(e.accessors.x).bind(this,i)).attr("y",d4.functor(e.accessors.y).bind(this,a)),u}}})}.call(this),function(){"use strict";d4.feature("grid",function(t){var e=d3.svg.axis(),n=d3.svg.axis();return{accessors:{formatXAxis:function(t){return t.orient("bottom")},formatYAxis:function(t){return t.orient("left")}},proxies:[{target:e,prefix:"x"},{target:n,prefix:"y"}],render:function(r,s,i){e.scale(this.x),n.scale(this.y);var a=d4.functor(r.accessors.formatXAxis).bind(this)(e),c=d4.functor(r.accessors.formatYAxis).bind(this)(n),u=d4.appendOnce(i,"g.grid.border."+t),o=d4.appendOnce(u,"rect"),d=d4.appendOnce(u,"g.x.grid."+t),f=d4.appendOnce(u,"g.y.grid."+t);return o.attr("transform","translate(0,0)").attr("x",0).attr("y",0).attr("width",this.width).attr("height",this.height),d.attr("transform","translate(0,"+this.height+")").call(a.tickSize(-this.height,0,0).tickFormat("")),f.attr("transform","translate(0,0)").call(c.tickSize(-this.width,0,0).tickFormat("")),u}}})}.call(this),function(){"use strict";d4.feature("groupedColumnSeries",function(t){var e=function(t){return t>0?"positive":"negative"},n=function(t){return this.groups(t[this.groups.$key])},r=function(t){var e,n=this.groups.$dimension,r=this[n],s=r(t.values[0][r.$key]);return"x"===n?e=[s,0]:"y"===n&&(e=[0,s]),"translate("+e+")"},s=function(){return this.groups.rangeBand()},i=function(t,e){var n=this[t],r=n.domain()[0],s=0>r?0:r;return Math.abs(n(e[n.$key])-n(s))},a=function(t,e){var n,r=this[t];return"y"===t?0>e[r.$key]?r(0):r(e[r.$key]):(n=e[r.$key]-Math.max(0,e[r.$key]),r(n))};return{accessors:{classes:function(t,n){return"bar fill item"+n+" "+e(t[this.valueKey])+" "+t[this.valueKey]},height:function(t,e){return d4.isOrdinalScale(this.y)?s.bind(this)(t):i.bind(this)(t,e)},key:d4.functor(d4.defaultKey),rx:0,ry:0,width:function(t,e){return d4.isOrdinalScale(this.x)?s.bind(this)():i.bind(this)(t,e)},groupPositions:function(t,e){return r.bind(this)(t,e)},x:function(t,e){return d4.isOrdinalScale(this.x)?n.bind(this)(t):a.bind(this)("x",t,e)},y:function(t,e){return d4.isOrdinalScale(this.y)?n.bind(this)(t):a.bind(this)("y",t,e)},xScaleId:function(){return"x"},yScaleId:function(){return"y"}},render:function(e,n,r){n.length>0&&(this.groupsOf=this.groupsOf||n[0].values.length);var s=d4.functor(e.accessors.xScaleId)(),i=d4.functor(e.accessors.yScaleId)(),a=d4.appendOnce(r,"g."+t),c=a.selectAll("g").data(n,d4.functor(e.accessors.key).bind(this));c.enter().append("g"),c.attr("class",function(t,e){return"series"+e+" "+this.x.$key}.bind(this)).attr("transform",d4.functor(e.accessors.groupPositions).bind(this));var u=c.selectAll("rect").data(function(t){return t.values}.bind(this));return u.enter().append("rect"),u.attr("class",d4.functor(e.accessors.classes).bind(this)).attr("x",d4.functor(e.accessors.x).bind(this)).attr("y",d4.functor(e.accessors.y).bind(this)).attr("ry",d4.functor(e.accessors.ry).bind(this)).attr("rx",d4.functor(e.accessors.rx).bind(this)).attr("width",d4.functor(e.accessors.width).bind(this,s)).attr("height",d4.functor(e.accessors.height).bind(this,i)),u.exit().remove(),c.exit().remove(),u}}})}.call(this),function(){"use strict";d4.feature("lineSeriesLabels",function(t){var e=function(e,n){var r=this.container.select("."+t).selectAll("."+t+" circle.dataPoint").data(n);r.enter().append("circle"),r.exit().remove(),r.attr("data-key",d4.functor(e.accessors.key).bind(this)).style("display","none").attr("r",d4.functor(e.accessors.r).bind(this)()).attr("class",function(t,n){return d4.functor(e.accessors.classes).bind(this)(t,n)+" dataPoint"}.bind(this))},n=function(e,n){var r=this.container.select("."+t).selectAll("."+t+" text.dataPoint").data(n);r.enter().append("text"),r.exit().remove(),r.attr("data-key",d4.functor(e.accessors.key).bind(this)).style("display","none").attr("class",function(t,n){return d4.functor(e.accessors.classes).bind(this)(t,n)+" dataPoint"}.bind(this))},r=function(e){this.container.select("."+t).append("rect").attr("class","overlay").style("fill-opacity",0).attr("width",this.width).attr("height",this.height).on("mouseover",function(){this.container.selectAll("."+t+" .dataPoint").style("display",null)}.bind(this)).on("mouseout",function(){this.container.selectAll("."+t+" .dataPoint").style("display","none")}.bind(this)).on("mousemove",d4.functor(e.accessors.mouseMove).bind(this))},s=function(t,s){d4.functor(t.accessors.displayPointValue).bind(this)()&&(d4.isNotFunction(this.x.invert)?d4.err(" In order to track the x position of a line series your scale must have an invert() function. However, your {0} scale does not have the invert() function.",this.x.$scale):(n.bind(this)(t,s),e.bind(this)(t,s),r.bind(this)(t)))};return{accessors:{classes:function(t,e){return"stroke series"+e},displayPointValue:!1,key:d4.functor(d4.defaultKey),mouseMove:function(e){var n=function(t,e){return"time"===this.x.$scale?t.getTime()>=e[this.x.$key].getTime():t>=e[this.x.$key]},r=d3.bisector(function(t){return t[this.x.$key] -}.bind(this)).right,s=this.container.select("."+t+" rect.overlay")[0][0],i=this.x.invert(d3.mouse(s)[0]);d4.each(e,function(e,s){var a=r(e.values,i,1),c=e.values[a-1];if(n.bind(this)(i,c)){var u=e.values[a];u=d4.isUndefined(u)?e.values[e.values.length-1]:u;var o=i-c[this.x.$key]>u[this.x.$key]-i?u:c;d4.functor(this.features[t].accessors.showDataPoint).bind(this)(o,e,s),d4.functor(this.features[t].accessors.showDataLabel).bind(this)(o,e,s)}else{var d="."+t+' .dataPoint[data-key="'+d4.functor(this.features[t].accessors.key).bind(this)(e,s)+'"]',f=this.container.select(d);f.style("display","none")}}.bind(this))},pointLabelText:function(t,e){var n=e.key+" "+this.x.$key+": "+t[this.x.$key];return n+=" "+this.y.$key+": "+t[this.y.$key]},r:4.5,showDataLabel:function(e,n,r){var s="."+t+' text.dataPoint[data-key="'+d4.functor(this.features[t].accessors.key).bind(this)(n,r)+'"]',i=this.container.select(s),a=20*r;i.style("display",null).attr("transform","translate(5,"+a+")").text(d4.functor(this.features[t].accessors.pointLabelText).bind(this)(e,n))},showDataPoint:function(e,n,r){var s="."+t+' circle.dataPoint[data-key="'+d4.functor(this.features[t].accessors.key).bind(this)(n,r)+'"]',i=this.container.select(s);i.style("display",null).attr("transform","translate("+this.x(e[this.x.$key])+","+this.y(e[this.y.$key])+")")},text:function(t){return t.key},x:function(t){return this.x(t.values[t.values.length-1][this.x.$key])},y:function(t){return this.y(t.values[t.values.length-1][this.y.$key])}},render:function(e,n,r){var i=d4.appendOnce(r,"g."+t),a=i.selectAll(".seriesLabel").data(n);return a.enter().append("text"),a.text(d4.functor(e.accessors.text).bind(this)).attr("x",d4.functor(e.accessors.x).bind(this)).attr("y",d4.functor(e.accessors.y).bind(this)).attr("data-key",d4.functor(e.accessors.key).bind(this)).attr("class",function(t,n){return d4.functor(e.accessors.classes).bind(this)(t,n)+" seriesLabel"}.bind(this)),s.bind(this)(e,n,r),a.exit().remove(),a}}})}.call(this),function(){"use strict";d4.feature("lineSeries",function(t){var e=d3.svg.line();return e.interpolate("linear"),{accessors:{classes:function(t,e){return"line stroke series"+e},key:d4.functor(d4.defaultKey),x:function(t){return this.x(t[this.x.$key])},y:function(t){return this.y(t[this.y.$key])}},proxies:[{target:e}],render:function(n,r,s){var i=d4.appendOnce(s,"g."+t);e.x(d4.functor(n.accessors.x).bind(this)).y(d4.functor(n.accessors.y).bind(this));var a=i.selectAll("g").data(r,d4.functor(n.accessors.key).bind(this));a.enter().append("g").attr("data-key",function(t){return t.key}).attr("class",d4.functor(n.accessors.classes).bind(this));var c=a.selectAll("path").data(function(t){return[t]});return c.enter().append("path"),c.attr("d",function(t){return e(t.values)}),c.exit().remove(),a.exit().remove(),a}}})}.call(this),function(){"use strict";d4.feature("referenceLine",function(t){return{accessors:{x1:function(){return this.x(this.x.domain()[0])},x2:function(){return this.x(this.x.domain()[1])},y1:function(){return this.y(this.y.domain()[1])},y2:function(){return this.y(this.y.domain()[0])},classes:function(){return"line"}},render:function(e,n,r){var s=d4.appendOnce(r,"g."+t),i=d4.appendOnce(s,"line");return s.select("line").attr("class",d4.functor(e.accessors.classes).bind(this)).attr("x1",d4.functor(e.accessors.x1).bind(this)).attr("x2",d4.functor(e.accessors.x2).bind(this)).attr("y1",d4.functor(e.accessors.y1).bind(this)).attr("y2",d4.functor(e.accessors.y2).bind(this)),i}}})}.call(this),function(){"use strict";d4.feature("stackedColumnConnectors",function(t){var e=function(t){return t?0>t?-1:1:0},n=function(t,n,r){return e(t[r])===e(n[r])},r=function(t,e,r,s,i){var a=d4.isOrdinalScale(this.y)?this.x.$key:this.y.$key;return 0!==e&&n(s[r].values[e-1],t,a)?i.bind(this)():0};return{accessors:{x1:function(t){return d4.isOrdinalScale(this.x)?this.x(t[this.x.$key]):this.x(t.y0+t.y)},y1:function(t){return d4.isOrdinalScale(this.y)?this.y(t[this.y.$key]):this.y(t.y0+t.y)},size:function(){return d4.isOrdinalScale(this.x)?this.x.rangeBand():this.y.rangeBand()},classes:function(t,e){return"series"+e}},render:function(e,n,s){var i=d4.appendOnce(s,"g."+t),a=i.selectAll("g").data(n);a.enter().append("g").attr("class",function(t,e){return"series"+e+" "+this.y.$key}.bind(this));var c=a.selectAll("line").data(function(t){return t.values}.bind(this));return c.enter().append("line"),c.attr("class",d4.functor(e.accessors.classes).bind(this)).attr("stroke-dasharray","5, 5").attr("x1",function(t,s,i){return r.bind(this)(t,s,i,n,function(){return d4.functor(e.accessors.x1).bind(this)(t)})}.bind(this)).attr("y1",function(t,s,i){var a=d4.isOrdinalScale(this.y)?d4.functor(e.accessors.size).bind(this)(t):0;return r.bind(this)(t,s,i,n,function(){return d4.functor(e.accessors.y1).bind(this)(t)+a})}.bind(this)).attr("x2",function(t,s,i){var a=d4.isOrdinalScale(this.x)?e.accessors.size.bind(this)(t):0;return r.bind(this)(t,s,i,n,function(){return d4.functor(e.accessors.x1).bind(this)(n[i].values[s-1])+a})}.bind(this)).attr("y2",function(t,s,i){return r.bind(this)(t,s,i,n,function(){return d4.functor(e.accessors.y1).bind(this)(n[i].values[s-1])})}.bind(this)),a.exit().remove(),c.exit().remove(),c}}})}.call(this),function(){"use strict";d4.feature("stackedLabels",function(t){var e=function(t){return d4.isDefined(t.y0)?!0:d4.isContinuousScale(this.y)},n=function(t){return e.bind(this)(t)?"middle":"start"},r=function(t,e){var n=this[t];return n(e[n.$key])+n.rangeBand()/2},s=function(t,e){var n,r=this[t],s=Math.abs(r(e.y0)-r(e.y0+e.y))/2,i=10;return"x"===t&&(s*=-1,i*=-1),d4.isDefined(e.y0)?(n=e.y0+e.y,(0>=n?r(e.y0):r(n))+s):(0>=e[r.$key]?r(0):r(e[r.$key]))-i};return{accessors:{classes:"column-label",key:d4.functor(d4.defaultKey),stagger:!0,text:function(t){if(!d4.isDefined(t.y0))return t[this.valueKey];if(d4.isOrdinalScale(this.x)){if(Math.abs(this.y(t.y0)-this.y(t.y0+t.y))>20)return t[this.valueKey]}else if(Math.abs(this.x(t.y0)-this.x(t.y0+t.y))>20)return t[this.valueKey]},textAnchor:function(t){return n.bind(this)(t)},x:function(t){return d4.isOrdinalScale(this.x)?r.bind(this)("x",t):s.bind(this)("x",t)},y:function(t){return d4.isOrdinalScale(this.y)?r.bind(this)("y",t):s.bind(this)("y",t)}},render:function(e,n,r){var s=d4.appendOnce(r,"g."+t),i=s.selectAll("g").data(n,d4.functor(e.accessors.key).bind(this));i.enter().append("g").attr("class",function(t,e){return"series"+e+" "+this.x.$key}.bind(this)),i.exit().remove();var a=i.selectAll("text").data(function(t){return t.values}.bind(this));return a.enter().append("text"),a.text(d4.functor(e.accessors.text).bind(this)).attr("text-anchor",d4.functor(e.accessors.textAnchor).bind(this)).attr("class",d4.functor(e.accessors.classes).bind(this)).attr("y",d4.functor(e.accessors.y).bind(this)).attr("x",d4.functor(e.accessors.x).bind(this)),d4.functor(e.accessors.stagger).bind(this)()&&(d4.isContinuousScale(this.y)?s.selectAll("text").call(d4.helpers.staggerTextVertically,-1):s.selectAll("text").call(d4.helpers.staggerTextHorizontally,1)),s.selectAll("text").call(function(t){var e;d4.each(t,function(t){d4.each(t,function(t){var n=d3.select(t);e=t.getBoundingClientRect(),null===n.attr("transform")&&n.attr("transform","translate(0,"+Math.floor(e.height/2)+")")})})}),i.exit().remove(),a.exit().remove(),a}}})}.call(this),function(){"use strict";var t=function(t){return t>0?"positive":"negative"},e=function(t,e){var n=this[t];return n(e[n.$key])},n=function(t){var e=this[t];return e.rangeBand()},r=function(t,e){var n=this[t],r=n.domain()[0],s=Math.max(r,0);return d4.isDefined(e.y0)?Math.abs(n(e.y0)-n(e.y0+e.y)):Math.abs(n(e[n.$key])-n(s))},s=function(t,e){var n,r=this[t];return d4.isDefined(e.y0)?"y"===t?(n=e.y0+e.y,0>n?r(e.y0):r(n)):(n=e.y0+e.y-Math.max(0,e.y),r(n)):"y"===t?0>e[r.$key]?r(0):r(e[r.$key]):(n=e[r.$key]-Math.max(0,e[r.$key]),r(n))},i=function(e,n,r){return{accessors:{classes:function(e,n){return"bar fill item"+n+" "+t(e[this.valueKey])+" "+e[this.y.$key]},key:d4.functor(d4.defaultKey)},render:function(t,s,i){var a=d4.appendOnce(i,"g."+e),c=a.selectAll("g").data(s,d4.functor(t.accessors.key).bind(this));c.enter().append("g").attr("class",function(t,e){return"series"+e+" "+this.y.$key}.bind(this)),c.exit().remove();var u=c.selectAll(n).data(function(t){return t.values});return u.enter().append(n).attr("class",d4.functor(t.accessors.classes).bind(this)),r.bind(this)(t,u),u.exit().remove(),c.exit().remove(),u}}};d4.feature("circleSeries",function(t){var a={accessors:{cx:function(t){var i=0;return d4.isOrdinalScale(this.x)?(i=n.bind(this)("x"),e.bind(this)("x",t)+i/2):(i=r.bind(this)("x",t),s.bind(this)("x",t)+i/2)},cy:function(t){var i=0;return d4.isOrdinalScale(this.y)?(i=n.bind(this)("y"),e.bind(this)("y",t)+i/2):(i=r.bind(this)("y",t),s.bind(this)("y",t)+i/2)},r:function(t){var e,s;return e=d4.isOrdinalScale(this.x)?n.bind(this)("x"):r.bind(this)("x",t),s=d4.isOrdinalScale(this.y)?n.bind(this)("y"):r.bind(this)("y",t),Math.min(e,s)/2}}},c=function(t,e){e.attr("r",d4.functor(t.accessors.r).bind(this)).attr("cx",d4.functor(t.accessors.cx).bind(this)).attr("cy",d4.functor(t.accessors.cy).bind(this))},u=i.bind(this)(t,"circle",c);return d4.merge(u,a)}),d4.feature("ellipseSeries",function(t){var a={accessors:{cx:function(t){var i=0;return d4.isOrdinalScale(this.x)?(i=n.bind(this)("x"),e.bind(this)("x",t)+i/2):(i=r.bind(this)("x",t),s.bind(this)("x",t)+i/2)},cy:function(t){var i=0;return d4.isOrdinalScale(this.y)?(i=n.bind(this)("y"),e.bind(this)("y",t)+i/2):(i=r.bind(this)("y",t),s.bind(this)("y",t)+i/2)},rx:function(t){return d4.isOrdinalScale(this.x)?n.bind(this)("x")/2:r.bind(this)("x",t)/2},ry:function(t){return d4.isOrdinalScale(this.y)?n.bind(this)("y")/2:r.bind(this)("y",t)/2}}},c=function(t,e){e.attr("rx",d4.functor(t.accessors.rx).bind(this)).attr("ry",d4.functor(t.accessors.ry).bind(this)).attr("cx",d4.functor(t.accessors.cx).bind(this)).attr("cy",d4.functor(t.accessors.cy).bind(this))},u=i.bind(this)(t,"ellipse",c);return d4.merge(u,a)}),d4.feature("rectSeries",function(t){var a={accessors:{height:function(t,e){return d4.isOrdinalScale(this[t])?n.bind(this)(t):r.bind(this)(t,e)},rx:0,ry:0,width:function(t,e){return d4.isOrdinalScale(this[t])?n.bind(this)(t):r.bind(this)(t,e)},x:function(t){return d4.isOrdinalScale(this.x)?e.bind(this)("x",t):s.bind(this)("x",t)},y:function(t){return d4.isOrdinalScale(this.y)?e.bind(this)("y",t):s.bind(this)("y",t)},xScaleId:function(){return"x"},yScaleId:function(){return"y"}}},c=function(t,e){var n=d4.functor(t.accessors.xScaleId)(),r=d4.functor(t.accessors.yScaleId)();e.attr("x",d4.functor(t.accessors.x).bind(this)).attr("y",d4.functor(t.accessors.y).bind(this)).attr("ry",d4.functor(t.accessors.ry).bind(this)).attr("rx",d4.functor(t.accessors.rx).bind(this)).attr("width",d4.functor(t.accessors.width).bind(this,n)).attr("height",d4.functor(t.accessors.height).bind(this,r))},u=i.bind(this)(t,"rect",c);return d4.merge(u,a)})}.call(this),function(){"use strict";d4.feature("trendLine",function(t){return{accessors:{tipSize:6,text:function(t){return t[this.valueKey]},textX:function(){return this.x(this.width)},textY:function(){return this.x(this.height)},x1:function(){return this.x(this.x.$key)},x2:function(){return this.x(this.width)},y1:function(){return this.y(this.y.$key)},y2:function(){return this.y(this.height)}},render:function(e,n,r){var s=this.container.select("defs");d4.appendOnce(s,"marker#"+t+"-start").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(e.accessors.tipSize).bind(this)()).attr("markerHeight",d4.functor(e.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(r,"g."+t);var i=d4.appendOnce(this.container.select("."+t),"line.line").attr("x1",d4.functor(e.accessors.x1).bind(this)).attr("x2",d4.functor(e.accessors.x2).bind(this)).attr("y1",d4.functor(e.accessors.y1).bind(this)).attr("y2",d4.functor(e.accessors.y2).bind(this)).attr("marker-end","url(#"+t+"-start)");return d4.appendOnce(this.container.select("."+t),"text.trendLine-label").text(d4.functor(e.accessors.text).bind(this)).attr("x",d4.functor(e.accessors.textX).bind(this)).attr("y",d4.functor(e.accessors.textY).bind(this)),i}}})}.call(this),function(){"use strict";d4.feature("waterfallConnectors",function(t){return{accessors:{beforeRender:function(t){var e=t.map(function(t){return t.values[0]});return d4.flatten(e)},classes:function(t,e){return"series"+e},span:function(){return d4.isOrdinalScale(this.x)?this.x.rangeBand():this.y.rangeBand()},x:function(t){if(d4.isOrdinalScale(this.x))return this.x(t[this.x.$key]);var e=0,n=t.y0+t.y-Math.max(0,t.y);return t.y>0&&(e=Math.abs(this.x(t.y0)-this.x(t.y0+t.y))),this.x(n)+e},y:function(t){return d4.isOrdinalScale(this.x)?this.y(t.y0+t.y):this.y(t[this.y.$key])}},render:function(e,n,r){var s=d4.appendOnce(r,"g."+t),i=s.selectAll("line").data(n);return i.enter().append("line"),i.exit().remove(),i.attr("class",d4.functor(e.accessors.classes).bind(this)).attr("x1",function(t,r){return 0===r?0:d4.functor(e.accessors.x).bind(this)(n[r-1])}.bind(this)).attr("y1",function(t,r){return 0===r?0:d4.functor(e.accessors.y).bind(this)(n[r-1])}.bind(this)).attr("x2",function(t,r){return 0===r?0:d4.isOrdinalScale(this.x)?d4.functor(e.accessors.x).bind(this)(t)+d4.functor(e.accessors.span).bind(this)():d4.functor(e.accessors.x).bind(this)(n[r-1])}.bind(this)).attr("y2",function(t,r){return 0===r?0:d4.isOrdinalScale(this.x)?d4.functor(e.accessors.y).bind(this)(n[r-1]):d4.functor(e.accessors.y).bind(this)(t)+d4.functor(e.accessors.span).bind(this)(t)}.bind(this)),i}}})}.call(this),function(){"use strict";d4.feature("xAxis",function(t){var e=d3.svg.axis().orient("bottom").tickPadding(10).tickSize(0),n=function(t,e){var n=d4.helpers.textSize(t,e);return n.text=t,n},r=function(t,e,n,r){if(t.text){var s=this.container.selectAll("."+r+".axis"),i=s.node().getBBox(),a=.8*t.height,c=s.append("text").text(t.text).attr("class",""+n);"bottom"===e.toLowerCase()?c.attr("transform","translate(0,"+(i.height+a)+")"):c.attr("transform","translate(0,"+(i.y-a/2)+")")}},s=function(t,e){switch(!0){case"top"===t.toLowerCase():e.attr("transform","translate(0,0)");break;case"bottom"===t.toLowerCase():e.attr("transform","translate(0,"+this.height+")")}},i={accessors:{align:"bottom",stagger:!0,subtitle:void 0,title:void 0,scaleId:function(){return"x"}},proxies:[{target:e}],render:function(i,a,c){var u=d4.functor(i.accessors.scaleId).bind(this)();i.scale(this[u]);var o=n(d4.functor(i.accessors.title).bind(this)(),"title"),d=n(d4.functor(i.accessors.subtitle).bind(this)(),"subtitle"),f=d4.functor(i.accessors.align).bind(this)(),h=d4.appendOnce(c,"g."+u+".axis."+t).attr("data-scale",this[u].$scale).call(e);return s.bind(this)(f,h),d4.functor(i.accessors.stagger).bind(this)()&&h.selectAll(".tick text").call(d4.helpers.staggerTextVertically,1),"top"===f?(r.bind(this)(d,f,"subtitle",u),r.bind(this)(o,f,"title",u)):(r.bind(this)(o,f,"title",u),r.bind(this)(d,f,"subtitle",u)),h}};return i})}.call(this),function(){"use strict";d4.feature("yAxis",function(t){var e=d3.svg.axis().orient("left").tickPadding(10).tickSize(0),n=function(t,e){var n=d4.helpers.textSize(t,e);return n.text=t,n},r=function(t,e,n,r){if(t.text){var s=this.container.selectAll("."+r+".axis"),i=s.node().getBBox(),a=.8*t.height,c=s.append("text").text(t.text).attr("class",""+n);"left"===e.toLowerCase()?c.call(d4.helpers.rotateText("rotate(90)translate(0,"+(Math.abs(i.x)+a)+")")):c.call(d4.helpers.rotateText("rotate(90)translate(0,"+(Math.abs(i.x)-(i.width+a))+")"))}},s=function(t,e){switch(!0){case"left"===t.toLowerCase():e.attr("transform","translate(0,0)");break;case"right"===t.toLowerCase():e.attr("transform","translate("+this.width+", 0)")}},i={accessors:{align:"left",stagger:!0,subtitle:void 0,title:void 0,scaleId:function(){return"y"}},proxies:[{target:e}],render:function(i,a,c){var u=d4.functor(i.accessors.scaleId).bind(this)();i.scale(this[u]);var o=n(d4.functor(i.accessors.title).bind(this)(),"title"),d=n(d4.functor(i.accessors.subtitle).bind(this)(),"subtitle"),f=d4.functor(i.accessors.align).bind(this)(),h=d4.appendOnce(c,"g."+u+".axis."+t).attr("data-scale",this[u].$scale).call(e);return h.selectAll(".tick text").call(d4.helpers.wrapText,this.margin[f]),s.bind(this)(f,h),d4.functor(i.accessors.stagger).bind(this)()&&this.container.selectAll("."+u+".axis .tick text").call(d4.helpers.staggerTextHorizontally,-1),"left"===f?(r.bind(this)(o,f,"title",u),r.bind(this)(d,f,"subtitle",u)):(r.bind(this)(d,f,"subtitle",u),r.bind(this)(o,f,"title",u)),h}};return i})}.call(this),function(){"use strict";d4.parser("nestedGroup",function(){var t={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};t.defined=function(){return!0},t.nestKey=function(){return t.x.key};var e=function(e){var n=[];return d4.each(e,function(e){t.defined(e)&&n.push(e)}.bind(this)),n},n=function(e,n){["x","y","value"].forEach(function(r){var s=n.map(function(t){return t[e[r].key]});t[r].values=d3.set(s).values()})},r=function(t,e,n){var r=d3.nest().key(function(e){return e[t]});return r.entries(n)},s=function(e,n){t[e].key=d4.functor(n)()},i=function(s){return s&&d4.extend(t.data,s),n(t,t.data),t.data=e(t.data),t.data=r(t.nestKey(),t.value.key,t.data),t};return i.nestKey=function(e){return t.nestKey=d4.functor(e).bind(t),i},i.defined=function(e){return t.defined=d4.functor(e).bind(t),i},d4.each(["x","y","value"],function(e){i[e]=function(n){return s.bind(t)(e,d4.functor(n)),i}}.bind(this)),i})}.call(this),function(){"use strict";d4.parser("nestedStack",function(){var t={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};t.defined=function(){return!0},t.nestKey=function(){return t.y.key};var e=function(e){var n=[];return d4.each(e,function(e){t.defined(e)&&n.push(e)}.bind(this)),n},n=function(e,n){["x","y","value"].forEach(function(r){var s=n.map(function(t){return t[e[r].key]});t[r].values=d3.set(s).values()})},r=function(t,e,n){var r=d3.nest().key(function(e){return e[t]});return r.entries(n)},s=function(e,n){var r={},s=d3.layout.stack().values(function(t){return t.values}).x(function(t){return t[e]}).y(function(e){return+e[t.value.key]}).out(function(t,n,s){t.y=s,t.y>=0?(t.y0=r[t[e]+"Pos"]=r[t[e]+"Pos"]||0,r[t[e]+"Pos"]+=s):(t.y0=r[t[e]+"Neg"]=r[t[e]+"Neg"]||0,r[t[e]+"Neg"]-=Math.abs(s))});s(n.reverse())},i=function(e,n){var r=d4.functor(n)();"x"===e&&"y"===r&&d4.err("You cannot use `y` as the key for an `x` dimension because it creates an ambiguous `y` property in the nested stack."),t[e].key=r},a=function(i){return i&&d4.extend(t.data,i),n(t,t.data),t.data=e(t.data),t.data=r(t.nestKey(),t.value.key,t.data),t.data.length>0&&s(t.x.key,t.data),t};return a.nestKey=function(e){return t.nestKey=d4.functor(e).bind(t),a},a.defined=function(e){return t.defined=d4.functor(e).bind(t),a},d4.each(["x","y","value"],function(e){a[e]=function(n){return i.bind(t)(e,d4.functor(n)),a}}.bind(this)),a})}.call(this),function(){"use strict";d4.parser("waterfall",function(){var t={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};t.nestKey=function(){return t.x.key};var e=function(e,n){["x","y","value"].forEach(function(r){var s=n.map(function(t){return t[e[r].key]});t[r].values=d3.set(s).values()})},n=function(t,e,n){var r=d3.nest().key(function(e){return e[t]});return r.entries(n)},r=function(e,n){var r=0,s=function(t){return isNaN(t)?0:t},i=d3.layout.stack().values(function(t){return t.values}).x(function(t){return t[e]}).y(function(e){return+e[t.value.key]}).out(function(e,n,i){isNaN(i)?(isNaN(n)&&(n=r),e.y0=0,e.y=n,e[t.value.key]=n,r=n):(isNaN(n)?(e.y0=r,r+=i):e.y0=n,e.y=i,e[t.value.key]=s(e[t.value.key]))});i(n)},s=function(e,n){t[e].key=d4.functor(n)()},i=function(s){return s&&d4.extend(t.data,s),e(t,t.data),t.data=n(t.nestKey(),t.value.key,t.data),t.data.length>0&&r(t.x.key,t.data),t};return i.nestKey=function(e){return t.nestKey=d4.functor(e).bind(t),i},d4.each(["x","y","value"],function(e){i[e]=function(n){return s.bind(t)(e,d4.functor(n)),i}}.bind(this)),i})}.call(this),function(){"use strict";var t=function(t,e){var n=t.map(function(t){return t.values.map(function(t){return t[e]}.bind(this))}.bind(this));return d3.set(d3.merge(n)).values()},e=function(t,e){switch(e){case"x":return[0,t.width];case"y":return[t.height,0];case"groups":var n=t.axes.groups.$dimension;return"x"===n?[0,t.axes.x.rangeBand()]:[t.axes.y.rangeBand(),0];default:return[]}},n=function(t,n,r){var s=t[r].$key,i=d3.extent(d3.merge(n.map(function(t){return d3.extent(t.values,function(t){return d4.isDate(t[s])?t[s]:t[s]+(t.y0||0)})}))),a=t[r];if(!a.domain.$dirty)if(d4.isDate(i[0])){var c=a.$min||i[0],u=a.$max||i[1];a.domain([c,u])}else a.domain([Math.min(a.$min||0,i[0]),a.$max||i[1]]);return a.range.$dirty||a.range(e(t,r)),a.clamp.$dirty||a.clamp(!0),t[r]};d4.builder("linearScaleForNestedData",n),d4.builder("timeScaleForNestedData",n),d4.builder("ordinalScaleForNestedData",function(n,r,s){var i,a=t(r,n[s].$key);i=n[s+"RoundBands"]?n[s+"RoundBands"]:n[s].$roundBands?n[s].$roundBands:.3,n[s+"RoundBands"]=i;var c=n[s];return c.domain.$dirty||c.domain(a),c.rangeRoundBands.$dirty||c.rangePoints.$dirty||c.rangeBands.$dirty||c.rangeRoundBands(e(n,s),i),c})}.call(this); \ No newline at end of file +(function(){"use strict";var a=this,b={},c=function(a){return a instanceof c?a:this instanceof c?void(this.d4Wrapped=a):new c(a)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=c),exports.d4=c):a.d4=c,c.charts={},c.features={},c.parsers={},c.builders={};var d=c.each=c.forEach=function(a,c,d){var e,f,g=Array.prototype.forEach;if(null!==a)if(g&&a.forEach===g)a.forEach(c,d);else if(a.length===+a.length){for(e=0,f=a.length;f>e;e++)if(c.call(d,a[e],e,a)===b)return}else{var h=d3.keys(a);for(e=0,f=h.length;f>e;e++)if(c.call(d,a[h[e]],h[e],a)===b)return}},e=function(a){return a.charAt(0).toUpperCase()+a.slice(1)},f=function(a,b,d,e){Object.defineProperty(a,b,{configurable:!0,get:function(){return c.functor(e)()},set:function(){g(" You cannot directly assign values to the {0} property. Instead use the {1}() function.",b,d)}})},g=c.err=function(){var a,b=Array.prototype.slice.call(arguments),c=b.shift();throw d(b,function(b,d){a=new RegExp("\\{"+d+"\\}","gi"),c=c.replace(a,b)}),new Error("[d4] "+c)},h=function(a){return d(["link"],function(b){a[b]&&!c.isNotFunction(a[b])||g("The supplied builder does not have a {0} function",b)}),a},i=function(a){return this.builder||(this.builder=h(a.bind(this)())),this},j=function(a,b,d){if(c.isNotFunction(d)){var e="$"+b;f(a,e,b,d)}},k=function(a,b,d,f){var g=d;c.isDefined(f)&&(g=f+e(d)),a[g]=function(c){return arguments.length?(j(a,d,c),b[d]=c,a):b[d]},j(a,d,b[d])},l=function(a,b,c,e){d(c,function(c){k(a,b,c,e)})},m=function(a){var b=a.accessors;b&&l(a,a.accessors,d3.keys(b))},n=function(a,b){d(d3.keys(b.axes),function(c){a[c]=function(d){return K.bind(b)(c,d),a},d(d3.keys(b.axes[c].accessors),function(d){a[c][d]=b.axes[c][d]})})},o=function(a){var b=d3.keys(d3.scale); +// manually add time scales to the supports scale types +b.push("time"),b.push("time.utc"),b.indexOf(a)<0&&g('The scale type: "{0}" is unrecognized. D4 only supports these scale types: {1}',a,b.sort().join(", "))},p=function(a,b,d){ +// Create a transparent proxy for functions needed by the d3 scale. +c.createAccessorProxy(b,a),b.scale=function(a){return arguments.length?(b.accessors.scale=a,d(),b):b.accessors.scale}},q=function(a,b,c){var e;switch(o(c.accessors.scale),!0){case"time"===c.accessors.scale:e=d3.time.scale();break;case"time.utc"===c.accessors.scale:e=d3.time.scale.utc();break;default:e=d3.scale[c.accessors.scale]()}m(c),b[a]=e,p(e,b.axes[a],function(){q(a,b,c)}), +// Danger Zone (TM): This is setting read-only function properties on a d3 scale instance. This may not be totally wise. +d(d3.keys(b.axes[a].accessors),function(c){f(b[a],"$"+c,b.axes[a][c],b.axes[a][c])})},r=function(a,b,d){b.axes[a]={accessors:c.extend({key:a,min:void 0,max:void 0},d)},q(a,b,b.axes[a])},s=function(a){d(d3.keys(a.axes),function(b){r(b,a,a.axes[b])}),c.isUndefined(a.axes.x)&&r("x",a,{scale:"ordinal"}),c.isUndefined(a.axes.y)&&r("y",a,{scale:"linear"})},t=function(a,b){var d=c.functor({link:function(a,b){c.builders[a.x.$scale+"ScaleForNestedData"](a,b,"x"),c.builders[a.y.$scale+"ScaleForNestedData"](a,b,"y"),a.groups&&c.builders[a.groups.$scale+"ScaleForNestedData"](a,b,"groups")}}),e=c.merge({},a.accessors);delete a.accessors;var f=c.merge({axes:{},features:{},height:400,margin:{top:20,right:20,bottom:40,left:40},mixins:[],outerHeight:460,outerWidth:460,width:400},a);return f=c.merge(f,e),s(f),i.bind(f)(b||d),f.accessors=["width","height","valueKey"].concat(d3.keys(e)||[]),f},u=function(a,b){b&&d(d3.keys(a._proxiedFunctions),function(c){d(a._proxiedFunctions[c],function(a){b[c].apply(b,a)})})},v=function(a,b,d){var e=a.features[b].accessors.beforeRender.bind(a)(d);return c.isDefined(e)&&(d=e),d},w=function(a,b){var c,d;a.mixins.forEach(function(e){c=v(a,e,b),d=a.features[e].render.bind(a)(a.features[e],c,a.chartArea),a.features[e].accessors.afterRender.bind(a)(a.features[e],c,a.chartArea,d),u(a.features[e],d)})},x=function(a,b){a.builder?(a.builder.link(a,b),w(a,b)):g("No builder defined")},y=function(a){"svg"===a.tagName?this.container=d3.select(a).classed("d4",!0).classed("chart",!0).attr("width",Math.max(0,this.width+this.margin.left+this.margin.right)).attr("height",Math.max(0,this.height+this.margin.top+this.margin.bottom)):"g"===a.tagName?this.container=d3.select(a).classed("d4",!0).classed("chart",!0):this.container=c.appendOnce(d3.select(a),"svg.d4.chart").attr("width",Math.max(0,this.width+this.margin.left+this.margin.right)).attr("height",Math.max(0,this.height+this.margin.top+this.margin.bottom)),c.appendOnce(this.container,"defs"),c.appendOnce(this.container,"g.margins").attr("transform","translate("+this.margin.left+","+this.margin.top+")"),this.chartArea=c.appendOnce(this.container.select("g.margins"),"g.chartArea")},z=function(a,b){var d=c.parsers.nestedGroup().x(a.x.$key).y(a.y.$key).nestKey(a.x.$key).value(a.valueKey)(b);return d.data},A=function(a,b){var d,e,f=!1;return c.isUndefined(a.valueKey)&&(a.valueKey=a.y.$key),b.length>0&&(e=b[0],c.isArray(e)?f=!0:(d=d3.keys(e),d.indexOf("key")+d.indexOf("values")<=0&&(f=!0))),f?z(a,b):b},B=function(a){return function(b){b.each(function(b){b=A(a,b),y.bind(a,this)(),x(a,b)})}},C=function(a,b){return a.overrides?a.overrides(b):{}},D=function(a,b,d){c.isDefined(d)?(d=Math.max(Math.min(d,a.length),0),a.splice(d,0,b)):a.push(b)},E=function(a){a._proxiedFunctions={on:[]},a.on=function(){return a._proxiedFunctions.on.push(Array.prototype.slice.call(arguments)),a}},F=function(a){m(a)},G=function(a){E(a),c.each(a.proxies,function(b){c.isUndefined(b.target)&&g("You included a feature which has a malformed proxy target.",a.name),c.createAccessorProxy(a,b.target,b.prefix)})},H=function(a){a||g("You need to supply an object or array of objects to mixin to the chart.");var b=c.flatten([a]);c.each(b,function(a){var b=a.name,d=C.bind(this)(a,b),e={accessors:{afterRender:function(){},beforeRender:function(){}},proxies:[]};a[b]=c.merge(c.merge(e,a.feature(b)),d),c.extend(this.features,a),D(this.mixins,b,a.index),G(this.features[b]),F(this.features[b])}.bind(this))},I=function(a){var b=[];c.isUndefined(a)&&g("A string or array of names is required in order to mixout a chart feature."),b.push(a),c.each(c.flatten(b),function(a){delete this.features[a],this.mixins=this.mixins.filter(function(b){return b!==a})}.bind(this))},J=function(a,b){var d=this.features[a];c.isNotFunction(b)&&g("You must supply a continuation function in order to use a chart feature."),d?b.bind(this)(d):g('Could not find feature: "{0}", maybe you forgot to mix it in?',a)},K=function(a,b){var d=this.axes[a];c.isNotFunction(b)&&g("You must supply a continuation function in order to use a chart axis."),d?b.bind(this)(d):g('Could not find axis: "{0}", maybe you forgot to define it?',a)},L=function(a){var b,d,e=a,f="[\\x20\\t\\r\\n\\f]",g="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",h=g.replace("w","w#"),i="\\["+f+"*("+g+")"+f+"*(?:([*^$|!~]?=)"+f+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+h+")|)|)"+f+"*\\]",j=["TAG","ID","CLASS"],k={ID:new RegExp("#("+g+")"),CLASS:new RegExp("\\.("+g+")"),TAG:new RegExp("^("+g.replace("w","w*")+")"),ATTR:new RegExp(""+i)},l=function(a){for(b=!1,m[a]=[],d=!0;d;)d=k[a].exec(e),null!==d&&(b=d.shift(),m[a].push(d[0]),e=e.slice(b.length))},m={};return c.each(j,l),c.each(j,function(a){for(;e&&(m[a]=m[a].join(" "),b););}),m},M=function(a){var b=B(a);/** + * This function returns the internal axes object as a parameter to the + * supplied function. + * @param {Function} funct - function which will perform the modifcation. + * @return {Function} chart instance + */ +/** + * Specifies an object, which d4 uses to initialize the chart with. By default + * d4 expects charts to return a builder object, which will be used to + * configure defaults for the chart. Typically this means determining the + * the default value for the various axes. This accessor allows you to + * override the existing builder provided by a chart and use your own. + * + *##### Examples + * + * myChart.builder = function(chart, data){ + * return { + * link: function(chart, data) { + * configureScales.bind(this)(chart, data); + * } + * }; + * }; + * + * @param {Function} funct - function which returns a builder object. + * @return {Function} chart instance + */ +/** + * This function creates a deep copy of the current chart and returns it. + * This is useful if you have to create several charts which have a variety + * of shared features but deviate from each other in a small number of ways. + * + *##### Examples + * + * var chart = d4.charts.column(); + * var clone = chart.clone(); + * + * @return {Function} a copy of the current chart + */ +/** + * To see what features are currently mixed into your chart you can use + * this method. This function cannot be chained. + * + *##### Examples + * + * // Mixout the yAxis which is provided as a default + * var chart = d4.charts.column() + * .mixout('yAxis'); + * + * // Now test that the feature has been removed. + * + * // => ["bars", "barLabels", "xAxis"] + * + * @return {Array} An array of features. + */ +/** + * To adjust the chart's margins supply either an object or a function that returns + * an object to this method. + * + *##### Examples + * + * // set the margin this using an object: + * chart.margin({ top: 10, right: 10, bottom: 10, left: 10 }); + * + * // set using a function: + * chart.margin(function(){ + * return { top: 10, right: 10, bottom: 10, left: 10 }; + * }); + * + * // since JavaScript is a pass by reference language you can also + * // set portions of the margin this way: + * chart.margin().left = 20; + * + * // there are also accessor method for each property of the margin + * // object: + * chart.marginLeft(20); + * chart.marginLeft() // => 20; + * + * @param {*} funct - an object or a function that returns an object. + * @return {Function} chart instance + */ +/** + * Specifies a feature to be mixed into a given chart. + * The feature is an object where the key represents the feature name, and a + * value which is a function that when invoked returns a d4 feature object. + * + *##### Examples + * + * // Mix in a single feature at a specific depth + * chart.mixin({ name : 'grid', feature : d4.features.grid, index: 0 }) + * + * // Mix in multiple features at once. + * chart.mixin([ + * { name : 'zeroLine', feature : d4.features.referenceLine }, + * { name : 'grid', feature : d4.features.grid, index: 0 } + * ]) + * + * @param {*} features - an object or array of objects describing the feature to mix in. + * @return {Function} chart instance + */ +/** + * Specifies an existing feature of a chart to be removed (mixed out). + * + *##### Examples + * + * // Mixout the yAxis which is provided as a default + * var chart = d4.charts.column() + * .mixout('yAxis'); + * + * // Now test that the feature has been removed. + * + * => ["bars", "barLabels", "xAxis"] + * + * @param {String} name - accessor name for chart feature. + * @return {Function} chart instance + */ +/** + * Returns or sets the outerHeight of the chart. + * + * @param {Number} height + * @return {Function} chart instance + */ +/** + * Returns or sets the outerWidth of the chart. + * + * @param {Number} width + * @return {Function} chart instance + */ +/** + * The heart of the d4 API is the `using` function, which allows you to + * contextually modify attributes of the chart or one of its features. + * + *##### Examples + * + * chart.mixin({ 'zeroLine': d4.features.referenceLine }) + * .using('zeroLine', function(zero) { + * zero + * .x1(function() { + * return this.x(0); + * }) + * }); + * + * @param {String} name - accessor name for chart feature. + * @param {Function} funct - function which will perform the modifcation. + * @return {Function} chart instance + */ +return l(b,a.margin,d3.keys(a.margin),"margin"),l(b,a,a.accessors),n(b,a),b.axes=function(c){return arguments.length?(c(a.axes),b):a.axes},b.builder=function(c){return a.builder=h(c.bind(a)()),b},b.clone=function(){var b=c.extend({},a);return M(b)},b.features=function(){return a.mixins},b.margin=function(d){return arguments.length?(a.margin=c.merge(a.margin,c.functor(d)()),b.height(b.outerHeight()-a.margin.top-a.margin.bottom),b.width(b.outerWidth()-a.margin.left-a.margin.right),b):a.margin},b.mixin=function(c){return H.bind(a)(c),b},b.mixout=function(c,d){return I.bind(a)(c,d),b},b.outerHeight=function(d){var e=c.functor(d)();return arguments.length?(a.outerHeight=e,b.height(e-a.margin.top-a.margin.bottom),b):a.outerHeight},b.outerWidth=function(d){var e=c.functor(d)();return arguments.length?(a.outerWidth=e,b.width(e-a.margin.left-a.margin.right),b):a.outerWidth},b.using=function(c,d){return J.bind(a)(c,d),b},b};/** + * This function conditionally appends a SVG element if it doesn't already + * exist within the parent element. + * + *##### Examples + * + * // this will create a svg element, with the id of chart and apply two classes "d4 and chart" + * d4.appendOnce(selection, 'svg#chart.d4.chart') + * + * @param {D3 Selection} - parent DOM element + * @param {String} - string to use as the dom selector + * + * @return {D3 Selection} selection + */ +c.appendOnce=function(a,b){var c,d=a.selectAll(b);return d.empty()&&(c=L(b),d=a.append(c.TAG).attr("class",c.CLASS.join(" ")),c.ID&&d.attr("id",c.ID.pop())),d},/** + * This function creates a d4 chart object. It is only used when creating a + * new chart factory. + * + *##### Examples + * + * var chart = d4.baseChart({ + * builder: myBuilder, + * config: { + * axes: { + * x: { + * scale: 'linear' + * }, + * y: { + * scale: 'ordinal' + * } + * } + * } + * }); + * + * @param {Object} options - object which contains an optional config and /or + * builder property + * @return {Function} chart instance + */ +c.baseChart=function(a){var b=t(a&&a.config||{},a&&a.builder||void 0);return M(b)},/** + * This function allows you to register a reusable chart builder with d4. + * @param {String} name - accessor name for chart builder. + * @param {Function} funct - function which will instantiate the chart builder. + * @return {Function} a reference to the chart builder + */ +c.builder=function(a,b){return c.builders[a]=b,c.builders[a]},/** + * This function allows you to register a reusable chart with d4. + * @param {String} name - accessor name for chart. + * @param {Function} funct - function which will instantiate the chart. + * @return {Function} a reference to the chart function + */ +c.chart=function(a,b){return c.charts[a]=b,c.charts[a]},/** + * This function allows create proxy accessor to other objects. This is most + * useful when you need a feature to transparently control a component of a + * d3 object. Consider the example of the yAxis feature. It allows you to control + * a d3 axis object. To the user the d4 axis feature and the d3 axis object are + * one in the same, and they will expect that they can interact with an d4 axis + * feature in the same way they could with a d3 axis object. Therefore before + * the feature is created we first use this function to create a transparent + * proxy that links the two. + * + *##### Examples + * + * d4.feature('yAxis', function(name) { + * var axis = d3.svg.axis(); + * var obj = { accessors : {} }; + * d4.createAccessorProxy(obj, axis); + * return obj; + * }); + * + * // Then when using the feature you can transparently access the axis properties + * chart.using('yAxis', function(axis){ + * // => 0 + * axis.ticks(); + * }); + * + * @param {Object} proxy - The proxy object, which masks the target. + * @param {Object} target - The target objet, which is masked by the proxy + * @param {String} prefix - Optional prefix to add to the method names, which helps avoid naming collisions on the proxy. + */ +c.createAccessorProxy=function(a,b,f){d(d3.keys(b),function(d){var g=d;c.isDefined(f)&&(g=f+e(d)),a[g]=function(){ +// target function is executed but proxy is returned so as not to break +// the chaining. +return arguments.length?(b[d].$dirty=!0,a[g].$dirty=!0,b[d].apply(b,arguments),a):b[d]()},b[d].$dirty=!1,a[g].$dirty=!1})},c.defaultKey=function(a,b){return(a.key||0)+"_"+b},/** + * Helper method to extend one object with the attributes of another. + * + *##### Examples: + * + * var opts = d4.extend({ + * margin: { + * top: 20, + * right: 20, + * bottom: 40, + * left: 40 + * }, + * width: 400 + * }, config); + * + * @param {Object} obj - the object to extend + * @param {Object} overrides - the second object who will extend the first. + * @return {Object} the first object which has now been extended; + */ +c.extend=function(a){return d(Array.prototype.slice.call(arguments,1),function(b){var d=function(a){var b=[];return c.each(a,function(a){var d=a;c.isObject(a)&&(d=c.extend({},a)),b.push(d)}),b};if(b)for(var e in b)if(b[e]&&b[e].constructor&&b[e].constructor===Object)a[e]=a[e]||{},c.extend(a[e],b[e]);else if(c.isArray(b[e])){var f=d(b[e].slice());c.isArray(a[e])?a[e]=a[e].concat(f):a[e]=f}else a[e]=b[e]}),a},/** + * This function allows you to register a reusable chart feature with d4. + * @param {String} name - accessor name for chart feature. + * @param {Function} funct - function which will instantiate the chart feature. + * @return {Function} a reference to the chart feature + */ +c.feature=function(a,b){return c.features[a]=b,c.features[a]},/** + * Helper method to flatten a multi-dimensional array into a single array. + * @param {Array} arr - array to be flattened. + * @return {Array} flattened array. + */ +c.flatten=function(a){var b=a.reduce(function(a,b){return a=c.isArray(a)?a:[a],b=c.isArray(b)?b:[b],a.concat(b)});return c.isArray(b)?b:[b]},/** + * Based on D3's own functor function. + * > If the specified value is a function, returns the specified value. Otherwise, + * > returns a function that returns the specified value. This method is used + * > internally as a lazy way of upcasting constant values to functions, in + * > cases where a property may be specified either as a function or a constant. + * > For example, many D3 layouts allow properties to be specified this way, + * > and it simplifies the implementation if we automatically convert constant + * > values to functions. + * + * @param {*} funct - An function or other variable to be wrapped in a function + * @return {Function} + */ +c.functor=function(a){return c.isFunction(a)?a:function(){return a}},/** + * Helper method to determine if a supplied argument is an array + * @param {*} obj - the argument to test + * @return {Boolean} + */ +c.isArray=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)},/** + * Helper method to determine if the supplied scale wants continuous as + * opposed to ordinal values. + */ +c.isContinuousScale=function(a){return c.isDefined(a.rangeRound)},/** + * Helper method to determine if a supplied argument is a date + * @param {*} obj - the argument to test + * @return {Boolean} + */ +c.isDate=function(a){return"[object Date]"===Object.prototype.toString.call(a)},/** + * Helper method to determine if a supplied argument is defined + * @param {*} value - the argument to test + * @return {Boolean} + */ +c.isDefined=function(a){return!c.isUndefined(a)},/** + * Helper method to determine if a supplied argument is a function + * @param {*} obj - the argument to test + * @return {Boolean} + */ +c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)},/** + * Helper method to determine if a supplied argument is not an object + * @param {*} obj - the argument to test + * @return {Boolean} + */ +c.isObject=function(a){return null!==a&&"object"==typeof a},/** + * Helper method to determine if the supplied scale wants ordinal as + * opposed to continuous values. + */ +c.isOrdinalScale=function(a){return c.isUndefined(a.rangeRound)},/** + * Helper method to determine if a supplied argument is not a function + * @param {*} obj - the argument to test + * @return {Boolean} + */ +c.isNotFunction=function(a){return!c.isFunction(a)},/** + * Helper method to determine if a supplied argument is not null + * @param {*} value - the argument to test + * @return {Boolean} + */ +c.isNotNull=function(a){return!c.isNull(a)},/** + * Helper method to determine if a supplied argument is null + * @param {*} value - the argument to test + * @return {Boolean} + */ +c.isNull=function(a){return null===a},/** + * Helper method to determine if a supplied argument is undefined + * @param {*} value - the argument to test + * @return {Boolean} + */ +c.isUndefined=function(a){return"undefined"==typeof a},/** + * Helper method to merge two objects together into a new object. This will leave + * the two orignal objects untouched. The overrides object will replace any + * values which also occur in the options object. + * + *##### Examples: + * + * var opts = d4.merge({ + * margin: { + * top: 20, + * right: 20, + * bottom: 40, + * left: 40 + * }, + * width: 400 + * }, config); + * + * @param {Object} options - the first object + * @param {Object} overrides - the second object to merge onto the top. + * @return {Object} newly merged object; + */ +c.merge=function(a,b){return c.extend(c.extend({},a),b)},/** + * This function allows you to register a reusable data parser with d4. + * @param {String} name - accessor name for data parser. + * @param {Function} funct - function which will instantiate the data parser. + * @return {*} a reference to the data parser + */ +c.parser=function(a,b){return c.parsers[a]=b,c.parsers[a]}}).call(this),function(){"use strict";d4.helpers={}; +// FIXME: Provide this using DI. +var a=function(a,b){var c=5,d=0,e=function(a,b){return!(a.rightb.right||a.bottomb.bottom)},f=function(a){var g,h,i,j=!1,k=0;a.each(function(){k>0&&(g=this.getBoundingClientRect(),h=i.getBoundingClientRect(),e(g,h)&&(b.bind(this)(h,g),j=!0)),k++,i=this}),j&&c>d&&(d++,f.bind(this)(a))};f.bind(this)(a)};d4.helpers.staggerTextVertically=function(b,c){var d=function(a,b){var d=d3.select(this),e=d.attr("data-last-vertical-offset")||1,f=a.top-b.top,g=(b.height-f+e)*c;d.attr("transform","translate(0,"+g+")"),d.attr("data-last-vertical-offset",Math.abs(g))};a.bind(this)(b,d)}, +// based on: http://bl.ocks.org/ezyang/4236639 +d4.helpers.rotateText=function(a){return function(b){b.each(function(){var c=d3.transform(d3.functor(a).apply(this,arguments));b.attr("alignment-baseline","central"),b.style("dominant-baseline","central"),c.rotate<=90&&c.rotate>=-90?(b.attr("text-anchor","begin"),b.attr("transform",c.toString())):(b.attr("text-anchor","end"),c.rotate=(c.rotate>0?-1:1)*(180-Math.abs(c.rotate)),b.attr("transform",c.toString()))})}},d4.helpers.staggerTextHorizontally=function(b,c){var d=function(a,b){var d=d3.select(this),e=+(d.attr("data-last-horizontal-offset")||1),f=a.left-b.left,g=(b.width-f+e)*c;d.attr("transform","translate("+g+", 0)"),d.attr("data-last-horizontal-offset",Math.abs(g))};a.bind(this)(b,d)},d4.helpers.textSize=function(a,b){var c={height:0,width:0,x:0,y:0};if(d4.isDefined(a)){var d=d3.select("body").append("svg").attr("class",""+b);d.append("text").attr("x",-5e3).text(a),c=d.node().getBBox(),d.remove()}return c}, +// From Mike Bostock's example on wrapping long axis text. +d4.helpers.wrapText=function(a,b){a.each(function(){var a,c=d3.select(this),d=c.text().split(/\s+/).reverse(),e=[],f=0,g=1.1,// ems +h=c.attr("x"),i=c.attr("y"),j=parseFloat(c.attr("dy")),k=c.text(null).append("tspan").attr("x",h).attr("y",i).attr("dy",j+"em");for(a=d.pop();a;)e.push(a),k.text(e.join(" ")),k.node().getComputedTextLength()>b-Math.abs(h)&&(e.pop(),k.text(e.join(" ")),e=[a],k=c.append("tspan").attr("x",h).attr("y",i).attr("dy",++f*g+j+"em").text(a)),a=d.pop()})}}.call(this),function(){"use strict";/* + * The column chart has two axes (`x` and `y`). By default the column chart expects + * linear values for the `y` and ordinal values on the `x`. The basic column chart + * has four default features: + * + *##### Features + * + * `bars` - series bars + * `barLabels` - data labels above the bars + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { x: '2010', y:-10 }, + * { x: '2011', y:20 }, + * { x: '2012', y:30 }, + * { x: '2013', y:40 }, + * { x: '2014', y:50 }, + * ]; + * var chart = d4.charts.column(); + * d3.select('#example') + * .datum(data) + * .call(chart); + * + * By default d4 expects a series object, which uses the following format: `{ x : '2010', y : 10 }`. + * The default format may not be desired and so we'll override it: + * + * var data = [ + * ['2010', -10], + * ['2011', 20], + * ['2012', 30], + * ['2013', 40], + * ['2014', 50] + * ]; + * var chart = d4.charts.column() + * .x(function(x) { + * x.key(0) + * }) + * .y(function(y){ + * y.key(1); + * }); + * + * d3.select('#example') + * .datum(data) + * .call(chart); + * + * @name column + */ +d4.chart("column",function(a){var b=a||{};return d4.baseChart(b).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * The donut chart + * + *##### Features + * + * `arcs` - The arc series + * `arcLabels` - The data labels linked to the arcs + * `radius` - The total radius of the chart + * `arcWidth` - The width of the arc + * + *##### Example Usage + * + * var generateData = function() { + * var data = []; + * var names = ['Clay Hauck', 'Diego Hickle', 'Heloise Quitzon', + * 'Hildegard Littel', 'Janiya Legros', 'Karolann Boehm', + * 'Lilyan Deckow IV', 'Lizeth Blick', 'Marlene O\'Kon', 'Marley Gutmann' + * ], + * pie = d3.layout.pie() + * .sort(null) + * .value(function(d) { + * return d.unitsSold; + * }); + * d4.each(names, function(name) { + * data.push({ + * unitsSold: Math.max(10, Math.random() * 100), + * salesman: name + * }); + * }); + * return pie(data); + * }; + * + * var chart = d4.charts.donut() + * .outerWidth($('#pie').width()) + * .margin({ + * left: 0, + * top: 0, + * right: 0, + * bottom: 0 + * }) + * .radius(function() { + * return this.width / 8; + * }) + * .arcWidth(50) + * .using('arcLabels', function(labels) { + * labels.text(function(d) { + * return d.data.salesman; + * }) + * }) + * .using('arcs', function(slices) { + * slices.key(function(d) { + * return d.data.salesman; + * }); + * }); + * + * + * var redraw = function() { + * var data = generateData(); + * d3.select('#pie') + * .datum(data) + * .call(chart); + * }; + * (function loop() { + * redraw(); + * setTimeout(loop, 4500); + * })(); + * + * @name donut + */ +d4.chart("donut",function(a){var b=a||{};return d4.baseChart(d4.extend({config:{accessors:{radius:function(){return Math.min(this.width,this.height)/2},arcWidth:function(a){return a/3}}}},b)).mixin([{name:"arcs",feature:d4.features.arcSeries},{name:"arcLabels",feature:d4.features.arcLabels}])})}.call(this),function(){"use strict";/* + * The grouped column chart is used to compare a series of data elements grouped + * along the xAxis. This chart is often useful in conjunction with a stacked column + * chart because they can use the same data series, and where the stacked column highlights + * the sum of the data series across an axis the grouped column can be used to show the + * relative distribution. + * + *##### Features + * + * `bars` - series bars + * `barLabels` - data labels above the bars + * `groupsOf` - an integer representing the number of columns in each group + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { year: '2010', unitsSold:-100, salesman : 'Bob' }, + * { year: '2011', unitsSold:200, salesman : 'Bob' }, + * { year: '2012', unitsSold:300, salesman : 'Bob' }, + * { year: '2013', unitsSold:400, salesman : 'Bob' }, + * { year: '2014', unitsSold:500, salesman : 'Bob' }, + * { year: '2010', unitsSold:100, salesman : 'Gina' }, + * { year: '2011', unitsSold:100, salesman : 'Gina' }, + * { year: '2012', unitsSold:-100, salesman : 'Gina' }, + * { year: '2013', unitsSold:500, salesman : 'Gina' }, + * { year: '2014', unitsSold:600, salesman : 'Gina' }, + * { year: '2010', unitsSold:400, salesman : 'Average' }, + * { year: '2011', unitsSold:0, salesman : 'Average' }, + * { year: '2012', unitsSold:400, salesman : 'Average' }, + * { year: '2013', unitsSold:400, salesman : 'Average' }, + * { year: '2014', unitsSold:400, salesman : 'Average' } + * ]; + * + * var parsedData = d4.parsers.nestedGroup() + * .x('year') + * .y('unitsSold') + * .value('unitsSold')(data); + * + * var chart = d4.charts.groupedColumn() + * .width($('#example').width()) + * .x.$key('year') + * .y.$key('unitsSold') + * .groupsOf(parsedData.data[0].values.length); + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name groupedColumn + */ +d4.chart("groupedColumn",function(a){var b=a||{},c=function(){return{accessors:{x:function(a){var b=this.x(a[this.x.$key]),c=this.groups(a[this.groups.$key]),d=this.groups.rangeBand()/2;return b+c+d}}}};return d4.baseChart(d4.extend({config:{axes:{groups:{scale:"ordinal",dimension:"x",roundBands:.1}},accessors:{groupsOf:1}}},b)).mixin([{name:"bars",feature:d4.features.groupedColumnSeries},{name:"barLabels",feature:d4.features.stackedLabels,overrides:c},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * The grouped row chart is used to compare a series of data elements grouped + * along the xAxis. This chart is often useful in conjunction with a stacked row + * chart because they can use the same data series, and where the stacked row highlights + * the sum of the data series across an axis the grouped row can be used to show the + * relative distribution. + * + *##### Features + * + * `bars` - series bars + * `barLabels` - data labels above the bars + * `groupsOf` - an integer representing the number of rows in each group + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { year: '2010', unitsSold:-100, salesman : 'Bob' }, + * { year: '2011', unitsSold:200, salesman : 'Bob' }, + * { year: '2012', unitsSold:300, salesman : 'Bob' }, + * { year: '2013', unitsSold:400, salesman : 'Bob' }, + * { year: '2014', unitsSold:500, salesman : 'Bob' }, + * { year: '2010', unitsSold:100, salesman : 'Gina' }, + * { year: '2011', unitsSold:100, salesman : 'Gina' }, + * { year: '2012', unitsSold:-100, salesman : 'Gina' }, + * { year: '2013', unitsSold:500, salesman : 'Gina' }, + * { year: '2014', unitsSold:600, salesman : 'Gina' }, + * { year: '2010', unitsSold:400, salesman : 'Average' }, + * { year: '2011', unitsSold:0, salesman : 'Average' }, + * { year: '2012', unitsSold:400, salesman : 'Average' }, + * { year: '2013', unitsSold:400, salesman : 'Average' }, + * { year: '2014', unitsSold:400, salesman : 'Average' } + * ]; + * + * var parsedData = d4.parsers.nestedGroup() + * .x('year') + * .y('unitsSold') + * .value('unitsSold')(data); + * + * var chart = d4.charts.groupedRow() + * .width($('#example').width()) + * .x.$key('year') + * .y.$key('unitsSold') + * .groupsOf(parsedData.data[0].values.length); + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name groupedRow + */ +d4.chart("groupedRow",function(a){var b=a||{},c=function(){return{accessors:{y:function(a){var b=this.y(a[this.y.$key]),c=this.groups(a[this.groups.$key]),d=this.groups.rangeBand()/3;return b+c+d}}}};return d4.baseChart(d4.extend({config:{accessors:{groupsOf:1},margin:{top:20,right:40,bottom:20,left:40},axes:{x:{scale:"linear"},y:{scale:"ordinal"},groups:{scale:"ordinal",dimension:"y",roundBands:.1}}}},b)).mixin([{name:"bars",feature:d4.features.groupedColumnSeries},{name:"barLabels",feature:d4.features.stackedLabels,overrides:c},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * The line series chart is used to compare a series of data elements grouped + * along the xAxis. + * + *##### Features + * + * `lineSeries` - series lines + * `lineSeriesLabels` - data labels beside the lines + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { year: '2010', unitsSold:-100, salesman : 'Bob' }, + * { year: '2011', unitsSold:200, salesman : 'Bob' }, + * { year: '2012', unitsSold:300, salesman : 'Bob' }, + * { year: '2013', unitsSold:400, salesman : 'Bob' }, + * { year: '2014', unitsSold:500, salesman : 'Bob' }, + * { year: '2010', unitsSold:100, salesman : 'Gina' }, + * { year: '2011', unitsSold:100, salesman : 'Gina' }, + * { year: '2012', unitsSold:-100, salesman : 'Gina' }, + * { year: '2013', unitsSold:500, salesman : 'Gina' }, + * { year: '2014', unitsSold:600, salesman : 'Gina' }, + * { year: '2010', unitsSold:400, salesman : 'Average' }, + * { year: '2011', unitsSold:0, salesman : 'Average' }, + * { year: '2012', unitsSold:400, salesman : 'Average' }, + * { year: '2013', unitsSold:400, salesman : 'Average' }, + * { year: '2014', unitsSold:400, salesman : 'Average' } + * ]; + * var parsedData = d4.parsers.nestedGroup() + * .x(function(){ + * return 'year'; + * }) + * .nestKey(function(){ + * return 'salesman'; + * }) + * .y(function(){ + * return 'unitsSold'; + * }) + * .value(function(){ + * return 'unitsSold'; + * })(data); + * + * var chart = d4.charts.line() + * .width($('#example').width()) + * .x.$key('year') + * .y.$key('unitsSold'); + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name line + */ +d4.chart("line",function(a){var b=a||{};return d4.baseChart(b).mixin([{name:"lineSeries",feature:d4.features.lineSeries},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis},{name:"lineSeriesLabels",feature:d4.features.lineSeriesLabels}])})}.call(this),function(){"use strict";/* + * The row chart has two axes (`x` and `y`). By default the column chart expects + * linear scale values for the `x` and ordinal scale values on the `y`. The basic column chart + * has four default features: + * + *##### Features + * + * `bars` - series bars + * `barLabels` - data labels to the right of the bars + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { y: '2010', x:-10 }, + * { y: '2011', x:20 }, + * { y: '2012', x:30 }, + * { y: '2013', x:40 }, + * { y: '2014', x:50 }, + * ]; + * var chart = d4.charts.row(); + * d3.select('#example') + * .datum(data) + * .call(chart); + * + * @name row + */ +d4.chart("row",function(a){var b=a||{};return d4.baseChart(d4.extend({config:{margin:{top:20,right:40,bottom:20,left:40},valueKey:"x",axes:{x:{scale:"linear"},y:{scale:"ordinal"}}}},b)).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";var a=function(){var a=function(a,b){d4.builders[a.x.$scale+"ScaleForNestedData"](a,b,"x"),d4.builders[a.y.$scale+"ScaleForNestedData"](a,b,"y"),d4.builders[a.z.$scale+"ScaleForNestedData"](a,b,"z"); +// FIXME: Remove this hard coding. +var c=5,d=Math.max(c+1,(a.height-a.margin.top-a.margin.bottom)/10);a.z.range([c,d])},b={link:function(b,c){a.bind(this)(b,c)}};return b},b=function(a,b){var c=this[a];return c(b[c.$key])+c.rangeBand()/2},c=function(a,b){var c,d=this[a],e=Math.abs(d(b.y0)-d(b.y0+b.y))/2,f=10;return"x"===a&&(e*=-1,f*=-1),d4.isDefined(b.y0)?(c=b.y0+b.y,d(c)+e):d(b[d.$key])-f},d=function(){return{accessors:{x:function(a){return d4.isOrdinalScale(this.x)?b.bind(this)("x",a):c.bind(this)("x",a)},y:function(a){return d4.isOrdinalScale(this.y)?b.bind(this)("y",a):c.bind(this)("y",a)}}}},e=function(){return{accessors:{cx:function(a){return this.x(a[this.x.$key])},cy:function(a){return this.y(a[this.y.$key])},r:function(a){return this.z(a[this.z.$key])}}}};/* + * The scatter plot has three axes (`x`, `y` and `z`). By default the scatter + * plot expects linear scale values for all axes. The basic scatter plot chart + * has these default features: + * + *##### Features + * + * `circles` - series of circles + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { age: 12, unitsSold: 0, month: 1 }, + * { age: 22, unitsSold: 200, month: 2 }, + * { age: 42, unitsSold: 300, month: 3 }, + * { age: 32, unitsSold: 400, month: 4 }, + * { age: 2 , unitsSold: 400, month: 2 } + * ]; + * + * var chart = d4.charts.scatterPlot() + * .x(function(x){ + * x.min(-10) + * x.key('age'); + * }) + * .y(function(y){ + * y.key('month'); + * }) + * .z(function(z){ + * z.key('unitsSold'); + * }); + * + * d3.select('#example') + * .datum(data) + * .call(chart); + * + * @name scatterPlot + */ +d4.chart("scatterPlot",function(b){var c=b||{};return d4.baseChart(d4.extend({builder:a,config:{axes:{x:{scale:"linear"},z:{scale:"linear"}}}},c)).mixin([{name:"circles",feature:d4.features.circleSeries,overrides:e},{name:"circleLabels",feature:d4.features.stackedLabels,overrides:d},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * The stacked column chart has two axes (`x` and `y`). By default the stacked + * column expects continious scale for the `y` axis and a discrete scale for + * the `x` axis. The stacked column has the following default features: + * + *##### Features + * + * `bars` - series of rects + * `barLabels` - individual data values inside the stacked rect + * `connectors` - visual lines that connect the various stacked columns together + * `columnTotals` - column labels which total the values of each stack. + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { year: '2010', unitsSold: 200, salesman : 'Bob' }, + * { year: '2011', unitsSold: 200, salesman : 'Bob' }, + * { year: '2012', unitsSold: 300, salesman : 'Bob' }, + * { year: '2013', unitsSold: -400, salesman : 'Bob' }, + * { year: '2014', unitsSold: -500, salesman : 'Bob' }, + * { year: '2010', unitsSold: 100, salesman : 'Gina' }, + * { year: '2011', unitsSold: 100, salesman : 'Gina' }, + * { year: '2012', unitsSold: 200, salesman : 'Gina' }, + * { year: '2013', unitsSold: -500, salesman : 'Gina' }, + * { year: '2014', unitsSold: -600, salesman : 'Gina' }, + * { year: '2010', unitsSold: 400, salesman : 'Average' }, + * { year: '2011', unitsSold: 100, salesman : 'Average' }, + * { year: '2012', unitsSold: 400, salesman : 'Average' }, + * { year: '2013', unitsSold: -400, salesman : 'Average' }, + * { year: '2014', unitsSold: -400, salesman : 'Average' } + * ]; + * + * var parsedData = d4.parsers.nestedStack() + * .x(function(){ + * return 'year'; + * }) + * .y(function(){ + * return 'salesman'; + * }) + * .value(function(){ + * return 'unitsSold'; + * })(data); + * + * var chart = d4.charts.stackedColumn() + * .x(function(x){ + * x.key('year'); + * }) + * .y(function(y){ + * y.key('unitsSold'); + * }) + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name stackedColumn + */ +d4.chart("stackedColumn",function(a){var b=a||{},c=function(){var a=function(a){var b=[];return a.map(function(a){a.values.map(function(a){b.push(a)})}),b},b=function(a){return d3.nest().key(function(a){return a[this.x.$key]}.bind(this)).rollup(function(a){var b=d3.sum(a,function(a){return a[this.valueKey]}.bind(this)),c=d3.sum(a,function(a){return Math.max(0,a[this.valueKey])}.bind(this));return{text:b,size:c}}.bind(this)).entries(a)},c=function(c){return b.bind(this)(a(c)).map(function(a){var b={};return b[this.x.$key]=a.key,b.size=a.values.size,b[this.valueKey]=a.values.text,b}.bind(this))};return{accessors:{beforeRender:function(a){return c.bind(this)(a)},y:function(a,b){var c=this[a],d=5;return c(b.size)-d}}}};return d4.baseChart(b).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"connectors",feature:d4.features.stackedColumnConnectors},{name:"columnTotals",feature:d4.features.columnLabels,overrides:c},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * The stacked row chart has two axes (`x` and `y`). By default the stacked + * row expects continious scale for the `x` axis and a discrete scale for + * the `y` axis. The stacked row has the following default features: + * + *##### Features + * + * `bars` - series of rects + * `barLabels` - individual data values inside the stacked rect + * `connectors` - visual lines that connect the various stacked columns together + * `columnTotals` - column labels which total the values of each stack. + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { year: '2010', unitsSold: 200, salesman : 'Bob' }, + * { year: '2011', unitsSold: 200, salesman : 'Bob' }, + * { year: '2012', unitsSold: 300, salesman : 'Bob' }, + * { year: '2013', unitsSold: -400, salesman : 'Bob' }, + * { year: '2014', unitsSold: -500, salesman : 'Bob' }, + * { year: '2010', unitsSold: 100, salesman : 'Gina' }, + * { year: '2011', unitsSold: 100, salesman : 'Gina' }, + * { year: '2012', unitsSold: 200, salesman : 'Gina' }, + * { year: '2013', unitsSold: -500, salesman : 'Gina' }, + * { year: '2014', unitsSold: -600, salesman : 'Gina' }, + * { year: '2010', unitsSold: 400, salesman : 'Average' }, + * { year: '2011', unitsSold: 200, salesman : 'Average' }, + * { year: '2012', unitsSold: 400, salesman : 'Average' }, + * { year: '2013', unitsSold: -400, salesman : 'Average' }, + * { year: '2014', unitsSold: -400, salesman : 'Average' } + * ]; + * + * var parsedData = d4.parsers.nestedStack() + * .x(function(){ + * return 'year'; + * }) + * .y(function(){ + * return 'salesman'; + * }) + * .value(function(){ + * return 'unitsSold'; + * })(data); + * + * var chart = d4.charts.stackedRow() + * .x(function(x){ + * x.key('unitsSold'); + * }) + * .valueKey('unitsSold') + * .y(function(y){ + * y.key('year'); + * }); + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name stackedRow + */ +d4.chart("stackedRow",function(a){var b=a||{},c=function(){var a=function(a){var b=[];return a.map(function(a){a.values.map(function(a){b.push(a)})}),b},b=function(a){return d3.nest().key(function(a){return a[this.y.$key]}.bind(this)).rollup(function(a){var b=d3.sum(a,function(a){return a[this.valueKey]}.bind(this)),c=d3.sum(a,function(a){return Math.max(0,a[this.valueKey])}.bind(this));return{text:b,size:c}}.bind(this)).entries(a)},c=function(c){return b.bind(this)(a(c)).map(function(a){var b={};return b[this.y.$key]=a.key,b.size=a.values.size,b[this.valueKey]=a.values.text,b}.bind(this))};return{accessors:{beforeRender:function(a){return c.bind(this)(a)},x:function(a){var b=5;return this.x(a.size)+b}}}};return d4.baseChart(d4.extend({config:{margin:{top:20,right:40,bottom:20,left:40},axes:{x:{scale:"linear"},y:{scale:"ordinal"}}}},b)).mixin([{name:"bars",feature:d4.features.rectSeries},{name:"barLabels",feature:d4.features.stackedLabels},{name:"connectors",feature:d4.features.stackedColumnConnectors},{name:"columnTotals",feature:d4.features.columnLabels,overrides:c},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";var a=function(){return{accessors:{y:function(a){if(d4.isContinuousScale(this.y)){var b=a.y0+a.y-Math.min(0,a.y);return this.y(b)}return this.y(a[this.y.$key])},x:function(a){if(d4.isOrdinalScale(this.x))return this.x(a[this.x.$key]);var b=a.y0+a.y-Math.max(0,a.y);return this.x(b)},width:function(a,b){return d4.isOrdinalScale(this.x)?this.x.rangeBand():Math.abs(this.x(b.y0)-this.x(b.y0+b.y))},height:function(a,b){return d4.isContinuousScale(this.y)?Math.abs(this.y(b.y0)-this.y(b.y0+b.y)):this.y.rangeBand()},classes:function(a,b,c){var d=a.y>0?"positive":"negative";return c>0&&0===a.y0&&(d="subtotal"),"bar fill item"+b+" "+d+" "+a[this.y.$key]}}}},b=function(){return{accessors:{y:function(a){if(d4.isContinuousScale(this.y)){var b=Math.abs(this.y(a.y0)-this.y(a.y0+a.y)),c=a.y0+a.y-Math.max(0,a.y);return this.y(c)-10-b}return this.y(a[this.y.$key])+this.y.rangeBand()/2},x:function(a){if(d4.isOrdinalScale(this.x))return this.x(a[this.x.$key])+this.x.rangeBand()/2;var b=a.y0+a.y-Math.max(0,a.y),c=Math.abs(this.x(a.y0)-this.x(a.y0+a.y));return this.x(b)+10+c},text:function(a){return a[this.valueKey]}}}},c=function(){var a=function(a,b){var c;return"x"===b?[0,a.width]:(c=[0,a.height],d4.isOrdinalScale(a.x)?c.reverse():c)},b=function(b,c,d){var e=d.map(function(a){return a.key}.bind(this));b[c].domain(e).rangeRoundBands(a.bind(this)(b,c),b.xRoundBands||.3)},c=function(b,c,d){var e=d3.extent(d3.merge(d.map(function(a){return d3.extent(a.values,function(a){ +// This is anti-intuative but the stack only returns y and y0 even +// when it applies to the x dimension; +return a.y+a.y0})})));e[0]=d4.isDefined(b[c].$min)?b[c].$min:Math.min(0,e[0]),d4.isDefined(b[c].$max)&&(e[1]=b[c].$max),b[c].domain(e),b[c].range(a.bind(this)(b,c)).clamp(!0).nice()},d=function(a,d){d4.isOrdinalScale(a.x)?(b.bind(this)(a,"x",d),c.bind(this)(a,"y",d)):(b.bind(this)(a,"y",d),c.bind(this)(a,"x",d))},e={link:function(a,b){d.bind(this)(a,b)}};return e};/* + * The waterfall chart visually tallies the cumulative result of negative and + * positive values over a data series. In addition to specifying the normal + * positive and negative values d4's also lets you designate a column as a subtotal + * column by passing in an "e" as the value key, which may be a familiar convention + * if you have used think-cell. + * + * The waterfall chart has two axes (`x` and `y`). By default the stacked + * column expects continious scale for the `y` axis and a discrete scale for + * the `x` axis. This will render the waterfall chart vertically. However, + * if you swap the scale types then the waterfall will render horizontally. + * + *##### Features + * + * `bars` - series of rects + * `connectors` - visual lines that connect the various stacked columns together + * `columnLabels` - column labels which total the values of each rect. + * `xAxis` - the axis for the x dimension + * `yAxis` - the axis for the y dimension + * + *##### Example Usage + * + * var data = [ + * { 'category': 'Job', 'value': 27 }, + * { 'category': 'Groceries', 'value': -3 }, + * { 'category': 'Allowance', 'value': 22 }, + * { 'category': 'Subtotal', 'value': 'e' }, + * { 'category': 'Videos', 'value': -22 }, + * { 'category': 'Coffee', 'value': -4 }, + * { 'category': 'Total', 'value': 'e' } + * ]; + * var parsedData = d4.parsers.waterfall() + * .x(function() { + * return 'category'; + * }) + * .y(function() { + * return 'value'; + * }) + * .nestKey(function() { + * return 'category'; + * })(data); + * + * var chart = d4.charts.waterfall() + * .width($('#example').width()) + * .x(function(x){ + * x.key('category'); + * }) + * .y(function(y){ + * y.key('value'); + * }); + * + * d3.select('#example') + * .datum(parsedData.data) + * .call(chart); + * + * @name waterfall + */ +d4.chart("waterfall",function(d){var e=d||{};return d4.baseChart(d4.extend({builder:c},e)).mixin([{name:"bars",feature:d4.features.rectSeries,overrides:a},{name:"connectors",feature:d4.features.waterfallConnectors},{name:"columnLabels",feature:d4.features.stackedLabels,overrides:b},{name:"xAxis",feature:d4.features.xAxis},{name:"yAxis",feature:d4.features.yAxis}])})}.call(this),function(){"use strict";/* + * Arc labels are used to annotate arc series, for example those created by pie and donut charts. + * Many of the accessors of this feature proxy directly to D3's arc object: + * https://github.com/mbostock/d3/wiki/SVG-Shapes#arc + * + *##### Accessors + * + * `centroid` - proxied accessor to the navtive d3 function + * `classes` - classes assigned to the arc label. + * `duration` - time in milliseconds for the transition to occur. + * `endAngle` - proxied accessor to the navtive d3 function + * `innerRadius` - proxied accessor to the navtive d3 function + * `key` - unique identifier used for linking the element during d3's transition process + * `outerRadius` - proxied accessor to the navtive d3 function + * `startAngle` - proxied accessor to the navtive d3 function + * `text` - value to display in the label. + * `x` - position across the x axis + * `y` - position across the y axis + * + * @name arcLabels + */ +d4.feature("arcLabels",function(a){var b=d3.svg.arc();return{accessors:{classes:function(a,b){return"arc stroke fill series"+b},duration:750,key:d4.functor(d4.defaultKey),text:function(a){return a.value},x:function(){return this.width/2},y:function(){return this.height/2}},proxies:[{target:b}],render:function(c,d,e){var f=function(a){return 180/Math.PI*(a.startAngle+a.endAngle)/2-90},g=function(a){var c=d3.interpolate(this._current,a);return this._current=c(0),function(d){return"translate("+b.centroid(c(d))+") rotate("+f(a)+")"}},h=d4.functor(this.radius).bind(this)(),i=d4.functor(c.accessors.x).bind(this)(),j=d4.functor(c.accessors.y).bind(this)();b.innerRadius(h).outerRadius(h+10);var k=e.selectAll("g."+a).data(d);k.enter().append("g").attr("class",a).attr("transform","translate("+i+","+j+")");var l=k.selectAll("text").data(function(a){return a.values},d4.functor(c.accessors.key).bind(this)); +// update +// create new elements as needed +//remove old elements as needed +return l.transition().duration(d4.functor(c.accessors.duration).bind(this)()).attrTween("transform",g),l.enter().append("text").attr("dy",5).attr("transform",function(a){return"translate("+b.centroid(a)+") rotate("+f(a)+")"}).style("text-anchor","start").text(d4.functor(c.accessors.text).bind(this)).attr("class",d4.functor(c.accessors.classes).bind(this)).attr("data-key",d4.functor(c.accessors.key).bind(this)).attr("d",b).each(function(a){this._current=a}),l.exit().remove(),k.exit().remove(),b}}})}.call(this),function(){"use strict";/* + * Arc series is a collection of arcs suitable for those needed by pie and donut charts. + * Many of the accessors of this feature proxy directly to D3's arc object: + * https://github.com/mbostock/d3/wiki/SVG-Shapes#arc + * + *##### Accessors + * + * `centroid` - proxied accessor to the navtive d3 function + * `classes` - classes assigned to the arc label. + * `duration` - time in milliseconds for the transition to occur. + * `endAngle` - proxied accessor to the navtive d3 function + * `innerRadius` - proxied accessor to the navtive d3 function + * `key` - unique identifier used for linking the element during d3's transition process + * `outerRadius` - proxied accessor to the navtive d3 function + * `startAngle` - proxied accessor to the navtive d3 function + * `x` - position across the x axis + * `y` - position across the y axis + * + * @name arcSeries + */ +d4.feature("arcSeries",function(a){var b=d3.svg.arc();return{accessors:{classes:function(a,b){return"arc stroke fill series"+b},duration:750,key:d4.functor(d4.defaultKey),x:function(){return this.width/2},y:function(){return this.height/2}},proxies:[{target:b}],render:function(c,d,e){ +// extracted from: http://bl.ocks.org/mbostock/1346410 +// Store the displayed angles in _current. +// Then, interpolate from _current to the new angles. +// During the transition, _current is updated in-place by d3.interpolate. +var f=function(a){var c=d3.interpolate(this._current,a);return this._current=c(0),function(a){return b(c(a))}},g=d4.functor(this.radius).bind(this)(),h=d4.functor(c.accessors.x).bind(this)(),i=d4.functor(c.accessors.y).bind(this)(),j=d4.functor(this.arcWidth).bind(this)(g);b.innerRadius(g).outerRadius(g-j);var k=d4.appendOnce(e,"g."+a),l=k.selectAll("g."+a+"-group").data(d);l.enter().append("g"),l.attr("class",a+"-group").attr("transform","translate("+h+","+i+")");var m=l.selectAll("path").data(function(a){return a.values},d4.functor(c.accessors.key).bind(this)); +// update +// create new elements as needed +//remove old elements as needed +return m.enter().append("path").each(function(a){this._current=a}),m.transition().duration(d4.functor(c.accessors.duration).bind(this)()).attrTween("d",f),m.attr("class",d4.functor(c.accessors.classes).bind(this)).attr("data-key",d4.functor(c.accessors.key).bind(this)).attr("d",b),m.exit().remove(),l.exit().remove(),b}}})}.call(this),function(){"use strict";/* + * The arrow feature is a convienient way to visually draw attention to a portion + * of a chart by pointing an arrow at it. + * + * @name arrow + */ +d4.feature("arrow",function(a){return{accessors:{classes:"line",tipSize:6,x1:function(){return this.x(0)},x2:function(){return this.x(this.width)},y1:function(){return this.y(0)},y2:function(){return this.y(this.height)}},render:function(b,c,d){var e=this.container.select("defs");d4.appendOnce(e,"marker#"+a+"-end").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(b.accessors.tipSize).bind(this)).attr("markerHeight",d4.functor(b.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(e,"marker#"+a+"-start").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(b.accessors.tipSize).bind(this)()).attr("markerHeight",d4.functor(b.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(d,"g."+a);var f=d4.appendOnce(this.container.select("."+a),"line").attr("class",d4.functor(b.accessors.classes).bind(this)).attr("x1",d4.functor(b.accessors.x1).bind(this)).attr("x2",d4.functor(b.accessors.x2).bind(this)).attr("y1",d4.functor(b.accessors.y1).bind(this)).attr("y2",d4.functor(b.accessors.y2).bind(this)).attr("marker-end","url(#"+a+"-end)");return f}}})}.call(this),function(){"use strict";d4.feature("brush",function(a){var b=d3.svg.brush(),c=function(a){ +// User passed a d4 scale function directly into the brush's axis accessor. +// User passed a d4 scale function directly into the brush's axis accessor. +return d4.isDefined(a.$scale)?a:d4.functor(a).bind(this)()},d=function(a){return d4.isNull(b.y())?function(b){var c=b[this.x.$key],d=a[0]<=c&&c<=a[1];return d}.bind(this):d4.isNull(b.x())?function(b){var c=b[this.y.$key],d=a[0]<=c&&c<=a[1];return d}.bind(this):d4.isNotNull(b.x())&&d4.isNotNull(b.y())?function(b){var c=a[0][0]<=b[this.x.$key]&&b[this.x.$key]<=a[1][0]&&a[0][1]<=b[this.y.$key]&&b[this.y.$key]<=a[1][1];return c}.bind(this):void 0},e={accessors:{brushable:function(){return d3.selectAll(".brushable")},brushend:function(){this.container.classed("selecting",!d3.event.target.empty())},brushmove:function(){var b=d3.event.target.extent(),c=d.bind(this)(b);this.features[a].accessors.brushable().classed("selected",c)},brushstart:function(){this.container.classed("selecting",!0)},clamp:b.clamp,clear:b.clear,extent:b.extent,empty:b.empty,event:b.event,selection:function(a){return a},x:function(){return null},y:function(){return null}},render:function(d,e,f){var g=c.bind(this)(d.accessors.x),h=c.bind(this)(d.accessors.y);return null!==typeof g&&b.x(g),null!==typeof h&&b.y(h),b.on("brushstart",d4.functor(d.accessors.brushstart).bind(this)).on("brush",d4.functor(d.accessors.brushmove).bind(this)).on("brushend",d4.functor(d.accessors.brushend).bind(this)),d4.appendOnce(f,"g."+a).call(b),d.accessors.selection.bind(this)(f.select(".brush")),b}};return e})}.call(this),function(){"use strict";/* + * The columnLabels feature is used to affix data labels to column series. + * + * @name columnLabels + */ +d4.feature("columnLabels",function(a){ +// FIXME: Remove this hardcoded variable or expose it as a setting. +var b=5,c=function(){return d4.isContinuousScale(this.y)?"middle":"start"};return{accessors:{key:d4.functor(d4.defaultKey),x:function(a,b){var c=this[a];if(d4.isOrdinalScale(c))return c(b[c.$key])+c.rangeBand()/2;var d=Math.abs(c(b[c.$key])-c(0));return c(b[c.$key])-d/2},y:function(a,c){var d=this[a];if(d4.isOrdinalScale(d))return d(c[d.$key])+d.rangeBand()/2+b;var e=Math.abs(d(c[d.$key])-d(0));return(c[d.$key]<0?d(c[d.$key])-e:d(c[d.$key]))-b},text:function(a){return a[this.valueKey]},xScaleId:function(){return"x"},yScaleId:function(){return"y"}},render:function(b,d,e){var f=d4.functor(b.accessors.xScaleId)(),g=d4.functor(b.accessors.yScaleId)(),h=d4.appendOnce(e,"g."+a),i=h.selectAll("text").data(d,d4.functor(b.accessors.key).bind(this));return i.enter().append("text"),i.exit().remove(),i.attr("class","column-label "+a).text(d4.functor(b.accessors.text).bind(this)).attr("text-anchor",c.bind(this)).attr("x",d4.functor(b.accessors.x).bind(this,f)).attr("y",d4.functor(b.accessors.y).bind(this,g)),i}}})}.call(this),function(){"use strict";/* + * This feature allows you to specify a grid over a portion or the entire chart area. + * + * @name grid + */ +d4.feature("grid",function(a){var b=d3.svg.axis(),c=d3.svg.axis();return{accessors:{formatXAxis:function(a){return a.orient("bottom")},formatYAxis:function(a){return a.orient("left")}},proxies:[{target:b,prefix:"x"},{target:c,prefix:"y"}],render:function(d,e,f){b.scale(this.x),c.scale(this.y);var g=d4.functor(d.accessors.formatXAxis).bind(this)(b),h=d4.functor(d.accessors.formatYAxis).bind(this)(c),i=d4.appendOnce(f,"g.grid.border."+a),j=d4.appendOnce(i,"rect"),k=d4.appendOnce(i,"g.x.grid."+a),l=d4.appendOnce(i,"g.y.grid."+a);return j.attr("transform","translate(0,0)").attr("x",0).attr("y",0).attr("width",this.width).attr("height",this.height),k.attr("transform","translate(0,"+this.height+")").call(g.tickSize(-this.height,0,0).tickFormat("")),l.attr("transform","translate(0,0)").call(h.tickSize(-this.width,0,0).tickFormat("")),i}}})}.call(this),function(){"use strict";/* + * This feature is specifically designed to use with the groupedColumn and groupedRow charts. + * + * @name groupedColumnSeries + */ +d4.feature("groupedColumnSeries",function(a){var b=function(a){return a>0?"positive":"negative"},c=function(a){return this.groups(a[this.groups.$key])},d=function(a){var b,c=this.groups.$dimension,d=this[c],e=d(a.values[0][d.$key]);return"x"===c?b=[e,0]:"y"===c&&(b=[0,e]),"translate("+b+")"},e=function(){return this.groups.rangeBand()},f=function(a,b){var c=this[a],d=c.domain()[0],e=0>d?0:d;return Math.abs(c(b[c.$key])-c(e))},g=function(a,b){var c,d=this[a];return"y"===a?d(b[d.$key]<0?0:b[d.$key]):(c=b[d.$key]-Math.max(0,b[d.$key]),d(c))};return{accessors:{classes:function(a,c){return"bar fill item"+c+" "+b(a[this.valueKey])+" "+a[this.valueKey]},height:function(a,b){return d4.isOrdinalScale(this.y)?e.bind(this)(a):f.bind(this)(a,b)},key:d4.functor(d4.defaultKey),rx:0,ry:0,width:function(a,b){return d4.isOrdinalScale(this.x)?e.bind(this)():f.bind(this)(a,b)},groupPositions:function(a,b){return d.bind(this)(a,b)},x:function(a,b){return d4.isOrdinalScale(this.x)?c.bind(this)(a):g.bind(this)("x",a,b)},y:function(a,b){return d4.isOrdinalScale(this.y)?c.bind(this)(a):g.bind(this)("y",a,b)},xScaleId:function(){return"x"},yScaleId:function(){return"y"}},render:function(b,c,d){c.length>0&&(this.groupsOf=this.groupsOf||c[0].values.length);var e=d4.functor(b.accessors.xScaleId)(),f=d4.functor(b.accessors.yScaleId)(),g=d4.appendOnce(d,"g."+a),h=g.selectAll("g").data(c,d4.functor(b.accessors.key).bind(this));h.enter().append("g"),h.attr("class",function(a,b){return"series"+b+" "+this.x.$key}.bind(this)).attr("transform",d4.functor(b.accessors.groupPositions).bind(this));var i=h.selectAll("rect").data(function(a){return a.values}.bind(this));return i.enter().append("rect"),i.attr("class",d4.functor(b.accessors.classes).bind(this)).attr("x",d4.functor(b.accessors.x).bind(this)).attr("y",d4.functor(b.accessors.y).bind(this)).attr("ry",d4.functor(b.accessors.ry).bind(this)).attr("rx",d4.functor(b.accessors.rx).bind(this)).attr("width",d4.functor(b.accessors.width).bind(this,e)).attr("height",d4.functor(b.accessors.height).bind(this,f)),i.exit().remove(),h.exit().remove(),i}}})}.call(this),function(){"use strict";/* + * Approach based off this example: + * http://bl.ocks.org/mbostock/3902569 + * + * @name lineSeriesLabels + */ +d4.feature("lineSeriesLabels",function(a){var b=function(b,c){var d=this.container.select("."+a).selectAll("."+a+" circle.dataPoint").data(c);d.enter().append("circle"),d.exit().remove(),d.attr("data-key",d4.functor(b.accessors.key).bind(this)).style("display","none").attr("r",d4.functor(b.accessors.r).bind(this)()).attr("class",function(a,c){return d4.functor(b.accessors.classes).bind(this)(a,c)+" dataPoint"}.bind(this))},c=function(b,c){var d=this.container.select("."+a).selectAll("."+a+" text.dataPoint").data(c);d.enter().append("text"),d.exit().remove(),d.attr("data-key",d4.functor(b.accessors.key).bind(this)).style("display","none").attr("class",function(a,c){return d4.functor(b.accessors.classes).bind(this)(a,c)+" dataPoint"}.bind(this))},d=function(b){this.container.select("."+a).append("rect").attr("class","overlay").style("fill-opacity",0).attr("width",this.width).attr("height",this.height).on("mouseover",function(){this.container.selectAll("."+a+" .dataPoint").style("display",null)}.bind(this)).on("mouseout",function(){this.container.selectAll("."+a+" .dataPoint").style("display","none")}.bind(this)).on("mousemove",d4.functor(b.accessors.mouseMove).bind(this))},e=function(a,e){d4.functor(a.accessors.displayPointValue).bind(this)()&&(d4.isNotFunction(this.x.invert)?d4.err(" In order to track the x position of a line series your scale must have an invert() function. However, your {0} scale does not have the invert() function.",this.x.$scale):(c.bind(this)(a,e),b.bind(this)(a,e),d.bind(this)(a)))};return{accessors:{classes:function(a,b){return"stroke series"+b},displayPointValue:!1,key:d4.functor(d4.defaultKey),mouseMove:function(b){var c=function(a,b){return"time"===this.x.$scale?a.getTime()>=b[this.x.$key].getTime():a>=b[this.x.$key]},d=d3.bisector(function(a){return a[this.x.$key]}.bind(this)).right,e=this.container.select("."+a+" rect.overlay")[0][0],f=this.x.invert(d3.mouse(e)[0]);d4.each(b,function(b,e){var g=d(b.values,f,1),h=b.values[g-1];if(c.bind(this)(f,h)){var i=b.values[g];i=d4.isUndefined(i)?b.values[b.values.length-1]:i;var j=f-h[this.x.$key]>i[this.x.$key]-f?i:h;d4.functor(this.features[a].accessors.showDataPoint).bind(this)(j,b,e),d4.functor(this.features[a].accessors.showDataLabel).bind(this)(j,b,e)}else{var k="."+a+' .dataPoint[data-key="'+d4.functor(this.features[a].accessors.key).bind(this)(b,e)+'"]',l=this.container.select(k);l.style("display","none")}}.bind(this))},pointLabelText:function(a,b){var c=b.key+" "+this.x.$key+": "+a[this.x.$key];return c+=" "+this.y.$key+": "+a[this.y.$key]},r:4.5,showDataLabel:function(b,c,d){var e="."+a+' text.dataPoint[data-key="'+d4.functor(this.features[a].accessors.key).bind(this)(c,d)+'"]',f=this.container.select(e),g=20*d;f.style("display",null).attr("transform","translate(5,"+g+")").text(d4.functor(this.features[a].accessors.pointLabelText).bind(this)(b,c))},showDataPoint:function(b,c,d){var e="."+a+' circle.dataPoint[data-key="'+d4.functor(this.features[a].accessors.key).bind(this)(c,d)+'"]',f=this.container.select(e);f.style("display",null).attr("transform","translate("+this.x(b[this.x.$key])+","+this.y(b[this.y.$key])+")")},text:function(a){return a.key},x:function(a){return this.x(a.values[a.values.length-1][this.x.$key])},y:function(a){return this.y(a.values[a.values.length-1][this.y.$key])}},render:function(b,c,d){var f=d4.appendOnce(d,"g."+a),g=f.selectAll(".seriesLabel").data(c);return g.enter().append("text"),g.text(d4.functor(b.accessors.text).bind(this)).attr("x",d4.functor(b.accessors.x).bind(this)).attr("y",d4.functor(b.accessors.y).bind(this)).attr("data-key",d4.functor(b.accessors.key).bind(this)).attr("class",function(a,c){return d4.functor(b.accessors.classes).bind(this)(a,c)+" seriesLabel"}.bind(this)),e.bind(this)(b,c,d),g.exit().remove(),g}}})}.call(this),function(){"use strict";/* + * + * @name lineSeries + */ +d4.feature("lineSeries",function(a){var b=d3.svg.line();return b.interpolate("linear"),{accessors:{classes:function(a,b){return"line stroke series"+b},key:d4.functor(d4.defaultKey),x:function(a){return this.x(a[this.x.$key])},y:function(a){return this.y(a[this.y.$key])}},proxies:[{target:b}],render:function(c,d,e){var f=d4.appendOnce(e,"g."+a);b.x(d4.functor(c.accessors.x).bind(this)).y(d4.functor(c.accessors.y).bind(this));var g=f.selectAll("g").data(d,d4.functor(c.accessors.key).bind(this));g.enter().append("g").attr("data-key",function(a){return a.key}).attr("class",d4.functor(c.accessors.classes).bind(this));var h=g.selectAll("path").data(function(a){return[a]});return h.enter().append("path"),h.attr("d",function(a){return b(a.values)}),h.exit().remove(),g.exit().remove(),g}}})}.call(this),function(){"use strict";/* + * The reference line feature is helpful when you want to apply a line to a chart + * which demarcates a value within the data. For example a common use of this + * feature is to specify the zero value across an axis. + * + * @name referenceLine + */ +d4.feature("referenceLine",function(a){return{accessors:{x1:function(){return this.x(this.x.domain()[0])},x2:function(){return this.x(this.x.domain()[1])},y1:function(){return this.y(this.y.domain()[1])},y2:function(){return this.y(this.y.domain()[0])},classes:function(){return"line"}},render:function(b,c,d){var e=d4.appendOnce(d,"g."+a),f=d4.appendOnce(e,"line");return e.select("line").attr("class",d4.functor(b.accessors.classes).bind(this)).attr("x1",d4.functor(b.accessors.x1).bind(this)).attr("x2",d4.functor(b.accessors.x2).bind(this)).attr("y1",d4.functor(b.accessors.y1).bind(this)).attr("y2",d4.functor(b.accessors.y2).bind(this)),f}}})}.call(this),function(){"use strict";/* + * Column connectors helpful when displaying a stacked column chart. + * A connector will not connect positve and negative columns. This is because + * in a stacked column a negative column may move many series below its previous + * location. This creates a messy collection of crisscrossing lines. + * + * @name stackedColumnConnectors + */ +d4.feature("stackedColumnConnectors",function(a){var b=function(a){return a?0>a?-1:1:0},c=function(a,c,d){return b(a[d])===b(c[d])},d=function(a,b,d,e,f){var g=d4.isOrdinalScale(this.y)?this.x.$key:this.y.$key;return 0!==b&&c(e[d].values[b-1],a,g)?f.bind(this)():0};return{accessors:{x1:function(a){return d4.isOrdinalScale(this.x)?this.x(a[this.x.$key]):this.x(a.y0+a.y)},y1:function(a){return d4.isOrdinalScale(this.y)?this.y(a[this.y.$key]):this.y(a.y0+a.y)},size:function(){return d4.isOrdinalScale(this.x)?this.x.rangeBand():this.y.rangeBand()},classes:function(a,b){return"series"+b}},render:function(b,c,e){var f=d4.appendOnce(e,"g."+a),g=f.selectAll("g").data(c);g.enter().append("g").attr("class",function(a,b){return"series"+b+" "+this.y.$key}.bind(this));var h=g.selectAll("line").data(function(a){return a.values}.bind(this));return h.enter().append("line"),h.attr("class",d4.functor(b.accessors.classes).bind(this)).attr("stroke-dasharray","5, 5").attr("x1",function(a,e,f){return d.bind(this)(a,e,f,c,function(){return d4.functor(b.accessors.x1).bind(this)(a)})}.bind(this)).attr("y1",function(a,e,f){var g=d4.isOrdinalScale(this.y)?d4.functor(b.accessors.size).bind(this)(a):0;return d.bind(this)(a,e,f,c,function(){return d4.functor(b.accessors.y1).bind(this)(a)+g})}.bind(this)).attr("x2",function(a,e,f){var g=d4.isOrdinalScale(this.x)?b.accessors.size.bind(this)(a):0;return d.bind(this)(a,e,f,c,function(){return d4.functor(b.accessors.x1).bind(this)(c[f].values[e-1])+g})}.bind(this)).attr("y2",function(a,e,f){return d.bind(this)(a,e,f,c,function(){return d4.functor(b.accessors.y1).bind(this)(c[f].values[e-1])})}.bind(this)),g.exit().remove(),h.exit().remove(),h}}})}.call(this),function(){"use strict";/* + * The stackedLabels are appropriate for use with the stacked shape series. + * + * @name stackedLabels + */ +d4.feature("stackedLabels",function(a){ +// FIXME: We should not need to sniff this out. +var b=function(a){return d4.isDefined(a.y0)?!0:d4.isContinuousScale(this.y)},c=function(a){return b.bind(this)(a)?"middle":"start"},d=function(a,b){var c=this[a];return c(b[c.$key])+c.rangeBand()/2},e=function(a,b){var c,d=this[a],e=Math.abs(d(b.y0)-d(b.y0+b.y))/2,f=10;return"x"===a&&(e*=-1,f*=-1),d4.isDefined(b.y0)?(c=b.y0+b.y,d(0>=c?b.y0:c)+e):d(b[d.$key]<=0?0:b[d.$key])-f};return{accessors:{classes:"column-label",key:d4.functor(d4.defaultKey),stagger:!0,text:function(a){if(!d4.isDefined(a.y0))return a[this.valueKey];if(d4.isOrdinalScale(this.x)){if(Math.abs(this.y(a.y0)-this.y(a.y0+a.y))>20)return a[this.valueKey]}else if(Math.abs(this.x(a.y0)-this.x(a.y0+a.y))>20)return a[this.valueKey]},textAnchor:function(a){return c.bind(this)(a)},x:function(a){return d4.isOrdinalScale(this.x)?d.bind(this)("x",a):e.bind(this)("x",a)},y:function(a){return d4.isOrdinalScale(this.y)?d.bind(this)("y",a):e.bind(this)("y",a)}},render:function(b,c,d){var e=d4.appendOnce(d,"g."+a),f=e.selectAll("g").data(c,d4.functor(b.accessors.key).bind(this));f.enter().append("g").attr("class",function(a,b){return"series"+b+" "+this.x.$key}.bind(this)),f.exit().remove();var g=f.selectAll("text").data(function(a){return a.values}.bind(this)); +// FIXME: This should be moved into a helper injected using DI. +return g.enter().append("text"),g.text(d4.functor(b.accessors.text).bind(this)).attr("text-anchor",d4.functor(b.accessors.textAnchor).bind(this)).attr("class",d4.functor(b.accessors.classes).bind(this)).attr("y",d4.functor(b.accessors.y).bind(this)).attr("x",d4.functor(b.accessors.x).bind(this)),d4.functor(b.accessors.stagger).bind(this)()&&(d4.isContinuousScale(this.y)?e.selectAll("text").call(d4.helpers.staggerTextVertically,-1):e.selectAll("text").call(d4.helpers.staggerTextHorizontally,1)),e.selectAll("text").call(function(a){var b;d4.each(a,function(a){d4.each(a,function(a){var c=d3.select(a);b=a.getBoundingClientRect(),null===c.attr("transform")&&c.attr("transform","translate(0,"+Math.floor(b.height/2)+")")})})}),f.exit().remove(),g.exit().remove(),g}}})}.call(this),function(){"use strict";var a=function(a){return a>0?"positive":"negative"},b=function(a,b){var c=this[a];return c(b[c.$key])},c=function(a){var b=this[a];return b.rangeBand()},d=function(a,b){var c=this[a],d=c.domain()[0],e=Math.max(d,0);return d4.isDefined(b.y0)?Math.abs(c(b.y0)-c(b.y0+b.y)):Math.abs(c(b[c.$key])-c(e))},e=function(a,b){var c,d=this[a];return d4.isDefined(b.y0)?"y"===a?(c=b.y0+b.y,d(0>c?b.y0:c)):(c=b.y0+b.y-Math.max(0,b.y),d(c)):"y"===a?d(b[d.$key]<0?0:b[d.$key]):(c=b[d.$key]-Math.max(0,b[d.$key]),d(c))},f=function(b,c,d){return{accessors:{classes:function(b,c){return"bar fill item"+c+" "+a(b[this.valueKey])+" "+b[this.y.$key]},key:d4.functor(d4.defaultKey)},render:function(a,e,f){var g=d4.appendOnce(f,"g."+b),h=g.selectAll("g").data(e,d4.functor(a.accessors.key).bind(this));h.enter().append("g").attr("class",function(a,b){return"series"+b+" "+this.y.$key}.bind(this)),h.exit().remove();var i=h.selectAll(c).data(function(a){return a.values});return i.enter().append(c).attr("class",d4.functor(a.accessors.classes).bind(this)),d.bind(this)(a,i),i.exit().remove(),h.exit().remove(),i}}};/** + * This feature is useful for displaying charts which need stacked circles. + * Note: Many of the d4 charts use the stacked series as the base, and simply + * renders only one series, if there is nothing to stack. + * + *##### Accessors + * + * `classes` - classes assigned to each circle in the series + * `cx` - placement on the chart's x axis + * `cy` - placement on the chart's y axis + * `r` - radius of the circle + * + * @name circleSeries + */ +d4.feature("circleSeries",function(a){var g={accessors:{cx:function(a){var f=0;return d4.isOrdinalScale(this.x)?(f=c.bind(this)("x"),b.bind(this)("x",a)+f/2):(f=d.bind(this)("x",a),e.bind(this)("x",a)+f/2)},cy:function(a){var f=0;return d4.isOrdinalScale(this.y)?(f=c.bind(this)("y"),b.bind(this)("y",a)+f/2):(f=d.bind(this)("y",a),e.bind(this)("y",a)+f/2)},r:function(a){var b,e;return b=d4.isOrdinalScale(this.x)?c.bind(this)("x"):d.bind(this)("x",a),e=d4.isOrdinalScale(this.y)?c.bind(this)("y"):d.bind(this)("y",a),Math.min(b,e)/2}}},h=function(a,b){b.attr("r",d4.functor(a.accessors.r).bind(this)).attr("cx",d4.functor(a.accessors.cx).bind(this)).attr("cy",d4.functor(a.accessors.cy).bind(this))},i=f.bind(this)(a,"circle",h);return d4.merge(i,g)}),/** + * This feature is useful for displaying charts which need stacked ellipses. + * Note: Many of the d4 charts use the stacked series as the base, and simply + * renders only one series, if there is nothing to stack. + * + *##### Accessors + * + * `classes` - classes assigned to each ellipse in the series + * `cx` - placement on the chart's x axis + * `cy` - placement on the chart's y axis + * `rx` - radius of the ellipse on the x axis + * `ry` - radius of the ellipse on the y axis + * + * @name ellipseSeries + */ +d4.feature("ellipseSeries",function(a){var g={accessors:{cx:function(a){var f=0;return d4.isOrdinalScale(this.x)?(f=c.bind(this)("x"),b.bind(this)("x",a)+f/2):(f=d.bind(this)("x",a),e.bind(this)("x",a)+f/2)},cy:function(a){var f=0;return d4.isOrdinalScale(this.y)?(f=c.bind(this)("y"),b.bind(this)("y",a)+f/2):(f=d.bind(this)("y",a),e.bind(this)("y",a)+f/2)},rx:function(a){return d4.isOrdinalScale(this.x)?c.bind(this)("x")/2:d.bind(this)("x",a)/2},ry:function(a){return d4.isOrdinalScale(this.y)?c.bind(this)("y")/2:d.bind(this)("y",a)/2}}},h=function(a,b){b.attr("rx",d4.functor(a.accessors.rx).bind(this)).attr("ry",d4.functor(a.accessors.ry).bind(this)).attr("cx",d4.functor(a.accessors.cx).bind(this)).attr("cy",d4.functor(a.accessors.cy).bind(this))},i=f.bind(this)(a,"ellipse",h);return d4.merge(i,g)}),/** + * This feature is useful for displaying charts which need stacked rects. + * Note: Many of the d4 charts use the stacked series as the base, and simply + * renders only one series, if there is nothing to stack. + * + *##### Accessors + * + * `classes` - classes assigned to each rect in the series + * `height` - height of the rect + * `rx` - rounding of the corners against the x dimension + * `ry` - rounding of the corners against the y dimension + * `width` - width of the rect + * `x` - placement on the chart's x axis + * `y` - placement on the chart's y axis + * + * @name rectSeries + */ +d4.feature("rectSeries",function(a){var g={accessors:{height:function(a,b){return d4.isOrdinalScale(this[a])?c.bind(this)(a):d.bind(this)(a,b)},rx:0,ry:0,width:function(a,b){return d4.isOrdinalScale(this[a])?c.bind(this)(a):d.bind(this)(a,b)},x:function(a){return d4.isOrdinalScale(this.x)?b.bind(this)("x",a):e.bind(this)("x",a)},y:function(a){return d4.isOrdinalScale(this.y)?b.bind(this)("y",a):e.bind(this)("y",a)},xScaleId:function(){return"x"},yScaleId:function(){return"y"}}},h=function(a,b){var c=d4.functor(a.accessors.xScaleId)(),d=d4.functor(a.accessors.yScaleId)();b.attr("x",d4.functor(a.accessors.x).bind(this)).attr("y",d4.functor(a.accessors.y).bind(this)).attr("ry",d4.functor(a.accessors.ry).bind(this)).attr("rx",d4.functor(a.accessors.rx).bind(this)).attr("width",d4.functor(a.accessors.width).bind(this,c)).attr("height",d4.functor(a.accessors.height).bind(this,d))},i=f.bind(this)(a,"rect",h);return d4.merge(i,g)})}.call(this),function(){"use strict";/* + * A trendline allows you to associate a line with a numerical value. + * + * @name trendLine + */ +d4.feature("trendLine",function(a){return{accessors:{tipSize:6,text:function(a){return a[this.valueKey]},textX:function(){return this.x(this.width)},textY:function(){return this.x(this.height)},x1:function(){return this.x(this.x.$key)},x2:function(){return this.x(this.width)},y1:function(){return this.y(this.y.$key)},y2:function(){return this.y(this.height)}},render:function(b,c,d){var e=this.container.select("defs");d4.appendOnce(e,"marker#"+a+"-start").attr("viewBox","0 0 10 10").attr("refX",10).attr("refY",5).attr("markerWidth",d4.functor(b.accessors.tipSize).bind(this)()).attr("markerHeight",d4.functor(b.accessors.tipSize).bind(this)).attr("orient","auto").append("path").attr("d","M 0 0 L 10 5 L 0 10 z"),d4.appendOnce(d,"g."+a);var f=d4.appendOnce(this.container.select("."+a),"line.line").attr("x1",d4.functor(b.accessors.x1).bind(this)).attr("x2",d4.functor(b.accessors.x2).bind(this)).attr("y1",d4.functor(b.accessors.y1).bind(this)).attr("y2",d4.functor(b.accessors.y2).bind(this)).attr("marker-end","url(#"+a+"-start)");return d4.appendOnce(this.container.select("."+a),"text.trendLine-label").text(d4.functor(b.accessors.text).bind(this)).attr("x",d4.functor(b.accessors.textX).bind(this)).attr("y",d4.functor(b.accessors.textY).bind(this)),f}}})}.call(this),function(){"use strict";/* + * Waterfall connectors are orthogonal series connectors which visually join + * column series together by spanning the top or bottom of adjacent columns. + * + *##### Accessors + * + * `x` - Used in placement of the connector lines. + * `y` - Used in placement of the connector lines. + * `span` - calculates the length of the connector line + * `classes` - applies the class to the connector lines. + * + * @name waterfallConnectors + */ +d4.feature("waterfallConnectors",function(a){return{accessors:{beforeRender:function(a){var b=a.map(function(a){return a.values[0]});return d4.flatten(b)},classes:function(a,b){return"series"+b},span:function(){return d4.isOrdinalScale(this.x)?this.x.rangeBand():this.y.rangeBand()},x:function(a){if(d4.isOrdinalScale(this.x))return this.x(a[this.x.$key]);var b=0,c=a.y0+a.y-Math.max(0,a.y);return a.y>0&&(b=Math.abs(this.x(a.y0)-this.x(a.y0+a.y))),this.x(c)+b},y:function(a){return d4.isOrdinalScale(this.x)?this.y(a.y0+a.y):this.y(a[this.y.$key])}},render:function(b,c,d){var e=d4.appendOnce(d,"g."+a),f=e.selectAll("line").data(c);return f.enter().append("line"),f.exit().remove(),f.attr("class",d4.functor(b.accessors.classes).bind(this)).attr("x1",function(a,d){return 0===d?0:d4.functor(b.accessors.x).bind(this)(c[d-1])}.bind(this)).attr("y1",function(a,d){return 0===d?0:d4.functor(b.accessors.y).bind(this)(c[d-1])}.bind(this)).attr("x2",function(a,d){return 0===d?0:d4.isOrdinalScale(this.x)?d4.functor(b.accessors.x).bind(this)(a)+d4.functor(b.accessors.span).bind(this)():d4.functor(b.accessors.x).bind(this)(c[d-1])}.bind(this)).attr("y2",function(a,d){return 0===d?0:d4.isOrdinalScale(this.x)?d4.functor(b.accessors.y).bind(this)(c[d-1]):d4.functor(b.accessors.y).bind(this)(a)+d4.functor(b.accessors.span).bind(this)(a)}.bind(this)),f}}})}.call(this),function(){"use strict";/* This feature creates an xAxis for use within d4. There are a variety of + * accessors described below which modify the behavior and apperance of the axis. + * + *##### Accessors + * + * `axis` - The d3 axis object itself. + * `innerTickSize` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#innerTickSize + * `orient` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#orient + * `outerTickSize`- see: https://github.com/mbostock/d3/wiki/SVG-Axes#outerTickSize + * `scale` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#scale + * `stagger` - (true | false) determines if the axis should stagger overlapping text (true by default) + * `tickFormat` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickFormat + * `tickPadding` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickPadding + * `tickSize` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickSize + * `tickSubdivide`- see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickSubdivide + * `tickValues` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickValues + * `ticks` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#ticks + * + * + * var chart = d4.charts.groupedColumn() + * .using('yAxis', function(axis){ + * + * // adjust the number of tick marks based on the height of the chart + * axis.ticks($('#example').height()/20); + * + * // set the inner and outer tick sizes + * axis.tickSize(10,5); + * + * // adjust the tick padding + * axis.tickPadding(5); + * + * }) + * .using('xAxis', function(axis){ + * + * // position the tickmarks on the top of the axis line + * axis.orient('top'); + * + * // move the axis to the top of the chart. + * axis.align('top'); + * }) + * + * @name xAxis + */ +d4.feature("xAxis",function(a){var b=d3.svg.axis().orient("bottom").tickPadding(10).tickSize(0),c=function(a,b){var c=d4.helpers.textSize(a,b);return c.text=a,c},d=function(a,b,c,d){if(a.text){var e=this.container.selectAll("."+d+".axis"),f=e.node().getBBox(),g=.8*a.height,h=e.append("text").text(a.text).attr("class",""+c);"bottom"===b.toLowerCase()?h.attr("transform","translate(0,"+(f.height+g)+")"):h.attr("transform","translate(0,"+(f.y-g/2)+")")}},e=function(a,b){switch(!0){case"top"===a.toLowerCase():b.attr("transform","translate(0,0)");break;case"bottom"===a.toLowerCase():b.attr("transform","translate(0,"+this.height+")")}},f={accessors:{align:"bottom",stagger:!0,subtitle:void 0,title:void 0,scaleId:function(){return"x"}},proxies:[{target:b}],render:function(f,g,h){var i=d4.functor(f.accessors.scaleId).bind(this)();f.scale(this[i]);var j=c(d4.functor(f.accessors.title).bind(this)(),"title"),k=c(d4.functor(f.accessors.subtitle).bind(this)(),"subtitle"),l=d4.functor(f.accessors.align).bind(this)(),m=d4.appendOnce(h,"g."+i+".axis."+a).attr("data-scale",this[i].$scale).call(b); +// FIXME: This should be moved into a helper injected using DI. +return e.bind(this)(l,m),d4.functor(f.accessors.stagger).bind(this)()&&m.selectAll(".tick text").call(d4.helpers.staggerTextVertically,1),"top"===l?(d.bind(this)(k,l,"subtitle",i),d.bind(this)(j,l,"title",i)):(d.bind(this)(j,l,"title",i),d.bind(this)(k,l,"subtitle",i)),m}};return f})}.call(this),function(){"use strict";/* This feature creates an xAxis for use within d4. There are a variety of + * accessors described below which modify the behavior and apperance of the axis. + * + *##### Accessors + * `axis` - The d3 axis object itself. + * `innerTickSize` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#innerTickSize + * `orient` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#orient + * `outerTickSize`- see: https://github.com/mbostock/d3/wiki/SVG-Axes#outerTickSize + * `scale` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#scale + * `stagger` - (true | false) determines if the axis should stagger overlapping text (true by default) + * `tickFormat` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickFormat + * `tickPadding` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickPadding + * `tickSize` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickSize + * `tickSubdivide`- see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickSubdivide + * `tickValues` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#tickValues + * `ticks` - see: https://github.com/mbostock/d3/wiki/SVG-Axes#ticks + * + *##### Examples + * + * var chart = d4.charts.groupedColumn() + * .using('yAxis', function(axis){ + * + * // adjust the number of tick marks based on the height of the chart + * axis.ticks($('#example').height()/20); + * + * // set the inner and outer tick sizes + * axis.tickSize(10,5); + * + * // adjust the tick padding + * axis.tickPadding(5); + * + * }) + * .using('xAxis', function(axis){ + * + * // position the tickmarks on the top of the axis line + * axis.orient('top'); + * + * // move the axis to the top of the chart. + * axis.y(-20); + * }) + * + * @name yAxis + */ +d4.feature("yAxis",function(a){var b=d3.svg.axis().orient("left").tickPadding(10).tickSize(0),c=function(a,b){var c=d4.helpers.textSize(a,b);return c.text=a,c},d=function(a,b,c,d){if(a.text){var e=this.container.selectAll("."+d+".axis"),f=e.node().getBBox(),g=.8*a.height,h=e.append("text").text(a.text).attr("class",""+c);"left"===b.toLowerCase()?h.call(d4.helpers.rotateText("rotate(90)translate(0,"+(Math.abs(f.x)+g)+")")):h.call(d4.helpers.rotateText("rotate(90)translate(0,"+(Math.abs(f.x)-(f.width+g))+")"))}},e=function(a,b){switch(!0){case"left"===a.toLowerCase():b.attr("transform","translate(0,0)");break;case"right"===a.toLowerCase():b.attr("transform","translate("+this.width+", 0)")}},f={accessors:{align:"left",stagger:!0,subtitle:void 0,title:void 0,scaleId:function(){return"y"}},proxies:[{target:b}],render:function(f,g,h){var i=d4.functor(f.accessors.scaleId).bind(this)();f.scale(this[i]);var j=c(d4.functor(f.accessors.title).bind(this)(),"title"),k=c(d4.functor(f.accessors.subtitle).bind(this)(),"subtitle"),l=d4.functor(f.accessors.align).bind(this)(),m=d4.appendOnce(h,"g."+i+".axis."+a).attr("data-scale",this[i].$scale).call(b); +// FIXME: This should be moved into a helper injected using DI. +return m.selectAll(".tick text").call(d4.helpers.wrapText,this.margin[l]),e.bind(this)(l,m),d4.functor(f.accessors.stagger).bind(this)()&&this.container.selectAll("."+i+".axis .tick text").call(d4.helpers.staggerTextHorizontally,-1),"left"===l?(d.bind(this)(j,l,"title",i),d.bind(this)(k,l,"subtitle",i)):(d.bind(this)(k,l,"subtitle",i),d.bind(this)(j,l,"title",i)),m}};return f})}.call(this),function(){"use strict";/** + * The nested group parser is useful for grouped column charts where multiple + * data items need to appear relative to the axis value, for example grouped + * column charts or multi-series line charts. + * + * _____________________ + * | _ | + * | _ _ | |_ | + * | | | | | | | | + * ---------------------- + * + * This module makes use of the d3's "nest" data structure layout + * + * https://github.com/mbostock/d3/wiki/Arrays#-nest + * + *##### Approach + * + * Just like D3, this parser uses a chaining declaritiave style to build up + * the necessary prerequistes to create the waterfall data. Here is a simple + * example. Given a data item structure like this: {"category" : "Category One", "value" : 23 } + * + * var parser = d4.parsers.nestedGroup() + * .x('category') + * .y('value') + * .value('value'); + * + * var groupedColumnData = parser(data); + * + * Keep reading for more information on these various accessor functions. + * + *##### Accessor Methods + * + * `x` - A function which returns a key to access the x values in the data array + * `y` - A function which returns a key to access the y values in the data array + * `value` - A function which returns a key to access the values in the data array. + * `data` - An array of objects with their dimensions specified like this: + * + * var data = [ + * {"year" : "2010", "category" : "Category One", "value" : 23 }, + * {"year" : "2010", "category" : "Category Two", "value" : 55 }, + * {"year" : "2010", "category" : "Category Three", "value" : -10 }, + * {"year" : "2010", "category" : "Category Four", "value" : 5 }] + * + * @name nestedGroup + **/ +d4.parser("nestedGroup",function(){var a={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};a.defined=function(){return!0},a.nestKey=function(){return a.x.key};var b=function(b){var c=[];return d4.each(b,function(b){a.defined(b)&&c.push(b)}.bind(this)),c},c=function(b,c){["x","y","value"].forEach(function(d){var e=c.map(function(a){return a[b[d].key]});a[d].values=d3.set(e).values()})},d=function(a,b,c){var d=d3.nest().key(function(b){return b[a]});return d.entries(c)},e=function(b,c){a[b].key=d4.functor(c)()},f=function(e){return e&&d4.extend(a.data,e),c(a,a.data),a.data=b(a.data),a.data=d(a.nestKey(),a.value.key,a.data),a};return f.nestKey=function(b){return a.nestKey=d4.functor(b).bind(a),f},f.defined=function(b){return a.defined=d4.functor(b).bind(a),f},d4.each(["x","y","value"],function(b){f[b]=function(c){return e.bind(a)(b,d4.functor(c)),f}}.bind(this)),f})}.call(this),function(){"use strict";/** + * The nested stack parser is useful for charts which take a data series + * and wants to sort them across a dimension and then display the results. + * The most common usecase would be a stacked column chart like this: + * + * _____________________ + * | _ | + * | | | _ | + * | |-| | | _ | + * | |-| |-| |-| | + * | | | |-| |-| | + * ---------------------- + * + * This module makes use of the d3's "nest" data structure, and "stack" layout + * + * + https://github.com/mbostock/d3/wiki/Arrays#-nest + * + https://github.com/mbostock/d3/wiki/Stack-Layout + * + *##### Approach + * + * Just like D3, this parser uses a chaining declaritiave style to build up + * the necessary prerequistes to create the stacked data. Here is a simple + * example: + * + * var parser = d4.parsers.nestedStack() + * .x(function() { + * return 'title'; + * }) + * .y(function(){ + * return 'group'; + * }) + * .value(function() { + * return 'values'; + * }); + * + * var stackedData = parser(data); + * + * Keep reading for more information on these various accessor functions. + * + *##### Benefits + * + Supports negative and positive stacked data series. + * + *##### Limitations + * + The parser expects the stack will occur on the yAxis, which means it is only suitable for column charts presently. + * + *##### Accessor Methods + * + * `x` : - function which returns a key to access the x values in the data array + * `y` : - function which returns a key to access the y values in the data array + * `value` : - function which returns a key to access the values in the data array. + * `data` : array - An array of objects with their dimensions specified like this: + * + * var data = [{ "title": "3 Years", "group" : "one", "value": 30 }, + * { "title": "3 Years", "group" : "two", "value": 20 }, + * { "title": "3 Years", "group" : "three", "value": 10 }, + * { "title": "5 Years", "group" : "one", "value": 3 }, + * { "title": "5 Years", "group" : "two", "value": 2 }, + * { "title": "5 Years", "group" : "three", "value": 1 }] + * + *##### Example Usage + * + * Given the example data and dimension variables above you can use this module + * in the following way: + * + * var parser = d4.parsers.nestedStack() + * .x(function() { + * return 'title'; + * }) + * .y(function(){ + * return 'group'; + * }) + * .value(function() { + * return 'value'; + * }) + * .call(data); + * + * The `parser` variable will now be an object containing the following structure: + * + * { + * data: Array + * value: { + * key: string, + * values: Array + * }, + * x: { + * key: string, + * values: Array + * }, + * y: { + * key: string, + * values: Array + * } + * } + * + * @name nestedStack + **/ +d4.parser("nestedStack",function(){var a={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};a.defined=function(){return!0},a.nestKey=function(){return a.y.key};var b=function(b){var c=[];return d4.each(b,function(b){a.defined(b)&&c.push(b)}.bind(this)),c},c=function(b,c){["x","y","value"].forEach(function(d){var e=c.map(function(a){return a[b[d].key]});a[d].values=d3.set(e).values()})},d=function(a,b,c){var d=d3.nest().key(function(b){return b[a]});return d.entries(c)},e=function(b,c){var d={},e=d3.layout.stack().values(function(a){return a.values}).x(function(a){return a[b]}).y(function(b){return+b[a.value.key]}).out(function(a,c,e){a.y=e,a.y>=0?(a.y0=d[a[b]+"Pos"]=d[a[b]+"Pos"]||0,d[a[b]+"Pos"]+=e):(a.y0=d[a[b]+"Neg"]=d[a[b]+"Neg"]||0,d[a[b]+"Neg"]-=Math.abs(e))});e(c.reverse())},f=function(b,c){var d=d4.functor(c)();"x"===b&&"y"===d&&d4.err("You cannot use `y` as the key for an `x` dimension because it creates an ambiguous `y` property in the nested stack."),a[b].key=d},g=function(f){return f&&d4.extend(a.data,f),c(a,a.data),a.data=b(a.data),a.data=d(a.nestKey(),a.value.key,a.data),a.data.length>0&&e(a.x.key,a.data),a};return g.nestKey=function(b){return a.nestKey=d4.functor(b).bind(a),g},g.defined=function(b){return a.defined=d4.functor(b).bind(a),g},d4.each(["x","y","value"],function(b){g[b]=function(c){return f.bind(a)(b,d4.functor(c)),g}}.bind(this)),g})}.call(this),function(){"use strict";/** + * The waterfall parser is useful for waterfall charts where data items need to account + * for the position of earlier values: + * + * _____________________ + * | _ _______ | + * | |_|___ | | | | | + * | |_|__|_| | | | + * | |_| | + * ---------------------- + * + * This module makes use of the d3's "nest" data structure, and "stack" layout + * https://github.com/mbostock/d3/wiki/Arrays#-nest + * https://github.com/mbostock/d3/wiki/Stack-Layout + * + * + *##### Approach: + * Just like D3, this parser uses a chaining declaritiave style to build up + * the necessary prerequistes to create the waterfall data. Here is a simple + * example. Given a data item structure like this: {"category" : "Category One", "value" : 23 } + * + * var parser = d4.parsers.waterfall() + * .x(function() { + * return 'category'; + * }) + * .y(function(){ + * return 'value'; + * }) + * .value(function() { + * return 'value'; + * }); + * + * var waterfallData = parser(data); + * + * Keep reading for more information on these various accessor functions. + * + *##### Benefits: + * Supports horizontal or vertical waterfalls + * Supports totaling series using a special "e" value in a data item. + * + *##### Limitations: + * + * Does not support stacked waterfalls. + * + *##### Accessors: + * + * `x` : - function which returns a key to access the x values in the data array + * `y` : - function which returns a key to access the y values in the data array + * `value` : - function which returns a key to access the values in the data array. + * `data` : array - An array of objects with their dimensions specified + * like this: + * + * var data = [ + * {"category" : "Category One", "value" : 23 }, + * {"category" : "Category Two", "value" : 55 }, + * {"category" : "Category Three", "value" : -10 }, + * {"category" : "Category Four", "value" : 5 }, + * {"category" : "Category Five", "value" : "e" }] + * + *##### SPECIAL NOTE: + * + * Waterfalls charts typically have the ability to display subtotals at any point. + * In order to use this feature simply set the value of your subtotal column to "e." + * + *##### Example Usage: + * + * Given the example data and dimension variables above you can use this module + * in the following way: + * + * var parser = d4.parsers.nestedStack() + * .dimensions(dimensions) + * .call(data); + * + * The `parser` variable will now be an object containing the following structure: + * { + * data: Array + * value: { + * key: string, + * values: Array + * }, + * x: { + * key: string, + * values: Array + * }, + * y: { + * key: string, + * values: Array + * } + * } + * + * @name waterfall + **/ +d4.parser("waterfall",function(){var a={x:{key:"x",values:[]},y:{key:"y",values:[]},value:{key:"value",values:[]},data:[]};a.nestKey=function(){return a.x.key};var b=function(b,c){["x","y","value"].forEach(function(d){var e=c.map(function(a){return a[b[d].key]});a[d].values=d3.set(e).values()})},c=function(a,b,c){var d=d3.nest().key(function(b){return b[a]});return d.entries(c)},d=function(b,c){var d=0,e=function(a){return isNaN(a)?0:a},f=d3.layout.stack().values(function(a){return a.values}).x(function(a){return a[b]}).y(function(b){return+b[a.value.key]}).out(function(b,c,f){isNaN(f)?(isNaN(c)&&(c=d),b.y0=0,b.y=c,b[a.value.key]=c,d=c):(isNaN(c)?(b.y0=d,d+=f):b.y0=c,b.y=f,b[a.value.key]=e(b[a.value.key]))});f(c)},e=function(b,c){a[b].key=d4.functor(c)()},f=function(e){return e&&d4.extend(a.data,e),b(a,a.data),a.data=c(a.nestKey(),a.value.key,a.data),a.data.length>0&&d(a.x.key,a.data),a};return f.nestKey=function(b){return a.nestKey=d4.functor(b).bind(a),f},d4.each(["x","y","value"],function(b){f[b]=function(c){return e.bind(a)(b,d4.functor(c)),f}}.bind(this)),f})}.call(this),function(){"use strict";var a=function(a,b){var c=a.map(function(a){return a.values.map(function(a){return a[b]}.bind(this))}.bind(this));return d3.set(d3.merge(c)).values()},b=function(a,b){ +// This may not be a very robust approach. +switch(b){case"x":return[0,a.width];case"y":return[a.height,0];case"groups":var c=a.axes.groups.$dimension;return"x"===c?[0,a.axes.x.rangeBand()]:[a.axes.y.rangeBand(),0];default:return[]}},c=function(a,c,d){var e=a[d].$key,f=d3.extent(d3.merge(c.map(function(a){return d3.extent(a.values,function(a){return d4.isDate(a[e])?a[e]:a[e]+(a.y0||0)})}))),g=a[d];if(!g.domain.$dirty)if(d4.isDate(f[0])){var h=g.$min||f[0],i=g.$max||f[1];g.domain([h,i])}else g.domain([Math.min(g.$min||0,f[0]),g.$max||f[1]]);return g.range.$dirty||g.range(b(a,d)),g.clamp.$dirty||g.clamp(!0),a[d]};/** + * Creates a linear scale for a dimension of a given chart. + * @name linearScaleForNestedData + * @param {Object} d4 chart object + * @param {Array} data array + * @param {string} string represnting a dimension e.g. `x`,`y`. + * @return {Object} Chart scale object + */ +d4.builder("linearScaleForNestedData",c),/** + * Creates a time scale for a dimension of a given chart. + * @name timeScaleForNestedData + * @param {Object} d4 chart object + * @param {Array} data array + * @param {string} string represnting a dimension e.g. `x`,`y`. + * @return {Object} Chart scale object + */ +d4.builder("timeScaleForNestedData",c),/** + * Creates an ordinal scale for a dimension of a given chart. + * @name ordinalScaleForNestedData + * @param {Object} d4 chart object + * @param {Array} data array + * @param {string} string represnting a dimension e.g. `x`,`y`. + * @return {Object} Chart scale object + */ +d4.builder("ordinalScaleForNestedData",function(c,d,e){var f,g=a(d,c[e].$key);f=c[e+"RoundBands"]?c[e+"RoundBands"]:c[e].$roundBands?c[e].$roundBands:.3,c[e+"RoundBands"]=f;var h=c[e];return h.domain.$dirty||h.domain(g),h.rangeRoundBands.$dirty||h.rangePoints.$dirty||h.rangeBands.$dirty||h.rangeRoundBands(b(c,e),f),h})}.call(this); \ No newline at end of file diff --git a/package.json b/package.json index 9ac059c5..a2481d7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "d4", - "version": "0.9.4", + "version": "0.9.5", "description": "A friendly reusable chart DSL for D3", "repository": { "type": "git", @@ -27,7 +27,7 @@ "grunt-cli": "~0.1.11", "grunt-contrib-concat": "~0.1.3", "grunt-contrib-jshint": "~0.1.1", - "grunt-contrib-uglify": "~0.1.1", + "grunt-contrib-uglify": "~0.11.1", "grunt-contrib-watch": "~0.3.1", "grunt-jsbeautifier": "^0.2.7", "grunt-mocha": "~0.4.6", diff --git a/src/features/brush.js b/src/features/brush.js index e0d1e26c..5389d884 100644 --- a/src/features/brush.js +++ b/src/features/brush.js @@ -91,7 +91,6 @@ .call(brush); scope.accessors.selection.bind(this)(selection.select('.brush')); - scope.accessors.brush.bind(this)(brush); return brush; } }; diff --git a/test/lib/d4.js b/test/lib/d4.js index 679a1cae..30c347b1 100644 --- a/test/lib/d4.js +++ b/test/lib/d4.js @@ -1,6 +1,6 @@ -/*! d4 - v0.9.4 +/*! d4 - v0.9.5 * License: MIT Expat - * Date: 2015-04-14 + * Date: 2016-02-26 * Copyright: Mark Daggett, D4 Team */ /*! @@ -2903,7 +2903,6 @@ .call(brush); scope.accessors.selection.bind(this)(selection.select('.brush')); - scope.accessors.brush.bind(this)(brush); return brush; } };