I am trying to write a jQuery Plugin from a piece of JS code I had written. What this plugin does is it converts a select box into a map of Australia where I can select individual states. It's working perfectly well. However, I'd like to know how I can write it with OOP principles like SOLID etc. can someone review my code and suggest changes.
;(function ( $, window, document, undefined ) {
// undefined is used here as the undefined global variable in ECMAScript 3 is
// mutable (ie. it can be changed by someone else). undefined isn't really being
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
// can no longer be modified.
// window and document are passed through as local variable rather than global
// as this (slightly) quickens the resolution process and can be more efficiently
// minified (especially when both are regularly referenced in your plugin).
// Create the defaults once
var pluginName = "genAusMap",
defaults = {};
// The actual plugin constructor
function Plugin ( element, options ) {
this.element = element;
var imagesLoaded = 0;
var canvas, ctx,ausMap,states;
var elemLeft,elemTop;
this.setCanvas = function(c,w,h){
canvas = c;
canvas.setAttribute('width',w);
canvas.setAttribute('height',h);
// Add event listener for `click` events.
$(canvas).on('click', function(event) {
var x = event.pageX - elemLeft, y = event.pageY - elemTop;
canvas.width = canvas.width; // clear the canvas
ctx.drawImage(ausMap, 0, 0);
if (y > 59 && y < 164 && x > 146 && x < 205) {
drawImageOnLoad('nt');
}
if (y > 59 && y < 192 && x > 205 && x < 301) {
drawImageOnLoad('qld');
}
if (y > 164 && y < 249 && x > 147 && x < 214) {
drawImageOnLoad('sa');
}
if (y > 260 && y < 295 && x > 229 && x < 261) {
drawImageOnLoad('tas');
}
if (y > 223 && y < 260 && x > 213 && x < 265) {
drawImageOnLoad('vic');
}
if ((y > 191 && y < 222 && x > 220 && x < 297) || (y > 221 & y < 233 & x > 230 & x < 277) || (y > 233 & y < 245 & x > 254 & x < 269) ) {
// ctx.rect(220,191,77,31); ctx.rect(230,221,47,12); ctx.rect(254,233,15,12); ctx.stroke(); // draw a rectangle box with the various co-ordinates to know where to start from and where to end for nsw /
drawImageOnLoad('nsw');
}
if ((y > 207 && y < 232 && x > 240 && x < 270) || (y > 233 & y < 245 & x > 254 & x < 269)) {
// ctx.rect(240,207,30,25); ctx.rect(254,233,15,12); ctx.stroke();
drawImageOnLoad('act');
}
if (y > 75 && y < 235 && x > 40 && x < 146) {
drawImageOnLoad('wa');
}
});
};
this.setCanvasOffsets = function(l,t){
elemLeft = l;
elemTop = t;
};
this.getCanvas = function(){
return canvas;
};
this.setCtx = function(c){
ctx = c;
};
this.getCtx = function(){
return ctx;
};
this.setAusMap = function(map){
ausMap = map;
}
this.setStates = function(listOfStates){
states = listOfStates;
}
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
var checkAllImagesLoaded = function () {
imagesLoaded += 1;
if(imagesLoaded == 9) {
drawImageOnLoad();
}
};
var drawImageOnLoad = function(drawState){
drawState = typeof drawState !== 'undefined' ? drawState : ''; // Assigning Default value
if(imagesLoaded == 9) {
canvas.width = canvas.width;
ctx.drawImage(ausMap, 0, 0);
ctx.globalAlpha = 0.5;
$.each(states, function(state){
state = this;
console.log(drawState);
if(drawState == state.getAttribute('data-name')) {
ctx.drawImage(state, parseInt(state.getAttribute('data-positionX')), parseInt(state.getAttribute('data-positionY')));
//selectDeselectOption(state.getAttribute('data-name'));
}
});
}
};
this.imageObj = function(src, x, y,name){
this.src = src;
this.x = x;
this.y = y;
this.name = name;
};
this.loadImage = function(image, onload) {
var img = new Image();
img.onload = checkAllImagesLoaded;
img.src = image.src;
img.setAttribute('data-positionX',image.x);
img.setAttribute('data-positionY', image.y);
img.setAttribute('data-name', image.name);
return img;
};
var selectDeselectOption = function(state){
$(this.element).val(state);
};
if(this.element.tagName == 'SELECT') {
this.settings = $.extend( {}, defaults, options );
this._defaults = defaults;
this._name = pluginName;
this.states = [];
this.init();
} else {
alert('Cannot instantiate plugin '+pluginName+' on a '+this.element.tagName+'. Try using a SELECT element instead');
}
}
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
$el = $(this.element);
this.setCanvas(document.createElement('canvas'),319,313);
this.setCtx(this.getCanvas().getContext("2d"));
this.setAusMap(this.loadImage(new this.imageObj(this.settings.mapOfAustralia ,0,0)));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/act.png',0,0,'act')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/nsw.png',0,0,'nsw')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/nt.png',0,0,'nt')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/sa.png',0,0,'sa')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/qld.png',0,0,'qld')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/tas.png',0,0,'tas')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/vic.png',0,0,'vic')));
this.states.push(this.loadImage(new this.imageObj('http://localhost/test/wa.png',0,0,'wa')));
this.setStates(this.states);
$el.after(this.getCanvas());
console.log(this.getCanvas());
this.setCanvasOffsets(this.getCanvas().offsetLeft,this.getCanvas().offsetTop)
}
});
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[ pluginName ] = function ( options ) {
this.each(function() {
if ( !$.data( this, "plugin_" + pluginName ) ) {
$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
}
});
// chain jQuery functions
return this;
};
})( jQuery, window, document );