summaryrefslogtreecommitdiffstats
path: root/views/layouts/presentation_files/visualize.jQuery.js
diff options
context:
space:
mode:
authorMichael Francis <edude03@gmail.com>2011-05-28 13:28:16 -0400
committerMichael Francis <edude03@gmail.com>2011-05-28 13:28:16 -0400
commit2389d66da849798f8d4ec5f10e3b07c11da49185 (patch)
treee22556d12982395b469a23420c662662e3e064cc /views/layouts/presentation_files/visualize.jQuery.js
downloadotakuhub-2389d66da849798f8d4ec5f10e3b07c11da49185.tar.xz
Initial Commit
Diffstat (limited to 'views/layouts/presentation_files/visualize.jQuery.js')
-rw-r--r--views/layouts/presentation_files/visualize.jQuery.js463
1 files changed, 463 insertions, 0 deletions
diff --git a/views/layouts/presentation_files/visualize.jQuery.js b/views/layouts/presentation_files/visualize.jQuery.js
new file mode 100644
index 0000000..dbd4af4
--- /dev/null
+++ b/views/layouts/presentation_files/visualize.jQuery.js
@@ -0,0 +1,463 @@
+/*
+ * --------------------------------------------------------------------
+ * jQuery inputToButton plugin
+ * Author: Scott Jehl, scott@filamentgroup.com
+ * Copyright (c) 2009 Filament Group
+ * licensed under MIT (filamentgroup.com/examples/mit-license.txt)
+ * --------------------------------------------------------------------
+*/
+(function($) {
+$.fn.visualize = function(options, container){
+ return $(this).each(function(){
+ //configuration
+ var o = $.extend({
+ type: 'bar', //also available: area, pie, line
+ width: $(this).width(), //height of canvas - defaults to table height
+ height: $(this).height(), //height of canvas - defaults to table height
+ appendTitle: true, //table caption text is added to chart
+ title: null, //grabs from table caption if null
+ appendKey: true, //color key is added to chart
+ rowFilter: ' ',
+ colFilter: ' ',
+ colors: ['#be1e2d','#666699','#92d5ea','#ee8310','#8d10ee','#5a3b16','#26a4ed','#f45a90','#e9e744'],
+ textColors: [], //corresponds with colors array. null/undefined items will fall back to CSS
+ parseDirection: 'x', //which direction to parse the table data
+ pieMargin: 20, //pie charts only - spacing around pie
+ pieLabelsAsPercent: true,
+ pieLabelPos: 'inside',
+ lineWeight: 4, //for line and area - stroke weight
+ barGroupMargin: 10,
+ barMargin: 1, //space around bars in bar chart (added to both sides of bar)
+ yLabelInterval: 30 //distance between y labels
+ },options);
+
+ //reset width, height to numbers
+ o.width = parseFloat(o.width);
+ o.height = parseFloat(o.height);
+
+
+ var self = $(this);
+
+ //function to scrape data from html table
+ function scrapeTable(){
+ var colors = o.colors;
+ var textColors = o.textColors;
+ var tableData = {
+ dataGroups: function(){
+ var dataGroups = [];
+ if(o.parseDirection == 'x'){
+ self.find('tr:gt(0)').filter(o.rowFilter).each(function(i){
+ dataGroups[i] = {};
+ dataGroups[i].points = [];
+ dataGroups[i].color = colors[i];
+ if(textColors[i]){ dataGroups[i].textColor = textColors[i]; }
+ $(this).find('td').filter(o.colFilter).each(function(){
+ dataGroups[i].points.push( parseFloat($(this).text()) );
+ });
+ });
+ }
+ else {
+ var cols = self.find('tr:eq(1) td').filter(o.colFilter).size();
+ for(var i=0; i<cols; i++){
+ dataGroups[i] = {};
+ dataGroups[i].points = [];
+ dataGroups[i].color = colors[i];
+ if(textColors[i]){ dataGroups[i].textColor = textColors[i]; }
+ self.find('tr:gt(0)').filter(o.rowFilter).each(function(){
+ dataGroups[i].points.push( $(this).find('td').filter(o.colFilter).eq(i).text()*1 );
+ });
+ };
+ }
+ return dataGroups;
+ },
+ allData: function(){
+ var allData = [];
+ $(this.dataGroups()).each(function(){
+ allData.push(this.points);
+ });
+ return allData;
+ },
+ dataSum: function(){
+ var dataSum = 0;
+ var allData = this.allData().join(',').split(',');
+ $(allData).each(function(){
+ dataSum += parseFloat(this);
+ });
+ return dataSum
+ },
+ topValue: function(){
+ var topValue = 0;
+ var allData = this.allData().join(',').split(',');
+ $(allData).each(function(){
+ if(parseFloat(this,10)>topValue) topValue = parseFloat(this);
+ });
+ return topValue;
+ },
+ bottomValue: function(){
+ var bottomValue = 0;
+ var allData = this.allData().join(',').split(',');
+ $(allData).each(function(){
+ if(this<bottomValue) bottomValue = parseFloat(this);
+ });
+ return bottomValue;
+ },
+ memberTotals: function(){
+ var memberTotals = [];
+ var dataGroups = this.dataGroups();
+ $(dataGroups).each(function(l){
+ var count = 0;
+ $(dataGroups[l].points).each(function(m){
+ count +=dataGroups[l].points[m];
+ });
+ memberTotals.push(count);
+ });
+ return memberTotals;
+ },
+ yTotals: function(){
+ var yTotals = [];
+ var dataGroups = this.dataGroups();
+ var loopLength = this.xLabels().length;
+ for(var i = 0; i<loopLength; i++){
+ yTotals[i] =[];
+ var thisTotal = 0;
+ $(dataGroups).each(function(l){
+ yTotals[i].push(this.points[i]);
+ });
+ yTotals[i].join(',').split(',');
+ $(yTotals[i]).each(function(){
+ thisTotal += parseFloat(this);
+ });
+ yTotals[i] = thisTotal;
+
+ }
+ return yTotals;
+ },
+ topYtotal: function(){
+ var topYtotal = 0;
+ var yTotals = this.yTotals().join(',').split(',');
+ $(yTotals).each(function(){
+ if(parseFloat(this,10)>topYtotal) topYtotal = parseFloat(this);
+ });
+ return topYtotal;
+ },
+ totalYRange: function(){
+ return this.topValue() - this.bottomValue();
+ },
+ xLabels: function(){
+ var xLabels = [];
+ if(o.parseDirection == 'x'){
+ self.find('tr:eq(0) th').filter(o.colFilter).each(function(){
+ xLabels.push($(this).html());
+ });
+ }
+ else {
+ self.find('tr:gt(0) th').filter(o.rowFilter).each(function(){
+ xLabels.push($(this).html());
+ });
+ }
+ return xLabels;
+ },
+ yLabels: function(){
+ var yLabels = [];
+ yLabels.push(bottomValue);
+ var numLabels = Math.round(o.height / o.yLabelInterval);
+ var loopInterval = Math.ceil(totalYRange / numLabels) || 1;
+ while( yLabels[yLabels.length-1] < topValue - loopInterval){
+ yLabels.push(yLabels[yLabels.length-1] + loopInterval);
+ }
+ yLabels.push(topValue);
+ return yLabels;
+ }
+ };
+
+ return tableData;
+ };
+
+
+ //function to create a chart
+ var createChart = {
+ pie: function(){
+
+ canvasContain.addClass('visualize-pie');
+
+ if(o.pieLabelPos == 'outside'){ canvasContain.addClass('visualize-pie-outside'); }
+
+ var centerx = Math.round(canvas.width()/2);
+ var centery = Math.round(canvas.height()/2);
+ var radius = centery - o.pieMargin;
+ var counter = 0.0;
+ var toRad = function(integer){ return (Math.PI/180)*integer; };
+ var labels = $('<ul class="visualize-labels"></ul>')
+ .insertAfter(canvas);
+
+ //draw the pie pieces
+ $.each(memberTotals, function(i){
+ var fraction = (this <= 0 || isNaN(this))? 0 : this / dataSum;
+ ctx.beginPath();
+ ctx.moveTo(centerx, centery);
+ ctx.arc(centerx, centery, radius,
+ counter * Math.PI * 2 - Math.PI * 0.5,
+ (counter + fraction) * Math.PI * 2 - Math.PI * 0.5,
+ false);
+ ctx.lineTo(centerx, centery);
+ ctx.closePath();
+ ctx.fillStyle = dataGroups[i].color;
+ ctx.fill();
+ // draw labels
+ var sliceMiddle = (counter + fraction/2);
+ var distance = o.pieLabelPos == 'inside' ? radius/1.5 : radius + radius / 5;
+ var labelx = Math.round(centerx + Math.sin(sliceMiddle * Math.PI * 2) * (distance));
+ var labely = Math.round(centery - Math.cos(sliceMiddle * Math.PI * 2) * (distance));
+ var leftRight = (labelx > centerx) ? 'right' : 'left';
+ var topBottom = (labely > centery) ? 'bottom' : 'top';
+ var percentage = parseFloat((fraction*100).toFixed(2));
+
+ if(percentage){
+ var labelval = (o.pieLabelsAsPercent) ? percentage + '%' : this;
+ var labeltext = $('<span class="visualize-label">' + labelval +'</span>')
+ .css(leftRight, 0)
+ .css(topBottom, 0);
+ if(labeltext)
+ var label = $('<li class="visualize-label-pos"></li>')
+ .appendTo(labels)
+ .css({left: labelx, top: labely})
+ .append(labeltext);
+ labeltext
+ .css('font-size', radius / 8)
+ .css('margin-'+leftRight, -labeltext.width()/2)
+ .css('margin-'+topBottom, -labeltext.outerHeight()/2);
+
+ if(dataGroups[i].textColor){ labeltext.css('color', dataGroups[i].textColor); }
+ }
+ counter+=fraction;
+ });
+ },
+
+ line: function(area){
+
+ if(area){ canvasContain.addClass('visualize-area'); }
+ else{ canvasContain.addClass('visualize-line'); }
+
+ //write X labels
+ var xInterval = canvas.width() / (xLabels.length -1);
+ var xlabelsUL = $('<ul class="visualize-labels-x"></ul>')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+ $.each(xLabels, function(i){
+ var thisLi = $('<li><span>'+this+'</span></li>')
+ .prepend('<span class="line" />')
+ .css('left', xInterval * i)
+ .appendTo(xlabelsUL);
+ var label = thisLi.find('span:not(.line)');
+ var leftOffset = label.width()/-2;
+ if(i == 0){ leftOffset = 0; }
+ else if(i== xLabels.length-1){ leftOffset = -label.width(); }
+ label
+ .css('margin-left', leftOffset)
+ .addClass('label');
+ });
+
+ //write Y labels
+ var yScale = canvas.height() / totalYRange;
+ var liBottom = canvas.height() / (yLabels.length-1);
+ var ylabelsUL = $('<ul class="visualize-labels-y"></ul>')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+
+ $.each(yLabels, function(i){
+ var thisLi = $('<li><span>'+this+'</span></li>')
+ .prepend('<span class="line" />')
+ .css('bottom',liBottom*i)
+ .prependTo(ylabelsUL);
+ var label = thisLi.find('span:not(.line)');
+ var topOffset = label.height()/-2;
+ if(i == 0){ topOffset = -label.height(); }
+ else if(i== yLabels.length-1){ topOffset = 0; }
+ label
+ .css('margin-top', topOffset)
+ .addClass('label');
+ });
+
+ //start from the bottom left
+ ctx.translate(0,zeroLoc);
+ //iterate and draw
+ $.each(dataGroups,function(h){
+ ctx.beginPath();
+ ctx.lineWidth = o.lineWeight;
+ ctx.lineJoin = 'round';
+ var points = this.points;
+ var integer = 0;
+ ctx.moveTo(0,-(points[0]*yScale));
+ $.each(points, function(){
+ ctx.lineTo(integer,-(this*yScale));
+ integer+=xInterval;
+ });
+ ctx.strokeStyle = this.color;
+ ctx.stroke();
+ if(area){
+ ctx.lineTo(integer,0);
+ ctx.lineTo(0,0);
+ ctx.closePath();
+ ctx.fillStyle = this.color;
+ ctx.globalAlpha = .3;
+ ctx.fill();
+ ctx.globalAlpha = 1.0;
+ }
+ else {ctx.closePath();}
+ });
+ },
+
+ area: function(){
+ createChart.line(true);
+ },
+
+ bar: function(){
+
+ canvasContain.addClass('visualize-bar');
+
+ //write X labels
+ var xInterval = canvas.width() / (xLabels.length);
+ var xlabelsUL = $('<ul class="visualize-labels-x"></ul>')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+ $.each(xLabels, function(i){
+ var thisLi = $('<li><span class="label">'+this+'</span></li>')
+ .prepend('<span class="line" />')
+ .css('left', xInterval * i)
+ .width(xInterval)
+ .appendTo(xlabelsUL);
+ var label = thisLi.find('span.label');
+ label.addClass('label');
+ });
+
+ //write Y labels
+ var yScale = canvas.height() / totalYRange;
+ var liBottom = canvas.height() / (yLabels.length-1);
+ var ylabelsUL = $('<ul class="visualize-labels-y"></ul>')
+ .width(canvas.width())
+ .height(canvas.height())
+ .insertBefore(canvas);
+ $.each(yLabels, function(i){
+ var thisLi = $('<li><span>'+this+'</span></li>')
+ .prepend('<span class="line" />')
+ .css('bottom',liBottom*i)
+ .prependTo(ylabelsUL);
+ var label = thisLi.find('span:not(.line)');
+ var topOffset = label.height()/-2;
+ if(i == 0){ topOffset = -label.height(); }
+ else if(i== yLabels.length-1){ topOffset = 0; }
+ label
+ .css('margin-top', topOffset)
+ .addClass('label');
+ });
+
+ //start from the bottom left
+ ctx.translate(0,zeroLoc);
+ //iterate and draw
+ for(var h=0; h<dataGroups.length; h++){
+ ctx.beginPath();
+ var linewidth = (xInterval-o.barGroupMargin*2) / dataGroups.length; //removed +1
+ var strokeWidth = linewidth - (o.barMargin*2);
+ ctx.lineWidth = strokeWidth;
+ var points = dataGroups[h].points;
+ var integer = 0;
+ for(var i=0; i<points.length; i++){
+ var xVal = (integer-o.barGroupMargin)+(h*linewidth)+linewidth/2;
+ xVal += o.barGroupMargin*2;
+
+ ctx.moveTo(xVal, 0);
+ ctx.lineTo(xVal, Math.round(-points[i]*yScale));
+ integer+=xInterval;
+ }
+ ctx.strokeStyle = dataGroups[h].color;
+ ctx.stroke();
+ ctx.closePath();
+ }
+ }
+ };
+
+ //create new canvas, set w&h attrs (not inline styles)
+ var canvasNode = document.createElement("canvas");
+ canvasNode.setAttribute('height',o.height);
+ canvasNode.setAttribute('width',o.width);
+ var canvas = $(canvasNode);
+
+ //get title for chart
+ var title = o.title || self.find('caption').text();
+
+ //create canvas wrapper div, set inline w&h, append
+ var canvasContain = (container || $('<div class="visualize" role="img" aria-label="Chart representing data from the table: '+ title +'" />'))
+ .height(o.height)
+ .width(o.width)
+ .append(canvas);
+
+ //scrape table (this should be cleaned up into an obj)
+ var tableData = scrapeTable();
+ var dataGroups = tableData.dataGroups();
+ var allData = tableData.allData();
+ var dataSum = tableData.dataSum();
+ var topValue = tableData.topValue();
+ var bottomValue = tableData.bottomValue();
+ var memberTotals = tableData.memberTotals();
+ var totalYRange = tableData.totalYRange();
+ var zeroLoc = o.height * (topValue/totalYRange);
+ var xLabels = tableData.xLabels();
+ var yLabels = tableData.yLabels();
+
+ //title/key container
+ if(o.appendTitle || o.appendKey){
+ var infoContain = $('<div class="visualize-info"></div>')
+ .appendTo(canvasContain);
+ }
+
+ //append title
+ if(o.appendTitle){
+ $('<div class="visualize-title">'+ title +'</div>').appendTo(infoContain);
+ }
+
+
+ //append key
+ if(o.appendKey){
+ var newKey = $('<ul class="visualize-key"></ul>');
+ var selector;
+ if(o.parseDirection == 'x'){
+ selector = self.find('tr:gt(0) th').filter(o.rowFilter);
+ }
+ else{
+ selector = self.find('tr:eq(0) th').filter(o.colFilter);
+ }
+
+ selector.each(function(i){
+ $('<li><span class="visualize-key-color" style="background: '+dataGroups[i].color+'"></span><span class="visualize-key-label">'+ $(this).text() +'</span></li>')
+ .appendTo(newKey);
+ });
+ newKey.appendTo(infoContain);
+ };
+
+ //append new canvas to page
+
+ if(!container){canvasContain.insertAfter(this); }
+ if( typeof(G_vmlCanvasManager) != 'undefined' ){ G_vmlCanvasManager.init(); G_vmlCanvasManager.initElement(canvas[0]); }
+
+ //set up the drawing board
+ var ctx = canvas[0].getContext('2d');
+
+ //create chart
+ createChart[o.type]();
+
+ //clean up some doubled lines that sit on top of canvas borders (done via JS due to IE)
+ $('.visualize-line li:first-child span.line, .visualize-line li:last-child span.line, .visualize-area li:first-child span.line, .visualize-area li:last-child span.line, .visualize-bar li:first-child span.line,.visualize-bar .visualize-labels-y li:last-child span.line').css('border','none');
+ if(!container){
+ //add event for updating
+ canvasContain.bind('visualizeRefresh', function(){
+ self.visualize(o, $(this).empty());
+ });
+ }
+ }).next(); //returns canvas(es)
+};
+})(jQuery);
+
+