postrest 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/app.rb +1 -1
- data/public/index.htm +116 -0
- data/public/node_modules/pivottable/CONTRIBUTING.md +19 -0
- data/public/node_modules/pivottable/LICENSE.md +9 -0
- data/public/node_modules/pivottable/ReadMe.md +155 -0
- data/public/node_modules/pivottable/bower.json +31 -0
- data/public/node_modules/pivottable/c3_renderers.coffee +155 -0
- data/public/node_modules/pivottable/d3_renderers.coffee +73 -0
- data/public/node_modules/pivottable/dist/c3_renderers.js +256 -0
- data/public/node_modules/pivottable/dist/c3_renderers.js.map +1 -0
- data/public/node_modules/pivottable/dist/c3_renderers.min.js +2 -0
- data/public/node_modules/pivottable/dist/c3_renderers.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/d3_renderers.js +105 -0
- data/public/node_modules/pivottable/dist/d3_renderers.js.map +1 -0
- data/public/node_modules/pivottable/dist/d3_renderers.min.js +2 -0
- data/public/node_modules/pivottable/dist/d3_renderers.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/export_renderers.js +80 -0
- data/public/node_modules/pivottable/dist/export_renderers.js.map +1 -0
- data/public/node_modules/pivottable/dist/export_renderers.min.js +2 -0
- data/public/node_modules/pivottable/dist/export_renderers.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/gchart_renderers.js +183 -0
- data/public/node_modules/pivottable/dist/gchart_renderers.js.map +1 -0
- data/public/node_modules/pivottable/dist/gchart_renderers.min.js +2 -0
- data/public/node_modules/pivottable/dist/gchart_renderers.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.css +97 -0
- data/public/node_modules/pivottable/dist/pivot.es.js +78 -0
- data/public/node_modules/pivottable/dist/pivot.es.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.es.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.es.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.fr.js +78 -0
- data/public/node_modules/pivottable/dist/pivot.fr.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.fr.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.fr.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.js +1511 -0
- data/public/node_modules/pivottable/dist/pivot.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.min.css +1 -0
- data/public/node_modules/pivottable/dist/pivot.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.nl.js +78 -0
- data/public/node_modules/pivottable/dist/pivot.nl.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.nl.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.nl.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.pt.js +104 -0
- data/public/node_modules/pivottable/dist/pivot.pt.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.pt.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.pt.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.ru.js +78 -0
- data/public/node_modules/pivottable/dist/pivot.ru.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.ru.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.ru.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.tr.js +104 -0
- data/public/node_modules/pivottable/dist/pivot.tr.js.map +1 -0
- data/public/node_modules/pivottable/dist/pivot.tr.min.js +2 -0
- data/public/node_modules/pivottable/dist/pivot.tr.min.js.map +1 -0
- data/public/node_modules/pivottable/dist/tips_data.min.js +247 -0
- data/public/node_modules/pivottable/examples/c3.html +61 -0
- data/public/node_modules/pivottable/examples/d3.html +49 -0
- data/public/node_modules/pivottable/examples/fully_loaded.html +80 -0
- data/public/node_modules/pivottable/examples/gchart.html +53 -0
- data/public/node_modules/pivottable/examples/gh-fork-ribbon.css +140 -0
- data/public/node_modules/pivottable/examples/gh-fork-ribbon.ie.css +78 -0
- data/public/node_modules/pivottable/examples/index.html +85 -0
- data/public/node_modules/pivottable/examples/local.html +74 -0
- data/public/node_modules/pivottable/examples/montreal_2014.csv +366 -0
- data/public/node_modules/pivottable/examples/montreal_2014.html +106 -0
- data/public/node_modules/pivottable/examples/mps.csv +309 -0
- data/public/node_modules/pivottable/examples/mps.html +45 -0
- data/public/node_modules/pivottable/examples/mps.json +1 -0
- data/public/node_modules/pivottable/examples/mps_agg.html +44 -0
- data/public/node_modules/pivottable/examples/mps_csv.html +42 -0
- data/public/node_modules/pivottable/examples/mps_export.html +44 -0
- data/public/node_modules/pivottable/examples/mps_fr.html +40 -0
- data/public/node_modules/pivottable/examples/mps_prepop.html +42 -0
- data/public/node_modules/pivottable/examples/onrefresh.html +52 -0
- data/public/node_modules/pivottable/examples/rcsvs.html +87 -0
- data/public/node_modules/pivottable/examples/scatter.html +53 -0
- data/public/node_modules/pivottable/examples/show_code.js +17 -0
- data/public/node_modules/pivottable/examples/simple.html +41 -0
- data/public/node_modules/pivottable/examples/simple_agg.html +51 -0
- data/public/node_modules/pivottable/examples/simple_function.html +57 -0
- data/public/node_modules/pivottable/examples/simple_ui.html +42 -0
- data/public/node_modules/pivottable/examples/simple_ui_from_table.html +60 -0
- data/public/node_modules/pivottable/export_renderers.coffee +57 -0
- data/public/node_modules/pivottable/gchart_renderers.coffee +111 -0
- data/public/node_modules/pivottable/gulpFile.js +95 -0
- data/public/node_modules/pivottable/images/animation.gif +0 -0
- data/public/node_modules/pivottable/images/filters.png +0 -0
- data/public/node_modules/pivottable/images/gender_age_bins.png +0 -0
- data/public/node_modules/pivottable/images/gender_imbalance.png +0 -0
- data/public/node_modules/pivottable/images/gender_imbalance_instructions.png +0 -0
- data/public/node_modules/pivottable/images/initial_state.png +0 -0
- data/public/node_modules/pivottable/images/province_x_party_heatmap.png +0 -0
- data/public/node_modules/pivottable/images/province_x_party_heatmap_instructions.png +0 -0
- data/public/node_modules/pivottable/images/simple.png +0 -0
- data/public/node_modules/pivottable/images/simple_ui.png +0 -0
- data/public/node_modules/pivottable/images/whats_what.png +0 -0
- data/public/node_modules/pivottable/index.html +14 -0
- data/public/node_modules/pivottable/node_modules/jquery/AUTHORS.txt +278 -0
- data/public/node_modules/pivottable/node_modules/jquery/LICENSE.txt +36 -0
- data/public/node_modules/pivottable/node_modules/jquery/README.md +65 -0
- data/public/node_modules/pivottable/node_modules/jquery/bower.json +14 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.js +9842 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.min.js +4 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.min.map +1 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.js +7877 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.min.js +4 -0
- data/public/node_modules/pivottable/node_modules/jquery/dist/jquery.slim.min.map +1 -0
- data/public/node_modules/pivottable/node_modules/jquery/package.json +122 -0
- data/public/node_modules/pivottable/node_modules/jquery/sizzle/LICENSE.txt +36 -0
- data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.js +2143 -0
- data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.min.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/sizzle/dist/sizzle.min.map +1 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax.js +845 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/jsonp.js +100 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/load.js +83 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/parseJSON.js +13 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/parseXML.js +27 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/script.js +68 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/location.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/nonce.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/var/rquery.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/ajax/xhr.js +167 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes.js +11 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes/attr.js +142 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes/classes.js +177 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes/prop.js +125 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes/support.js +36 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/attributes/val.js +177 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/callbacks.js +232 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core.js +494 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/DOMEval.js +14 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/access.js +65 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/init.js +134 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/parseHTML.js +41 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/ready.js +103 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/support.js +18 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/core/var/rsingleTag.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css.js +515 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/addGetHookIf.js +24 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/adjustCSS.js +65 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/curCSS.js +60 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/defaultDisplay.js +72 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/hiddenVisibleSelectors.js +18 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/showHide.js +48 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/support.js +121 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/cssExpand.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/getStyles.js +15 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/isHidden.js +16 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/rmargin.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/rnumnonpx.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/css/var/swap.js +24 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data.js +187 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/Data.js +200 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/accepts.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/support.js +23 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/var/acceptData.js +18 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/var/dataPriv.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/data/var/dataUser.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/deferred.js +158 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/deferred/exceptionHook.js +19 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/deprecated.js +32 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/dimensions.js +54 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/effects.js +629 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/effects/Tween.js +121 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/effects/animatedSelector.js +13 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/effects/support.js +58 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event.js +710 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event/ajax.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event/alias.js +27 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event/focusin.js +53 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event/support.js +9 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/event/trigger.js +199 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/exports/amd.js +24 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/exports/global.js +26 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/intro.js +44 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/jquery.js +37 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation.js +481 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/_evalUrl.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/buildFragment.js +102 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/createSafeFragment.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/getAll.js +21 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/setGlobalEval.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/support.js +33 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/nodeNames.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rcheckableType.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rleadingWhitespace.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rscriptType.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/var/rtagName.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/manipulation/wrapMap.js +27 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/offset.js +218 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/outro.js +2 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/queue.js +143 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/queue/delay.js +22 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/selector-native.js +211 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/selector-sizzle.js +14 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/selector.js +1 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/serialize.js +125 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/support.js +63 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/traversing.js +175 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/traversing/findFilter.js +100 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/dir.js +20 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/rneedsContext.js +6 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/traversing/var/siblings.js +15 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/arr.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/class2type.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/concat.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/deletedIds.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/document.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/documentElement.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/hasOwn.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/indexOf.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/pnum.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/push.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/rcssNum.js +7 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/rnotwhite.js +3 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/slice.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/support.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/var/toString.js +5 -0
- data/public/node_modules/pivottable/node_modules/jquery/src/wrap.js +79 -0
- data/public/node_modules/pivottable/package.json +70 -0
- data/public/node_modules/pivottable/pivot.coffee +957 -0
- data/public/node_modules/pivottable/pivot.es.coffee +57 -0
- data/public/node_modules/pivottable/pivot.fr.coffee +57 -0
- data/public/node_modules/pivottable/pivot.nl.coffee +55 -0
- data/public/node_modules/pivottable/pivot.pt.coffee +80 -0
- data/public/node_modules/pivottable/pivot.ru.coffee +56 -0
- data/public/node_modules/pivottable/pivot.tr.coffee +80 -0
- data/public/node_modules/pivottable/pivottable.jquery.json +33 -0
- data/public/node_modules/pivottable/tests/boot.js +152 -0
- data/public/node_modules/pivottable/tests/index.html +35 -0
- data/public/node_modules/pivottable/tests/pivot_spec.coffee +458 -0
- data/public/vendor.js +5 -0
- metadata +232 -1
@@ -0,0 +1,79 @@
|
|
1
|
+
define( [
|
2
|
+
"./core",
|
3
|
+
"./core/init",
|
4
|
+
"./manipulation", // clone
|
5
|
+
"./traversing" // parent, contents
|
6
|
+
], function( jQuery ) {
|
7
|
+
|
8
|
+
jQuery.fn.extend( {
|
9
|
+
wrapAll: function( html ) {
|
10
|
+
var wrap;
|
11
|
+
|
12
|
+
if ( jQuery.isFunction( html ) ) {
|
13
|
+
return this.each( function( i ) {
|
14
|
+
jQuery( this ).wrapAll( html.call( this, i ) );
|
15
|
+
} );
|
16
|
+
}
|
17
|
+
|
18
|
+
if ( this[ 0 ] ) {
|
19
|
+
|
20
|
+
// The elements to wrap the target around
|
21
|
+
wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
|
22
|
+
|
23
|
+
if ( this[ 0 ].parentNode ) {
|
24
|
+
wrap.insertBefore( this[ 0 ] );
|
25
|
+
}
|
26
|
+
|
27
|
+
wrap.map( function() {
|
28
|
+
var elem = this;
|
29
|
+
|
30
|
+
while ( elem.firstElementChild ) {
|
31
|
+
elem = elem.firstElementChild;
|
32
|
+
}
|
33
|
+
|
34
|
+
return elem;
|
35
|
+
} ).append( this );
|
36
|
+
}
|
37
|
+
|
38
|
+
return this;
|
39
|
+
},
|
40
|
+
|
41
|
+
wrapInner: function( html ) {
|
42
|
+
if ( jQuery.isFunction( html ) ) {
|
43
|
+
return this.each( function( i ) {
|
44
|
+
jQuery( this ).wrapInner( html.call( this, i ) );
|
45
|
+
} );
|
46
|
+
}
|
47
|
+
|
48
|
+
return this.each( function() {
|
49
|
+
var self = jQuery( this ),
|
50
|
+
contents = self.contents();
|
51
|
+
|
52
|
+
if ( contents.length ) {
|
53
|
+
contents.wrapAll( html );
|
54
|
+
|
55
|
+
} else {
|
56
|
+
self.append( html );
|
57
|
+
}
|
58
|
+
} );
|
59
|
+
},
|
60
|
+
|
61
|
+
wrap: function( html ) {
|
62
|
+
var isFunction = jQuery.isFunction( html );
|
63
|
+
|
64
|
+
return this.each( function( i ) {
|
65
|
+
jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
|
66
|
+
} );
|
67
|
+
},
|
68
|
+
|
69
|
+
unwrap: function() {
|
70
|
+
return this.parent().each( function() {
|
71
|
+
if ( !jQuery.nodeName( this, "body" ) ) {
|
72
|
+
jQuery( this ).replaceWith( this.childNodes );
|
73
|
+
}
|
74
|
+
} ).end();
|
75
|
+
}
|
76
|
+
} );
|
77
|
+
|
78
|
+
return jQuery;
|
79
|
+
} );
|
@@ -0,0 +1,70 @@
|
|
1
|
+
{
|
2
|
+
"name": "pivottable",
|
3
|
+
"version": "2.0.2",
|
4
|
+
"description": "Javascript Pivot Table (aka Pivot Grid, Pivot Chart, Cross-Tab) implementation with drag'n'drop",
|
5
|
+
"main": "dist/pivot.js",
|
6
|
+
"keywords": [
|
7
|
+
"pivot",
|
8
|
+
"crosstab",
|
9
|
+
"grid",
|
10
|
+
"table",
|
11
|
+
"pivottable",
|
12
|
+
"pivotgrid",
|
13
|
+
"pivotchart",
|
14
|
+
"jquery",
|
15
|
+
"jquery-plugin"
|
16
|
+
],
|
17
|
+
"repository": {
|
18
|
+
"type": "git",
|
19
|
+
"url": "git://github.com/nicolaskruchten/pivottable.git"
|
20
|
+
},
|
21
|
+
"author": {
|
22
|
+
"name": "Nicolas Kruchten"
|
23
|
+
},
|
24
|
+
"license": "MIT",
|
25
|
+
"bugs": {
|
26
|
+
"url": "https://github.com/nicolaskruchten/pivottable/issues"
|
27
|
+
},
|
28
|
+
"homepage": "https://github.com/nicolaskruchten/pivottable",
|
29
|
+
"dependencies": {
|
30
|
+
"jquery": ">=1.9.0"
|
31
|
+
},
|
32
|
+
"devDependencies": {
|
33
|
+
"gulp-coffee": "^2.2.0",
|
34
|
+
"gulp-uglify": "^1.0.2",
|
35
|
+
"gulp-sourcemaps": "^1.2.8",
|
36
|
+
"gulp": "^3.8.10",
|
37
|
+
"run-sequence": "^1.0.2",
|
38
|
+
"gulp-tag-version": "^1.2.1",
|
39
|
+
"gulp-git": "^0.5.5",
|
40
|
+
"gulp-bump": "^0.1.11",
|
41
|
+
"gulp-filter": "^1.0.2",
|
42
|
+
"gulp-util": "^3.0.1",
|
43
|
+
"gulp-rename": "^1.2.0",
|
44
|
+
"gulp-minify-css": "^0.3.11",
|
45
|
+
"gulp-concat": "^2.4.2"
|
46
|
+
},
|
47
|
+
"gitHead": "a2f694fc3011471a7fe4d300c9f4b6c6edf1cffe",
|
48
|
+
"_id": "pivottable@2.0.2",
|
49
|
+
"scripts": {},
|
50
|
+
"_shasum": "901dea3a4a37fca6db4e1b658364bce803cf9380",
|
51
|
+
"_from": "pivottable@*",
|
52
|
+
"_npmVersion": "2.11.3",
|
53
|
+
"_nodeVersion": "0.12.7",
|
54
|
+
"_npmUser": {
|
55
|
+
"name": "nicolaskruchten",
|
56
|
+
"email": "nicolas@kruchten.com"
|
57
|
+
},
|
58
|
+
"dist": {
|
59
|
+
"shasum": "901dea3a4a37fca6db4e1b658364bce803cf9380",
|
60
|
+
"tarball": "https://registry.npmjs.org/pivottable/-/pivottable-2.0.2.tgz"
|
61
|
+
},
|
62
|
+
"maintainers": [
|
63
|
+
{
|
64
|
+
"name": "nicolaskruchten",
|
65
|
+
"email": "nicolas@kruchten.com"
|
66
|
+
}
|
67
|
+
],
|
68
|
+
"directories": {},
|
69
|
+
"_resolved": "https://registry.npmjs.org/pivottable/-/pivottable-2.0.2.tgz"
|
70
|
+
}
|
@@ -0,0 +1,957 @@
|
|
1
|
+
callWithJQuery = (pivotModule) ->
|
2
|
+
if typeof exports is "object" and typeof module is "object" # CommonJS
|
3
|
+
pivotModule require("jquery")
|
4
|
+
else if typeof define is "function" and define.amd # AMD
|
5
|
+
define ["jquery"], pivotModule
|
6
|
+
# Plain browser env
|
7
|
+
else
|
8
|
+
pivotModule jQuery
|
9
|
+
|
10
|
+
callWithJQuery ($) ->
|
11
|
+
|
12
|
+
###
|
13
|
+
Utilities
|
14
|
+
###
|
15
|
+
|
16
|
+
addSeparators = (nStr, thousandsSep, decimalSep) ->
|
17
|
+
nStr += ''
|
18
|
+
x = nStr.split('.')
|
19
|
+
x1 = x[0]
|
20
|
+
x2 = if x.length > 1 then decimalSep + x[1] else ''
|
21
|
+
rgx = /(\d+)(\d{3})/
|
22
|
+
x1 = x1.replace(rgx, '$1' + thousandsSep + '$2') while rgx.test(x1)
|
23
|
+
return x1 + x2
|
24
|
+
|
25
|
+
numberFormat = (opts) ->
|
26
|
+
defaults =
|
27
|
+
digitsAfterDecimal: 2, scaler: 1,
|
28
|
+
thousandsSep: ",", decimalSep: "."
|
29
|
+
prefix: "", suffix: ""
|
30
|
+
showZero: false
|
31
|
+
opts = $.extend defaults, opts
|
32
|
+
(x) ->
|
33
|
+
return "" if isNaN(x) or not isFinite(x)
|
34
|
+
return "" if x == 0 and not opts.showZero
|
35
|
+
result = addSeparators (opts.scaler*x).toFixed(opts.digitsAfterDecimal), opts.thousandsSep, opts.decimalSep
|
36
|
+
return ""+opts.prefix+result+opts.suffix
|
37
|
+
|
38
|
+
#aggregator templates default to US number formatting but this is overrideable
|
39
|
+
usFmt = numberFormat()
|
40
|
+
usFmtInt = numberFormat(digitsAfterDecimal: 0)
|
41
|
+
usFmtPct = numberFormat(digitsAfterDecimal:1, scaler: 100, suffix: "%")
|
42
|
+
|
43
|
+
aggregatorTemplates =
|
44
|
+
count: (formatter=usFmtInt) -> () -> (data, rowKey, colKey) ->
|
45
|
+
count: 0
|
46
|
+
push: -> @count++
|
47
|
+
value: -> @count
|
48
|
+
format: formatter
|
49
|
+
|
50
|
+
countUnique: (formatter=usFmtInt) -> ([attr]) -> (data, rowKey, colKey) ->
|
51
|
+
uniq: []
|
52
|
+
push: (record) -> @uniq.push(record[attr]) if record[attr] not in @uniq
|
53
|
+
value: -> @uniq.length
|
54
|
+
format: formatter
|
55
|
+
numInputs: if attr? then 0 else 1
|
56
|
+
|
57
|
+
listUnique: (sep) -> ([attr]) -> (data, rowKey, colKey) ->
|
58
|
+
uniq: []
|
59
|
+
push: (record) -> @uniq.push(record[attr]) if record[attr] not in @uniq
|
60
|
+
value: -> @uniq.join sep
|
61
|
+
format: (x) -> x
|
62
|
+
numInputs: if attr? then 0 else 1
|
63
|
+
|
64
|
+
sum: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
|
65
|
+
sum: 0
|
66
|
+
push: (record) -> @sum += parseFloat(record[attr]) if not isNaN parseFloat(record[attr])
|
67
|
+
value: -> @sum
|
68
|
+
format: formatter
|
69
|
+
numInputs: if attr? then 0 else 1
|
70
|
+
|
71
|
+
min: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
|
72
|
+
val: null
|
73
|
+
push: (record) ->
|
74
|
+
x = parseFloat(record[attr])
|
75
|
+
if not isNaN x then @val = Math.min(x, @val ? x)
|
76
|
+
value: -> @val
|
77
|
+
format: formatter
|
78
|
+
numInputs: if attr? then 0 else 1
|
79
|
+
|
80
|
+
max: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
|
81
|
+
val: null
|
82
|
+
push: (record) ->
|
83
|
+
x = parseFloat(record[attr])
|
84
|
+
if not isNaN x then @val = Math.max(x, @val ? x)
|
85
|
+
value: -> @val
|
86
|
+
format: formatter
|
87
|
+
numInputs: if attr? then 0 else 1
|
88
|
+
|
89
|
+
average: (formatter=usFmt) -> ([attr]) -> (data, rowKey, colKey) ->
|
90
|
+
sum: 0
|
91
|
+
len: 0
|
92
|
+
push: (record) ->
|
93
|
+
if not isNaN parseFloat(record[attr])
|
94
|
+
@sum += parseFloat(record[attr])
|
95
|
+
@len++
|
96
|
+
value: -> @sum/@len
|
97
|
+
format: formatter
|
98
|
+
numInputs: if attr? then 0 else 1
|
99
|
+
|
100
|
+
sumOverSum: (formatter=usFmt) -> ([num, denom]) -> (data, rowKey, colKey) ->
|
101
|
+
sumNum: 0
|
102
|
+
sumDenom: 0
|
103
|
+
push: (record) ->
|
104
|
+
@sumNum += parseFloat(record[num]) if not isNaN parseFloat(record[num])
|
105
|
+
@sumDenom += parseFloat(record[denom]) if not isNaN parseFloat(record[denom])
|
106
|
+
value: -> @sumNum/@sumDenom
|
107
|
+
format: formatter
|
108
|
+
numInputs: if num? and denom? then 0 else 2
|
109
|
+
|
110
|
+
sumOverSumBound80: (upper=true, formatter=usFmt) -> ([num, denom]) -> (data, rowKey, colKey) ->
|
111
|
+
sumNum: 0
|
112
|
+
sumDenom: 0
|
113
|
+
push: (record) ->
|
114
|
+
@sumNum += parseFloat(record[num]) if not isNaN parseFloat(record[num])
|
115
|
+
@sumDenom += parseFloat(record[denom]) if not isNaN parseFloat(record[denom])
|
116
|
+
value: ->
|
117
|
+
sign = if upper then 1 else -1
|
118
|
+
(0.821187207574908/@sumDenom + @sumNum/@sumDenom + 1.2815515655446004*sign*
|
119
|
+
Math.sqrt(0.410593603787454/ (@sumDenom*@sumDenom) + (@sumNum*(1 - @sumNum/ @sumDenom))/ (@sumDenom*@sumDenom)))/
|
120
|
+
(1 + 1.642374415149816/@sumDenom)
|
121
|
+
format: formatter
|
122
|
+
numInputs: if num? and denom? then 0 else 2
|
123
|
+
|
124
|
+
fractionOf: (wrapped, type="total", formatter=usFmtPct) -> (x...) -> (data, rowKey, colKey) ->
|
125
|
+
selector: {total:[[],[]],row:[rowKey,[]],col:[[],colKey]}[type]
|
126
|
+
inner: wrapped(x...)(data, rowKey, colKey)
|
127
|
+
push: (record) -> @inner.push record
|
128
|
+
format: formatter
|
129
|
+
value: -> @inner.value() / data.getAggregator(@selector...).inner.value()
|
130
|
+
numInputs: wrapped(x...)().numInputs
|
131
|
+
|
132
|
+
#default aggregators & renderers use US naming and number formatting
|
133
|
+
aggregators = do (tpl = aggregatorTemplates) ->
|
134
|
+
"Count": tpl.count(usFmtInt)
|
135
|
+
"Count Unique Values": tpl.countUnique(usFmtInt)
|
136
|
+
"List Unique Values": tpl.listUnique(", ")
|
137
|
+
"Sum": tpl.sum(usFmt)
|
138
|
+
"Integer Sum": tpl.sum(usFmtInt)
|
139
|
+
"Average": tpl.average(usFmt)
|
140
|
+
"Minimum": tpl.min(usFmt)
|
141
|
+
"Maximum": tpl.max(usFmt)
|
142
|
+
"Sum over Sum": tpl.sumOverSum(usFmt)
|
143
|
+
"80% Upper Bound": tpl.sumOverSumBound80(true, usFmt)
|
144
|
+
"80% Lower Bound": tpl.sumOverSumBound80(false, usFmt)
|
145
|
+
"Sum as Fraction of Total": tpl.fractionOf(tpl.sum(), "total", usFmtPct)
|
146
|
+
"Sum as Fraction of Rows": tpl.fractionOf(tpl.sum(), "row", usFmtPct)
|
147
|
+
"Sum as Fraction of Columns": tpl.fractionOf(tpl.sum(), "col", usFmtPct)
|
148
|
+
"Count as Fraction of Total": tpl.fractionOf(tpl.count(), "total", usFmtPct)
|
149
|
+
"Count as Fraction of Rows": tpl.fractionOf(tpl.count(), "row", usFmtPct)
|
150
|
+
"Count as Fraction of Columns": tpl.fractionOf(tpl.count(), "col", usFmtPct)
|
151
|
+
|
152
|
+
renderers =
|
153
|
+
"Table": (pvtData, opts) -> pivotTableRenderer(pvtData, opts)
|
154
|
+
"Table Barchart": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).barchart()
|
155
|
+
"Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap()
|
156
|
+
"Row Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap("rowheatmap")
|
157
|
+
"Col Heatmap": (pvtData, opts) -> $(pivotTableRenderer(pvtData, opts)).heatmap("colheatmap")
|
158
|
+
|
159
|
+
locales =
|
160
|
+
en:
|
161
|
+
aggregators: aggregators
|
162
|
+
renderers: renderers
|
163
|
+
localeStrings:
|
164
|
+
renderError: "An error occurred rendering the PivotTable results."
|
165
|
+
computeError: "An error occurred computing the PivotTable results."
|
166
|
+
uiRenderError: "An error occurred rendering the PivotTable UI."
|
167
|
+
selectAll: "Select All"
|
168
|
+
selectNone: "Select None"
|
169
|
+
tooMany: "(too many to list)"
|
170
|
+
filterResults: "Filter results"
|
171
|
+
totals: "Totals" #for table renderer
|
172
|
+
vs: "vs" #for gchart renderer
|
173
|
+
by: "by" #for gchart renderer
|
174
|
+
|
175
|
+
#dateFormat deriver l10n requires month and day names to be passed in directly
|
176
|
+
mthNamesEn = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
|
177
|
+
dayNamesEn = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]
|
178
|
+
zeroPad = (number) -> ("0"+number).substr(-2,2)
|
179
|
+
|
180
|
+
derivers =
|
181
|
+
bin: (col, binWidth) -> (record) -> record[col] - record[col] % binWidth
|
182
|
+
dateFormat: (col, formatString, utcOutput=false, mthNames=mthNamesEn, dayNames=dayNamesEn) ->
|
183
|
+
utc = if utcOutput then "UTC" else ""
|
184
|
+
(record) -> #thanks http://stackoverflow.com/a/12213072/112871
|
185
|
+
date = new Date(Date.parse(record[col]))
|
186
|
+
if isNaN(date) then return ""
|
187
|
+
formatString.replace /%(.)/g, (m, p) ->
|
188
|
+
switch p
|
189
|
+
when "y" then date["get#{utc}FullYear"]()
|
190
|
+
when "m" then zeroPad(date["get#{utc}Month"]()+1)
|
191
|
+
when "n" then mthNames[date["get#{utc}Month"]()]
|
192
|
+
when "d" then zeroPad(date["get#{utc}Date"]())
|
193
|
+
when "w" then dayNames[date["get#{utc}Day"]()]
|
194
|
+
when "x" then date["get#{utc}Day"]()
|
195
|
+
when "H" then zeroPad(date["get#{utc}Hours"]())
|
196
|
+
when "M" then zeroPad(date["get#{utc}Minutes"]())
|
197
|
+
when "S" then zeroPad(date["get#{utc}Seconds"]())
|
198
|
+
else "%" + p
|
199
|
+
|
200
|
+
naturalSort = (as, bs) => #thanks http://stackoverflow.com/a/4373421/112871
|
201
|
+
rx = /(\d+)|(\D+)/g
|
202
|
+
rd = /\d/
|
203
|
+
rz = /^0/
|
204
|
+
if typeof as is "number" or typeof bs is "number"
|
205
|
+
return 1 if isNaN(as)
|
206
|
+
return -1 if isNaN(bs)
|
207
|
+
return as - bs
|
208
|
+
a = String(as).toLowerCase()
|
209
|
+
b = String(bs).toLowerCase()
|
210
|
+
return 0 if a is b
|
211
|
+
return (if a > b then 1 else -1) unless rd.test(a) and rd.test(b)
|
212
|
+
a = a.match(rx)
|
213
|
+
b = b.match(rx)
|
214
|
+
while a.length and b.length
|
215
|
+
a1 = a.shift()
|
216
|
+
b1 = b.shift()
|
217
|
+
if a1 isnt b1
|
218
|
+
if rd.test(a1) and rd.test(b1)
|
219
|
+
return a1.replace(rz, ".0") - b1.replace(rz, ".0")
|
220
|
+
else
|
221
|
+
return (if a1 > b1 then 1 else -1)
|
222
|
+
a.length - b.length
|
223
|
+
|
224
|
+
sortAs = (order) ->
|
225
|
+
mapping = {}
|
226
|
+
for i, x of order
|
227
|
+
mapping[x] = i
|
228
|
+
(a, b) ->
|
229
|
+
if mapping[a]? and mapping[b]?
|
230
|
+
return mapping[a] - mapping[b]
|
231
|
+
else if mapping[a]?
|
232
|
+
return -1
|
233
|
+
else if mapping[b]?
|
234
|
+
return 1
|
235
|
+
else
|
236
|
+
return naturalSort(a,b)
|
237
|
+
|
238
|
+
getSort = (sorters, attr) ->
|
239
|
+
sort = sorters(attr)
|
240
|
+
if $.isFunction(sort)
|
241
|
+
return sort
|
242
|
+
else
|
243
|
+
return naturalSort
|
244
|
+
|
245
|
+
###
|
246
|
+
Data Model class
|
247
|
+
###
|
248
|
+
|
249
|
+
class PivotData
|
250
|
+
constructor: (input, opts) ->
|
251
|
+
@aggregator = opts.aggregator
|
252
|
+
@aggregatorName = opts.aggregatorName
|
253
|
+
@colAttrs = opts.cols
|
254
|
+
@rowAttrs = opts.rows
|
255
|
+
@valAttrs = opts.vals
|
256
|
+
@sorters = opts.sorters
|
257
|
+
@tree = {}
|
258
|
+
@rowKeys = []
|
259
|
+
@colKeys = []
|
260
|
+
@rowTotals = {}
|
261
|
+
@colTotals = {}
|
262
|
+
@allTotal = @aggregator(this, [], [])
|
263
|
+
@sorted = false
|
264
|
+
|
265
|
+
# iterate through input, accumulating data for cells
|
266
|
+
PivotData.forEachRecord input, opts.derivedAttributes, (record) =>
|
267
|
+
@processRecord(record) if opts.filter(record)
|
268
|
+
|
269
|
+
#can handle arrays or jQuery selections of tables
|
270
|
+
@forEachRecord = (input, derivedAttributes, f) ->
|
271
|
+
if $.isEmptyObject derivedAttributes
|
272
|
+
addRecord = f
|
273
|
+
else
|
274
|
+
addRecord = (record) ->
|
275
|
+
record[k] = v(record) ? record[k] for k, v of derivedAttributes
|
276
|
+
f(record)
|
277
|
+
|
278
|
+
#if it's a function, have it call us back
|
279
|
+
if $.isFunction(input)
|
280
|
+
input(addRecord)
|
281
|
+
else if $.isArray(input)
|
282
|
+
if $.isArray(input[0]) #array of arrays
|
283
|
+
for own i, compactRecord of input when i > 0
|
284
|
+
record = {}
|
285
|
+
record[k] = compactRecord[j] for own j, k of input[0]
|
286
|
+
addRecord(record)
|
287
|
+
else #array of objects
|
288
|
+
addRecord(record) for record in input
|
289
|
+
else if input instanceof jQuery
|
290
|
+
tblCols = []
|
291
|
+
$("thead > tr > th", input).each (i) -> tblCols.push $(this).text()
|
292
|
+
$("tbody > tr", input).each (i) ->
|
293
|
+
record = {}
|
294
|
+
$("td", this).each (j) -> record[tblCols[j]] = $(this).text()
|
295
|
+
addRecord(record)
|
296
|
+
else
|
297
|
+
throw new Error("unknown input format")
|
298
|
+
|
299
|
+
#converts to [{attr:val, attr:val},{attr:val, attr:val}] using method above
|
300
|
+
@convertToArray = (input) ->
|
301
|
+
result = []
|
302
|
+
PivotData.forEachRecord input, {}, (record) -> result.push record
|
303
|
+
return result
|
304
|
+
|
305
|
+
arrSort: (attrs) =>
|
306
|
+
sortersArr = (getSort(@sorters, a) for a in attrs)
|
307
|
+
(a,b) ->
|
308
|
+
for own i, sorter of sortersArr
|
309
|
+
comparison = sorter(a[i], b[i])
|
310
|
+
return comparison if comparison != 0
|
311
|
+
return 0
|
312
|
+
|
313
|
+
sortKeys: () =>
|
314
|
+
if not @sorted
|
315
|
+
@sorted = true
|
316
|
+
@rowKeys.sort @arrSort(@rowAttrs)
|
317
|
+
@colKeys.sort @arrSort(@colAttrs)
|
318
|
+
|
319
|
+
getColKeys: () =>
|
320
|
+
@sortKeys()
|
321
|
+
return @colKeys
|
322
|
+
|
323
|
+
getRowKeys: () =>
|
324
|
+
@sortKeys()
|
325
|
+
return @rowKeys
|
326
|
+
|
327
|
+
processRecord: (record) -> #this code is called in a tight loop
|
328
|
+
colKey = []
|
329
|
+
rowKey = []
|
330
|
+
colKey.push record[x] ? "null" for x in @colAttrs
|
331
|
+
rowKey.push record[x] ? "null" for x in @rowAttrs
|
332
|
+
flatRowKey = rowKey.join(String.fromCharCode(0))
|
333
|
+
flatColKey = colKey.join(String.fromCharCode(0))
|
334
|
+
|
335
|
+
@allTotal.push record
|
336
|
+
|
337
|
+
if rowKey.length != 0
|
338
|
+
if not @rowTotals[flatRowKey]
|
339
|
+
@rowKeys.push rowKey
|
340
|
+
@rowTotals[flatRowKey] = @aggregator(this, rowKey, [])
|
341
|
+
@rowTotals[flatRowKey].push record
|
342
|
+
|
343
|
+
if colKey.length != 0
|
344
|
+
if not @colTotals[flatColKey]
|
345
|
+
@colKeys.push colKey
|
346
|
+
@colTotals[flatColKey] = @aggregator(this, [], colKey)
|
347
|
+
@colTotals[flatColKey].push record
|
348
|
+
|
349
|
+
if colKey.length != 0 and rowKey.length != 0
|
350
|
+
if not @tree[flatRowKey]
|
351
|
+
@tree[flatRowKey] = {}
|
352
|
+
if not @tree[flatRowKey][flatColKey]
|
353
|
+
@tree[flatRowKey][flatColKey] = @aggregator(this, rowKey, colKey)
|
354
|
+
@tree[flatRowKey][flatColKey].push record
|
355
|
+
|
356
|
+
getAggregator: (rowKey, colKey) =>
|
357
|
+
flatRowKey = rowKey.join(String.fromCharCode(0))
|
358
|
+
flatColKey = colKey.join(String.fromCharCode(0))
|
359
|
+
if rowKey.length == 0 and colKey.length == 0
|
360
|
+
agg = @allTotal
|
361
|
+
else if rowKey.length == 0
|
362
|
+
agg = @colTotals[flatColKey]
|
363
|
+
else if colKey.length == 0
|
364
|
+
agg = @rowTotals[flatRowKey]
|
365
|
+
else
|
366
|
+
agg = @tree[flatRowKey][flatColKey]
|
367
|
+
return agg ? {value: (-> null), format: -> ""}
|
368
|
+
|
369
|
+
#expose these to the outside world
|
370
|
+
$.pivotUtilities = {aggregatorTemplates, aggregators, renderers, derivers, locales,
|
371
|
+
naturalSort, numberFormat, sortAs, PivotData}
|
372
|
+
|
373
|
+
###
|
374
|
+
Default Renderer for hierarchical table layout
|
375
|
+
###
|
376
|
+
|
377
|
+
pivotTableRenderer = (pivotData, opts) ->
|
378
|
+
|
379
|
+
defaults =
|
380
|
+
localeStrings:
|
381
|
+
totals: "Totals"
|
382
|
+
|
383
|
+
opts = $.extend defaults, opts
|
384
|
+
|
385
|
+
colAttrs = pivotData.colAttrs
|
386
|
+
rowAttrs = pivotData.rowAttrs
|
387
|
+
rowKeys = pivotData.getRowKeys()
|
388
|
+
colKeys = pivotData.getColKeys()
|
389
|
+
|
390
|
+
#now actually build the output
|
391
|
+
result = document.createElement("table")
|
392
|
+
result.className = "pvtTable"
|
393
|
+
|
394
|
+
#helper function for setting row/col-span in pivotTableRenderer
|
395
|
+
spanSize = (arr, i, j) ->
|
396
|
+
if i != 0
|
397
|
+
noDraw = true
|
398
|
+
for x in [0..j]
|
399
|
+
if arr[i-1][x] != arr[i][x]
|
400
|
+
noDraw = false
|
401
|
+
if noDraw
|
402
|
+
return -1 #do not draw cell
|
403
|
+
len = 0
|
404
|
+
while i+len < arr.length
|
405
|
+
stop = false
|
406
|
+
for x in [0..j]
|
407
|
+
stop = true if arr[i][x] != arr[i+len][x]
|
408
|
+
break if stop
|
409
|
+
len++
|
410
|
+
return len
|
411
|
+
|
412
|
+
#the first few rows are for col headers
|
413
|
+
for own j, c of colAttrs
|
414
|
+
tr = document.createElement("tr")
|
415
|
+
if parseInt(j) == 0 and rowAttrs.length != 0
|
416
|
+
th = document.createElement("th")
|
417
|
+
th.setAttribute("colspan", rowAttrs.length)
|
418
|
+
th.setAttribute("rowspan", colAttrs.length)
|
419
|
+
tr.appendChild th
|
420
|
+
th = document.createElement("th")
|
421
|
+
th.className = "pvtAxisLabel"
|
422
|
+
th.textContent = c
|
423
|
+
tr.appendChild th
|
424
|
+
for own i, colKey of colKeys
|
425
|
+
x = spanSize(colKeys, parseInt(i), parseInt(j))
|
426
|
+
if x != -1
|
427
|
+
th = document.createElement("th")
|
428
|
+
th.className = "pvtColLabel"
|
429
|
+
th.textContent = colKey[j]
|
430
|
+
th.setAttribute("colspan", x)
|
431
|
+
if parseInt(j) == colAttrs.length-1 and rowAttrs.length != 0
|
432
|
+
th.setAttribute("rowspan", 2)
|
433
|
+
tr.appendChild th
|
434
|
+
if parseInt(j) == 0
|
435
|
+
th = document.createElement("th")
|
436
|
+
th.className = "pvtTotalLabel"
|
437
|
+
th.innerHTML = opts.localeStrings.totals
|
438
|
+
th.setAttribute("rowspan", colAttrs.length + (if rowAttrs.length ==0 then 0 else 1))
|
439
|
+
tr.appendChild th
|
440
|
+
result.appendChild tr
|
441
|
+
|
442
|
+
#then a row for row header headers
|
443
|
+
if rowAttrs.length !=0
|
444
|
+
tr = document.createElement("tr")
|
445
|
+
for own i, r of rowAttrs
|
446
|
+
th = document.createElement("th")
|
447
|
+
th.className = "pvtAxisLabel"
|
448
|
+
th.textContent = r
|
449
|
+
tr.appendChild th
|
450
|
+
th = document.createElement("th")
|
451
|
+
if colAttrs.length ==0
|
452
|
+
th.className = "pvtTotalLabel"
|
453
|
+
th.innerHTML = opts.localeStrings.totals
|
454
|
+
tr.appendChild th
|
455
|
+
result.appendChild tr
|
456
|
+
|
457
|
+
#now the actual data rows, with their row headers and totals
|
458
|
+
for own i, rowKey of rowKeys
|
459
|
+
tr = document.createElement("tr")
|
460
|
+
for own j, txt of rowKey
|
461
|
+
x = spanSize(rowKeys, parseInt(i), parseInt(j))
|
462
|
+
if x != -1
|
463
|
+
th = document.createElement("th")
|
464
|
+
th.className = "pvtRowLabel"
|
465
|
+
th.textContent = txt
|
466
|
+
th.setAttribute("rowspan", x)
|
467
|
+
if parseInt(j) == rowAttrs.length-1 and colAttrs.length !=0
|
468
|
+
th.setAttribute("colspan",2)
|
469
|
+
tr.appendChild th
|
470
|
+
for own j, colKey of colKeys #this is the tight loop
|
471
|
+
aggregator = pivotData.getAggregator(rowKey, colKey)
|
472
|
+
val = aggregator.value()
|
473
|
+
td = document.createElement("td")
|
474
|
+
td.className = "pvtVal row#{i} col#{j}"
|
475
|
+
td.textContent = aggregator.format(val)
|
476
|
+
td.setAttribute("data-value", val)
|
477
|
+
tr.appendChild td
|
478
|
+
|
479
|
+
totalAggregator = pivotData.getAggregator(rowKey, [])
|
480
|
+
val = totalAggregator.value()
|
481
|
+
td = document.createElement("td")
|
482
|
+
td.className = "pvtTotal rowTotal"
|
483
|
+
td.textContent = totalAggregator.format(val)
|
484
|
+
td.setAttribute("data-value", val)
|
485
|
+
td.setAttribute("data-for", "row"+i)
|
486
|
+
tr.appendChild td
|
487
|
+
result.appendChild tr
|
488
|
+
|
489
|
+
#finally, the row for col totals, and a grand total
|
490
|
+
tr = document.createElement("tr")
|
491
|
+
th = document.createElement("th")
|
492
|
+
th.className = "pvtTotalLabel"
|
493
|
+
th.innerHTML = opts.localeStrings.totals
|
494
|
+
th.setAttribute("colspan", rowAttrs.length + (if colAttrs.length == 0 then 0 else 1))
|
495
|
+
tr.appendChild th
|
496
|
+
for own j, colKey of colKeys
|
497
|
+
totalAggregator = pivotData.getAggregator([], colKey)
|
498
|
+
val = totalAggregator.value()
|
499
|
+
td = document.createElement("td")
|
500
|
+
td.className = "pvtTotal colTotal"
|
501
|
+
td.textContent = totalAggregator.format(val)
|
502
|
+
td.setAttribute("data-value", val)
|
503
|
+
td.setAttribute("data-for", "col"+j)
|
504
|
+
tr.appendChild td
|
505
|
+
totalAggregator = pivotData.getAggregator([], [])
|
506
|
+
val = totalAggregator.value()
|
507
|
+
td = document.createElement("td")
|
508
|
+
td.className = "pvtGrandTotal"
|
509
|
+
td.textContent = totalAggregator.format(val)
|
510
|
+
td.setAttribute("data-value", val)
|
511
|
+
tr.appendChild td
|
512
|
+
result.appendChild tr
|
513
|
+
|
514
|
+
#squirrel this away for later
|
515
|
+
result.setAttribute("data-numrows", rowKeys.length)
|
516
|
+
result.setAttribute("data-numcols", colKeys.length)
|
517
|
+
|
518
|
+
return result
|
519
|
+
|
520
|
+
###
|
521
|
+
Pivot Table core: create PivotData object and call Renderer on it
|
522
|
+
###
|
523
|
+
|
524
|
+
$.fn.pivot = (input, opts) ->
|
525
|
+
defaults =
|
526
|
+
cols : []
|
527
|
+
rows: []
|
528
|
+
vals: []
|
529
|
+
filter: -> true
|
530
|
+
aggregator: aggregatorTemplates.count()()
|
531
|
+
aggregatorName: "Count"
|
532
|
+
sorters: ->
|
533
|
+
derivedAttributes: {},
|
534
|
+
renderer: pivotTableRenderer
|
535
|
+
rendererOptions: null
|
536
|
+
localeStrings: locales.en.localeStrings
|
537
|
+
|
538
|
+
opts = $.extend defaults, opts
|
539
|
+
|
540
|
+
result = null
|
541
|
+
try
|
542
|
+
pivotData = new PivotData(input, opts)
|
543
|
+
try
|
544
|
+
result = opts.renderer(pivotData, opts.rendererOptions)
|
545
|
+
catch e
|
546
|
+
console.error(e.stack) if console?
|
547
|
+
result = $("<span>").html opts.localeStrings.renderError
|
548
|
+
catch e
|
549
|
+
console.error(e.stack) if console?
|
550
|
+
result = $("<span>").html opts.localeStrings.computeError
|
551
|
+
|
552
|
+
x = this[0]
|
553
|
+
x.removeChild(x.lastChild) while x.hasChildNodes()
|
554
|
+
return @append result
|
555
|
+
|
556
|
+
|
557
|
+
###
|
558
|
+
Pivot Table UI: calls Pivot Table core above with options set by user
|
559
|
+
###
|
560
|
+
|
561
|
+
$.fn.pivotUI = (input, inputOpts, overwrite = false, locale="en") ->
|
562
|
+
if not locales[locale]?
|
563
|
+
locale = "en"
|
564
|
+
defaults =
|
565
|
+
derivedAttributes: {}
|
566
|
+
aggregators: locales[locale].aggregators
|
567
|
+
renderers: locales[locale].renderers
|
568
|
+
hiddenAttributes: []
|
569
|
+
menuLimit: 200
|
570
|
+
cols: [], rows: [], vals: []
|
571
|
+
exclusions: {}
|
572
|
+
inclusions: {}
|
573
|
+
unusedAttrsVertical: 85
|
574
|
+
autoSortUnusedAttrs: false
|
575
|
+
rendererOptions: localeStrings: locales[locale].localeStrings
|
576
|
+
onRefresh: null
|
577
|
+
filter: -> true
|
578
|
+
sorters: ->
|
579
|
+
localeStrings: locales[locale].localeStrings
|
580
|
+
|
581
|
+
existingOpts = @data "pivotUIOptions"
|
582
|
+
if not existingOpts? or overwrite
|
583
|
+
opts = $.extend defaults, inputOpts
|
584
|
+
else
|
585
|
+
opts = existingOpts
|
586
|
+
|
587
|
+
try
|
588
|
+
#cache the input in some useful form
|
589
|
+
input = PivotData.convertToArray(input)
|
590
|
+
tblCols = (k for own k of input[0])
|
591
|
+
tblCols.push c for own c of opts.derivedAttributes when (c not in tblCols)
|
592
|
+
|
593
|
+
#figure out the cardinality and some stats
|
594
|
+
axisValues = {}
|
595
|
+
axisValues[x] = {} for x in tblCols
|
596
|
+
|
597
|
+
PivotData.forEachRecord input, opts.derivedAttributes, (record) ->
|
598
|
+
for own k, v of record when opts.filter(record)
|
599
|
+
v ?= "null"
|
600
|
+
axisValues[k][v] ?= 0
|
601
|
+
axisValues[k][v]++
|
602
|
+
|
603
|
+
#start building the output
|
604
|
+
uiTable = $("<table>", "class": "pvtUi").attr("cellpadding", 5)
|
605
|
+
|
606
|
+
#renderer control
|
607
|
+
rendererControl = $("<td>")
|
608
|
+
|
609
|
+
renderer = $("<select>")
|
610
|
+
.addClass('pvtRenderer')
|
611
|
+
.appendTo(rendererControl)
|
612
|
+
.bind "change", -> refresh() #capture reference
|
613
|
+
for own x of opts.renderers
|
614
|
+
$("<option>").val(x).html(x).appendTo(renderer)
|
615
|
+
|
616
|
+
|
617
|
+
#axis list, including the double-click menu
|
618
|
+
colList = $("<td>").addClass('pvtAxisContainer pvtUnused')
|
619
|
+
shownAttributes = (c for c in tblCols when c not in opts.hiddenAttributes)
|
620
|
+
|
621
|
+
unusedAttrsVerticalAutoOverride = false
|
622
|
+
if opts.unusedAttrsVertical == "auto"
|
623
|
+
unusedAttrsVerticalAutoCutoff = 120 # legacy support
|
624
|
+
else
|
625
|
+
unusedAttrsVerticalAutoCutoff = parseInt opts.unusedAttrsVertical
|
626
|
+
|
627
|
+
if not isNaN(unusedAttrsVerticalAutoCutoff)
|
628
|
+
attrLength = 0
|
629
|
+
attrLength += a.length for a in shownAttributes
|
630
|
+
unusedAttrsVerticalAutoOverride = attrLength > unusedAttrsVerticalAutoCutoff
|
631
|
+
|
632
|
+
if opts.unusedAttrsVertical == true or unusedAttrsVerticalAutoOverride
|
633
|
+
colList.addClass('pvtVertList')
|
634
|
+
else
|
635
|
+
colList.addClass('pvtHorizList')
|
636
|
+
|
637
|
+
for own i, c of shownAttributes
|
638
|
+
do (c) ->
|
639
|
+
keys = (k for k of axisValues[c])
|
640
|
+
hasExcludedItem = false
|
641
|
+
valueList = $("<div>").addClass('pvtFilterBox').hide()
|
642
|
+
|
643
|
+
valueList.append $("<h4>").text("#{c} (#{keys.length})")
|
644
|
+
if keys.length > opts.menuLimit
|
645
|
+
valueList.append $("<p>").html(opts.localeStrings.tooMany)
|
646
|
+
else
|
647
|
+
btns = $("<p>").appendTo(valueList)
|
648
|
+
btns.append $("<button>", {type:"button"}).html(opts.localeStrings.selectAll).bind "click", ->
|
649
|
+
valueList.find("input:visible").prop "checked", true
|
650
|
+
btns.append $("<button>", {type:"button"}).html(opts.localeStrings.selectNone).bind "click", ->
|
651
|
+
valueList.find("input:visible").prop "checked", false
|
652
|
+
btns.append $("<br>")
|
653
|
+
btns.append $("<input>", {type: "text", placeholder: opts.localeStrings.filterResults, class: "pvtSearch"}).bind "keyup", ->
|
654
|
+
filter = $(this).val().toLowerCase()
|
655
|
+
valueList.find('.pvtCheckContainer p').each ->
|
656
|
+
testString = $(this).text().toLowerCase().indexOf(filter)
|
657
|
+
if testString isnt -1
|
658
|
+
$(this).show()
|
659
|
+
else
|
660
|
+
$(this).hide()
|
661
|
+
|
662
|
+
checkContainer = $("<div>").addClass("pvtCheckContainer").appendTo(valueList)
|
663
|
+
|
664
|
+
for k in keys.sort(getSort(opts.sorters, c))
|
665
|
+
v = axisValues[c][k]
|
666
|
+
filterItem = $("<label>")
|
667
|
+
filterItemExcluded = false
|
668
|
+
if opts.inclusions[c]
|
669
|
+
filterItemExcluded = (k not in opts.inclusions[c])
|
670
|
+
else if opts.exclusions[c]
|
671
|
+
filterItemExcluded = (k in opts.exclusions[c])
|
672
|
+
hasExcludedItem ||= filterItemExcluded
|
673
|
+
$("<input>")
|
674
|
+
.attr("type", "checkbox").addClass('pvtFilter')
|
675
|
+
.attr("checked", !filterItemExcluded).data("filter", [c,k])
|
676
|
+
.appendTo filterItem
|
677
|
+
filterItem.append $("<span>").text k
|
678
|
+
filterItem.append $("<span>").text " ("+v+")"
|
679
|
+
checkContainer.append $("<p>").append(filterItem)
|
680
|
+
|
681
|
+
updateFilter = ->
|
682
|
+
unselectedCount = valueList.find("[type='checkbox']").length -
|
683
|
+
valueList.find("[type='checkbox']:checked").length
|
684
|
+
if unselectedCount > 0
|
685
|
+
attrElem.addClass "pvtFilteredAttribute"
|
686
|
+
else
|
687
|
+
attrElem.removeClass "pvtFilteredAttribute"
|
688
|
+
if keys.length > opts.menuLimit
|
689
|
+
valueList.toggle()
|
690
|
+
else
|
691
|
+
valueList.toggle(0, refresh)
|
692
|
+
|
693
|
+
$("<p>").appendTo(valueList)
|
694
|
+
.append $("<button>", {type:"button"}).text("OK").bind "click", updateFilter
|
695
|
+
|
696
|
+
showFilterList = (e) ->
|
697
|
+
{left: clickLeft, top: clickTop, } = $(e.currentTarget).position()
|
698
|
+
valueList.css(left: clickLeft+10, top: clickTop+10).toggle()
|
699
|
+
valueList.find('.pvtSearch').val('')
|
700
|
+
valueList.find('.pvtCheckContainer p').show()
|
701
|
+
|
702
|
+
triangleLink = $("<span>").addClass('pvtTriangle').html(" ▾")
|
703
|
+
.bind "click", showFilterList
|
704
|
+
|
705
|
+
attrElem = $("<li>").addClass("axis_#{i}")
|
706
|
+
.append $("<span>").addClass('pvtAttr').text(c).data("attrName", c).append(triangleLink)
|
707
|
+
attrElem.addClass('pvtFilteredAttribute') if hasExcludedItem
|
708
|
+
colList.append(attrElem).append(valueList)
|
709
|
+
|
710
|
+
attrElem.bind "dblclick", showFilterList
|
711
|
+
|
712
|
+
tr1 = $("<tr>").appendTo(uiTable)
|
713
|
+
|
714
|
+
#aggregator menu and value area
|
715
|
+
|
716
|
+
aggregator = $("<select>").addClass('pvtAggregator')
|
717
|
+
.bind "change", -> refresh() #capture reference
|
718
|
+
for own x of opts.aggregators
|
719
|
+
aggregator.append $("<option>").val(x).html(x)
|
720
|
+
|
721
|
+
$("<td>").addClass('pvtVals')
|
722
|
+
.appendTo(tr1)
|
723
|
+
.append(aggregator)
|
724
|
+
.append($("<br>"))
|
725
|
+
|
726
|
+
#column axes
|
727
|
+
$("<td>").addClass('pvtAxisContainer pvtHorizList pvtCols').appendTo(tr1)
|
728
|
+
|
729
|
+
tr2 = $("<tr>").appendTo(uiTable)
|
730
|
+
|
731
|
+
#row axes
|
732
|
+
tr2.append $("<td>").addClass('pvtAxisContainer pvtRows').attr("valign", "top")
|
733
|
+
|
734
|
+
#the actual pivot table container
|
735
|
+
pivotTable = $("<td>")
|
736
|
+
.attr("valign", "top")
|
737
|
+
.addClass('pvtRendererArea')
|
738
|
+
.appendTo(tr2)
|
739
|
+
|
740
|
+
#finally the renderer dropdown and unused attribs are inserted at the requested location
|
741
|
+
if opts.unusedAttrsVertical == true or unusedAttrsVerticalAutoOverride
|
742
|
+
uiTable.find('tr:nth-child(1)').prepend rendererControl
|
743
|
+
uiTable.find('tr:nth-child(2)').prepend colList
|
744
|
+
else
|
745
|
+
uiTable.prepend $("<tr>").append(rendererControl).append(colList)
|
746
|
+
|
747
|
+
#render the UI in its default state
|
748
|
+
@html uiTable
|
749
|
+
|
750
|
+
#set up the UI initial state as requested by moving elements around
|
751
|
+
|
752
|
+
for x in opts.cols
|
753
|
+
@find(".pvtCols").append @find(".axis_#{$.inArray(x, shownAttributes)}")
|
754
|
+
for x in opts.rows
|
755
|
+
@find(".pvtRows").append @find(".axis_#{$.inArray(x, shownAttributes)}")
|
756
|
+
if opts.aggregatorName?
|
757
|
+
@find(".pvtAggregator").val opts.aggregatorName
|
758
|
+
if opts.rendererName?
|
759
|
+
@find(".pvtRenderer").val opts.rendererName
|
760
|
+
|
761
|
+
initialRender = true
|
762
|
+
|
763
|
+
#set up for refreshing
|
764
|
+
refreshDelayed = =>
|
765
|
+
subopts =
|
766
|
+
derivedAttributes: opts.derivedAttributes
|
767
|
+
localeStrings: opts.localeStrings
|
768
|
+
rendererOptions: opts.rendererOptions
|
769
|
+
sorters: opts.sorters
|
770
|
+
cols: [], rows: []
|
771
|
+
|
772
|
+
numInputsToProcess = opts.aggregators[aggregator.val()]([])().numInputs ? 0
|
773
|
+
vals = []
|
774
|
+
@find(".pvtRows li span.pvtAttr").each -> subopts.rows.push $(this).data("attrName")
|
775
|
+
@find(".pvtCols li span.pvtAttr").each -> subopts.cols.push $(this).data("attrName")
|
776
|
+
@find(".pvtVals select.pvtAttrDropdown").each ->
|
777
|
+
if numInputsToProcess == 0
|
778
|
+
$(this).remove()
|
779
|
+
else
|
780
|
+
numInputsToProcess--
|
781
|
+
vals.push $(this).val() if $(this).val() != ""
|
782
|
+
|
783
|
+
if numInputsToProcess != 0
|
784
|
+
pvtVals = @find(".pvtVals")
|
785
|
+
for x in [0...numInputsToProcess]
|
786
|
+
newDropdown = $("<select>")
|
787
|
+
.addClass('pvtAttrDropdown')
|
788
|
+
.append($("<option>"))
|
789
|
+
.bind "change", -> refresh()
|
790
|
+
for attr in shownAttributes
|
791
|
+
newDropdown.append($("<option>").val(attr).text(attr))
|
792
|
+
pvtVals.append(newDropdown)
|
793
|
+
|
794
|
+
if initialRender
|
795
|
+
vals = opts.vals
|
796
|
+
i = 0
|
797
|
+
@find(".pvtVals select.pvtAttrDropdown").each ->
|
798
|
+
$(this).val vals[i]
|
799
|
+
i++
|
800
|
+
initialRender = false
|
801
|
+
|
802
|
+
subopts.aggregatorName = aggregator.val()
|
803
|
+
subopts.vals = vals
|
804
|
+
subopts.aggregator = opts.aggregators[aggregator.val()](vals)
|
805
|
+
subopts.renderer = opts.renderers[renderer.val()]
|
806
|
+
|
807
|
+
#construct filter here
|
808
|
+
exclusions = {}
|
809
|
+
@find('input.pvtFilter').not(':checked').each ->
|
810
|
+
filter = $(this).data("filter")
|
811
|
+
if exclusions[filter[0]]?
|
812
|
+
exclusions[filter[0]].push( filter[1] )
|
813
|
+
else
|
814
|
+
exclusions[filter[0]] = [ filter[1] ]
|
815
|
+
#include inclusions when exclusions present
|
816
|
+
inclusions = {}
|
817
|
+
@find('input.pvtFilter:checked').each ->
|
818
|
+
filter = $(this).data("filter")
|
819
|
+
if exclusions[filter[0]]?
|
820
|
+
if inclusions[filter[0]]?
|
821
|
+
inclusions[filter[0]].push( filter[1] )
|
822
|
+
else
|
823
|
+
inclusions[filter[0]] = [ filter[1] ]
|
824
|
+
|
825
|
+
subopts.filter = (record) ->
|
826
|
+
return false if not opts.filter(record)
|
827
|
+
for k,excludedItems of exclusions
|
828
|
+
return false if ""+record[k] in excludedItems
|
829
|
+
return true
|
830
|
+
|
831
|
+
pivotTable.pivot(input,subopts)
|
832
|
+
pivotUIOptions = $.extend opts,
|
833
|
+
cols: subopts.cols
|
834
|
+
rows: subopts.rows
|
835
|
+
vals: vals
|
836
|
+
exclusions: exclusions
|
837
|
+
inclusions: inclusions
|
838
|
+
inclusionsInfo: inclusions #duplicated for backwards-compatibility
|
839
|
+
aggregatorName: aggregator.val()
|
840
|
+
rendererName: renderer.val()
|
841
|
+
|
842
|
+
@data "pivotUIOptions", pivotUIOptions
|
843
|
+
|
844
|
+
# if requested make sure unused columns are in alphabetical order
|
845
|
+
if opts.autoSortUnusedAttrs
|
846
|
+
unusedAttrsContainer = @find("td.pvtUnused.pvtAxisContainer")
|
847
|
+
$(unusedAttrsContainer).children("li")
|
848
|
+
.sort((a, b) => naturalSort($(a).text(), $(b).text()))
|
849
|
+
.appendTo unusedAttrsContainer
|
850
|
+
|
851
|
+
pivotTable.css("opacity", 1)
|
852
|
+
opts.onRefresh(pivotUIOptions) if opts.onRefresh?
|
853
|
+
|
854
|
+
refresh = =>
|
855
|
+
pivotTable.css("opacity", 0.5)
|
856
|
+
setTimeout refreshDelayed, 10
|
857
|
+
|
858
|
+
#the very first refresh will actually display the table
|
859
|
+
refresh()
|
860
|
+
|
861
|
+
@find(".pvtAxisContainer").sortable
|
862
|
+
update: (e, ui) -> refresh() if not ui.sender?
|
863
|
+
connectWith: @find(".pvtAxisContainer")
|
864
|
+
items: 'li'
|
865
|
+
placeholder: 'pvtPlaceholder'
|
866
|
+
catch e
|
867
|
+
console.error(e.stack) if console?
|
868
|
+
@html opts.localeStrings.uiRenderError
|
869
|
+
return this
|
870
|
+
|
871
|
+
###
|
872
|
+
Heatmap post-processing
|
873
|
+
###
|
874
|
+
|
875
|
+
$.fn.heatmap = (scope = "heatmap") ->
|
876
|
+
numRows = @data "numrows"
|
877
|
+
numCols = @data "numcols"
|
878
|
+
|
879
|
+
colorGen = (color, min, max) ->
|
880
|
+
hexGen = switch color
|
881
|
+
when "red" then (hex) -> "ff#{hex}#{hex}"
|
882
|
+
when "green" then (hex) -> "#{hex}ff#{hex}"
|
883
|
+
when "blue" then (hex) -> "#{hex}#{hex}ff"
|
884
|
+
|
885
|
+
return (x) ->
|
886
|
+
intensity = 255 - Math.round 255*(x-min)/(max-min)
|
887
|
+
hex = intensity.toString(16).split(".")[0]
|
888
|
+
hex = 0+hex if hex.length == 1
|
889
|
+
return hexGen(hex)
|
890
|
+
|
891
|
+
heatmapper = (scope, color) =>
|
892
|
+
forEachCell = (f) =>
|
893
|
+
@find(scope).each ->
|
894
|
+
x = $(this).data("value")
|
895
|
+
f(x, $(this)) if x? and isFinite(x)
|
896
|
+
|
897
|
+
values = []
|
898
|
+
forEachCell (x) -> values.push x
|
899
|
+
colorFor = colorGen color, Math.min(values...), Math.max(values...)
|
900
|
+
forEachCell (x, elem) -> elem.css "background-color", "#" + colorFor(x)
|
901
|
+
|
902
|
+
switch scope
|
903
|
+
when "heatmap"
|
904
|
+
heatmapper ".pvtVal", "red"
|
905
|
+
when "rowheatmap"
|
906
|
+
heatmapper ".pvtVal.row#{i}", "red" for i in [0...numRows]
|
907
|
+
when "colheatmap"
|
908
|
+
heatmapper ".pvtVal.col#{j}", "red" for j in [0...numCols]
|
909
|
+
|
910
|
+
heatmapper ".pvtTotal.rowTotal", "red"
|
911
|
+
heatmapper ".pvtTotal.colTotal", "red"
|
912
|
+
|
913
|
+
return this
|
914
|
+
|
915
|
+
###
|
916
|
+
Barchart post-processing
|
917
|
+
###
|
918
|
+
|
919
|
+
$.fn.barchart = ->
|
920
|
+
numRows = @data "numrows"
|
921
|
+
numCols = @data "numcols"
|
922
|
+
|
923
|
+
barcharter = (scope) =>
|
924
|
+
forEachCell = (f) =>
|
925
|
+
@find(scope).each ->
|
926
|
+
x = $(this).data("value")
|
927
|
+
f(x, $(this)) if x? and isFinite(x)
|
928
|
+
|
929
|
+
values = []
|
930
|
+
forEachCell (x) -> values.push x
|
931
|
+
max = Math.max(values...)
|
932
|
+
scaler = (x) -> 100*x/(1.4*max)
|
933
|
+
forEachCell (x, elem) ->
|
934
|
+
text = elem.text()
|
935
|
+
wrapper = $("<div>").css
|
936
|
+
"position": "relative"
|
937
|
+
"height": "55px"
|
938
|
+
wrapper.append $("<div>").css
|
939
|
+
"position": "absolute"
|
940
|
+
"bottom": 0
|
941
|
+
"left": 0
|
942
|
+
"right": 0
|
943
|
+
"height": scaler(x) + "%"
|
944
|
+
"background-color": "gray"
|
945
|
+
wrapper.append $("<div>").text(text).css
|
946
|
+
"position":"relative"
|
947
|
+
"padding-left":"5px"
|
948
|
+
"padding-right":"5px"
|
949
|
+
|
950
|
+
elem.css("padding": 0,"padding-top": "5px", "text-align": "center").html wrapper
|
951
|
+
|
952
|
+
barcharter ".pvtVal.row#{i}" for i in [0...numRows]
|
953
|
+
barcharter ".pvtTotal.colTotal"
|
954
|
+
|
955
|
+
return this
|
956
|
+
|
957
|
+
|