diff --git a/Gruntfile.js b/Gruntfile.js index 841f0aac..75cff796 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -53,6 +53,14 @@ module.exports = function(grunt) { } } }, + browserify: { + specs: { + src: ["test/tests/browserify-test.js"], + dest: "test/tests/d4-bundle.js", + options: { + } + } + }, mocha: { options: { run: true, @@ -124,8 +132,9 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-mocha'); grunt.loadNpmTasks('grunt-plato'); grunt.loadNpmTasks('grunt-remove-logging'); + grunt.loadNpmTasks('grunt-browserify'); - grunt.registerTask('test', ['concat', 'mocha']); + grunt.registerTask('test', ['concat', 'browserify', 'mocha']); grunt.registerTask('quality', ['plato']); grunt.registerTask('default', ['jsbeautifier', 'jshint', 'test']); grunt.registerTask('release', ['default', 'concat', 'uglify', 'removelogging']); diff --git a/d4.js b/d4.js index f85c5200..2979b57f 100644 --- a/d4.js +++ b/d4.js @@ -1,6 +1,6 @@ -/*! d4 - v0.9.5 +/*! d4 - v0.9.6 * License: MIT Expat - * Date: 2016-03-10 + * Date: 2016-03-28 * Copyright: Mark Daggett, D4 Team */ /*! @@ -9,6 +9,9 @@ (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Underscore may be freely distributed under the MIT license. */ + +var d4; + (function() { 'use strict'; @@ -16,7 +19,7 @@ var breaker = {}; // Create a safe reference to the d4 object. - var d4 = function(obj) { + d4 = function(obj) { if (obj instanceof d4) { return obj; } diff --git a/d4.min.js b/d4.min.js index 2a436efc..aeccaefc 100644 --- a/d4.min.js +++ b/d4.min.js @@ -1,6 +1,6 @@ -/*! d4 - v0.9.5 +/*! d4 - v0.9.6 * License: MIT Expat - * Date: 2016-02-26 + * Date: 2016-03-28 * Copyright: Mark Daggett, D4 Team */ /*! @@ -9,13 +9,13 @@ (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Underscore may be freely distributed under the MIT license. */ -(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); +var d4;(function(){"use strict";var a=this,b={};d4=function(a){return a instanceof d4?a:this instanceof d4?void(this.d4Wrapped=a):new d4(a)},"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=d4),exports.d4=d4):a.d4=d4,d4.charts={},d4.features={},d4.parsers={},d4.builders={};var c=d4.each=d4.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}},d=function(a){return a.charAt(0).toUpperCase()+a.slice(1)},e=function(a,b,c,d){Object.defineProperty(a,b,{configurable:!0,get:function(){return d4.functor(d)()},set:function(){f(" You cannot directly assign values to the {0} property. Instead use the {1}() function.",b,c)}})},f=d4.err=function(){var a,b=Array.prototype.slice.call(arguments),d=b.shift();throw c(b,function(b,c){a=new RegExp("\\{"+c+"\\}","gi"),d=d.replace(a,b)}),new Error("[d4] "+d)},g=function(a){return c(["link"],function(b){a[b]&&!d4.isNotFunction(a[b])||f("The supplied builder does not have a {0} function",b)}),a},h=function(a){return this.builder||(this.builder=g(a.bind(this)())),this},i=function(a,b,c){if(d4.isNotFunction(c)){var d="$"+b;e(a,d,b,c)}},j=function(a,b,c,e){var f=c;d4.isDefined(e)&&(f=e+d(c)),a[f]=function(d){return arguments.length?(i(a,c,d),b[c]=d,a):b[c]},i(a,c,b[c])},k=function(a,b,d,e){c(d,function(c){j(a,b,c,e)})},l=function(a){var b=a.accessors;b&&k(a,a.accessors,d3.keys(b))},m=function(a,b){c(d3.keys(b.axes),function(d){a[d]=function(c){return J.bind(b)(d,c),a},c(d3.keys(b.axes[d].accessors),function(c){a[d][c]=b.axes[d][c]})})},n=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){ +b.push("time"),b.push("time.utc"),b.indexOf(a)<0&&f('The scale type: "{0}" is unrecognized. D4 only supports these scale types: {1}',a,b.sort().join(", "))},o=function(a,b,c){ // 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)}), +d4.createAccessorProxy(b,a),b.scale=function(a){return arguments.length?(b.accessors.scale=a,c(),b):b.accessors.scale}},p=function(a,b,d){var f;switch(n(d.accessors.scale),!0){case"time"===d.accessors.scale:f=d3.time.scale();break;case"time.utc"===d.accessors.scale:f=d3.time.scale.utc();break;default:f=d3.scale[d.accessors.scale]()}l(d),b[a]=f,o(f,b.axes[a],function(){p(a,b,d)}), // 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);/** +c(d3.keys(b.axes[a].accessors),function(c){e(b[a],"$"+c,b.axes[a][c],b.axes[a][c])})},q=function(a,b,c){b.axes[a]={accessors:d4.extend({key:a,min:void 0,max:void 0},c)},p(a,b,b.axes[a])},r=function(a){c(d3.keys(a.axes),function(b){q(b,a,a.axes[b])}),d4.isUndefined(a.axes.x)&&q("x",a,{scale:"ordinal"}),d4.isUndefined(a.axes.y)&&q("y",a,{scale:"linear"})},s=function(a,b){var c=d4.functor({link:function(a,b){d4.builders[a.x.$scale+"ScaleForNestedData"](a,b,"x"),d4.builders[a.y.$scale+"ScaleForNestedData"](a,b,"y"),a.groups&&d4.builders[a.groups.$scale+"ScaleForNestedData"](a,b,"groups")}}),d=d4.merge({},a.accessors);delete a.accessors;var e=d4.merge({axes:{},features:{},height:400,margin:{top:20,right:20,bottom:40,left:40},mixins:[],outerHeight:460,outerWidth:460,width:400},a);return e=d4.merge(e,d),r(e),h.bind(e)(b||c),e.accessors=["width","height","valueKey"].concat(d3.keys(d)||[]),e},t=function(a,b){b&&c(d3.keys(a._proxiedFunctions),function(d){c(a._proxiedFunctions[d],function(a){b[d].apply(b,a)})})},u=function(a,b,c){var d=a.features[b].accessors.beforeRender.bind(a)(c);return d4.isDefined(d)&&(c=d),c},v=function(a,b){var c,d;a.mixins.forEach(function(e){c=u(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),t(a.features[e],d)})},w=function(a,b){a.builder?(a.builder.link(a,b),v(a,b)):f("No builder defined")},x=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=d4.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)),d4.appendOnce(this.container,"defs"),d4.appendOnce(this.container,"g.margins").attr("transform","translate("+this.margin.left+","+this.margin.top+")"),this.chartArea=d4.appendOnce(this.container.select("g.margins"),"g.chartArea")},y=function(a,b){var c=d4.parsers.nestedGroup().x(a.x.$key).y(a.y.$key).nestKey(a.x.$key).value(a.valueKey)(b);return c.data},z=function(a,b){var c,d,e=!1;return d4.isUndefined(a.valueKey)&&(a.valueKey=a.y.$key),b.length>0&&(d=b[0],d4.isArray(d)?e=!0:(c=d3.keys(d),c.indexOf("key")+c.indexOf("values")<=0&&(e=!0))),e?y(a,b):b},A=function(a){return function(b){b.each(function(b){b=z(a,b),x.bind(a,this)(),w(a,b)})}},B=function(a,b){return a.overrides?a.overrides(b):{}},C=function(a,b,c){d4.isDefined(c)?(c=Math.max(Math.min(c,a.length),0),a.splice(c,0,b)):a.push(b)},D=function(a){a._proxiedFunctions={on:[]},a.on=function(){return a._proxiedFunctions.on.push(Array.prototype.slice.call(arguments)),a}},E=function(a){l(a)},F=function(a){D(a),d4.each(a.proxies,function(b){d4.isUndefined(b.target)&&f("You included a feature which has a malformed proxy target.",a.name),d4.createAccessorProxy(a,b.target,b.prefix)})},G=function(a){a||f("You need to supply an object or array of objects to mixin to the chart.");var b=d4.flatten([a]);d4.each(b,function(a){var b=a.name,c=B.bind(this)(a,b),d={accessors:{afterRender:function(){},beforeRender:function(){}},proxies:[]};a[b]=d4.merge(d4.merge(d,a.feature(b)),c),d4.extend(this.features,a),C(this.mixins,b,a.index),F(this.features[b]),E(this.features[b])}.bind(this))},H=function(a){var b=[];d4.isUndefined(a)&&f("A string or array of names is required in order to mixout a chart feature."),b.push(a),d4.each(d4.flatten(b),function(a){delete this.features[a],this.mixins=this.mixins.filter(function(b){return b!==a})}.bind(this))},I=function(a,b){var c=this.features[a];d4.isNotFunction(b)&&f("You must supply a continuation function in order to use a chart feature."),c?b.bind(this)(c):f('Could not find feature: "{0}", maybe you forgot to mix it in?',a)},J=function(a,b){var c=this.axes[a];d4.isNotFunction(b)&&f("You must supply a continuation function in order to use a chart axis."),c?b.bind(this)(c):f('Could not find axis: "{0}", maybe you forgot to define it?',a)},K=function(a){var b,c,d=a,e="[\\x20\\t\\r\\n\\f]",f="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",g=f.replace("w","w#"),h="\\["+e+"*("+f+")"+e+"*(?:([*^$|!~]?=)"+e+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+g+")|)|)"+e+"*\\]",i=["TAG","ID","CLASS"],j={ID:new RegExp("#("+f+")"),CLASS:new RegExp("\\.("+f+")"),TAG:new RegExp("^("+f.replace("w","w*")+")"),ATTR:new RegExp(""+h)},k=function(a){for(b=!1,l[a]=[],c=!0;c;)c=j[a].exec(d),null!==c&&(b=c.shift(),l[a].push(c[0]),d=d.slice(b.length))},l={};return d4.each(i,k),d4.each(i,function(a){for(;d&&(l[a]=l[a].join(" "),b););}),l},L=function(a){var b=A(a);/** * This function returns the internal axes object as a parameter to the * supplied function. * @param {Function} funct - function which will perform the modifcation. @@ -64,7 +64,7 @@ d(d3.keys(b.axes[a].accessors),function(c){f(b[a],"$"+c,b.axes[a][c],b.axes[a][c * .mixout('yAxis'); * * // Now test that the feature has been removed. - * + * console.log(chart.features()); * // => ["bars", "barLabels", "xAxis"] * * @return {Array} An array of features. @@ -124,7 +124,7 @@ d(d3.keys(b.axes[a].accessors),function(c){f(b[a],"$"+c,b.axes[a][c],b.axes[a][c * .mixout('yAxis'); * * // Now test that the feature has been removed. - * + * console.log(chart.features()); * => ["bars", "barLabels", "xAxis"] * * @param {String} name - accessor name for chart feature. @@ -160,7 +160,7 @@ d(d3.keys(b.axes[a].accessors),function(c){f(b[a],"$"+c,b.axes[a][c],b.axes[a][c * @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};/** +return k(b,a.margin,d3.keys(a.margin),"margin"),k(b,a,a.accessors),m(b,a),b.axes=function(c){return arguments.length?(c(a.axes),b):a.axes},b.builder=function(c){return a.builder=g(c.bind(a)()),b},b.clone=function(){var b=d4.extend({},a);return L(b)},b.features=function(){return a.mixins},b.margin=function(c){return arguments.length?(a.margin=d4.merge(a.margin,d4.functor(c)()),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 G.bind(a)(c),b},b.mixout=function(c,d){return H.bind(a)(c,d),b},b.outerHeight=function(c){var d=d4.functor(c)();return arguments.length?(a.outerHeight=d,b.height(d-a.margin.top-a.margin.bottom),b):a.outerHeight},b.outerWidth=function(c){var d=d4.functor(c)();return arguments.length?(a.outerWidth=d,b.width(d-a.margin.left-a.margin.right),b):a.outerWidth},b.using=function(c,d){return I.bind(a)(c,d),b},b};/** * This function conditionally appends a SVG element if it doesn't already * exist within the parent element. * @@ -174,7 +174,7 @@ return l(b,a.margin,d3.keys(a.margin),"margin"),l(b,a,a.accessors),n(b,a),b.axes * * @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},/** +d4.appendOnce=function(a,b){var c,d=a.selectAll(b);return d.empty()&&(c=K(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. * @@ -198,19 +198,19 @@ c.appendOnce=function(a,b){var c,d=a.selectAll(b);return d.empty()&&(c=L(b),d=a. * builder property * @return {Function} chart instance */ -c.baseChart=function(a){var b=t(a&&a.config||{},a&&a.builder||void 0);return M(b)},/** +d4.baseChart=function(a){var b=s(a&&a.config||{},a&&a.builder||void 0);return L(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]},/** +d4.builder=function(a,b){return d4.builders[a]=b,d4.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]},/** +d4.chart=function(a,b){return d4.charts[a]=b,d4.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 @@ -239,10 +239,10 @@ c.chart=function(a,b){return c.charts[a]=b,c.charts[a]},/** * @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(){ +d4.createAccessorProxy=function(a,b,e){c(d3.keys(b),function(c){var f=c;d4.isDefined(e)&&(f=e+d(c)),a[f]=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},/** +return arguments.length?(b[c].$dirty=!0,a[f].$dirty=!0,b[c].apply(b,arguments),a):b[c]()},b[c].$dirty=!1,a[f].$dirty=!1})},d4.defaultKey=function(a,b){return(a.key||0)+"_"+b},/** * Helper method to extend one object with the attributes of another. * *##### Examples: @@ -261,18 +261,18 @@ return arguments.length?(b[d].$dirty=!0,a[g].$dirty=!0,b[d].apply(b,arguments),a * @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},/** +d4.extend=function(a){return c(Array.prototype.slice.call(arguments,1),function(b){var c=function(a){var b=[];return d4.each(a,function(a){var c=a;d4.isObject(a)&&(c=d4.extend({},a)),b.push(c)}),b};if(b)for(var d in b)if(b[d]&&b[d].constructor&&b[d].constructor===Object)a[d]=a[d]||{},d4.extend(a[d],b[d]);else if(d4.isArray(b[d])){var e=c(b[d].slice());d4.isArray(a[d])?a[d]=a[d].concat(e):a[d]=e}else a[d]=b[d]}),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]},/** +d4.feature=function(a,b){return d4.features[a]=b,d4.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]},/** +d4.flatten=function(a){var b=a.reduce(function(a,b){return a=d4.isArray(a)?a:[a],b=d4.isArray(b)?b:[b],a.concat(b)});return d4.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 @@ -285,60 +285,60 @@ c.flatten=function(a){var b=a.reduce(function(a,b){return a=c.isArray(a)?a:[a],b * @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}},/** +d4.functor=function(a){return d4.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)},/** +d4.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)},/** +d4.isContinuousScale=function(a){return d4.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)},/** +d4.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)},/** +d4.isDefined=function(a){return!d4.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)},/** +d4.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},/** +d4.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)},/** +d4.isOrdinalScale=function(a){return d4.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)},/** +d4.isNotFunction=function(a){return!d4.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)},/** +d4.isNotNull=function(a){return!d4.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},/** +d4.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},/** +d4.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. @@ -359,13 +359,13 @@ c.isUndefined=function(a){return"undefined"==typeof a},/** * @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)},/** +d4.merge=function(a,b){return d4.extend(d4.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={}; +d4.parser=function(a,b){return d4.parsers[a]=b,d4.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 @@ -984,7 +984,7 @@ d4.feature("groupedColumnSeries",function(a){var b=function(a){return a>0?"posit * * @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";/* +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){d4.appendOnce(this.container.select("."+a),"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 */ diff --git a/package.json b/package.json index f4cb08f6..c7f92d4e 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "chai": "~1.9.0", "chai-spies": "~0.5.1", "grunt": "~0.4.0", + "grunt-browserify": "^5.0.0", "grunt-cli": "~0.1.11", "grunt-contrib-concat": "~0.1.3", "grunt-contrib-jshint": "~0.1.1", diff --git a/src/base.js b/src/base.js index 01a1dd44..4956b20e 100644 --- a/src/base.js +++ b/src/base.js @@ -4,6 +4,9 @@ (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors Underscore may be freely distributed under the MIT license. */ + +var d4; + (function() { 'use strict'; @@ -11,7 +14,7 @@ var breaker = {}; // Create a safe reference to the d4 object. - var d4 = function(obj) { + d4 = function(obj) { if (obj instanceof d4) { return obj; } diff --git a/test/index.html b/test/index.html index 5d8f3a21..fb2f5d7d 100644 --- a/test/index.html +++ b/test/index.html @@ -16,6 +16,7 @@ d4 test suite + diff --git a/test/tests/browserify-test.js b/test/tests/browserify-test.js new file mode 100644 index 00000000..c85c8ae1 --- /dev/null +++ b/test/tests/browserify-test.js @@ -0,0 +1,13 @@ +/*global describe:true*/ +/*global it:true*/ +/*global beforeEach:true*/ +/*global document:true*/ + +'use strict'; + +describe( 'using browserify', function(){ + it('should compile d4 with require', function() { + var d4 = require( '../lib/d4.js' ); + expect(d4).to.not.be.an('undefined'); + }); +});