From b26ea4c77e7d48467030aea8f5addc5d76fe814a Mon Sep 17 00:00:00 2001 From: Luis Leiva Date: Thu, 16 Nov 2017 13:25:44 +0100 Subject: [PATCH] Fixed undo/redo on multitouch events --- jquery.sketchable.memento.js | 45 ++++++++++++++++++------------------ sketchable.memento.js | 36 +++++++++++++++-------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/jquery.sketchable.memento.js b/jquery.sketchable.memento.js index 0038476..f41b28c 100644 --- a/jquery.sketchable.memento.js +++ b/jquery.sketchable.memento.js @@ -57,12 +57,14 @@ function restore(snapshot) { // Manipulate canvas via jQuery sketchable API. // This way, we don't lose default drawing settings et al. - $instance.sketchable('handler', function(elem, data){ + $instance.sketchable('handler', function(elem, data) { //data.sketch.clear().drawImage(snapshot.src); // Note: jSketch.drawImage after clear creates some flickering, // so use the native HTMLCanvasElement.drawImage method instead. data.sketch.clear(); data.sketch.graphics.drawImage(snapshot, 0,0); + // Update strokes. + data.strokes = stack[stpos].strokes.slice(); }); }; /** @@ -95,10 +97,6 @@ */ this.undo = function() { prev(); - $instance.sketchable('handler', function(elem, data) { - if (stack[stpos]) - data.strokes = stack[stpos].strokes.slice(); - }); return this; }; /** @@ -107,10 +105,6 @@ */ this.redo = function() { next(); - $instance.sketchable('handler', function(elem, data) { - if (stack[stpos]) - data.strokes = stack[stpos].strokes.slice(); - }); return this; }; /** @@ -124,13 +118,19 @@ }; /** * Save current state. + * @param {Object} evt DOM event. * @return {MementoCanvas} Class instance. */ - this.save = function() { - stpos++; - if (stpos < stack.length) stack.length = stpos; - $instance.sketchable('handler', function(elem, data) { - stack.push({ image: elem[0].toDataURL(), strokes: data.strokes.slice() }); + this.save = function(evt) { + instance.handler(function(elem, data) { + // With multitouch events, only the first event should be used to store a snapshot. + // Then, the subsequent multitouch events must update current strokes data. + if (evt && evt.identifier > 0) { + stack[stpos].strokes = data.strokes.slice(); + } else { + stack.push({ image: elem.toDataURL(), strokes: data.strokes.slice() }); + stpos++; + } }); return this; }; @@ -160,16 +160,15 @@ * @memberof $.fn.sketchable.plugins */ $.fn.sketchable.plugins.memento = function($instance) { + // Access the instance configuration. var config = $instance.sketchable('config'); var callbacks = { clear: function(elem, data) { - data.memento.reset(); + data.memento.reset().save(); }, mouseup: function(elem, data, evt) { - // Don't store multitouch events separately. - if (evt.type.indexOf('touch') === 0 && evt.identifier > 0) return; - data.memento.save(); + data.memento.save(evt); }, destroy: function(elem, data) { data.memento.destroy(); @@ -203,12 +202,12 @@ override(events[i]); } - // Expose public API: all sketchable instances will have these methods. + // Expose public API: all jQuery sketchable instances will have these methods. $.extend($.fn.sketchable.api, { /** * Goes back to the previous CANVAS state, if available. * @memberof $.fn.sketchable - * @example $('canvas').sketchable('undo'); + * @example jqueryElem.sketchable('undo'); */ undo: function() { var elem = $(this), data = elem.data(namespace); @@ -217,7 +216,7 @@ /** * Goes forward to the previous CANVAS state, if available. * @memberof $.fn.sketchable - * @example $('canvas').sketchable('redo'); + * @example jqueryElem.sketchable('redo'); */ redo: function() { var elem = $(this), data = elem.data(namespace); @@ -226,12 +225,12 @@ /** * Save a snapshot of the current CANVAS status. * @memberof $.fn.sketchable - * @example $('canvas').sketchable('save'); + * @example jqueryElem.sketchable('save'); */ save: function() { var elem = $(this), data = elem.data(namespace); data.memento.save(); - }, + } }); // Initialize plugin here. diff --git a/sketchable.memento.js b/sketchable.memento.js index e8063f2..288bc5d 100644 --- a/sketchable.memento.js +++ b/sketchable.memento.js @@ -60,12 +60,14 @@ function restore(snapshot) { // Manipulate canvas via jQuery sketchable API. // This way, we don't lose default drawing settings et al. - instance.handler(function(elem, data){ + instance.handler(function(elem, data) { //data.sketch.clear().drawImage(snapshot.src); // Note: jSketch.drawImage after clear creates some flickering, // so use the native HTMLCanvasElement.drawImage method instead. data.sketch.clear(); data.sketch.graphics.drawImage(snapshot, 0,0); + // Update strokes. + data.strokes = stack[stpos].strokes.slice(); }); }; /** @@ -98,10 +100,6 @@ */ this.undo = function() { prev(); - instance.handler(function(elem, data) { - if (stack[stpos]) - data.strokes = stack[stpos].strokes.slice(); - }); return this; }; /** @@ -110,10 +108,6 @@ */ this.redo = function() { next(); - instance.handler(function(elem, data) { - if (stack[stpos]) - data.strokes = stack[stpos].strokes.slice(); - }); return this; }; /** @@ -127,12 +121,19 @@ }; /** * Save current state. + * @param {Object} evt DOM event. + * @return {MementoCanvas} Class instance. */ - this.save = function() { - stpos++; - if (stpos < stack.length) stack.length = stpos; + this.save = function(evt) { instance.handler(function(elem, data) { - stack.push({ image: elem.toDataURL(), strokes: data.strokes.slice() }); + // With multitouch events, only the first event should be used to store a snapshot. + // Then, the subsequent multitouch events must update current strokes data. + if (evt && evt.identifier > 0) { + stack[stpos].strokes = data.strokes.slice(); + } else { + stack.push({ image: elem.toDataURL(), strokes: data.strokes.slice() }); + stpos++; + } }); return this; }; @@ -167,12 +168,10 @@ var callbacks = { clear: function(elem, data) { - data.memento.reset(); + data.memento.reset().save(); }, mouseup: function(elem, data, evt) { - // Don't store multitouch events separately. - if (evt.type.indexOf('touch') === 0 && evt.identifier > 0) return; - data.memento.save(); + data.memento.save(evt); }, destroy: function(elem, data) { data.memento.destroy(); @@ -211,6 +210,7 @@ /** * Goes back to the previous CANVAS state, if available. * @memberof Sketchable + * @example sketchableInstance.undo(); */ undo: function() { var elem = this.elem, data = dataBind(elem)[namespace]; @@ -219,6 +219,7 @@ /** * Goes forward to the previous CANVAS state, if available. * @memberof Sketchable + * @example sketchableInstance.redo(); */ redo: function() { var elem = this.elem, data = dataBind(elem)[namespace]; @@ -227,6 +228,7 @@ /** * Save a snapshot of the current CANVAS status. * @memberof Sketchable + * @example sketchableInstance.save(); */ save: function() { var elem = this.elem, data = dataBind(elem)[namespace];