xcharts-rails 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}());
|