xcharts-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +41 -0
- data/Rakefile +1 -0
- data/lib/xcharts_rails.rb +5 -0
- data/lib/xcharts_rails/engine.rb +10 -0
- data/lib/xcharts_rails/version.rb +3 -0
- data/vendor/assets/javascripts/xcharts.js +1158 -0
- data/vendor/assets/stylesheets/xcharts.css +283 -0
- data/xcharts_rails.gemspec +21 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b06e86246b2a3823363bd102b3bae6124e5aa456
|
4
|
+
data.tar.gz: 355c8a203bbb4c68d472bf94bc227b3a9662afb1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 64dba6c8161ce1079d758183d7732207895b7746cdfeb0979c6192d1bccda85a7dca9e385103c349d928c85408b6895d6d1dac31cd6852c2bee04d9a35923aff
|
7
|
+
data.tar.gz: fdd0bfabbcdf9af52a1164201136d64323c0b88432e94e9cefa70f0948aea473f936a6633ef7912f07e720b45c7973de2000547f12d7eac382192fecb7132280
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
xcharts
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Orlando Del Aguila
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# xcharts-rails gem
|
2
|
+
|
3
|
+
A gem to add [Xcharts](http://tenxer.github.io/xcharts/) into your Rails application Assets Pipeline.
|
4
|
+
|
5
|
+
This repository is a fork of [orlando/xcharts_rails](https://github.com/orlando/xcharts_rails).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'xcharts-rails'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Now add `xcharts` to `application.js` and `application.css`:
|
18
|
+
|
19
|
+
Open `application.js` and add the following lines:
|
20
|
+
|
21
|
+
//= require d3.v3
|
22
|
+
//= require xcharts
|
23
|
+
|
24
|
+
Then open `application.css` and add the following line:
|
25
|
+
|
26
|
+
*= require xcharts
|
27
|
+
|
28
|
+
Now you are ready to follow [the Xcharts documentation](http://tenxer.github.io/xcharts/docs/#data).
|
29
|
+
|
30
|
+
## Contributing
|
31
|
+
|
32
|
+
1. Fork it
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
36
|
+
5. Create new Pull Request
|
37
|
+
|
38
|
+
## Copyright
|
39
|
+
|
40
|
+
Copyright (c) 2014 Guillaume Hain. See LICENSE.txt for
|
41
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,1158 @@
|
|
1
|
+
/*!
|
2
|
+
xCharts v0.3.0 Copyright (c) 2012, tenXer, Inc. All Rights Reserved.
|
3
|
+
@license MIT license. http://github.com/tenXer/xcharts for details
|
4
|
+
*/
|
5
|
+
|
6
|
+
(function () {
|
7
|
+
|
8
|
+
var xChart,
|
9
|
+
_vis = {},
|
10
|
+
_scales = {},
|
11
|
+
_visutils = {};
|
12
|
+
(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,v=e.reduce,h=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.3";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduce===v)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduceRight===h)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?-1!=n.indexOf(t):E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2);return w.map(n,function(n){return(w.isFunction(t)?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t){return w.isEmpty(t)?[]:w.filter(n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var F=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=F(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||void 0===r)return 1;if(e>r||void 0===e)return-1}return n.index<t.index?-1:1}),"value")};var k=function(n,t,r,e){var u={},i=F(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return k(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return k(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:F(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i};var I=function(){};w.bind=function(n,t){var r,e;if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));if(!w.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));I.prototype=n.prototype;var u=new I;I.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},w.bindAll=function(n){var t=o.call(arguments,1);return 0==t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=S(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&S(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return S(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),w.isFunction=function(n){return"function"==typeof n},w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return void 0===n},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+(0|Math.random()*(t-n+1))};var T={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};T.unescape=w.invert(T.escape);var M={escape:RegExp("["+w.keys(T.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(T.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(M[n],function(t){return T[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=""+ ++N;return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){r=w.defaults({},r,w.templateSettings);var e=RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(D,function(n){return"\\"+B[n]}),r&&(i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(i+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),a&&(i+="';\n"+a+"\n__p+='"),u=o+t.length,t}),i+="';\n",r.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=Function(r.variable||"obj","_",i)}catch(o){throw o.source=i,o}if(t)return a(t,w);var c=function(n){return a.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+i+"}",c},w.chain=function(n){return w(n).chain()};var z=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);function getInsertionPoint(zIndex) {
|
13
|
+
return _.chain(_.range(zIndex, 10)).reverse().map(function (z) {
|
14
|
+
return 'g[data-index="' + z + '"]';
|
15
|
+
}).value().join(', ');
|
16
|
+
}
|
17
|
+
|
18
|
+
function colorClass(el, i) {
|
19
|
+
var c = el.getAttribute('class');
|
20
|
+
return ((c !== null) ? c.replace(/color\d+/g, '') : '') + ' color' + i;
|
21
|
+
}
|
22
|
+
|
23
|
+
_visutils = {
|
24
|
+
getInsertionPoint: getInsertionPoint,
|
25
|
+
colorClass: colorClass
|
26
|
+
};
|
27
|
+
var local = this,
|
28
|
+
defaultSpacing = 0.25;
|
29
|
+
|
30
|
+
function _getDomain(data, axis) {
|
31
|
+
return _.chain(data)
|
32
|
+
.pluck('data')
|
33
|
+
.flatten()
|
34
|
+
.pluck(axis)
|
35
|
+
.uniq()
|
36
|
+
.filter(function (d) {
|
37
|
+
return d !== undefined && d !== null;
|
38
|
+
})
|
39
|
+
.value()
|
40
|
+
.sort(d3.ascending);
|
41
|
+
}
|
42
|
+
|
43
|
+
_scales.ordinal = function (data, axis, bounds, extents) {
|
44
|
+
var domain = _getDomain(data, axis);
|
45
|
+
return d3.scale.ordinal()
|
46
|
+
.domain(domain)
|
47
|
+
.rangeRoundBands(bounds, defaultSpacing);
|
48
|
+
};
|
49
|
+
|
50
|
+
_scales.linear = function (data, axis, bounds, extents) {
|
51
|
+
return d3.scale.linear()
|
52
|
+
.domain(extents)
|
53
|
+
.nice()
|
54
|
+
.rangeRound(bounds);
|
55
|
+
};
|
56
|
+
|
57
|
+
_scales.exponential = function (data, axis, bounds, extents) {
|
58
|
+
return d3.scale.pow()
|
59
|
+
.exponent(0.65)
|
60
|
+
.domain(extents)
|
61
|
+
.nice()
|
62
|
+
.rangeRound(bounds);
|
63
|
+
};
|
64
|
+
|
65
|
+
_scales.time = function (data, axis, bounds, extents) {
|
66
|
+
return d3.time.scale()
|
67
|
+
.domain(_.map(extents, function (d) { return new Date(d); }))
|
68
|
+
.range(bounds);
|
69
|
+
};
|
70
|
+
|
71
|
+
function _extendDomain(domain, axis) {
|
72
|
+
var min = domain[0],
|
73
|
+
max = domain[1],
|
74
|
+
diff,
|
75
|
+
e;
|
76
|
+
|
77
|
+
if (min === max) {
|
78
|
+
e = Math.max(Math.round(min / 10), 4);
|
79
|
+
min -= e;
|
80
|
+
max += e;
|
81
|
+
}
|
82
|
+
|
83
|
+
diff = max - min;
|
84
|
+
min = (min) ? min - (diff / 10) : min;
|
85
|
+
min = (domain[0] > 0) ? Math.max(min, 0) : min;
|
86
|
+
max = (max) ? max + (diff / 10) : max;
|
87
|
+
max = (domain[1] < 0) ? Math.min(max, 0) : max;
|
88
|
+
|
89
|
+
return [min, max];
|
90
|
+
}
|
91
|
+
|
92
|
+
function _getExtents(options, data, xType, yType) {
|
93
|
+
var extents,
|
94
|
+
nData = _.chain(data)
|
95
|
+
.pluck('data')
|
96
|
+
.flatten()
|
97
|
+
.value();
|
98
|
+
|
99
|
+
extents = {
|
100
|
+
x: d3.extent(nData, function (d) { return d.x; }),
|
101
|
+
y: d3.extent(nData, function (d) { return d.y; })
|
102
|
+
};
|
103
|
+
|
104
|
+
_.each([xType, yType], function (type, i) {
|
105
|
+
var axis = (i) ? 'y' : 'x',
|
106
|
+
extended;
|
107
|
+
extents[axis] = d3.extent(nData, function (d) { return d[axis]; });
|
108
|
+
if (type === 'ordinal') {
|
109
|
+
return;
|
110
|
+
}
|
111
|
+
|
112
|
+
_.each([axis + 'Min', axis + 'Max'], function (minMax, i) {
|
113
|
+
if (type !== 'time') {
|
114
|
+
extended = _extendDomain(extents[axis]);
|
115
|
+
}
|
116
|
+
|
117
|
+
if (options.hasOwnProperty(minMax) && options[minMax] !== null) {
|
118
|
+
extents[axis][i] = options[minMax];
|
119
|
+
} else if (type !== 'time') {
|
120
|
+
extents[axis][i] = extended[i];
|
121
|
+
}
|
122
|
+
});
|
123
|
+
});
|
124
|
+
|
125
|
+
return extents;
|
126
|
+
}
|
127
|
+
|
128
|
+
_scales.xy = function (self, data, xType, yType) {
|
129
|
+
var o = self._options,
|
130
|
+
extents = _getExtents(o, data, xType, yType),
|
131
|
+
scales = {},
|
132
|
+
horiz = [o.axisPaddingLeft, self._width],
|
133
|
+
vert = [self._height, o.axisPaddingTop],
|
134
|
+
xScale,
|
135
|
+
yScale;
|
136
|
+
|
137
|
+
_.each([xType, yType], function (type, i) {
|
138
|
+
var axis = (i === 0) ? 'x' : 'y',
|
139
|
+
bounds = (i === 0) ? horiz : vert,
|
140
|
+
fn = xChart.getScale(type);
|
141
|
+
scales[axis] = fn(data, axis, bounds, extents[axis]);
|
142
|
+
});
|
143
|
+
|
144
|
+
return scales;
|
145
|
+
};
|
146
|
+
(function () {
|
147
|
+
var zIndex = 2,
|
148
|
+
selector = 'g.bar',
|
149
|
+
insertBefore = _visutils.getInsertionPoint(zIndex);
|
150
|
+
|
151
|
+
function postUpdateScale(self, scaleData, mainData, compData) {
|
152
|
+
self.xScale2 = d3.scale.ordinal()
|
153
|
+
.domain(d3.range(0, mainData.length))
|
154
|
+
.rangeRoundBands([0, self.xScale.rangeBand()], 0.08);
|
155
|
+
}
|
156
|
+
|
157
|
+
function enter(self, storage, className, data, callbacks) {
|
158
|
+
var barGroups, bars,
|
159
|
+
yZero = self.yZero;
|
160
|
+
|
161
|
+
barGroups = self._g.selectAll(selector + className)
|
162
|
+
.data(data, function (d) {
|
163
|
+
return d.className;
|
164
|
+
});
|
165
|
+
|
166
|
+
barGroups.enter().insert('g', insertBefore)
|
167
|
+
.attr('data-index', zIndex)
|
168
|
+
.style('opacity', 0)
|
169
|
+
.attr('class', function (d, i) {
|
170
|
+
var cl = _.uniq((className + d.className).split('.')).join(' ');
|
171
|
+
return cl + ' bar ' + _visutils.colorClass(this, i);
|
172
|
+
})
|
173
|
+
.attr('transform', function (d, i) {
|
174
|
+
return 'translate(' + self.xScale2(i) + ',0)';
|
175
|
+
});
|
176
|
+
|
177
|
+
bars = barGroups.selectAll('rect')
|
178
|
+
.data(function (d) {
|
179
|
+
return d.data;
|
180
|
+
}, function (d) {
|
181
|
+
return d.x;
|
182
|
+
});
|
183
|
+
|
184
|
+
bars.enter().append('rect')
|
185
|
+
.attr('width', 0)
|
186
|
+
.attr('rx', 3)
|
187
|
+
.attr('ry', 3)
|
188
|
+
.attr('x', function (d) {
|
189
|
+
return self.xScale(d.x) + (self.xScale2.rangeBand() / 2);
|
190
|
+
})
|
191
|
+
.attr('height', function (d) {
|
192
|
+
return Math.abs(yZero - self.yScale(d.y));
|
193
|
+
})
|
194
|
+
.attr('y', function (d) {
|
195
|
+
return (d.y < 0) ? yZero : self.yScale(d.y);
|
196
|
+
})
|
197
|
+
.on('mouseover', callbacks.mouseover)
|
198
|
+
.on('mouseout', callbacks.mouseout)
|
199
|
+
.on('click', callbacks.click);
|
200
|
+
|
201
|
+
storage.barGroups = barGroups;
|
202
|
+
storage.bars = bars;
|
203
|
+
}
|
204
|
+
|
205
|
+
function update(self, storage, timing) {
|
206
|
+
var yZero = self.yZero;
|
207
|
+
|
208
|
+
storage.barGroups
|
209
|
+
.attr('class', function (d, i) {
|
210
|
+
return _visutils.colorClass(this, i);
|
211
|
+
})
|
212
|
+
.transition().duration(timing)
|
213
|
+
.style('opacity', 1)
|
214
|
+
.attr('transform', function (d, i) {
|
215
|
+
return 'translate(' + self.xScale2(i) + ',0)';
|
216
|
+
});
|
217
|
+
|
218
|
+
storage.bars.transition().duration(timing)
|
219
|
+
.attr('width', self.xScale2.rangeBand())
|
220
|
+
.attr('x', function (d) {
|
221
|
+
return self.xScale(d.x);
|
222
|
+
})
|
223
|
+
.attr('height', function (d) {
|
224
|
+
return Math.abs(yZero - self.yScale(d.y));
|
225
|
+
})
|
226
|
+
.attr('y', function (d) {
|
227
|
+
return (d.y < 0) ? yZero : self.yScale(d.y);
|
228
|
+
});
|
229
|
+
}
|
230
|
+
|
231
|
+
function exit(self, storage, timing) {
|
232
|
+
storage.bars.exit()
|
233
|
+
.transition().duration(timing)
|
234
|
+
.attr('width', 0)
|
235
|
+
.remove();
|
236
|
+
storage.barGroups.exit()
|
237
|
+
.transition().duration(timing)
|
238
|
+
.style('opacity', 0)
|
239
|
+
.remove();
|
240
|
+
}
|
241
|
+
|
242
|
+
function destroy(self, storage, timing) {
|
243
|
+
var band = (self.xScale2) ? self.xScale2.rangeBand() / 2 : 0;
|
244
|
+
delete self.xScale2;
|
245
|
+
storage.bars
|
246
|
+
.transition().duration(timing)
|
247
|
+
.attr('width', 0)
|
248
|
+
.attr('x', function (d) {
|
249
|
+
return self.xScale(d.x) + band;
|
250
|
+
});
|
251
|
+
}
|
252
|
+
|
253
|
+
_vis.bar = {
|
254
|
+
postUpdateScale: postUpdateScale,
|
255
|
+
enter: enter,
|
256
|
+
update: update,
|
257
|
+
exit: exit,
|
258
|
+
destroy: destroy
|
259
|
+
};
|
260
|
+
}());
|
261
|
+
(function () {
|
262
|
+
|
263
|
+
var zIndex = 3,
|
264
|
+
selector = 'g.line',
|
265
|
+
insertBefore = _visutils.getInsertionPoint(zIndex);
|
266
|
+
|
267
|
+
function enter(self, storage, className, data, callbacks) {
|
268
|
+
var inter = self._options.interpolation,
|
269
|
+
x = function (d, i) {
|
270
|
+
if (!self.xScale2 && !self.xScale.rangeBand) {
|
271
|
+
return self.xScale(d.x);
|
272
|
+
}
|
273
|
+
return self.xScale(d.x) + (self.xScale.rangeBand() / 2);
|
274
|
+
},
|
275
|
+
y = function (d) { return self.yScale(d.y); },
|
276
|
+
line = d3.svg.line()
|
277
|
+
.x(x)
|
278
|
+
.interpolate(inter),
|
279
|
+
area = d3.svg.area()
|
280
|
+
.x(x)
|
281
|
+
.y1(self.yZero)
|
282
|
+
.interpolate(inter),
|
283
|
+
container,
|
284
|
+
fills,
|
285
|
+
paths;
|
286
|
+
|
287
|
+
function datum(d) {
|
288
|
+
return [d.data];
|
289
|
+
}
|
290
|
+
|
291
|
+
container = self._g.selectAll(selector + className)
|
292
|
+
.data(data, function (d) {
|
293
|
+
return d.className;
|
294
|
+
});
|
295
|
+
|
296
|
+
container.enter().insert('g', insertBefore)
|
297
|
+
.attr('data-index', zIndex)
|
298
|
+
.attr('class', function (d, i) {
|
299
|
+
var cl = _.uniq((className + d.className).split('.')).join(' ');
|
300
|
+
return cl + ' line ' + _visutils.colorClass(this, i);
|
301
|
+
});
|
302
|
+
|
303
|
+
fills = container.selectAll('path.fill')
|
304
|
+
.data(datum);
|
305
|
+
|
306
|
+
fills.enter().append('path')
|
307
|
+
.attr('class', 'fill')
|
308
|
+
.style('opacity', 0)
|
309
|
+
.attr('d', area.y0(y));
|
310
|
+
|
311
|
+
paths = container.selectAll('path.line')
|
312
|
+
.data(datum);
|
313
|
+
|
314
|
+
paths.enter().append('path')
|
315
|
+
.attr('class', 'line')
|
316
|
+
.style('opacity', 0)
|
317
|
+
.attr('d', line.y(y));
|
318
|
+
|
319
|
+
storage.lineContainers = container;
|
320
|
+
storage.lineFills = fills;
|
321
|
+
storage.linePaths = paths;
|
322
|
+
storage.lineX = x;
|
323
|
+
storage.lineY = y;
|
324
|
+
storage.lineA = area;
|
325
|
+
storage.line = line;
|
326
|
+
}
|
327
|
+
|
328
|
+
function update(self, storage, timing) {
|
329
|
+
storage.lineContainers
|
330
|
+
.attr('class', function (d, i) {
|
331
|
+
return _visutils.colorClass(this, i);
|
332
|
+
});
|
333
|
+
|
334
|
+
storage.lineFills.transition().duration(timing)
|
335
|
+
.style('opacity', 1)
|
336
|
+
.attr('d', storage.lineA.y0(storage.lineY));
|
337
|
+
|
338
|
+
storage.linePaths.transition().duration(timing)
|
339
|
+
.style('opacity', 1)
|
340
|
+
.attr('d', storage.line.y(storage.lineY));
|
341
|
+
}
|
342
|
+
|
343
|
+
function exit(self, storage) {
|
344
|
+
storage.linePaths.exit()
|
345
|
+
.style('opacity', 0)
|
346
|
+
.remove();
|
347
|
+
storage.lineFills.exit()
|
348
|
+
.style('opacity', 0)
|
349
|
+
.remove();
|
350
|
+
|
351
|
+
storage.lineContainers.exit()
|
352
|
+
.remove();
|
353
|
+
}
|
354
|
+
|
355
|
+
function destroy(self, storage, timing) {
|
356
|
+
storage.linePaths.transition().duration(timing)
|
357
|
+
.style('opacity', 0);
|
358
|
+
storage.lineFills.transition().duration(timing)
|
359
|
+
.style('opacity', 0);
|
360
|
+
}
|
361
|
+
|
362
|
+
_vis.line = {
|
363
|
+
enter: enter,
|
364
|
+
update: update,
|
365
|
+
exit: exit,
|
366
|
+
destroy: destroy
|
367
|
+
};
|
368
|
+
}());
|
369
|
+
(function () {
|
370
|
+
var line = _vis.line;
|
371
|
+
|
372
|
+
function enter(self, storage, className, data, callbacks) {
|
373
|
+
var circles;
|
374
|
+
|
375
|
+
line.enter(self, storage, className, data, callbacks);
|
376
|
+
|
377
|
+
circles = storage.lineContainers.selectAll('circle')
|
378
|
+
.data(function (d) {
|
379
|
+
return d.data;
|
380
|
+
}, function (d) {
|
381
|
+
return d.x;
|
382
|
+
});
|
383
|
+
|
384
|
+
circles.enter().append('circle')
|
385
|
+
.style('opacity', 0)
|
386
|
+
.attr('cx', storage.lineX)
|
387
|
+
.attr('cy', storage.lineY)
|
388
|
+
.attr('r', 5)
|
389
|
+
.on('mouseover', callbacks.mouseover)
|
390
|
+
.on('mouseout', callbacks.mouseout)
|
391
|
+
.on('click', callbacks.click);
|
392
|
+
|
393
|
+
storage.lineCircles = circles;
|
394
|
+
}
|
395
|
+
|
396
|
+
function update(self, storage, timing) {
|
397
|
+
line.update.apply(null, _.toArray(arguments));
|
398
|
+
|
399
|
+
storage.lineCircles.transition().duration(timing)
|
400
|
+
.style('opacity', 1)
|
401
|
+
.attr('cx', storage.lineX)
|
402
|
+
.attr('cy', storage.lineY);
|
403
|
+
}
|
404
|
+
|
405
|
+
function exit(self, storage) {
|
406
|
+
storage.lineCircles.exit()
|
407
|
+
.remove();
|
408
|
+
line.exit.apply(null, _.toArray(arguments));
|
409
|
+
}
|
410
|
+
|
411
|
+
function destroy(self, storage, timing) {
|
412
|
+
line.destroy.apply(null, _.toArray(arguments));
|
413
|
+
if (!storage.lineCircles) {
|
414
|
+
return;
|
415
|
+
}
|
416
|
+
storage.lineCircles.transition().duration(timing)
|
417
|
+
.style('opacity', 0);
|
418
|
+
}
|
419
|
+
|
420
|
+
_vis['line-dotted'] = {
|
421
|
+
enter: enter,
|
422
|
+
update: update,
|
423
|
+
exit: exit,
|
424
|
+
destroy: destroy
|
425
|
+
};
|
426
|
+
}());
|
427
|
+
(function () {
|
428
|
+
var line = _vis['line-dotted'];
|
429
|
+
|
430
|
+
function enter(self, storage, className, data, callbacks) {
|
431
|
+
line.enter(self, storage, className, data, callbacks);
|
432
|
+
}
|
433
|
+
|
434
|
+
function _accumulate_data(data) {
|
435
|
+
function reduce(memo, num) {
|
436
|
+
return memo + num.y;
|
437
|
+
}
|
438
|
+
|
439
|
+
var nData = _.map(data, function (set) {
|
440
|
+
var i = set.data.length,
|
441
|
+
d = _.clone(set.data);
|
442
|
+
set = _.clone(set);
|
443
|
+
while (i) {
|
444
|
+
i -= 1;
|
445
|
+
// Need to clone here, otherwise we are actually setting the same
|
446
|
+
// data onto the original data set.
|
447
|
+
d[i] = _.clone(set.data[i]);
|
448
|
+
d[i].y0 = set.data[i].y;
|
449
|
+
d[i].y = _.reduce(_.first(set.data, i), reduce, set.data[i].y);
|
450
|
+
}
|
451
|
+
return _.extend(set, { data: d });
|
452
|
+
});
|
453
|
+
|
454
|
+
return nData;
|
455
|
+
}
|
456
|
+
|
457
|
+
function _resetData(self) {
|
458
|
+
if (!self.hasOwnProperty('cumulativeOMainData')) {
|
459
|
+
return;
|
460
|
+
}
|
461
|
+
self._mainData = self.cumulativeOMainData;
|
462
|
+
delete self.cumulativeOMainData;
|
463
|
+
self._compData = self.cumulativeOCompData;
|
464
|
+
delete self.cumulativeOCompData;
|
465
|
+
}
|
466
|
+
|
467
|
+
function preUpdateScale(self, data) {
|
468
|
+
_resetData(self);
|
469
|
+
self.cumulativeOMainData = self._mainData;
|
470
|
+
self._mainData = _accumulate_data(self._mainData);
|
471
|
+
self.cumulativeOCompData = self._compData;
|
472
|
+
self._compData = _accumulate_data(self._compData);
|
473
|
+
}
|
474
|
+
|
475
|
+
function destroy(self, storage, timing) {
|
476
|
+
_resetData(self);
|
477
|
+
line.destroy.apply(null, _.toArray(arguments));
|
478
|
+
}
|
479
|
+
|
480
|
+
_vis.cumulative = {
|
481
|
+
preUpdateScale: preUpdateScale,
|
482
|
+
enter: enter,
|
483
|
+
update: line.update,
|
484
|
+
exit: line.exit,
|
485
|
+
destroy: destroy
|
486
|
+
};
|
487
|
+
}());
|
488
|
+
var emptyData = [[]],
|
489
|
+
defaults = {
|
490
|
+
// User interaction callbacks
|
491
|
+
mouseover: function (data, i) {},
|
492
|
+
mouseout: function (data, i) {},
|
493
|
+
click: function (data, i) {},
|
494
|
+
|
495
|
+
// Padding between the axes and the contents of the chart
|
496
|
+
axisPaddingTop: 0,
|
497
|
+
axisPaddingRight: 0,
|
498
|
+
axisPaddingBottom: 5,
|
499
|
+
axisPaddingLeft: 20,
|
500
|
+
|
501
|
+
// Padding around the edge of the chart (space for axis labels, etc)
|
502
|
+
paddingTop: 0,
|
503
|
+
paddingRight: 0,
|
504
|
+
paddingBottom: 20,
|
505
|
+
paddingLeft: 60,
|
506
|
+
|
507
|
+
// Axis tick formatting
|
508
|
+
tickHintX: 10,
|
509
|
+
tickFormatX: function (x) { return x; },
|
510
|
+
tickHintY: 10,
|
511
|
+
tickFormatY: function (y) { return y; },
|
512
|
+
|
513
|
+
// Min/Max Axis Values
|
514
|
+
xMin: null,
|
515
|
+
xMax: null,
|
516
|
+
yMin: null,
|
517
|
+
yMax: null,
|
518
|
+
|
519
|
+
// Pre-format input data
|
520
|
+
dataFormatX: function (x) { return x; },
|
521
|
+
dataFormatY: function (y) { return y; },
|
522
|
+
|
523
|
+
unsupported: function (selector) {
|
524
|
+
d3.select(selector).text('SVG is not supported on your browser');
|
525
|
+
},
|
526
|
+
|
527
|
+
// Callback functions if no data
|
528
|
+
empty: function (self, selector, d) {},
|
529
|
+
notempty: function (self, selector) {},
|
530
|
+
|
531
|
+
timing: 750,
|
532
|
+
|
533
|
+
// Line interpolation
|
534
|
+
interpolation: 'monotone',
|
535
|
+
|
536
|
+
// Data sorting
|
537
|
+
sortX: function (a, b) {
|
538
|
+
return (!a.x && !b.x) ? 0 : (a.x < b.x) ? -1 : 1;
|
539
|
+
}
|
540
|
+
};
|
541
|
+
|
542
|
+
// What/how should the warning/error be presented?
|
543
|
+
function svgEnabled() {
|
544
|
+
var d = document;
|
545
|
+
return (!!d.createElementNS &&
|
546
|
+
!!d.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
|
547
|
+
}
|
548
|
+
|
549
|
+
/**
|
550
|
+
* Creates a new chart
|
551
|
+
*
|
552
|
+
* @param string type The drawing type for the main data
|
553
|
+
* @param array data Data to render in the chart
|
554
|
+
* @param string selector CSS Selector for the parent element for the chart
|
555
|
+
* @param object options Optional. See `defaults` for options
|
556
|
+
*
|
557
|
+
* Examples:
|
558
|
+
* var data = {
|
559
|
+
* "main": [
|
560
|
+
* {
|
561
|
+
* "data": [
|
562
|
+
* {
|
563
|
+
* "x": "2012-08-09T07:00:00.522Z",
|
564
|
+
* "y": 68
|
565
|
+
* },
|
566
|
+
* {
|
567
|
+
* "x": "2012-08-10T07:00:00.522Z",
|
568
|
+
* "y": 295
|
569
|
+
* },
|
570
|
+
* {
|
571
|
+
* "x": "2012-08-11T07:00:00.522Z",
|
572
|
+
* "y": 339
|
573
|
+
* },
|
574
|
+
* ],
|
575
|
+
* "className": ".foo"
|
576
|
+
* }
|
577
|
+
* ],
|
578
|
+
* "xScale": "ordinal",
|
579
|
+
* "yScale": "linear",
|
580
|
+
* "comp": [
|
581
|
+
* {
|
582
|
+
* "data": [
|
583
|
+
* {
|
584
|
+
* "x": "2012-08-09T07:00:00.522Z",
|
585
|
+
* "y": 288
|
586
|
+
* },
|
587
|
+
* {
|
588
|
+
* "x": "2012-08-10T07:00:00.522Z",
|
589
|
+
* "y": 407
|
590
|
+
* },
|
591
|
+
* {
|
592
|
+
* "x": "2012-08-11T07:00:00.522Z",
|
593
|
+
* "y": 459
|
594
|
+
* }
|
595
|
+
* ],
|
596
|
+
* "className": ".comp.comp_foo",
|
597
|
+
* "type": "line-arrowed"
|
598
|
+
* }
|
599
|
+
* ]
|
600
|
+
* },
|
601
|
+
* myChart = new Chart('bar', data, '#chart');
|
602
|
+
*
|
603
|
+
*/
|
604
|
+
function xChart(type, data, selector, options) {
|
605
|
+
var self = this,
|
606
|
+
resizeLock;
|
607
|
+
|
608
|
+
self._options = options = _.defaults(options || {}, defaults);
|
609
|
+
|
610
|
+
if (svgEnabled() === false) {
|
611
|
+
return options.unsupported(selector);
|
612
|
+
}
|
613
|
+
|
614
|
+
self._selector = selector;
|
615
|
+
self._container = d3.select(selector);
|
616
|
+
self._drawSvg();
|
617
|
+
self._mainStorage = {};
|
618
|
+
self._compStorage = {};
|
619
|
+
|
620
|
+
data = _.clone(data);
|
621
|
+
if (type && !data.type) {
|
622
|
+
data.type = type;
|
623
|
+
}
|
624
|
+
|
625
|
+
self.setData(data);
|
626
|
+
|
627
|
+
d3.select(window).on('resize.for.' + selector, function () {
|
628
|
+
if (resizeLock) {
|
629
|
+
clearTimeout(resizeLock);
|
630
|
+
}
|
631
|
+
resizeLock = setTimeout(function () {
|
632
|
+
resizeLock = null;
|
633
|
+
self._resize();
|
634
|
+
}, 500);
|
635
|
+
});
|
636
|
+
}
|
637
|
+
|
638
|
+
/**
|
639
|
+
* Add a visualization type
|
640
|
+
*
|
641
|
+
* @param string type Unique key/name used with setType
|
642
|
+
* @param object vis object map of vis methods
|
643
|
+
*/
|
644
|
+
xChart.setVis = function (type, vis) {
|
645
|
+
if (_vis.hasOwnProperty(type)) {
|
646
|
+
throw 'Cannot override vis type "' + type + '".';
|
647
|
+
}
|
648
|
+
_vis[type] = vis;
|
649
|
+
};
|
650
|
+
|
651
|
+
/**
|
652
|
+
* Get a clone of a visualization
|
653
|
+
* Useful for extending vis functionality
|
654
|
+
*
|
655
|
+
* @param string type Unique key/name of the vis
|
656
|
+
*/
|
657
|
+
xChart.getVis = function (type) {
|
658
|
+
if (!_vis.hasOwnProperty(type)) {
|
659
|
+
throw 'Vis type "' + type + '" does not exist.';
|
660
|
+
}
|
661
|
+
|
662
|
+
return _.clone(_vis[type]);
|
663
|
+
};
|
664
|
+
|
665
|
+
xChart.setScale = function (name, fn) {
|
666
|
+
if (_scales.hasOwnProperty(name)) {
|
667
|
+
throw 'Scale type "' + name + '" already exists.';
|
668
|
+
}
|
669
|
+
|
670
|
+
_scales[name] = fn;
|
671
|
+
};
|
672
|
+
|
673
|
+
xChart.getScale = function (name) {
|
674
|
+
if (!_scales.hasOwnProperty(name)) {
|
675
|
+
throw 'Scale type "' + name + '" does not exist.';
|
676
|
+
}
|
677
|
+
return _scales[name];
|
678
|
+
};
|
679
|
+
|
680
|
+
xChart.visutils = _visutils;
|
681
|
+
|
682
|
+
_.defaults(xChart.prototype, {
|
683
|
+
/**
|
684
|
+
* Set or change the drawing type for the main data.
|
685
|
+
*
|
686
|
+
* @param string type Must be an available drawing type
|
687
|
+
*
|
688
|
+
*/
|
689
|
+
setType: function (type, skipDraw) {
|
690
|
+
var self = this;
|
691
|
+
|
692
|
+
if (self._type && type === self._type) {
|
693
|
+
return;
|
694
|
+
}
|
695
|
+
|
696
|
+
if (!_vis.hasOwnProperty(type)) {
|
697
|
+
throw 'Vis type "' + type + '" is not defined.';
|
698
|
+
}
|
699
|
+
|
700
|
+
if (self._type) {
|
701
|
+
self._destroy(self._vis, self._mainStorage);
|
702
|
+
}
|
703
|
+
|
704
|
+
self._type = type;
|
705
|
+
self._vis = _vis[type];
|
706
|
+
if (!skipDraw) {
|
707
|
+
self._draw();
|
708
|
+
}
|
709
|
+
},
|
710
|
+
|
711
|
+
/**
|
712
|
+
* Set and update the data for the chart. Optionally skip drawing.
|
713
|
+
*
|
714
|
+
* @param object data New data. See new xChart example for format
|
715
|
+
*
|
716
|
+
*/
|
717
|
+
setData: function (data) {
|
718
|
+
var self = this,
|
719
|
+
o = self._options,
|
720
|
+
nData = _.clone(data);
|
721
|
+
|
722
|
+
if (!data.hasOwnProperty('main')) {
|
723
|
+
throw 'No "main" key found in given chart data.';
|
724
|
+
}
|
725
|
+
|
726
|
+
switch (data.type) {
|
727
|
+
case 'bar':
|
728
|
+
// force the xScale to be ordinal
|
729
|
+
data.xScale = 'ordinal';
|
730
|
+
break;
|
731
|
+
case undefined:
|
732
|
+
data.type = self._type;
|
733
|
+
break;
|
734
|
+
}
|
735
|
+
|
736
|
+
o.xMin = (isNaN(parseInt(data.xMin, 10))) ? o.xMin : data.xMin;
|
737
|
+
o.xMax = (isNaN(parseInt(data.xMax, 10))) ? o.xMax : data.xMax;
|
738
|
+
o.yMin = (isNaN(parseInt(data.yMin, 10))) ? o.yMin : data.yMin;
|
739
|
+
o.yMax = (isNaN(parseInt(data.yMax, 10))) ? o.yMax : data.yMax;
|
740
|
+
|
741
|
+
if (self._vis) {
|
742
|
+
self._destroy(self._vis, self._mainStorage);
|
743
|
+
}
|
744
|
+
|
745
|
+
self.setType(data.type, true);
|
746
|
+
|
747
|
+
function _mapData(set) {
|
748
|
+
var d = _.map(_.clone(set.data), function (p) {
|
749
|
+
var np = _.clone(p);
|
750
|
+
if (p.hasOwnProperty('x')) {
|
751
|
+
np.x = o.dataFormatX(p.x);
|
752
|
+
}
|
753
|
+
if (p.hasOwnProperty('y')) {
|
754
|
+
np.y = o.dataFormatY(p.y);
|
755
|
+
}
|
756
|
+
return np;
|
757
|
+
}).sort(o.sortX);
|
758
|
+
return _.extend(_.clone(set), { data: d });
|
759
|
+
}
|
760
|
+
|
761
|
+
nData.main = _.map(nData.main, _mapData);
|
762
|
+
self._mainData = nData.main;
|
763
|
+
self._xScaleType = nData.xScale;
|
764
|
+
self._yScaleType = nData.yScale;
|
765
|
+
|
766
|
+
if (nData.hasOwnProperty('comp')) {
|
767
|
+
nData.comp = _.map(nData.comp, _mapData);
|
768
|
+
self._compData = nData.comp;
|
769
|
+
} else {
|
770
|
+
self._compData = [];
|
771
|
+
}
|
772
|
+
|
773
|
+
self._draw();
|
774
|
+
},
|
775
|
+
|
776
|
+
/**
|
777
|
+
* Change the scale of an axis
|
778
|
+
*
|
779
|
+
* @param string axis Name of an axis. One of 'x' or 'y'
|
780
|
+
* @param string type Name of the scale type
|
781
|
+
*
|
782
|
+
*/
|
783
|
+
setScale: function (axis, type) {
|
784
|
+
var self = this;
|
785
|
+
|
786
|
+
switch (axis) {
|
787
|
+
case 'x':
|
788
|
+
self._xScaleType = type;
|
789
|
+
break;
|
790
|
+
case 'y':
|
791
|
+
self._yScaleType = type;
|
792
|
+
break;
|
793
|
+
default:
|
794
|
+
throw 'Cannot change scale of unknown axis "' + axis + '".';
|
795
|
+
}
|
796
|
+
|
797
|
+
self._draw();
|
798
|
+
},
|
799
|
+
|
800
|
+
/**
|
801
|
+
* Create the SVG element and g container. Resize if necessary.
|
802
|
+
*/
|
803
|
+
_drawSvg: function () {
|
804
|
+
var self = this,
|
805
|
+
c = self._container,
|
806
|
+
options = self._options,
|
807
|
+
width = parseInt(c.style('width').replace('px', ''), 10),
|
808
|
+
height = parseInt(c.style('height').replace('px', ''), 10),
|
809
|
+
svg,
|
810
|
+
g,
|
811
|
+
gScale;
|
812
|
+
|
813
|
+
svg = c.selectAll('svg')
|
814
|
+
.data(emptyData);
|
815
|
+
|
816
|
+
svg.enter().append('svg')
|
817
|
+
// Inherit the height and width from the parent element
|
818
|
+
.attr('height', height)
|
819
|
+
.attr('width', width)
|
820
|
+
.attr('class', 'xchart');
|
821
|
+
|
822
|
+
svg.transition()
|
823
|
+
.attr('width', width)
|
824
|
+
.attr('height', height);
|
825
|
+
|
826
|
+
g = svg.selectAll('g')
|
827
|
+
.data(emptyData);
|
828
|
+
|
829
|
+
g.enter().append('g')
|
830
|
+
.attr(
|
831
|
+
'transform',
|
832
|
+
'translate(' + options.paddingLeft + ',' + options.paddingTop + ')'
|
833
|
+
);
|
834
|
+
|
835
|
+
gScale = g.selectAll('g.scale')
|
836
|
+
.data(emptyData);
|
837
|
+
|
838
|
+
gScale.enter().append('g')
|
839
|
+
.attr('class', 'scale');
|
840
|
+
|
841
|
+
self._svg = svg;
|
842
|
+
self._g = g;
|
843
|
+
self._gScale = gScale;
|
844
|
+
|
845
|
+
self._height = height - options.paddingTop - options.paddingBottom -
|
846
|
+
options.axisPaddingTop - options.axisPaddingBottom;
|
847
|
+
self._width = width - options.paddingLeft - options.paddingRight -
|
848
|
+
options.axisPaddingLeft - options.axisPaddingRight;
|
849
|
+
},
|
850
|
+
|
851
|
+
/**
|
852
|
+
* Resize the visualization
|
853
|
+
*/
|
854
|
+
_resize: function (event) {
|
855
|
+
var self = this;
|
856
|
+
|
857
|
+
self._drawSvg();
|
858
|
+
self._draw();
|
859
|
+
},
|
860
|
+
|
861
|
+
/**
|
862
|
+
* Draw the x and y axes
|
863
|
+
*/
|
864
|
+
_drawAxes: function () {
|
865
|
+
if (this._noData) {
|
866
|
+
return;
|
867
|
+
}
|
868
|
+
var self = this,
|
869
|
+
o = self._options,
|
870
|
+
t = self._gScale.transition().duration(o.timing),
|
871
|
+
xTicks = o.tickHintX,
|
872
|
+
yTicks = o.tickHintY,
|
873
|
+
bottom = self._height + o.axisPaddingTop + o.axisPaddingBottom,
|
874
|
+
zeroLine = d3.svg.line().x(function (d) { return d; }),
|
875
|
+
zLine,
|
876
|
+
zLinePath,
|
877
|
+
xAxis,
|
878
|
+
xRules,
|
879
|
+
yAxis,
|
880
|
+
yRules,
|
881
|
+
labels;
|
882
|
+
|
883
|
+
xRules = d3.svg.axis()
|
884
|
+
.scale(self.xScale)
|
885
|
+
.ticks(xTicks)
|
886
|
+
.tickSize(-self._height)
|
887
|
+
.tickFormat(o.tickFormatX)
|
888
|
+
.orient('bottom');
|
889
|
+
|
890
|
+
xAxis = self._gScale.selectAll('g.axisX')
|
891
|
+
.data(emptyData);
|
892
|
+
|
893
|
+
xAxis.enter().append('g')
|
894
|
+
.attr('class', 'axis axisX')
|
895
|
+
.attr('transform', 'translate(0,' + bottom + ')');
|
896
|
+
|
897
|
+
xAxis.call(xRules);
|
898
|
+
|
899
|
+
labels = self._gScale.selectAll('.axisX g')[0];
|
900
|
+
if (labels.length > (self._width / 80)) {
|
901
|
+
labels.sort(function (a, b) {
|
902
|
+
var r = /translate\(([^,)]+)/;
|
903
|
+
a = a.getAttribute('transform').match(r);
|
904
|
+
b = b.getAttribute('transform').match(r);
|
905
|
+
return parseFloat(a[1], 10) - parseFloat(b[1], 10);
|
906
|
+
});
|
907
|
+
|
908
|
+
d3.selectAll(labels)
|
909
|
+
.filter(function (d, i) {
|
910
|
+
return i % (Math.ceil(labels.length / xTicks) + 1);
|
911
|
+
})
|
912
|
+
.remove();
|
913
|
+
}
|
914
|
+
|
915
|
+
yRules = d3.svg.axis()
|
916
|
+
.scale(self.yScale)
|
917
|
+
.ticks(yTicks)
|
918
|
+
.tickSize(-self._width - o.axisPaddingRight - o.axisPaddingLeft)
|
919
|
+
.tickFormat(o.tickFormatY)
|
920
|
+
.orient('left');
|
921
|
+
|
922
|
+
yAxis = self._gScale.selectAll('g.axisY')
|
923
|
+
.data(emptyData);
|
924
|
+
|
925
|
+
yAxis.enter().append('g')
|
926
|
+
.attr('class', 'axis axisY')
|
927
|
+
.attr('transform', 'translate(0,0)');
|
928
|
+
|
929
|
+
t.selectAll('g.axisY')
|
930
|
+
.call(yRules);
|
931
|
+
|
932
|
+
// zero line
|
933
|
+
zLine = self._gScale.selectAll('g.axisZero')
|
934
|
+
.data([[]]);
|
935
|
+
|
936
|
+
zLine.enter().append('g')
|
937
|
+
.attr('class', 'axisZero');
|
938
|
+
|
939
|
+
zLinePath = zLine.selectAll('line')
|
940
|
+
.data([[]]);
|
941
|
+
|
942
|
+
zLinePath.enter().append('line')
|
943
|
+
.attr('x1', 0)
|
944
|
+
.attr('x2', self._width + o.axisPaddingLeft + o.axisPaddingRight)
|
945
|
+
.attr('y1', self.yZero)
|
946
|
+
.attr('y2', self.yZero);
|
947
|
+
|
948
|
+
zLinePath.transition().duration(o.timing)
|
949
|
+
.attr('y1', self.yZero)
|
950
|
+
.attr('y2', self.yZero);
|
951
|
+
},
|
952
|
+
|
953
|
+
/**
|
954
|
+
* Update the x and y scales (used when drawing)
|
955
|
+
*
|
956
|
+
* Optional methods in drawing types:
|
957
|
+
* preUpdateScale
|
958
|
+
* postUpdateScale
|
959
|
+
*
|
960
|
+
* Example implementation in vis type:
|
961
|
+
*
|
962
|
+
* function postUpdateScale(self, scaleData, mainData, compData) {
|
963
|
+
* self.xScale2 = d3.scale.ordinal()
|
964
|
+
* .domain(d3.range(0, mainData.length))
|
965
|
+
* .rangeRoundBands([0, self.xScale.rangeBand()], 0.08);
|
966
|
+
* }
|
967
|
+
*
|
968
|
+
*/
|
969
|
+
_updateScale: function () {
|
970
|
+
var self = this,
|
971
|
+
_unionData = function () {
|
972
|
+
return _.union(self._mainData, self._compData);
|
973
|
+
},
|
974
|
+
scaleData = _unionData(),
|
975
|
+
vis = self._vis,
|
976
|
+
scale,
|
977
|
+
min;
|
978
|
+
|
979
|
+
delete self.xScale;
|
980
|
+
delete self.yScale;
|
981
|
+
delete self.yZero;
|
982
|
+
|
983
|
+
if (vis.hasOwnProperty('preUpdateScale')) {
|
984
|
+
vis.preUpdateScale(self, scaleData, self._mainData, self._compData);
|
985
|
+
}
|
986
|
+
|
987
|
+
// Just in case preUpdateScale modified
|
988
|
+
scaleData = _unionData();
|
989
|
+
scale = _scales.xy(self, scaleData, self._xScaleType, self._yScaleType);
|
990
|
+
|
991
|
+
self.xScale = scale.x;
|
992
|
+
self.yScale = scale.y;
|
993
|
+
|
994
|
+
min = self.yScale.domain()[0];
|
995
|
+
self.yZero = (min > 0) ? self.yScale(min) : self.yScale(0);
|
996
|
+
|
997
|
+
if (vis.hasOwnProperty('postUpdateScale')) {
|
998
|
+
vis.postUpdateScale(self, scaleData, self._mainData, self._compData);
|
999
|
+
}
|
1000
|
+
},
|
1001
|
+
|
1002
|
+
/**
|
1003
|
+
* Create (Enter) the elements for the vis
|
1004
|
+
*
|
1005
|
+
* Required method
|
1006
|
+
*
|
1007
|
+
* Example implementation in vis type:
|
1008
|
+
*
|
1009
|
+
* function enter(self, data, callbacks) {
|
1010
|
+
* var foo = self._g.selectAll('g.foobar')
|
1011
|
+
* .data(data);
|
1012
|
+
* foo.enter().append('g')
|
1013
|
+
* .attr('class', 'foobar');
|
1014
|
+
* self.foo = foo;
|
1015
|
+
* }
|
1016
|
+
*/
|
1017
|
+
_enter: function (vis, storage, data, className) {
|
1018
|
+
var self = this,
|
1019
|
+
callbacks = {
|
1020
|
+
click: self._options.click,
|
1021
|
+
mouseover: self._options.mouseover,
|
1022
|
+
mouseout: self._options.mouseout
|
1023
|
+
};
|
1024
|
+
self._checkVisMethod(vis, 'enter');
|
1025
|
+
vis.enter(self, storage, className, data, callbacks);
|
1026
|
+
},
|
1027
|
+
|
1028
|
+
/**
|
1029
|
+
* Update the elements opened by the select method
|
1030
|
+
*
|
1031
|
+
* Required method
|
1032
|
+
*
|
1033
|
+
* Example implementation in vis type:
|
1034
|
+
*
|
1035
|
+
* function update(self, timing) {
|
1036
|
+
* self.bars.transition().duration(timing)
|
1037
|
+
* .attr('width', self.xScale2.rangeBand())
|
1038
|
+
* .attr('height', function (d) {
|
1039
|
+
* return self.yScale(d.y);
|
1040
|
+
* });
|
1041
|
+
* }
|
1042
|
+
*/
|
1043
|
+
_update: function (vis, storage) {
|
1044
|
+
var self = this;
|
1045
|
+
self._checkVisMethod(vis, 'update');
|
1046
|
+
vis.update(self, storage, self._options.timing);
|
1047
|
+
},
|
1048
|
+
|
1049
|
+
/**
|
1050
|
+
* Remove or transition out the elements that no longer have data
|
1051
|
+
*
|
1052
|
+
* Required method
|
1053
|
+
*
|
1054
|
+
* Example implementation in vis type:
|
1055
|
+
*
|
1056
|
+
* function exit(self) {
|
1057
|
+
* self.bars.exit().remove();
|
1058
|
+
* }
|
1059
|
+
*/
|
1060
|
+
_exit: function (vis, storage) {
|
1061
|
+
var self = this;
|
1062
|
+
self._checkVisMethod(vis, 'exit');
|
1063
|
+
vis.exit(self, storage, self._options.timing);
|
1064
|
+
},
|
1065
|
+
|
1066
|
+
/**
|
1067
|
+
* Destroy the current vis type (transition to new type)
|
1068
|
+
*
|
1069
|
+
* Required method
|
1070
|
+
*
|
1071
|
+
* Example implementation in vis type:
|
1072
|
+
*
|
1073
|
+
* function destroy(self, timing) {
|
1074
|
+
* self.bars.transition().duration(timing)
|
1075
|
+
* attr('height', 0);
|
1076
|
+
* delete self.bars;
|
1077
|
+
* }
|
1078
|
+
*/
|
1079
|
+
_destroy: function (vis, storage) {
|
1080
|
+
var self = this;
|
1081
|
+
self._checkVisMethod(vis, 'destroy');
|
1082
|
+
try {
|
1083
|
+
vis.destroy(self, storage, self._options.timing);
|
1084
|
+
} catch (e) {}
|
1085
|
+
},
|
1086
|
+
|
1087
|
+
/**
|
1088
|
+
* Draw the visualization
|
1089
|
+
*/
|
1090
|
+
_draw: function () {
|
1091
|
+
var self = this,
|
1092
|
+
o = self._options,
|
1093
|
+
comp,
|
1094
|
+
compKeys;
|
1095
|
+
|
1096
|
+
self._noData = _.flatten(_.pluck(self._mainData, 'data')
|
1097
|
+
.concat(_.pluck(self._compData, 'data'))).length === 0;
|
1098
|
+
|
1099
|
+
self._updateScale();
|
1100
|
+
self._drawAxes();
|
1101
|
+
|
1102
|
+
self._enter(self._vis, self._mainStorage, self._mainData, '.main');
|
1103
|
+
self._exit(self._vis, self._mainStorage);
|
1104
|
+
self._update(self._vis, self._mainStorage);
|
1105
|
+
|
1106
|
+
comp = _.chain(self._compData).groupBy(function (d) {
|
1107
|
+
return d.type;
|
1108
|
+
});
|
1109
|
+
compKeys = comp.keys();
|
1110
|
+
|
1111
|
+
// Find old comp vis items and remove any that no longer exist
|
1112
|
+
_.each(self._compStorage, function (d, key) {
|
1113
|
+
if (-1 === compKeys.indexOf(key).value()) {
|
1114
|
+
var vis = _vis[key];
|
1115
|
+
self._enter(vis, d, [], '.comp.' + key.replace(/\W+/g, ''));
|
1116
|
+
self._exit(vis, d);
|
1117
|
+
}
|
1118
|
+
});
|
1119
|
+
|
1120
|
+
comp.each(function (d, key) {
|
1121
|
+
var vis = _vis[key], storage;
|
1122
|
+
if (!self._compStorage.hasOwnProperty(key)) {
|
1123
|
+
self._compStorage[key] = {};
|
1124
|
+
}
|
1125
|
+
storage = self._compStorage[key];
|
1126
|
+
self._enter(vis, storage, d, '.comp.' + key.replace(/\W+/g, ''));
|
1127
|
+
self._exit(vis, storage);
|
1128
|
+
self._update(vis, storage);
|
1129
|
+
});
|
1130
|
+
|
1131
|
+
if (self._noData) {
|
1132
|
+
o.empty(self, self._selector, self._mainData);
|
1133
|
+
} else {
|
1134
|
+
o.notempty(self, self._selector);
|
1135
|
+
}
|
1136
|
+
},
|
1137
|
+
|
1138
|
+
/**
|
1139
|
+
* Ensure drawing method exists
|
1140
|
+
*/
|
1141
|
+
_checkVisMethod: function (vis, method) {
|
1142
|
+
var self = this;
|
1143
|
+
if (!vis[method]) {
|
1144
|
+
throw 'Required method "' + method + '" not found on vis type "' +
|
1145
|
+
self._type + '".';
|
1146
|
+
}
|
1147
|
+
}
|
1148
|
+
});
|
1149
|
+
if (typeof define === 'function' && define.amd && typeof define.amd === 'object') {
|
1150
|
+
define(function () {
|
1151
|
+
return xChart;
|
1152
|
+
});
|
1153
|
+
return;
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
window.xChart = xChart;
|
1157
|
+
|
1158
|
+
}());
|