diff --git a/jquery.sketchable.js b/jquery.sketchable.js index 3c71ebb..057f1e6 100644 --- a/jquery.sketchable.js +++ b/jquery.sketchable.js @@ -161,9 +161,9 @@ elem.unbind("mouseup", mouseupHandler); elem.unbind("mousemove", mousemoveHandler); elem.unbind("mousedown", mousedownHandler); - elem.unbind("touchstart", touchHandler); - elem.unbind("touchmove", touchHandler); - elem.unbind("touchend", touchHandler); + elem.unbind("touchstart", touchdownHandler); + elem.unbind("touchmove", touchmoveHandler); + elem.unbind("touchend", touchupHandler); } elem.removeData(_ns); diff --git a/jquery.sketchable.memento.js b/jquery.sketchable.memento.js index d134460..3218583 100644 --- a/jquery.sketchable.memento.js +++ b/jquery.sketchable.memento.js @@ -3,14 +3,14 @@ */ /** * @name $ - * @class - * See the jQuery library for full details. + * @class + * See the jQuery library for full details. * This just documents the method that is added to jQuery by this plugin. */ /** * @name $.fn - * @class - * See the jQuery library for full details. + * @class + * See the jQuery library for full details. * This just documents the method that is added to jQuery by this plugin. */ ;(function($) { @@ -23,12 +23,12 @@ * var mc = new MementoCanvas( $('canvas-selector') ); */ var MementoCanvas = function($canvas) { - + // Private stuff ////////////////////////////////////////////////////////// var stack = []; var stpos = -1; var self = this; - + function prev() { if (stpos > 0) { stpos--; @@ -59,8 +59,8 @@ data.sketch.graphics.drawImage(snapshot, 0,0); }); }; - - // Key event manager. + + // Key event manager. // Undo: "Ctrl + Z" // Redo: "Ctrl + Y" or "Ctrl + Shift + Z" // TODO: decouple shortcut definition, perhaps via jquery.hotkeys plugin. @@ -79,10 +79,10 @@ } } }; - + // Public stuff /////////////////////////////////////////////////////////// - - /** + + /** * Goes back to the last saved state, if available. * @name undo * @memberOf MementoCanvas @@ -90,10 +90,11 @@ this.undo = function() { prev(); $canvas.sketchable('handler', function(elem, data) { - data.strokes = stack[stpos].strokes.slice(); + if (stack[stpos]) + data.strokes = stack[stpos].strokes.slice(); }); }; - /** + /** * Goes forward to the last saved state, if available. * @name redo * @memberOf MementoCanvas @@ -101,10 +102,11 @@ this.redo = function() { next(); $canvas.sketchable('handler', function(elem, data) { - data.strokes = stack[stpos].strokes.slice(); + if (stack[stpos]) + data.strokes = stack[stpos].strokes.slice(); }); }; - /** + /** * Resets stack. * @name reset * @memberOf MementoCanvas @@ -113,7 +115,7 @@ stack = []; stpos = -1; }; - /** + /** * Save state. * @name save * @memberOf MementoCanvas @@ -125,7 +127,7 @@ stack.push({ image: elem[0].toDataURL(), strokes: data.strokes.slice() }); }); }; - /** + /** * Init instance. * @name init * @memberOf MementoCanvas @@ -135,7 +137,7 @@ $(document).off("keypress", keyManager); $(document).on("keypress", keyManager); }; - /** + /** * Destroy instance. * @name destroy * @memberOf MementoCanvas @@ -144,19 +146,19 @@ $(document).off("keypress", keyManager); this.reset(); }; - + }; - + // Bind plugin extension //////////////////////////////////////////////////// - + var plugin = $.fn.sketchable; var availMethods = plugin('methods'); - + function configure(elem, opts) { var self = elem, options = $.extend(true, plugin.defaults, opts); // Actually this plugin is singleton, so exit early. if (!options.interactive) return opts; - + var mc = new MementoCanvas(elem); var callbacks = { init: function(elem, data) { @@ -171,7 +173,7 @@ data.memento.destroy(); } }; - + // A helper function to override user-defined event listeners. function override(ev) { if (options && options.events && typeof options.events[ev] === 'function') { @@ -196,7 +198,7 @@ } plugin.isMementoReady = true; } - + // Expose public API for jquery.sketchable plugin. $.extend(availMethods, { undo: function() { @@ -206,13 +208,13 @@ mc.redo(); } }); - + return plugin.defaults; }; - - /** + + /** * Creates a new memento-capable jQuery.sketchable object. - * @param {String|Object} method name of the method to invoke, + * @param {String|Object} method name of the method to invoke, * or a configuration object. * @return jQuery * @class @@ -225,5 +227,5 @@ var conf = configure(this, opts); return initfn.call(this, conf); }; - + })(jQuery); diff --git a/jquery.sketchable.memento.min.js b/jquery.sketchable.memento.min.js index fd74865..f774995 100644 --- a/jquery.sketchable.memento.min.js +++ b/jquery.sketchable.memento.min.js @@ -1,4 +1 @@ -/*! - * Memento plugin for jQuery sketchable | v1.1 | Luis A. Leiva | MIT license - */ -(function(e){var a=function(m){var h=[];var g=-1;var i=this;function l(){if(g>0){g--;var o=new Image();o.src=h[g].image;o.onload=function(){j(this)}}}function k(){if(g0){stpos--;var snapshot=new Image;snapshot.src=stack[stpos].image;snapshot.onload=function(){restore(this)}}}function next(){if(stpos-1){return methods}else 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. See jQuery.sketchable("methods").')}return this};$.fn.sketchable.defaults={interactive:true,mouseupMovements:false,relTimestamps:false,multitouch:true,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}};function getMousePos(e){var elem=$(e.target),pos=elem.offset();return{x:Math.round(e.pageX-pos.left),y:Math.round(e.pageY-pos.top)}}function saveMousePos(idx,data,pt){if(!data.coords[idx]){data.coords[idx]=[]}var time=(new Date).getTime();if(data.options.relTimestamps){if(data.strokes.length===0&&data.coords[idx].length===0)data.timestamp=time;time-=data.timestamp}data.coords[idx].push([pt.x,pt.y,time,+data.sketch.isDrawing])}function mousedownHandler(e){if(e.originalEvent.touches)return false;downHandler(e)}function mousemoveHandler(e){if(e.originalEvent.touches)return false;moveHandler(e)}function mouseupHandler(e){if(e.originalEvent.touches)return false;upHandler(e)}function touchdownHandler(e){var elem=$(e.target),data=elem.data(_ns),options=data.options;var touches=e.originalEvent.changedTouches;if(options.multitouch){for(var i=0;i0){data.sketch.fillCircle(p.x,p.y,options.graphics.firstPointSize)}if(!data.coords[idx]){data.coords[idx]=[]}if(data.coords[idx].length>0){data.strokes.push(data.coords[idx]);data.coords[idx]=[]}saveMousePos(idx,data,p);if(typeof options.events.mousedown==="function"){options.events.mousedown(elem,data,e)}}function moveHandler(e){var idx=e.identifier||0;var elem=$(e.target),data=elem.data(_ns),options=data.options;if((!options.mouseupMovements||data.strokes.length===0)&&!data.sketch.isDrawing)return;var p=getMousePos(e);if(data.sketch.isDrawing){var last=data.coords[idx][data.coords[idx].length-1];data.sketch.beginPath().line(last[0],last[1],p.x,p.y).stroke().closePath()}saveMousePos(idx,data,p);if(typeof options.events.mousemove==="function"){options.events.mousemove(elem,data,e)}}function upHandler(e){var idx=e.identifier||0;var elem=$(e.target),data=elem.data(_ns),options=data.options;data.sketch.isDrawing=false;data.strokes.push(data.coords[idx]);data.coords[idx]=[];if(typeof options.events.mouseup==="function"){options.events.mouseup(elem,data,e)}}})(jQuery); +(function($){var _ns="sketchable";var methods={init:function(opts){var options=$.extend(true,{},$.fn.sketchable.defaults,opts||{});return this.each(function(){var elem=$(this),data=elem.data(_ns);if(!data){if(options.interactive){elem.bind("mousedown",mousedownHandler);elem.bind("mousemove",mousemoveHandler);elem.bind("mouseup",mouseupHandler);elem.bind("touchstart",touchdownHandler);elem.bind("touchmove",touchmoveHandler);elem.bind("touchend",touchupHandler);this.onselectstart=function(){return false}}}var sketch=new jSketch(this,options.graphics);sketch.isDrawing=false;elem.data(_ns,{strokes:[],coords:{},timestamp:(new Date).getTime(),sketch:sketch,options:options});if(typeof options.events.init==="function"){options.events.init(elem,elem.data(_ns))}})},strokes:function(arr){if(arr){return this.each(function(){var elem=$(this),data=elem.data(_ns);data.strokes=arr})}else{var data=$(this).data(_ns);return data.strokes}},handler:function(callback){return this.each(function(){var elem=$(this),data=elem.data(_ns);callback(elem,data)})},clear:function(){return this.each(function(){var elem=$(this),data=elem.data(_ns)||{},options=data.options;if(data.sketch){data.sketch.clear();data.strokes=[];data.coords={}}if(options&&typeof options.events.clear==="function"){options.events.clear(elem,data)}})},reset:function(opts){return this.each(function(){var elem=$(this),data=elem.data(_ns)||{},options=data.options;elem.sketchable("destroy").sketchable(opts);if(options&&typeof options.events.reset==="function"){options.events.reset(elem,data)}})},destroy:function(){return this.each(function(){var elem=$(this),data=elem.data(_ns)||{},options=data.options;if(options.interactive){elem.unbind("mouseup",mouseupHandler);elem.unbind("mousemove",mousemoveHandler);elem.unbind("mousedown",mousedownHandler);elem.unbind("touchstart",touchdownHandler);elem.unbind("touchmove",touchmoveHandler);elem.unbind("touchend",touchupHandler)}elem.removeData(_ns);if(options&&typeof options.events.destroy==="function"){options.events.destroy(elem,data)}})}};$.fn.sketchable=function(method){if("methods functions hooks".split(" ").indexOf(method)>-1){return methods}else 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. See jQuery.sketchable("methods").')}return this};$.fn.sketchable.defaults={interactive:true,mouseupMovements:false,relTimestamps:false,multitouch:true,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}};function getMousePos(e){var elem=$(e.target),pos=elem.offset();return{x:Math.round(e.pageX-pos.left),y:Math.round(e.pageY-pos.top)}}function saveMousePos(idx,data,pt){if(!data.coords[idx]){data.coords[idx]=[]}var time=(new Date).getTime();if(data.options.relTimestamps){if(data.strokes.length===0&&data.coords[idx].length===0)data.timestamp=time;time-=data.timestamp}data.coords[idx].push([pt.x,pt.y,time,+data.sketch.isDrawing])}function mousedownHandler(e){if(e.originalEvent.touches)return false;downHandler(e)}function mousemoveHandler(e){if(e.originalEvent.touches)return false;moveHandler(e)}function mouseupHandler(e){if(e.originalEvent.touches)return false;upHandler(e)}function touchdownHandler(e){var elem=$(e.target),data=elem.data(_ns),options=data.options;var touches=e.originalEvent.changedTouches;if(options.multitouch){for(var i=0;i0){data.sketch.fillCircle(p.x,p.y,options.graphics.firstPointSize)}if(!data.coords[idx]){data.coords[idx]=[]}if(data.coords[idx].length>0){data.strokes.push(data.coords[idx]);data.coords[idx]=[]}saveMousePos(idx,data,p);if(typeof options.events.mousedown==="function"){options.events.mousedown(elem,data,e)}}function moveHandler(e){var idx=e.identifier||0;var elem=$(e.target),data=elem.data(_ns),options=data.options;if((!options.mouseupMovements||data.strokes.length===0)&&!data.sketch.isDrawing)return;var p=getMousePos(e);if(data.sketch.isDrawing){var last=data.coords[idx][data.coords[idx].length-1];data.sketch.beginPath().line(last[0],last[1],p.x,p.y).stroke().closePath()}saveMousePos(idx,data,p);if(typeof options.events.mousemove==="function"){options.events.mousemove(elem,data,e)}}function upHandler(e){var idx=e.identifier||0;var elem=$(e.target),data=elem.data(_ns),options=data.options;data.sketch.isDrawing=false;data.strokes.push(data.coords[idx]);data.coords[idx]=[];if(typeof options.events.mouseup==="function"){options.events.mouseup(elem,data,e)}}})(jQuery);