Here's the plugin overview without any of the logic that we will be using:
(function($) { var defaults = { columns: 6, // Number of viewable thumbnails imgHeight: 50, // jCarousel slider image height imgWidth: 75, // jCarousel slider image width jsonScript: '', // JSON return file './scripts/json/benchmark.js', 'class.somethinge.php', or anything that will return a JSON object can be used jsonObject: null, // JSON Object. Overrides jsonScript ajaxData: {}, // Data array to pass to the AJAX call cssClass: 'jcarousel-skin-benchmark', // jCarousel css skin to use imgEvent: 'click', // 'click' or 'mouseenter' afterEvent: $.noop, // Additional call added to the image event animate: true, // Turns off animation jCarouselEnabled: true, // Use jCarousel onComplete: $.noop }, initLoad = true, // set true for initial setup methods = { _init: function (options) { // Checks to see if the object already exists, much like a Singleton pattern would. return this.each(function () { // Even though we're using this.each, I'm only writing this plugin to work with an ID not a class. // However, you can have multiple instances of the plugin on the same page if you want. }); }, _getIntervalMax: function (max) { // Finds the max value that we will use on our x-axis }, _drawGraph: function (data, jsonData) { // Draws the bar graphs when we click on a jCarousel image }, _processAjax: function (data) { // Used to make AJAX calls to a DB or other data source. // The results will be returned in JSON format. }, _process: function (data, jsonData) { // Method used to generate the HTML needed for the plugin }, next: function () { // Exposed public method so that we can make the graph go to the next item auto-magically } } $.fn.graph = function (method) { if ( methods[method] ) { return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof method === 'object' || ! method ) { return methods._init.apply( this, arguments ); } else { $.error( 'Method ' + method + ' does not exist on jQuery.graph' ); } }; })(jQuery)
Now I'll give each method individually with comments to help understand what's going on.
_init: function (options) { return this.each(function () { // initial setup var $this = $(this), data = $this.data('graph'); // if data is set, then the plugin already exists and we don't need to do this step if (!data) { // Check to see if any options were passed in and combine them with our default options if (options) { options = $.extend({}, defaults, options) } // setup the data object that we'll be passing around var data = { element: $this, // The element as a jQuery object elementID: $this.attr('id'), // The element ID options: options, // The combined options total: 0 // Set to 0 because we don't know how many total items we have yet } // Check to see if we're using AJAX or just JSON object defined on the page if (options.jsonObject === null) { methods._processAjax(data); } else { methods._process(data, options.jsonObject); } } }); },
_getIntervalMax: function (max) { var multiplier = 1; // Hopefull we don't ever go above 999999 on our interval scale if (max > 100 && max < 999) { multiplier = 10; } else if (max > 1000 && max < 9999) { multiplier = 100; } else if (max > 10000 && max < 99999) { multiplier = 1000; } else if (max > 100000 && max < 999999) { multiplier = 10000; } // Switches MAX into a number < 100 and adds 10 so we don't // end up with over flow on the bar graphs numbers max = parseInt(max / multiplier, 0) + 10; // Divide by 6 until we find a number with no remainder // I'm using 6 because I want 6 intervals beyond 0 while (max % 6 != 0) { max += 1; } // Multiply out our number to make it fit the scale we want and send it back. return max * multiplier; },
_drawGraph: function (data, jsonData) { // Define everything that we're going to need to work with here var graph = $("#" + data.elementID + " .graphs"), caption = $("#" + data.elementID + " .graph_caption"), scaleMsg = $("#" + data.elementID + " .scaleMsg"), width = graph.width(), values = jsonData.results, ct = values.length, i, drawWidth = 0, max = Math.max.apply(null, values), scale = methods._getIntervalMax(max), temp = 0, scaleMax = (7 * scale) / 6, // Fixes the scale so that calculate distances will be correct options = data.options; caption.find("h2").html(jsonData.title); // Graph Title caption.find("h3").html(jsonData.def); // Graph definition scaleMsg.html(jsonData.scaleMsg); // Graph message // Interate through all the results for (i = 0; i < ct; i += 1) { drawWidth = Math.round( (values[i] / scaleMax) * width ); // Calculates the bar width in relation to the scale var bar = $("#" + data.elementID + "_graph_" + i.toString()); // Find the bar that we are going to modify // Are we going to animate this graph? if (options.animate === true) { // Perform animations. See jQuery API for help on .animate() bar.stop(true, false).animate({ width: drawWidth }, { duration: 500, complete: function () { temp += 1; // Is this the last bar that needs to be drawn? if (temp === (ct)) { // We don't call the afterEvent on initial loads if (initLoad === false) { options.afterEvent.call(); } else { initLoad = false; } } } }); } else { bar.width(drawWidth); // non-animated width adjustment } // Display the value to the right of the bar $("#" + data.elementID + "_graph_" + i.toString() + "_value").text(values[i] || "[Not Tested]"); } // afterEvent call when animation is off if (options.animate === false) { options.afterEvent.call(); } // Set the scale values along the x-axis for (i = 6; i >= 0; i -= 1) { $("#" + data.elementID + "_grid_base_" + i.toString()).html(" " + (scale / 6) * i); } },
_processAjax: function (data) { // See the jQuery API for $.ajax() on help with this section var options = data.options; $.ajax({ url: options.jsonScript, type: 'GET', data: options.ajaxData, dataType: 'json', success: function (jsonData) { methods._process(data, jsonData); }, complete: function (jqXHR, textStatus) { if (options.onComplete !== $.noop) { options.onComplete.call(); } } }); },
_process: function (data, jsonData) { var ct = jsonData.axis.length, total = ct, // count of the metrics we are going to compare options = data.options, i = 0, html = "<div class='graph_body'>\n" + "<div class='header' >\n" + "<div class='graph_caption'><h2></h2><h3></h3></div>\n" + "<div class='scaleMsg'></div>\n" + "</div>\n" + "<div class='graph_content clearfix'>\n" + "<div class='titles'>\n", html2 = "<div class='graphs'>\n", html3 = ""; // Generate the HTML needed for each bar graph for (i = 0; i < ct; i += 1) { if (i === 0) { extraClass = " first_bar"; } else if (i === (ct -1)) { extraClass = " last_bar"; } else { extraClass = ""; } html += "<div class='title' >" + jsonData.axis[i] + "</div>\n" html2 += "<div class='row'><div id='" + data.elementID + "_graph_" + i.toString() + "' class='bar" + extraClass + "'></div><div id='" + data.elementID + "_graph_" + i.toString() + "_value' class='value'></div></div>\n"; } // Generate the HTML needed for each interval on the x-axis for (i = 0; i < 7; i += 1) { html3 += "<div id='" + data.elementID + "_grid_base_" + i.toString() + "' class='axis'></div>"; } // Close everything up html2 += "</div>\n"; html += "</div>\n" + html2 + "<div class='spacer'></div>" + html3 + "</div>\n" + "</div>\n"; // Check to see if we're using jCarousel if (options.jCarouselEnabled === true) { ct = jsonData.metrics.length; html += "<ul class='metrics " + options.cssClass + "' >\n"; for (i = 0; i < ct; i += 1) { html += "<li><img src='" + jsonData.path + jsonData.metrics[i].img + "' alt='" + jsonData.metrics[i].title + "' height='" + options.imgHeight + "' width='" + options.imgWidth + "' /><p>" + jsonData.metrics[i].name + "</li>\n"; } html += "</ul>\n"; // attach the HTML to the element data.element.html(html); ct = 0; $("#" + data.elementID + " .metrics li").each( function () { $(this).data("test", jsonData.metrics[ct]).data("num", ct + 1);; // Setup the initial graph if (ct === 0) { methods._drawGraph(data, jsonData.metrics[ct]); $('#' + data.elementID + " .graph_body").data("num", ct + 1); } // Bind the click/mouseover event to the jCarousel item $(this).bind(options.imgEvent, function () { var me = $(this); $('#' + data.elementID + " .graph_body").data("num", me.data("num")); methods._drawGraph(data, me.data("test")); }); ct += 1; }); // jCarousel setup call $("#" + data.elementID + " .metrics").jcarousel({ scroll: options.columns, vertical: options.vertical }); } else { data.element.html(html); methods._drawGraph(data, jsonData.metrics[0]); } // set the total data.total = total; // Attach the data object to the element data.element.data('graph', data); },
next: function () { // Get the data object from the element var data = $(this).data('graph'), graph = $('#' + data.elementID + " .graph_body"), num = graph.data("num") + 1; // Perform next iteration num = num <= data.total ? num : 1; graph.data("num", num); // Scroll the jCarousel $('#' + data.elementID + " .metrics").data('jcarousel').scroll($.jcarousel.intval(num)); // Redraw the graphs methods._drawGraph(data, $("#" + data.elementID + " .metrics li:nth-child(" + num + ")").data("test")); }
That should be it, you now have the fully functional plugin. The only problem is that even with the plugin setup complete, it's not going to look very good at this point. Next time we'll go over setting up the jCarousel and Graph CSS that will complete the plugin. I'll also have the completed plugin up ready for download
No comments:
Post a Comment