diff options
author | Michael Francis <edude03@gmail.com> | 2011-05-28 13:28:16 -0400 |
---|---|---|
committer | Michael Francis <edude03@gmail.com> | 2011-05-28 13:28:16 -0400 |
commit | 2389d66da849798f8d4ec5f10e3b07c11da49185 (patch) | |
tree | e22556d12982395b469a23420c662662e3e064cc /views/layouts/presentation_files/visualize.jQuery.js | |
download | otakuhub-2389d66da849798f8d4ec5f10e3b07c11da49185.tar.xz |
Initial Commit
Diffstat (limited to 'views/layouts/presentation_files/visualize.jQuery.js')
-rw-r--r-- | views/layouts/presentation_files/visualize.jQuery.js | 463 |
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); + + |