diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..f3a75ac --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,26 @@ +module.exports = { + 'extends': 'google', + 'env': { + 'browser': true, + }, + 'rules': { + // --- BEGIN Disabled rules --- + 'no-var': 0, + 'padded-blocks': 0, + 'prefer-rest-params': 0, + 'spaced-comment': 0, + 'guard-for-in': 0, + 'one-var': 0, + 'no-multi-spaces': 0, + 'require-jsdoc': 0, + // --- BEGIN Errors --- + 'no-tabs': 2, + 'indent': ['error', 2], + 'quotes': 2, + // --- BEGIN Warnings --- + 'max-len': [1, 160], + 'comma-dangle': 1, + 'key-spacing': 1, + 'valid-jsdoc': 1, + }, +}; diff --git a/dist/jquery.sketchable.full.min.js b/dist/jquery.sketchable.full.min.js index 8f4f893..503ef68 100644 --- a/dist/jquery.sketchable.full.min.js +++ b/dist/jquery.sketchable.full.min.js @@ -1,2 +1,2 @@ -/*! jSketch drawing lib (all in one) | v2.0.0 | 2017-11-18 */ -!function(a){function b(a,b){if(!a)throw new Error("Sketchable requires a DOM element.");return"string"==typeof a&&(a=document.querySelector(a)),this.setContext(a),this.stageWidth=a.width,this.stageHeight=a.height,this.data=b,this.setDefaults()}b.prototype={setContext:function(a){if(!a)throw new Error("No canvas element specified.");return this.canvas=a,this.context=a.getContext("2d"),this},setDefaults:function(){return this.saveGraphics({fillStyle:this.data.fillStyle||"#F00",strokeStyle:this.data.strokeStyle||"#F0F",lineWidth:this.data.lineWidth||2,lineCap:this.data.lineCap||"round",lineJoin:this.data.lineJoin||"round",miterLimit:this.data.miterLimit||10}).restoreGraphics()},size:function(a,b){return this.stageWidth=a,this.stageHeight=b,this.canvas.width=a,this.canvas.height=b,this.restoreGraphics(),this},background:function(a){return this.beginFill(a),this.context.fillRect(0,0,this.stageWidth,this.stageHeight),this.endFill(),this},stage:function(a,b,c){return this.size(a,b).background(c),this},beginFill:function(a){return this.saveGraphics(),this.context.fillStyle=a,this},endFill:function(){return this.restoreGraphics(),this},lineStyle:function(a,b,c,d,e){return this.saveGraphics({strokeStyle:a||this.data.strokeStyle,lineWidth:b||this.data.lineWidth,lineCap:c||this.data.lineCap,lineJoin:d||this.data.lineJoin,miterLimit:e||this.data.miterLimit}).restoreGraphics()},moveTo:function(a,b){return this.context.moveTo(a,b),this},lineTo:function(a,b){return this.context.lineTo(a,b),this},line:function(a,b,c,d){return this.context.moveTo(a,b),this.lineTo(c,d),this},curveTo:function(a,b,c,d){return this.context.quadraticCurveTo(c,d,a,b),this},curve:function(a,b,c,d,e,f){return this.context.moveTo(a,b),this.curveTo(c,d,e,f),this},stroke:function(){return this.context.stroke(),this},strokeRect:function(a,b,c,d){return this.context.beginPath(),this.context.strokeRect(a,b,c,d),this.context.closePath(),this},fillRect:function(a,b,c,d){return this.context.beginPath(),this.context.fillRect(a,b,c,d),this.context.closePath(),this},strokeCircle:function(a,b,c){return this.context.beginPath(),this.context.arc(a,b,c,0,2*Math.PI,!1),this.context.stroke(),this.context.closePath(),this},fillCircle:function(a,b,c){return this.context.beginPath(),this.context.arc(a,b,c,0,2*Math.PI,!1),this.context.fill(),this.context.closePath(),this},radialCircle:function(a,b,c,d,e){var f=this.context.createRadialGradient(a,b,c,a,b,d||5);e&&"array"===e.constructor.name||(e=[this.context.fillStyle,"white"]);for(var g=0;g1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function f(a){return a.originalEvent.touches?!1:void l(a)}function g(a){return a.originalEvent.touches?!1:void m(a)}function h(a){return a.originalEvent.touches?!1:void n(a)}function i(a){o(a,l),a.preventDefault()}function j(a){o(a,m),a.preventDefault()}function k(a){o(a,n),a.preventDefault()}function l(b){if(3===b.which)return!1;var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive){g.sketch.isDrawing=!0;var i=d(b);h.graphics.firstPointSize>0&&g.sketch.beginFill(h.graphics.fillStyle).fillCircle(i.x,i.y,h.graphics.firstPointSize).endFill();var j=g.coords[c];j||(j=[]),j.length>0&&g.strokes.push(j),g.coords[c]=[],e(c,g,i),"function"==typeof h.events.mousedown&&h.events.mousedown(f,g,b)}}function m(b){var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive&&(h.mouseupMovements&&0!==g.strokes.length||g.sketch.isDrawing)){var i=d(b),j=g.coords[c],k=j[j.length-1];if(k){var l=g.sketch.beginPath();g.sketch.isDrawing?l.lineStyle(h.graphics.strokeStyle,h.graphics.lineWidth):h.mouseupMovements.visible!==!1&&l.lineStyle(h.mouseupMovements.strokeStyle||"#DDD",h.mouseupMovements.lineWidth||1),l.line(k[0],k[1],i.x,i.y).stroke().closePath()}e(c,g,i),"function"==typeof h.events.mousemove&&h.events.mousemove(f,g,b)}}function n(b){var c=b.identifier||0,d=a(b.target),e=d.data(p),f=e.options;f.interactive&&(e.sketch.isDrawing=!1,e.strokes.push(e.coords[c]),e.coords[c]=[],"function"==typeof f.events.mouseup&&f.events.mouseup(d,e,b))}function o(b,c){var d=a(b.target),e=d.data(p),f=e.options;if(f.multitouch)for(var g=b.originalEvent.changedTouches,h=0;h-1){var e=c(q,b);return e.apply(this,d)}return q[b]?q[b].apply(this,d):(a.error("Unknown method: "+b),this)},a.fn.sketchable.api=q,a.fn.sketchable.plugins={},a.fn.sketchable.defaults={interactive:!0,mouseupMovements:!1,relTimestamps:!1,multitouch:!0,cssCursors:!0,filterCoords:!1,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}}}(jQuery),function(a){function b(b){function c(a,c){b.sketchable("handler",function(b,d){d.sketch.clear(),d.sketch.context.drawImage(a,0,0),d.strokes=c.slice()})}function d(a){if(a.ctrlKey)switch(a.which){case 26:a.shiftKey?g.redo():g.undo();break;case 25:g.redo()}}var e=[],f=-1,g=this;this.undo=function(){return f>0&&(f--,this.restore()),this},this.redo=function(){return f0?e[f].strokes=c.strokes.slice():(e.push({image:b[0].toDataURL(),strokes:c.strokes.slice()}),f++)}),this},this.state=function(){return JSON.parse(JSON.stringify(e[f]))},this.restore=function(a){a||(a=e[f]);var b=new Image;b.src=a.image,b.onload=function(){c(this,a.strokes)}},this.init=function(){return a(document).off("keypress",d),a(document).on("keypress",d),this.save()},this.destroy=function(){return a(document).off("keypress",d),this.reset()}}var c="sketchable";a.fn.sketchable.plugins.memento=function(d){function e(a){if(!f.options["_bound$"+a])if(f.options["_bound$"+a]=!0,f.options.events&&"function"==typeof f.options.events[a]){var b=f.options.events[a];f.options.events[a]=function(){b.apply(d,arguments),g[a].apply(d,arguments)}}else f.options.events[a]=g[a]}for(var f=d.sketchable("config"),g={clear:function(a,b){b.memento.reset()},mouseup:function(a,b,c){b.memento.save(c)},destroy:function(a,b){b.memento.destroy()}},h="mouseup clear destroy".split(" "),i=0;i1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function f(a){return a.originalEvent.touches?!1:void l(a)}function g(a){return a.originalEvent.touches?!1:void m(a)}function h(a){return a.originalEvent.touches?!1:void n(a)}function i(a){o(a,l),a.preventDefault()}function j(a){o(a,m),a.preventDefault()}function k(a){o(a,n),a.preventDefault()}function l(b){if(3===b.which)return!1;var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive){var i=d(b);"function"==typeof h.events.mousedownBefore&&h.events.mousedownBefore(f,g,b),h.graphics.firstPointSize>0&&g.sketch.beginFill(h.graphics.fillStyle).fillCircle(i.x,i.y,h.graphics.firstPointSize).endFill(),g.sketch.isDrawing=!0,g.sketch.beginPath();var j=g.coords[c];j||(j=[]),j.length>0&&g.strokes.push(j),g.coords[c]=[],e(c,g,i),"function"==typeof h.events.mousedown&&h.events.mousedown(f,g,b)}}function m(b){var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive&&(h.mouseupMovements&&0!==g.strokes.length||g.sketch.isDrawing)){var i=d(b);"function"==typeof h.events.mousemoveBefore&&h.events.mousemoveBefore(f,g,b);var j=g.coords[c],k=j[j.length-1];if(k){var l=g.sketch;g.sketch.isDrawing?l.lineStyle(h.graphics.strokeStyle,h.graphics.lineWidth):h.mouseupMovements.visible!==!1&&l.lineStyle(h.mouseupMovements.strokeStyle||"#DDD",h.mouseupMovements.lineWidth||1),l.line(k[0],k[1],i.x,i.y).stroke()}e(c,g,i),"function"==typeof h.events.mousemove&&h.events.mousemove(f,g,b)}}function n(b){var c=b.identifier||0,d=a(b.target),e=d.data(p),f=e.options;f.interactive&&("function"==typeof f.events.mouseupBefore&&f.events.mouseupBefore(d,e,b),e.sketch.isDrawing=!1,e.sketch.closePath(),e.strokes.push(e.coords[c]),e.coords[c]=[],"function"==typeof f.events.mouseup&&f.events.mouseup(d,e,b))}function o(b,c){var d=a(b.target),e=d.data(p),f=e.options;if(f.multitouch)for(var g=b.originalEvent.changedTouches,h=0;h-1){var e=c(q,b);return e.apply(this,d)}return q[b]?q[b].apply(this,d):(a.error("Unknown method: "+b),this)},a.fn.sketchable.api=q,a.fn.sketchable.plugins={},a.fn.sketchable.defaults={interactive:!0,mouseupMovements:!1,relTimestamps:!1,multitouch:!0,cssCursors:!0,filterCoords:!1,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}}}(jQuery),function(a){function b(b){function c(a,c){b.sketchable("handler",function(b,d){d.sketch.clear(),d.sketch.context.drawImage(a,0,0),d.strokes=c.slice()})}function d(a){if(a.ctrlKey)switch(a.which){case 26:a.shiftKey?g.redo():g.undo();break;case 25:g.redo()}}var e=[],f=-1,g=this;this.undo=function(){return f>0&&(f--,this.restore()),this},this.redo=function(){return f0?e[f].strokes=c.strokes.slice():(e.push({image:b[0].toDataURL(),strokes:c.strokes.slice()}),f++)}),this},this.state=function(){return JSON.parse(JSON.stringify(e[f]))},this.restore=function(a){a||(a=e[f]);var b=new Image;b.src=a.image,b.onload=function(){c(this,a.strokes)}},this.init=function(){return a(document).off("keypress",d),a(document).on("keypress",d),this.save()},this.destroy=function(){return a(document).off("keypress",d),this.reset()}}var c="sketchable";a.fn.sketchable.plugins.memento=function(d){function e(a){if(!f.options["_bound$"+a])if(f.options["_bound$"+a]=!0,f.options.events&&"function"==typeof f.options.events[a]){var b=f.options.events[a];f.options.events[a]=function(){b.apply(d,arguments),g[a].apply(d,arguments)}}else f.options.events[a]=g[a]}for(var f=d.sketchable("config"),g={clear:function(a,b){b.memento.reset()},mouseup:function(a,b,c){b.memento.save(c)},destroy:function(a,b){b.memento.destroy()}},h="mouseup clear destroy".split(" "),i=0;i1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function f(a){return a.originalEvent.touches?!1:void l(a)}function g(a){return a.originalEvent.touches?!1:void m(a)}function h(a){return a.originalEvent.touches?!1:void n(a)}function i(a){o(a,l),a.preventDefault()}function j(a){o(a,m),a.preventDefault()}function k(a){o(a,n),a.preventDefault()}function l(b){if(3===b.which)return!1;var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive){g.sketch.isDrawing=!0;var i=d(b);h.graphics.firstPointSize>0&&g.sketch.beginFill(h.graphics.fillStyle).fillCircle(i.x,i.y,h.graphics.firstPointSize).endFill();var j=g.coords[c];j||(j=[]),j.length>0&&g.strokes.push(j),g.coords[c]=[],e(c,g,i),"function"==typeof h.events.mousedown&&h.events.mousedown(f,g,b)}}function m(b){var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive&&(h.mouseupMovements&&0!==g.strokes.length||g.sketch.isDrawing)){var i=d(b),j=g.coords[c],k=j[j.length-1];if(k){var l=g.sketch.beginPath();g.sketch.isDrawing?l.lineStyle(h.graphics.strokeStyle,h.graphics.lineWidth):h.mouseupMovements.visible!==!1&&l.lineStyle(h.mouseupMovements.strokeStyle||"#DDD",h.mouseupMovements.lineWidth||1),l.line(k[0],k[1],i.x,i.y).stroke().closePath()}e(c,g,i),"function"==typeof h.events.mousemove&&h.events.mousemove(f,g,b)}}function n(b){var c=b.identifier||0,d=a(b.target),e=d.data(p),f=e.options;f.interactive&&(e.sketch.isDrawing=!1,e.strokes.push(e.coords[c]),e.coords[c]=[],"function"==typeof f.events.mouseup&&f.events.mouseup(d,e,b))}function o(b,c){var d=a(b.target),e=d.data(p),f=e.options;if(f.multitouch)for(var g=b.originalEvent.changedTouches,h=0;h-1){var e=c(q,b);return e.apply(this,d)}return q[b]?q[b].apply(this,d):(a.error("Unknown method: "+b),this)},a.fn.sketchable.api=q,a.fn.sketchable.plugins={},a.fn.sketchable.defaults={interactive:!0,mouseupMovements:!1,relTimestamps:!1,multitouch:!0,cssCursors:!0,filterCoords:!1,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}}}(jQuery); \ No newline at end of file +!function(a){function b(a,b){b||(b=a.data(p).options),b.cssCursors&&(a[0].style.cursor=b.interactive?"pointer":"not-allowed"),this.onselectstart=function(){return!1}}function c(a,b){b=b.split(".");for(var c=0;c1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function f(a){return a.originalEvent.touches?!1:void l(a)}function g(a){return a.originalEvent.touches?!1:void m(a)}function h(a){return a.originalEvent.touches?!1:void n(a)}function i(a){o(a,l),a.preventDefault()}function j(a){o(a,m),a.preventDefault()}function k(a){o(a,n),a.preventDefault()}function l(b){if(3===b.which)return!1;var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive){var i=d(b);"function"==typeof h.events.mousedownBefore&&h.events.mousedownBefore(f,g,b),h.graphics.firstPointSize>0&&g.sketch.beginFill(h.graphics.fillStyle).fillCircle(i.x,i.y,h.graphics.firstPointSize).endFill(),g.sketch.isDrawing=!0,g.sketch.beginPath();var j=g.coords[c];j||(j=[]),j.length>0&&g.strokes.push(j),g.coords[c]=[],e(c,g,i),"function"==typeof h.events.mousedown&&h.events.mousedown(f,g,b)}}function m(b){var c=b.identifier||0,f=a(b.target),g=f.data(p),h=g.options;if(h.interactive&&(h.mouseupMovements&&0!==g.strokes.length||g.sketch.isDrawing)){var i=d(b);"function"==typeof h.events.mousemoveBefore&&h.events.mousemoveBefore(f,g,b);var j=g.coords[c],k=j[j.length-1];if(k){var l=g.sketch;g.sketch.isDrawing?l.lineStyle(h.graphics.strokeStyle,h.graphics.lineWidth):h.mouseupMovements.visible!==!1&&l.lineStyle(h.mouseupMovements.strokeStyle||"#DDD",h.mouseupMovements.lineWidth||1),l.line(k[0],k[1],i.x,i.y).stroke()}e(c,g,i),"function"==typeof h.events.mousemove&&h.events.mousemove(f,g,b)}}function n(b){var c=b.identifier||0,d=a(b.target),e=d.data(p),f=e.options;f.interactive&&("function"==typeof f.events.mouseupBefore&&f.events.mouseupBefore(d,e,b),e.sketch.isDrawing=!1,e.sketch.closePath(),e.strokes.push(e.coords[c]),e.coords[c]=[],"function"==typeof f.events.mouseup&&f.events.mouseup(d,e,b))}function o(b,c){var d=a(b.target),e=d.data(p),f=e.options;if(f.multitouch)for(var g=b.originalEvent.changedTouches,h=0;h-1){var e=c(q,b);return e.apply(this,d)}return q[b]?q[b].apply(this,d):(a.error("Unknown method: "+b),this)},a.fn.sketchable.api=q,a.fn.sketchable.plugins={},a.fn.sketchable.defaults={interactive:!0,mouseupMovements:!1,relTimestamps:!1,multitouch:!0,cssCursors:!0,filterCoords:!1,events:{},graphics:{firstPointSize:3,lineWidth:3,strokeStyle:"#F0F",fillStyle:"#F0F",lineCap:"round",lineJoin:"round",miterLimit:10}}}(jQuery); \ No newline at end of file diff --git a/dist/sketchable.full.min.js b/dist/sketchable.full.min.js index 3972abd..fbae887 100644 --- a/dist/sketchable.full.min.js +++ b/dist/sketchable.full.min.js @@ -1,2 +1,2 @@ -/*! jSketch drawing lib (all in one) | v2.0.0 | 2017-11-18 */ -!function(a){function b(a,b){if(!a)throw new Error("Sketchable requires a DOM element.");return"string"==typeof a&&(a=document.querySelector(a)),this.setContext(a),this.stageWidth=a.width,this.stageHeight=a.height,this.data=b,this.setDefaults()}b.prototype={setContext:function(a){if(!a)throw new Error("No canvas element specified.");return this.canvas=a,this.context=a.getContext("2d"),this},setDefaults:function(){return this.saveGraphics({fillStyle:this.data.fillStyle||"#F00",strokeStyle:this.data.strokeStyle||"#F0F",lineWidth:this.data.lineWidth||2,lineCap:this.data.lineCap||"round",lineJoin:this.data.lineJoin||"round",miterLimit:this.data.miterLimit||10}).restoreGraphics()},size:function(a,b){return this.stageWidth=a,this.stageHeight=b,this.canvas.width=a,this.canvas.height=b,this.restoreGraphics(),this},background:function(a){return this.beginFill(a),this.context.fillRect(0,0,this.stageWidth,this.stageHeight),this.endFill(),this},stage:function(a,b,c){return this.size(a,b).background(c),this},beginFill:function(a){return this.saveGraphics(),this.context.fillStyle=a,this},endFill:function(){return this.restoreGraphics(),this},lineStyle:function(a,b,c,d,e){return this.saveGraphics({strokeStyle:a||this.data.strokeStyle,lineWidth:b||this.data.lineWidth,lineCap:c||this.data.lineCap,lineJoin:d||this.data.lineJoin,miterLimit:e||this.data.miterLimit}).restoreGraphics()},moveTo:function(a,b){return this.context.moveTo(a,b),this},lineTo:function(a,b){return this.context.lineTo(a,b),this},line:function(a,b,c,d){return this.context.moveTo(a,b),this.lineTo(c,d),this},curveTo:function(a,b,c,d){return this.context.quadraticCurveTo(c,d,a,b),this},curve:function(a,b,c,d,e,f){return this.context.moveTo(a,b),this.curveTo(c,d,e,f),this},stroke:function(){return this.context.stroke(),this},strokeRect:function(a,b,c,d){return this.context.beginPath(),this.context.strokeRect(a,b,c,d),this.context.closePath(),this},fillRect:function(a,b,c,d){return this.context.beginPath(),this.context.fillRect(a,b,c,d),this.context.closePath(),this},strokeCircle:function(a,b,c){return this.context.beginPath(),this.context.arc(a,b,c,0,2*Math.PI,!1),this.context.stroke(),this.context.closePath(),this},fillCircle:function(a,b,c){return this.context.beginPath(),this.context.arc(a,b,c,0,2*Math.PI,!1),this.context.fill(),this.context.closePath(),this},radialCircle:function(a,b,c,d,e){var f=this.context.createRadialGradient(a,b,c,a,b,d||5);e&&"array"===e.constructor.name||(e=[this.context.fillStyle,"white"]);for(var g=0;g1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function g(a){return a.touches?!1:void m(a)}function h(a){return a.touches?!1:void n(a)}function i(a){return a.touches?!1:void o(a)}function j(a){p(a,m),a.preventDefault()}function k(a){p(a,n),a.preventDefault()}function l(a){p(a,o),a.preventDefault()}function m(a){if(Event.isRightClick(a))return!1;var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive){d.sketch.isDrawing=!0;var h=e(a);g.graphics.firstPointSize>0&&d.sketch.beginFill(g.graphics.fillStyle).fillCircle(h.x,h.y,g.graphics.firstPointSize).endFill();var i=d.coords[b];i||(i=[]),i.length>0&&d.strokes.push(i),d.coords[b]=[],f(b,d,h),"function"==typeof g.events.mousedown&&g.events.mousedown(c,d,a)}}function n(a){var b=a.identifier||0;if(elem=a.target,data=dataBind(elem)[q],options=data.options,options.interactive&&(options.mouseupMovements&&0!==data.strokes.length||data.sketch.isDrawing)){var c=e(a),d=data.coords[b],g=d[d.length-1];if(g){var h=data.sketch.beginPath();data.sketch.isDrawing?h.lineStyle(options.graphics.strokeStyle,options.graphics.lineWidth):options.mouseupMovements.visible!==!1&&h.lineStyle(options.mouseupMovements.strokeStyle||"#DDD",options.mouseupMovements.lineWidth||1),h.line(g[0],g[1],c.x,c.y).stroke().closePath()}f(b,data,c),"function"==typeof options.events.mousemove&&options.events.mousemove(elem,data,a)}}function o(a){var b=a.identifier||0;elem=a.target,data=dataBind(elem)[q],options=data.options,options.interactive&&(data.sketch.isDrawing=!1,data.strokes.push(data.coords[b]),data.coords[b]=[],"function"==typeof options.events.mouseup&&options.events.mouseup(elem,data,a))}function p(a,b){var c=a.target,d=dataBind(c)[q],e=d.options;if(e.multitouch)for(var f=a.changedTouches,g=0;g0&&(e--,this.restore()),this},this.redo=function(){return e0?d[e].strokes=c.strokes.slice():(d.push({image:a.toDataURL(),strokes:c.strokes.slice()}),e++)}),this},this.state=function(){return JSON.parse(JSON.stringify(d[e]))},this.restore=function(a){a||(a=d[e]);var c=new Image;c.src=a.image,c.onload=function(){b(this,a.strokes)}},this.init=function(){return Event.remove(document,"keypress",c),Event.add(document,"keypress",c),this.save()},this.destroy=function(){return Event.remove(document,"keypress",c),this.reset()}}var c="sketchable";Sketchable.prototype.plugins.memento=function(a){function d(b){if(!e.options["_bound$"+b])if(e.options["_bound$"+b]=!0,e.options.events&&"function"==typeof e.options.events[b]){var c=e.options.events[b];e.options.events[b]=function(){c.apply(a,arguments),f[b].apply(a,arguments)}}else e.options.events[b]=f[b]}for(var e=a.config(),f={clear:function(a,b){b.memento.reset()},mouseup:function(a,b,c){b.memento.save(c)},destroy:function(a,b){b.memento.destroy()}},g="mouseup clear destroy".split(" "),h=0;h1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function g(a){return a.touches?!1:void m(a)}function h(a){return a.touches?!1:void n(a)}function i(a){return a.touches?!1:void o(a)}function j(a){p(a,m),a.preventDefault()}function k(a){p(a,n),a.preventDefault()}function l(a){p(a,o),a.preventDefault()}function m(a){if(Event.isRightClick(a))return!1;var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive){var h=e(a);"function"==typeof g.events.mousedownBefore&&g.events.mousedownBefore(c,d,a),g.graphics.firstPointSize>0&&d.sketch.beginFill(g.graphics.fillStyle).fillCircle(h.x,h.y,g.graphics.firstPointSize).endFill(),d.sketch.isDrawing=!0,d.sketch.beginPath();var i=d.coords[b];i||(i=[]),i.length>0&&d.strokes.push(i),d.coords[b]=[],f(b,d,h),"function"==typeof g.events.mousedown&&g.events.mousedown(c,d,a)}}function n(a){var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive&&(g.mouseupMovements&&0!==d.strokes.length||d.sketch.isDrawing)){var h=e(a);"function"==typeof g.events.mousemoveBefore&&g.events.mousemoveBefore(c,d,a);var i=d.coords[b],j=i[i.length-1];if(j){var k=d.sketch;d.sketch.isDrawing?k.lineStyle(g.graphics.strokeStyle,g.graphics.lineWidth):g.mouseupMovements.visible!==!1&&k.lineStyle(g.mouseupMovements.strokeStyle||"#DDD",g.mouseupMovements.lineWidth||1),k.line(j[0],j[1],h.x,h.y).stroke()}f(b,d,h),"function"==typeof g.events.mousemove&&g.events.mousemove(c,d,a)}}function o(a){var b=a.identifier||0,c=a.target,d=dataBind(c)[q],e=d.options;e.interactive&&("function"==typeof e.events.mouseupBefore&&e.events.mouseupBefore(c,d,a),d.sketch.isDrawing=!1,d.sketch.closePath(),d.strokes.push(d.coords[b]),d.coords[b]=[],"function"==typeof e.events.mouseup&&e.events.mouseup(c,d,a))}function p(a,b){var c=a.target,d=dataBind(c)[q],e=d.options;if(e.multitouch)for(var f=a.changedTouches,g=0;g0&&(e--,this.restore()),this},this.redo=function(){return e0?d[e].strokes=c.strokes.slice():(d.push({image:a.toDataURL(),strokes:c.strokes.slice()}),e++)}),this},this.state=function(){return JSON.parse(JSON.stringify(d[e]))},this.restore=function(a){a||(a=d[e]);var c=new Image;c.src=a.image,c.onload=function(){b(this,a.strokes)}},this.init=function(){return Event.remove(document,"keypress",c),Event.add(document,"keypress",c),this.save()},this.destroy=function(){return Event.remove(document,"keypress",c),this.reset()}}var c="sketchable";Sketchable.prototype.plugins.memento=function(a){function d(b){if(!e.options["_bound$"+b])if(e.options["_bound$"+b]=!0,e.options.events&&"function"==typeof e.options.events[b]){var c=e.options.events[b];e.options.events[b]=function(){c.apply(a,arguments),f[b].apply(a,arguments)}}else e.options.events[b]=f[b]}for(var e=a.config(),f={clear:function(a,b){b.memento.reset()},mouseup:function(a,b,c){b.memento.save(c)},destroy:function(a,b){b.memento.destroy()}},g="mouseup clear destroy".split(" "),h=0;h1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function g(a){return a.touches?!1:void m(a)}function h(a){return a.touches?!1:void n(a)}function i(a){return a.touches?!1:void o(a)}function j(a){p(a,m),a.preventDefault()}function k(a){p(a,n),a.preventDefault()}function l(a){p(a,o),a.preventDefault()}function m(a){if(Event.isRightClick(a))return!1;var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive){d.sketch.isDrawing=!0;var h=e(a);g.graphics.firstPointSize>0&&d.sketch.beginFill(g.graphics.fillStyle).fillCircle(h.x,h.y,g.graphics.firstPointSize).endFill();var i=d.coords[b];i||(i=[]),i.length>0&&d.strokes.push(i),d.coords[b]=[],f(b,d,h),"function"==typeof g.events.mousedown&&g.events.mousedown(c,d,a)}}function n(a){var b=a.identifier||0;if(elem=a.target,data=dataBind(elem)[q],options=data.options,options.interactive&&(options.mouseupMovements&&0!==data.strokes.length||data.sketch.isDrawing)){var c=e(a),d=data.coords[b],g=d[d.length-1];if(g){var h=data.sketch.beginPath();data.sketch.isDrawing?h.lineStyle(options.graphics.strokeStyle,options.graphics.lineWidth):options.mouseupMovements.visible!==!1&&h.lineStyle(options.mouseupMovements.strokeStyle||"#DDD",options.mouseupMovements.lineWidth||1),h.line(g[0],g[1],c.x,c.y).stroke().closePath()}f(b,data,c),"function"==typeof options.events.mousemove&&options.events.mousemove(elem,data,a)}}function o(a){var b=a.identifier||0;elem=a.target,data=dataBind(elem)[q],options=data.options,options.interactive&&(data.sketch.isDrawing=!1,data.strokes.push(data.coords[b]),data.coords[b]=[],"function"==typeof options.events.mouseup&&options.events.mouseup(elem,data,a))}function p(a,b){var c=a.target,d=dataBind(c)[q],e=d.options;if(e.multitouch)for(var f=a.changedTouches,g=0;g1){var f=d.length-1,g=d[f],h=d[f-1];g[0]==h[0]&&g[1]==h[1]&&d.splice(f,1)}}function g(a){return a.touches?!1:void m(a)}function h(a){return a.touches?!1:void n(a)}function i(a){return a.touches?!1:void o(a)}function j(a){p(a,m),a.preventDefault()}function k(a){p(a,n),a.preventDefault()}function l(a){p(a,o),a.preventDefault()}function m(a){if(Event.isRightClick(a))return!1;var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive){var h=e(a);"function"==typeof g.events.mousedownBefore&&g.events.mousedownBefore(c,d,a),g.graphics.firstPointSize>0&&d.sketch.beginFill(g.graphics.fillStyle).fillCircle(h.x,h.y,g.graphics.firstPointSize).endFill(),d.sketch.isDrawing=!0,d.sketch.beginPath();var i=d.coords[b];i||(i=[]),i.length>0&&d.strokes.push(i),d.coords[b]=[],f(b,d,h),"function"==typeof g.events.mousedown&&g.events.mousedown(c,d,a)}}function n(a){var b=a.identifier||0,c=a.target,d=dataBind(c)[q],g=d.options;if(g.interactive&&(g.mouseupMovements&&0!==d.strokes.length||d.sketch.isDrawing)){var h=e(a);"function"==typeof g.events.mousemoveBefore&&g.events.mousemoveBefore(c,d,a);var i=d.coords[b],j=i[i.length-1];if(j){var k=d.sketch;d.sketch.isDrawing?k.lineStyle(g.graphics.strokeStyle,g.graphics.lineWidth):g.mouseupMovements.visible!==!1&&k.lineStyle(g.mouseupMovements.strokeStyle||"#DDD",g.mouseupMovements.lineWidth||1),k.line(j[0],j[1],h.x,h.y).stroke()}f(b,d,h),"function"==typeof g.events.mousemove&&g.events.mousemove(c,d,a)}}function o(a){var b=a.identifier||0,c=a.target,d=dataBind(c)[q],e=d.options;e.interactive&&("function"==typeof e.events.mouseupBefore&&e.events.mouseupBefore(c,d,a),d.sketch.isDrawing=!1,d.sketch.closePath(),d.strokes.push(d.coords[b]),d.coords[b]=[],"function"==typeof e.events.mouseup&&e.events.mouseup(c,d,a))}function p(a,b){var c=a.target,d=dataBind(c)[q],e=d.options;if(e.multitouch)for(var f=a.changedTouches,g=0;gjQuery Sketchable instance. * This is a jQuery wrapper for the jSketch drawing class. * @namespace $.fn.sketchable - * @param {String|Object} method - Method to invoke, or a configuration object. + * @param {String|Object} method Method to invoke, or a configuration object. * @return jQuery * @version 2.1 * @author Luis A. Leiva @@ -347,8 +343,8 @@ fillStyle: '#F0F', lineCap: 'round', lineJoin: 'round', - miterLimit: 10 - } + miterLimit: 10, + }, }; /** @@ -361,7 +357,9 @@ elem[0].style.cursor = options.interactive ? 'pointer' : 'not-allowed'; } // Fix unwanted highlight "bug". Note: `this` is the actual DOM element. - this.onselectstart = function() { return false }; + this.onselectstart = function() { + return false; + }; }; /** @@ -383,8 +381,8 @@ var elem = $(e.target), pos = elem.offset(); return { x: Math.round(e.pageX - pos.left), - y: Math.round(e.pageY - pos.top) - } + y: Math.round(e.pageY - pos.top), + }; }; /** @@ -402,7 +400,7 @@ time -= data.timestamp; } - coords.push([ pt.x, pt.y, time, +data.sketch.isDrawing ]); + coords.push([pt.x, pt.y, time, +data.sketch.isDrawing]); // Check if consecutive points should be removed. if (data.options.filterCoords && coords.length > 1) { @@ -471,9 +469,9 @@ if (e.which === 3) return false; var idx = e.identifier || 0, - elem = $(e.target), - data = elem.data(namespace), - options = data.options; + elem = $(e.target), + data = elem.data(namespace), + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; @@ -484,7 +482,10 @@ // Mark visually 1st point of stroke. if (options.graphics.firstPointSize > 0) { - data.sketch.beginFill(options.graphics.fillStyle).fillCircle(p.x, p.y, options.graphics.firstPointSize).endFill(); + data.sketch + .beginFill(options.graphics.fillStyle) + .fillCircle(p.x, p.y, options.graphics.firstPointSize) + .endFill(); } data.sketch.isDrawing = true; @@ -500,9 +501,8 @@ saveMousePos(idx, data, p); - if (typeof options.events.mousedown === 'function') { + if (typeof options.events.mousedown === 'function') options.events.mousedown(elem, data, e); - } }; /** @@ -510,9 +510,9 @@ */ function moveHandler(e) { var idx = e.identifier || 0, - elem = $(e.target), - data = elem.data(namespace), - options = data.options; + elem = $(e.target), + data = elem.data(namespace), + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; // Grab penup strokes AFTER drawing something on the canvas for the first time. @@ -539,9 +539,8 @@ saveMousePos(idx, data, p); - if (typeof options.events.mousemove === 'function') { + if (typeof options.events.mousemove === 'function') options.events.mousemove(elem, data, e); - } }; /** @@ -549,9 +548,9 @@ */ function upHandler(e) { var idx = e.identifier || 0, - elem = $(e.target), - data = elem.data(namespace), - options = data.options; + elem = $(e.target), + data = elem.data(namespace), + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; @@ -564,9 +563,8 @@ data.strokes.push(data.coords[idx]); data.coords[idx] = []; - if (typeof options.events.mouseup === 'function') { + if (typeof options.events.mouseup === 'function') options.events.mouseup(elem, data, e); - } }; /** diff --git a/jquery.sketchable.memento.js b/jquery.sketchable.memento.js index 5360b82..c21cb06 100644 --- a/jquery.sketchable.memento.js +++ b/jquery.sketchable.memento.js @@ -14,6 +14,7 @@ * and is part of the {@link $.fn.sketchable.plugins.memento} plugin. * @class * @version 2.1 + * @param {Sketchable} $instance jQuery Sketchable element. * @example * var sketcher = $('canvas').sketchable(); * // This is internally done by the plugin, plus some checks: @@ -38,7 +39,7 @@ // Note: jSketch.drawImage after clear creates some flickering, // so use the native HTMLCanvasElement.drawImage method instead. data.sketch.clear(); - data.sketch.context.drawImage(snapshot, 0,0); + data.sketch.context.drawImage(snapshot, 0, 0); // Update strokes. data.strokes = strokes.slice(); }); @@ -54,15 +55,15 @@ function keyManager(e) { if (e.ctrlKey) { switch (e.which) { - case 26: // Z - if (e.shiftKey) self.redo(); - else self.undo(); - break; - case 25: // Y - self.redo(); - break; - default: - break; + case 26: // Z + if (e.shiftKey) self.redo(); + else self.undo(); + break; + case 25: // Y + self.redo(); + break; + default: + break; } } } @@ -110,7 +111,7 @@ if (evt && evt.identifier > 0) { stack[stpos].strokes = data.strokes.slice(); } else { - stack.push({ image: elem[0].toDataURL(), strokes: data.strokes.slice() }); + stack.push({image: elem[0].toDataURL(), strokes: data.strokes.slice()}); stpos++; } }); @@ -177,7 +178,7 @@ }, destroy: function(elem, data) { data.memento.destroy(); - } + }, }; // A helper function to override user-defined event listeners. @@ -193,7 +194,7 @@ // Exec original function first, then exec our callback. fn.apply($instance, arguments); callbacks[evName].apply($instance, arguments); - } + }; } else { // User has not defined this event, so attach our callback. config.options.events[evName] = callbacks[evName]; @@ -263,8 +264,8 @@ restore: function(state) { var data = $(this).data(namespace); return data.memento.restore(state); - } - } + }, + }, }); // Initialize plugin here. diff --git a/jsketch.js b/jsketch.js index 0bd365b..7fe8078 100644 --- a/jsketch.js +++ b/jsketch.js @@ -22,406 +22,406 @@ * brush.setContext(canvas2).beginFill('#5F7').fillCircle(30,30,8).endFill(); */ ;(function(window) { + /** + * @constructor + * @param {Object|Strig} elem DOM element or selector. + * @param {Object} [options] Configuration (default: {@link Sketchable#defaults}). + */ + function jSketch(elem, options) { + if (!elem) throw new Error('Sketchable requires a DOM element.'); + if (typeof elem === 'string') elem = document.querySelector(elem); + // Set drawing context first. + this.setContext(elem); + // Scene defaults. + this.stageWidth = elem.width; + this.stageHeight = elem.height; + // Make room for storing some data such as line type, colors, etc. + this.data = options; + // Set drawing defaults. + // All methods are chainable. + return this.setDefaults(); + }; + /** + * jSketch methods (publicly extensible). + * @ignore + * @memberof jSketch + * @see jSketch + */ + jSketch.prototype = { /** - * @constructor - * @param {Object|Strig} elem DOM element or selector. - * @param {Object} [options] Configuration (default: {@link Sketchable#defaults}). + * Allows to change the drawing context at runtime. + * @param {Object} elem DOM element. + * @return jSketch + * @memberof jSketch */ - function jSketch(elem, options) { - if (!elem) throw new Error('Sketchable requires a DOM element.'); - if (typeof elem === 'string') elem = document.querySelector(elem); - // Set drawing context first. - this.setContext(elem); - // Scene defaults. - this.stageWidth = elem.width; - this.stageHeight = elem.height; - // Make room for storing some data such as line type, colors, etc. - this.data = options; - // Set drawing defaults. - // All methods are chainable. - return this.setDefaults(); - }; - /** - * jSketch methods (publicly extensible). - * @ignore - * @memberof jSketch - * @see jSketch - */ - jSketch.prototype = { - /** - * Allows to change the drawing context at runtime. - * @param {Object} elem DOM element. - * @return jSketch - * @memberof jSketch - */ - setContext: function(elem) { - if (!elem) throw new Error('No canvas element specified.'); - // Save shortcuts: canvas (DOM elem) & graphics (2D canvas context). - this.canvas = elem; - this.context = elem.getContext('2d'); - // Always allow chainability. - return this; - }, - /** - * Sets drawing defaults: - * - fillStyle: Fill style color ('#F00'). - * - strokeStyle: Stroke style color ('#F0F'). - * - lineWidth: Line width (2). - * - lineCap: Line cap ('round'). - * - lineJoin: Line join ('round'). - * - miterLimit: Line miter (10). Works only if the lineJoin attribute is "miter". - * @return jSketch - * @memberof jSketch - */ - setDefaults: function() { - return this.saveGraphics({ - fillStyle: this.data.fillStyle || '#F00', - strokeStyle: this.data.strokeStyle || '#F0F', - lineWidth: this.data.lineWidth || 2, - lineCap: this.data.lineCap || 'round', - lineJoin: this.data.lineJoin || 'round', - miterLimit: this.data.miterLimit || 10 - }).restoreGraphics(); - }, - /** - * Sets the dimensions of canvas. - * @param {Number} width New canvas width. - * @param {Number} height New canvas width. - * @return jSketch - * @memberof jSketch - */ - size: function(width, height) { - this.stageWidth = width; - this.stageHeight = height; - this.canvas.width = width; - this.canvas.height = height; - // On resizing we lose drawing options, so restore them. - this.restoreGraphics(); - return this; - }, - /** - * Sets the background color of canvas. - * @param {String} color An HTML color. - * @return jSketch - * @memberof jSketch - */ - background: function(color) { - this.beginFill(color); - this.context.fillRect(0,0, this.stageWidth,this.stageHeight); - this.endFill(); - return this; - }, - /** - * Shortcut for setting the size + background color. - * @param {Number} width New canvas width. - * @param {Number} height New canvas width. - * @param {String} bgcolor An HTML color. - * @return jSketch - * @memberof jSketch - */ - stage: function(width, height, bgcolor) { - this.size(width,height).background(bgcolor); - return this; - }, - /** - * Sets the fill color. - * @param {String} color An HTML color. - * @return jSketch - * @memberof jSketch - */ - beginFill: function(color) { - this.saveGraphics(); - this.context.fillStyle = color; - return this; - }, - /** - * Recovers the fill color that was set before beginFill(). - * @return jSketch - * @memberof jSketch - */ - endFill: function() { - this.restoreGraphics(); - return this; - }, - /** - * Sets the line style. - * @param {String} color An HTML color. - * @param {Number} thickness Line thickness. - * @param {String} capStyle Style of line cap. - * @param {String} joinStyle Style of line join. - * @param {String} miter Style of line miter. Only works if capStyle is "miter". - * @return jSketch - * @memberof jSketch - */ - lineStyle: function(color, thickness, capStyle, joinStyle, miter) { - return this.saveGraphics({ - strokeStyle: color || this.data.strokeStyle, - lineWidth: thickness || this.data.lineWidth, - lineCap: capStyle || this.data.lineCap, - lineJoin: joinStyle || this.data.lineJoin, - miterLimit: miter || this.data.miterLimit - }).restoreGraphics(); - }, - /** - * Move brush to a coordinate in canvas. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @return jSketch - * @memberof jSketch - */ - moveTo: function(x, y) { - this.context.moveTo(x,y); - return this; - }, - /** - * Draws line to given coordinate. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @return jSketch - * @memberof jSketch - */ - lineTo: function(x, y) { - this.context.lineTo(x,y); - return this; - }, - /** - * Draws line from point 1 to point 2. - * @param {Number} x1 Horizontal coordinate of point 1. - * @param {Number} y1 Vertical coordinate of point 1. - * @param {Number} x2 Horizontal coordinate of point 2. - * @param {Number} y2 Vertical coordinate of point 2. - * @return jSketch - * @memberof jSketch - */ - line: function(x1,y1, x2,y2) { - this.context.moveTo(x1,y1); - this.lineTo(x2,y2); - return this; - }, - /** - * Draws curve to given coordinate. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @param {Number} cpx Horizontal coordinate of control point. - * @param {Number} cpy Vertical coordinate of control point. - * @return jSketch - * @memberof jSketch - */ - curveTo: function(x,y, cpx,cpy) { - this.context.quadraticCurveTo(cpx,cpy, x,y); - return this; - }, - /** - * Draws curve from coordinate 1 to coordinate 2. - * @param {Number} x1 Horizontal coordinate of point 1. - * @param {Number} y1 Vertical coordinate of point 1. - * @param {Number} x2 Horizontal coordinate of point 2. - * @param {Number} y2 Vertical coordinate of point 2. - * @param {Number} cpx Horizontal coordinate of control point. - * @param {Number} cpy Vertical coordinate of control point. - * @return jSketch - * @memberof jSketch - */ - curve: function(x1,y1, x2,y2, cpx,cpy) { - this.context.moveTo(x1,y1); - this.curveTo(x2,y2, cpx,cpy); - return this; - }, - /** - * Strokes a given path. - * @return jSketch - * @memberof jSketch - */ - stroke: function() { - this.context.stroke(); - return this; - }, - /** - * Draws a stroke-only rectangle. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @param {Number} width Rectangle width. - * @param {Number} height Rectangle height. - * @return jSketch - * @memberof jSketch - */ - strokeRect: function(x,y, width,height) { - this.context.beginPath(); - this.context.strokeRect(x,y, width,height); - this.context.closePath(); - return this; - }, - /** - * Draws a filled rectangle. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @param {Number} width Rectangle width. - * @param {Number} height Rectangle height. - * @return jSketch - * @memberof jSketch - */ - fillRect: function(x,y, width,height) { - this.context.beginPath(); - this.context.fillRect(x,y, width,height); - this.context.closePath(); - return this; - }, - /** - * Draws a stroke-only circle. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @param {Number} radius Circle radius. - * @return jSketch - * @memberof jSketch - */ - strokeCircle: function(x,y, radius) { - this.context.beginPath(); - this.context.arc(x,y, radius, 0, 2*Math.PI, false); - this.context.stroke(); - this.context.closePath(); - return this; - }, - /** - * Draws a filled circle. - * @param {Number} x Horizontal coordinate. - * @param {Number} y Vertical coordinate. - * @param {Number} radius Circle radius. - * @return jSketch - * @memberof jSketch - */ - fillCircle: function(x,y, radius) { - this.context.beginPath(); - this.context.arc(x,y, radius, 0, 2*Math.PI, false); - this.context.fill(); - this.context.closePath(); - return this; - }, - /** - * Experimental. - * @ignore - */ - radialCircle: function(x,y, radius, glowSize, colors) { - var g = this.context.createRadialGradient(x,y, radius, x,y, glowSize || 5); - if (!colors || colors.constructor.name !== 'array') { - colors = [this.context.fillStyle, 'white']; - } - for (var s = 0; s < colors.length; s++) { - var color = colors[s]; - g.addColorStop(s, color); - } - this.beginFill(g).fillCircle(x,y, radius).endFill(); - return this; - }, - /** - * A path is started. - * @return jSketch - * @memberof jSketch - */ - beginPath: function() { - this.saveGraphics(); - this.context.beginPath(); - return this; - }, - /** - * A path is finished. - * @return jSketch - * @memberof jSketch - */ - closePath: function() { - this.context.closePath(); - this.restoreGraphics(); - return this; - }, - /** - * Sets brush to eraser mode. - * @return jSketch - * @memberof jSketch - */ - eraser: function() { - this.context.globalCompositeOperation = 'destination-out'; - return this; - }, - /** - * Sets brush to pencil mode. - * @return jSketch - * @memberof jSketch - */ - pencil: function() { - this.context.globalCompositeOperation = 'source-over'; - return this; - }, - /** - * Clears stage. - * @return jSketch - * @memberof jSketch - */ - clear: function() { - // Note: using 'this.canvas.width = this.canvas.width' resets _all_ styles, so better use clearRect. - this.context.clearRect(0,0, this.stageWidth,this.stageHeight); - return this; - }, - /** - * Saves a snapshot of all styles and transformations. - * @return jSketch - * @memberof jSketch - */ - save: function() { - this.context.save(); - return this; - }, - /** - * Restores previous drawing state. - * @return jSketch - * @memberof jSketch - */ - restore: function() { - this.context.restore(); - return this; - }, - /** - * Saves given drawing settings. - * @param {Object} [options] Graphics options. - * @return jSketch - * @memberof jSketch - */ - saveGraphics: function(options) { - for (var opt in options) { - this.data[opt] = options[opt]; - } - return this; - }, - /** - * Restores given drawing settings. - * @return jSketch - * @memberof jSketch - */ - restoreGraphics: function() { - for (var opt in this.data) { - this.context[opt] = this.data[opt]; - } - return this; - }, - /** - * Draws an image. - * @param {String} src Image source path. - * @param {Number} [x] Horizontal coordinate. - * @param {Number} [y] Vertical coordinate. - * @return jSketch - * @memberof jSketch - */ - drawImage: function(src, x,y) { - if (typeof x === 'undefined') x = 0; - if (typeof y === 'undefined') y = 0; - var self = this, img = new Image(); - img.src = src; - img.onload = function() { - self.context.drawImage(img, x,y); - } - return this; + setContext: function(elem) { + if (!elem) throw new Error('No canvas element specified.'); + // Save shortcuts: canvas (DOM elem) & graphics (2D canvas context). + this.canvas = elem; + this.context = elem.getContext('2d'); + // Always allow chainability. + return this; + }, + /** + * Sets drawing defaults: + * - fillStyle: Fill style color ('#F00'). + * - strokeStyle: Stroke style color ('#F0F'). + * - lineWidth: Line width (2). + * - lineCap: Line cap ('round'). + * - lineJoin: Line join ('round'). + * - miterLimit: Line miter (10). Works only if the lineJoin attribute is "miter". + * @return jSketch + * @memberof jSketch + */ + setDefaults: function() { + return this.saveGraphics({ + fillStyle: this.data.fillStyle || '#F00', + strokeStyle: this.data.strokeStyle || '#F0F', + lineWidth: this.data.lineWidth || 2, + lineCap: this.data.lineCap || 'round', + lineJoin: this.data.lineJoin || 'round', + miterLimit: this.data.miterLimit || 10, + }).restoreGraphics(); + }, + /** + * Sets the dimensions of canvas. + * @param {Number} width New canvas width. + * @param {Number} height New canvas width. + * @return jSketch + * @memberof jSketch + */ + size: function(width, height) { + this.stageWidth = width; + this.stageHeight = height; + this.canvas.width = width; + this.canvas.height = height; + // On resizing we lose drawing options, so restore them. + this.restoreGraphics(); + return this; + }, + /** + * Sets the background color of canvas. + * @param {String} color An HTML color. + * @return jSketch + * @memberof jSketch + */ + background: function(color) { + this.beginFill(color); + this.context.fillRect(0, 0, this.stageWidth, this.stageHeight); + this.endFill(); + return this; + }, + /** + * Shortcut for setting the size + background color. + * @param {Number} width New canvas width. + * @param {Number} height New canvas width. + * @param {String} bgcolor An HTML color. + * @return jSketch + * @memberof jSketch + */ + stage: function(width, height, bgcolor) { + this.size(width, height).background(bgcolor); + return this; + }, + /** + * Sets the fill color. + * @param {String} color An HTML color. + * @return jSketch + * @memberof jSketch + */ + beginFill: function(color) { + this.saveGraphics(); + this.context.fillStyle = color; + return this; + }, + /** + * Recovers the fill color that was set before beginFill(). + * @return jSketch + * @memberof jSketch + */ + endFill: function() { + this.restoreGraphics(); + return this; + }, + /** + * Sets the line style. + * @param {String} color An HTML color. + * @param {Number} thickness Line thickness. + * @param {String} capStyle Style of line cap. + * @param {String} joinStyle Style of line join. + * @param {String} miter Style of line miter. Only works if capStyle is "miter". + * @return jSketch + * @memberof jSketch + */ + lineStyle: function(color, thickness, capStyle, joinStyle, miter) { + return this.saveGraphics({ + strokeStyle: color || this.data.strokeStyle, + lineWidth: thickness || this.data.lineWidth, + lineCap: capStyle || this.data.lineCap, + lineJoin: joinStyle || this.data.lineJoin, + miterLimit: miter || this.data.miterLimit, + }).restoreGraphics(); + }, + /** + * Move brush to a coordinate in canvas. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @return jSketch + * @memberof jSketch + */ + moveTo: function(x, y) { + this.context.moveTo(x, y); + return this; + }, + /** + * Draws line to given coordinate. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @return jSketch + * @memberof jSketch + */ + lineTo: function(x, y) { + this.context.lineTo(x, y); + return this; + }, + /** + * Draws line from point 1 to point 2. + * @param {Number} x1 Horizontal coordinate of point 1. + * @param {Number} y1 Vertical coordinate of point 1. + * @param {Number} x2 Horizontal coordinate of point 2. + * @param {Number} y2 Vertical coordinate of point 2. + * @return jSketch + * @memberof jSketch + */ + line: function(x1, y1, x2, y2) { + this.context.moveTo(x1, y1); + this.lineTo(x2, y2); + return this; + }, + /** + * Draws curve to given coordinate. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @param {Number} cpx Horizontal coordinate of control point. + * @param {Number} cpy Vertical coordinate of control point. + * @return jSketch + * @memberof jSketch + */ + curveTo: function(x, y, cpx, cpy) { + this.context.quadraticCurveTo(cpx, cpy, x, y); + return this; + }, + /** + * Draws curve from coordinate 1 to coordinate 2. + * @param {Number} x1 Horizontal coordinate of point 1. + * @param {Number} y1 Vertical coordinate of point 1. + * @param {Number} x2 Horizontal coordinate of point 2. + * @param {Number} y2 Vertical coordinate of point 2. + * @param {Number} cpx Horizontal coordinate of control point. + * @param {Number} cpy Vertical coordinate of control point. + * @return jSketch + * @memberof jSketch + */ + curve: function(x1, y1, x2, y2, cpx, cpy) { + this.context.moveTo(x1, y1); + this.curveTo(x2, y2, cpx, cpy); + return this; + }, + /** + * Strokes a given path. + * @return jSketch + * @memberof jSketch + */ + stroke: function() { + this.context.stroke(); + return this; + }, + /** + * Draws a stroke-only rectangle. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @param {Number} width Rectangle width. + * @param {Number} height Rectangle height. + * @return jSketch + * @memberof jSketch + */ + strokeRect: function(x, y, width, height) { + this.context.beginPath(); + this.context.strokeRect(x, y, width, height); + this.context.closePath(); + return this; + }, + /** + * Draws a filled rectangle. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @param {Number} width Rectangle width. + * @param {Number} height Rectangle height. + * @return jSketch + * @memberof jSketch + */ + fillRect: function(x, y, width, height) { + this.context.beginPath(); + this.context.fillRect(x, y, width, height); + this.context.closePath(); + return this; + }, + /** + * Draws a stroke-only circle. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @param {Number} radius Circle radius. + * @return jSketch + * @memberof jSketch + */ + strokeCircle: function(x, y, radius) { + this.context.beginPath(); + this.context.arc(x, y, radius, 0, 2*Math.PI, false); + this.context.stroke(); + this.context.closePath(); + return this; + }, + /** + * Draws a filled circle. + * @param {Number} x Horizontal coordinate. + * @param {Number} y Vertical coordinate. + * @param {Number} radius Circle radius. + * @return jSketch + * @memberof jSketch + */ + fillCircle: function(x, y, radius) { + this.context.beginPath(); + this.context.arc(x, y, radius, 0, 2*Math.PI, false); + this.context.fill(); + this.context.closePath(); + return this; + }, + /** + * Experimental. + * @ignore + */ + radialCircle: function(x, y, radius, glowSize, colors) { + var g = this.context.createRadialGradient(x, y, radius, x, y, glowSize || 5); + if (!colors || colors.constructor.name !== 'array') { + colors = [this.context.fillStyle, 'white']; } - }; + for (var s = 0; s < colors.length; s++) { + var color = colors[s]; + g.addColorStop(s, color); + } + this.beginFill(g).fillCircle(x, y, radius).endFill(); + return this; + }, + /** + * A path is started. + * @return jSketch + * @memberof jSketch + */ + beginPath: function() { + this.saveGraphics(); + this.context.beginPath(); + return this; + }, + /** + * A path is finished. + * @return jSketch + * @memberof jSketch + */ + closePath: function() { + this.context.closePath(); + this.restoreGraphics(); + return this; + }, + /** + * Sets brush to eraser mode. + * @return jSketch + * @memberof jSketch + */ + eraser: function() { + this.context.globalCompositeOperation = 'destination-out'; + return this; + }, + /** + * Sets brush to pencil mode. + * @return jSketch + * @memberof jSketch + */ + pencil: function() { + this.context.globalCompositeOperation = 'source-over'; + return this; + }, + /** + * Clears stage. + * @return jSketch + * @memberof jSketch + */ + clear: function() { + // Note: using 'this.canvas.width = this.canvas.width' resets _all_ styles, so better use clearRect. + this.context.clearRect(0, 0, this.stageWidth, this.stageHeight); + return this; + }, + /** + * Saves a snapshot of all styles and transformations. + * @return jSketch + * @memberof jSketch + */ + save: function() { + this.context.save(); + return this; + }, + /** + * Restores previous drawing state. + * @return jSketch + * @memberof jSketch + */ + restore: function() { + this.context.restore(); + return this; + }, + /** + * Saves given drawing settings. + * @param {Object} [options] Graphics options. + * @return jSketch + * @memberof jSketch + */ + saveGraphics: function(options) { + for (var opt in options) { + this.data[opt] = options[opt]; + } + return this; + }, + /** + * Restores given drawing settings. + * @return jSketch + * @memberof jSketch + */ + restoreGraphics: function() { + for (var opt in this.data) { + this.context[opt] = this.data[opt]; + } + return this; + }, + /** + * Draws an image. + * @param {String} src Image source path. + * @param {Number} [x] Horizontal coordinate. + * @param {Number} [y] Vertical coordinate. + * @return jSketch + * @memberof jSketch + */ + drawImage: function(src, x, y) { + if (typeof x === 'undefined') x = 0; + if (typeof y === 'undefined') y = 0; + var self = this, img = new Image(); + img.src = src; + img.onload = function() { + self.context.drawImage(img, x, y); + }; + return this; + }, + }; - // Expose. - window.jSketch = jSketch; + // Expose. + window.jSketch = jSketch; })(this); diff --git a/package.json b/package.json index 4bf5859..c50c273 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dist": "grunt", + "lint": "eslint *sketchable*.js || echo [sudo] npm i -g eslint", "docs": "jsdoc --debug -c jsdoc.json && cp -rn figs/ docs/ || echo [sudo] npm i -g jsdoc" }, "repository": { @@ -21,6 +22,7 @@ "dependencies": { }, "devDependencies": { + "minami": "^1.2.3", "grunt": "^0.4.5", "grunt-contrib-concat": "^0.5.1", "grunt-contrib-clean": "0.6.0", diff --git a/sketchable.js b/sketchable.js index e0d7a16..5d79926 100644 --- a/sketchable.js +++ b/sketchable.js @@ -50,15 +50,15 @@ Sketchable.prototype = { /** * Initialize the selected CANVAS elements. - * @param {Object} [options] - Configuration (default: {@link Sketchable#defaults}). - * @return Sketchable + * @param {Object} [opts] - Configuration (default: {@link Sketchable#defaults}). + * @return {Sketchable} * @memberof Sketchable * @protected * @ignore */ - init: function(options) { + init: function(opts) { // Options will be available for all plugin methods. - var options = deepExtend({}, Sketchable.prototype.defaults, options || {}); + var options = deepExtend({}, Sketchable.prototype.defaults, opts || {}); var elem = this.elem, data = dataBind(elem)[namespace]; // Check if element is not initialized yet. if (!data) { @@ -73,7 +73,7 @@ postProcess(elem, options); } - var sketch = new jSketch(elem, options.graphics); + var sketch = new jSketch(elem, options.graphics); // eslint-disable-line new-cap // Reconfigure element data. dataBind(elem)[namespace] = data = { // All strokes will be stored here. @@ -89,34 +89,33 @@ // since we access the instance via `$('selector').sketchable('method')`. instance: this, // Save also a pointer to the given options. - options: options + options: options, }; // Trigger init event. - if (typeof options.events.init === 'function') { + if (typeof options.events.init === 'function') options.events.init(elem, data); - } + // Initialize plugins. - for (var name in this.plugins) { - this.plugins[name](this); - } + for (var name in this.plugins) this.plugins[name](this); // Make methods chainable. return this; }, /** * Change configuration of an existing Sketchable instance. - * @param {Object} [options] - Configuration (default: {@link Sketchable#defaults}). - * @return Sketchable + * @param {Object} [opts] - Configuration (default: {@link Sketchable#defaults}). + * @return {Sketchable} * @memberof Sketchable * @example * var sketcher = new Sketchable('canvas').config({ interactive: false }); * // Update later on: * sketcher.config({ interactive: true }); */ - config: function(options) { + config: function(opts) { var elem = this.elem, data = dataBind(elem)[namespace]; - if (options) { // setter - data.options = deepExtend({}, Sketchable.prototype.defaults, data.options, options); + + if (opts) { // setter + data.options = deepExtend({}, Sketchable.prototype.defaults, data.options, opts); postProcess(elem); return this; } else { // getter @@ -126,7 +125,7 @@ /** * Get/Set drawing data strokes sequence. * @param {Array} [arr] - Multidimensional array of [x,y,time,status] tuples; status = 0 (pen down) or 1 (pen up). - * @return Strokes object on get, Sketchable instance on set (with the new data attached). + * @return {Array|Sketchable} Strokes object on get, Sketchable instance on set (with the new data attached). * @memberof Sketchable * @example * // Getter: read associated strokes. @@ -135,20 +134,19 @@ * new Sketchable('canvas').strokes([ [arr1], ..., [arrN] ]); */ strokes: function(arr) { - var elem = this.elem; + var elem = this.elem, data = dataBind(elem)[namespace]; + if (arr) { // setter - var data = dataBind(elem)[namespace]; data.strokes = arr; return this; } else { // getter - var data = dataBind(elem)[namespace]; return data.strokes; } }, /** * Allows low-level manipulation of the sketchable canvas. * @param {Function} callback - Callback function, invoked with 2 arguments: elem (CANVAS element) and data (private element data). - * @return Sketchable + * @return {Sketchable} * @memberof Sketchable * @example * new Sketchable('canvas').handler(function(elem, data) { @@ -159,12 +157,13 @@ var elem = this.elem, data = dataBind(elem)[namespace]; callback(elem, data); + return this; }, /** * Clears canvas together with associated strokes data. * @see Sketchable.handler - * @return Sketchable + * @return {Sketchable} * @memberof Sketchable * @example * var sketcher = new Sketchable('canvas'); @@ -182,15 +181,15 @@ data.strokes = []; data.coords = {}; - if (typeof options.events.clear === 'function') { + if (typeof options.events.clear === 'function') options.events.clear(elem, data); - } + return this; }, /** * Reinitializes a sketchable canvas with given configuration options. - * @param {Object} [options] - Configuration (default: {@link Sketchable#defaults}). - * @return Sketchable + * @param {Object} [opts] - Configuration (default: {@link Sketchable#defaults}). + * @return {Sketchable} * @memberof Sketchable * @example * // Reset default state. @@ -198,19 +197,19 @@ * // Reset with custom configuration. * new Sketchable('canvas').reset({ interactive:false }); */ - reset: function(options) { + reset: function(opts) { var elem = this.elem, data = dataBind(elem)[namespace], options = data.options; - this.destroy().init(options); + this.destroy().init(opts); - if (typeof options.events.reset === 'function') { + if (typeof options.events.reset === 'function') options.events.reset(elem, data); - } + return this; }, /** * Destroys sketchable canvas, together with strokes data and associated events. - * @return Sketchable + * @return {Sketchable} * @memberof Sketchable * @example * // This will leave the canvas element intact. @@ -228,11 +227,11 @@ dataBind(elem)[namespace] = null; - if (typeof options.events.destroy === 'function') { + if (typeof options.events.destroy === 'function') options.events.destroy(elem, data); - } + return this; - } + }, }; @@ -333,12 +332,12 @@ fillStyle: '#F0F', lineCap: 'round', lineJoin: 'round', - miterLimit: 10 - } + miterLimit: 10, + }, }; /** - * @private + * @ignore */ function offset(el) { var box = el.getBoundingClientRect(); @@ -351,13 +350,13 @@ var top = box.top + scrollTop - clientTop; var left = box.left + scrollLeft - clientLeft; return { - top: Math.round(top), - left: Math.round(left) - } + top: Math.round(top), + left: Math.round(left), + }; }; /** - * @private + * @ignore */ function postProcess(elem, options) { if (!options) options = dataBind(elem)[namespace].options; @@ -366,22 +365,24 @@ elem.style.cursor = options.interactive ? 'pointer' : 'not-allowed'; } // Fix unwanted highlight "bug". - elem.onselectstart = function() { return false }; + elem.onselectstart = function() { + return false; + }; }; /** - * @private + * @ignore */ function getMousePos(e) { var elem = e.target, pos = offset(elem); return { x: Math.round(e.pageX - pos.left), - y: Math.round(e.pageY - pos.top) - } + y: Math.round(e.pageY - pos.top), + }; }; /** - * @private + * @ignore */ function saveMousePos(idx, data, pt) { // Current coords are already initialized. @@ -395,7 +396,7 @@ time -= data.timestamp; } - coords.push([ pt.x, pt.y, time, +data.sketch.isDrawing ]); + coords.push([pt.x, pt.y, time, +data.sketch.isDrawing]); // Check if consecutive points should be removed. if (data.options.filterCoords && coords.length > 1) { @@ -409,7 +410,7 @@ }; /** - * @private + * @ignore */ function mousedownHandler(e) { if (e.touches) return false; @@ -417,7 +418,7 @@ }; /** - * @private + * @ignore */ function mousemoveHandler(e) { if (e.touches) return false; @@ -425,7 +426,7 @@ }; /** - * @private + * @ignore */ function mouseupHandler(e) { if (e.touches) return false; @@ -433,7 +434,7 @@ }; /** - * @private + * @ignore */ function touchdownHandler(e) { execTouchEvent(e, downHandler); @@ -441,7 +442,7 @@ }; /** - * @private + * @ignore */ function touchmoveHandler(e) { execTouchEvent(e, moveHandler); @@ -449,7 +450,7 @@ }; /** - * @private + * @ignore */ function touchupHandler(e) { execTouchEvent(e, upHandler); @@ -457,16 +458,16 @@ }; /** - * @private + * @ignore */ function downHandler(e) { // Don't handle right clicks. if (Event.isRightClick(e)) return false; var idx = e.identifier || 0, - elem = e.target, - data = dataBind(elem)[namespace], - options = data.options; + elem = e.target, + data = dataBind(elem)[namespace], + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; @@ -477,7 +478,10 @@ // Mark visually 1st point of stroke. if (options.graphics.firstPointSize > 0) { - data.sketch.beginFill(options.graphics.fillStyle).fillCircle(p.x, p.y, options.graphics.firstPointSize).endFill(); + data.sketch + .beginFill(options.graphics.fillStyle) + .fillCircle(p.x, p.y, options.graphics.firstPointSize) + .endFill(); } data.sketch.isDrawing = true; @@ -493,19 +497,18 @@ saveMousePos(idx, data, p); - if (typeof options.events.mousedown === 'function') { + if (typeof options.events.mousedown === 'function') options.events.mousedown(elem, data, e); - } }; /** - * @private + * @ignore */ function moveHandler(e) { - var idx = e.identifier || 0 - elem = e.target, - data = dataBind(elem)[namespace], - options = data.options; + var idx = e.identifier || 0, + elem = e.target, + data = dataBind(elem)[namespace], + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; // Grab penup strokes AFTER drawing something on the canvas for the first time. @@ -532,19 +535,18 @@ saveMousePos(idx, data, p); - if (typeof options.events.mousemove === 'function') { + if (typeof options.events.mousemove === 'function') options.events.mousemove(elem, data, e); - } }; /** - * @private + * @ignore */ function upHandler(e) { - var idx = e.identifier || 0 - elem = e.target, - data = dataBind(elem)[namespace], - options = data.options; + var idx = e.identifier || 0, + elem = e.target, + data = dataBind(elem)[namespace], + options = data.options; // Exit early if interactivity is disabled. if (!options.interactive) return; @@ -557,13 +559,12 @@ data.strokes.push(data.coords[idx]); data.coords[idx] = []; - if (typeof options.events.mouseup === 'function') { + if (typeof options.events.mouseup === 'function') options.events.mouseup(elem, data, e); - } }; /** - * @private + * @ignore */ function execTouchEvent(e, callback) { var elem = e.target, data = dataBind(elem)[namespace], options = data.options; diff --git a/sketchable.memento.js b/sketchable.memento.js index 9fa8d96..f1a3205 100644 --- a/sketchable.memento.js +++ b/sketchable.memento.js @@ -16,6 +16,7 @@ * and is part of the {@link Sketchable.plugins.memento} plugin. * @class * @version 2.1 + * @param {Sketchable} instance Sketchable element. * @example * var sketcher = new Sketchable('canvas'); * // This is internally done by the plugin, plus some checks: @@ -40,7 +41,7 @@ // Note: jSketch.drawImage after clear creates some flickering, // so use the native HTMLCanvasElement.drawImage method instead. data.sketch.clear(); - data.sketch.context.drawImage(snapshot, 0,0); + data.sketch.context.drawImage(snapshot, 0, 0); // Update strokes. data.strokes = strokes.slice(); }); @@ -56,15 +57,15 @@ function keyManager(e) { if (e.ctrlKey) { switch (e.which) { - case 26: // Z - if (e.shiftKey) self.redo(); - else self.undo(); - break; - case 25: // Y - self.redo(); - break; - default: - break; + case 26: // Z + if (e.shiftKey) self.redo(); + else self.undo(); + break; + case 25: // Y + self.redo(); + break; + default: + break; } } } @@ -112,7 +113,7 @@ if (evt && evt.identifier > 0) { stack[stpos].strokes = data.strokes.slice(); } else { - stack.push({ image: elem.toDataURL(), strokes: data.strokes.slice() }); + stack.push({image: elem.toDataURL(), strokes: data.strokes.slice()}); stpos++; } }); @@ -163,7 +164,7 @@ /** * Memento plugin constructor for Sketchable instances. - * @param {Object} sketchable Sketchable instance. + * @param {Sketchable} instance Sketchable element. * @memberof Sketchable#plugins */ Sketchable.prototype.plugins.memento = function(instance) { @@ -179,7 +180,7 @@ }, destroy: function(elem, data) { data.memento.destroy(); - } + }, }; // A helper function to override user-defined event listeners. @@ -195,7 +196,7 @@ // Exec original function first, then exec our callback. fn.apply(instance, arguments); callbacks[evName].apply(instance, arguments); - } + }; } else { // User has not defined this event, so attach our callback. config.options.events[evName] = callbacks[evName]; @@ -265,8 +266,8 @@ restore: function(state) { var data = dataBind(instance.elem)[namespace]; return data.memento.restore(state); - } - } + }, + }, }); // Initialize plugin here. diff --git a/sketchable.utils.js b/sketchable.utils.js index 5f4fe3e..1063df4 100644 --- a/sketchable.utils.js +++ b/sketchable.utils.js @@ -1,8 +1,10 @@ +/* eslint-env browser */ + (function() { var cache = [0], expando = 'data' + Date.now(); function data(elem) { var cacheIndex = elem[expando], - nextCacheIndex = cache.length; + nextCacheIndex = cache.length; if (!cacheIndex) { cacheIndex = elem[expando] = nextCacheIndex; cache[cacheIndex] = {}; @@ -31,7 +33,7 @@ * @global * @module Event */ -var Event = { +window.Event = { /** * Add event to DOM element. * @memberof module:Event @@ -48,9 +50,11 @@ var Event = { if (elem.addEventListener) { // W3C standard elem.addEventListener(type, fn, false); } else if (elem.attachEvent) { // Old IE versions - elem.attachEvent("on"+type, fn); + elem.attachEvent('on'+type, fn); } else { // Really old browser - elem[type+fn] = function(){ fn(window.event); }; + elem[type+fn] = function() { + fn(window.event); + }; } }, /** @@ -68,7 +72,7 @@ var Event = { if (elem.removeEventListener) { // W3C standard elem.removeEventListener(type, fn, false); } else if (elem.detachEvent) { // Old IE versions - elem.detachEvent("on"+type, fn); + elem.detachEvent('on'+type, fn); } else { // Really old browser elem[type+fn] = null; } @@ -89,7 +93,7 @@ var Event = { if (ev.which) return ev.which === 3; else if (ev.button) return e.button === 2; return false; - } + }, }; @@ -109,7 +113,7 @@ var Event = { * // Now `ext` is `{ foo:1, bar: { a:false, b:false } }` * // and `one` is left intact. */ -var deepExtend = function(myObj) { +window.deepExtend = function(myObj) { myObj = myObj || {}; for (var i = 1; i < arguments.length; i++) { var obj = arguments[i];