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