mirror of https://github.com/luileito/jsketch.git
Added animate plugin
This commit is contained in:
parent
e66116d128
commit
58e6abea10
14
Gruntfile.js
14
Gruntfile.js
|
|
@ -11,6 +11,7 @@ module.exports = function(grunt) {
|
||||||
'sketchable.utils.js',
|
'sketchable.utils.js',
|
||||||
'sketchable.js',
|
'sketchable.js',
|
||||||
'sketchable.memento.js',
|
'sketchable.memento.js',
|
||||||
|
'sketchable.animate.js',
|
||||||
],
|
],
|
||||||
dest: 'dist/sketchable.full.js'
|
dest: 'dist/sketchable.full.js'
|
||||||
},
|
},
|
||||||
|
|
@ -19,6 +20,7 @@ module.exports = function(grunt) {
|
||||||
'jsketch.js',
|
'jsketch.js',
|
||||||
'jquery.sketchable.js',
|
'jquery.sketchable.js',
|
||||||
'jquery.sketchable.memento.js',
|
'jquery.sketchable.memento.js',
|
||||||
|
'jquery.sketchable.animate.js',
|
||||||
],
|
],
|
||||||
dest: 'dist/jquery.sketchable.full.js'
|
dest: 'dist/jquery.sketchable.full.js'
|
||||||
}
|
}
|
||||||
|
|
@ -40,6 +42,11 @@ module.exports = function(grunt) {
|
||||||
'dist/sketchable.memento.min.js': [ 'sketchable.memento.js' ]
|
'dist/sketchable.memento.min.js': [ 'sketchable.memento.js' ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
animate: {
|
||||||
|
files: {
|
||||||
|
'dist/sketchable.animate.min.js': [ 'sketchable.animate.js' ]
|
||||||
|
}
|
||||||
|
},
|
||||||
full: {
|
full: {
|
||||||
options: {
|
options: {
|
||||||
banner: '/*! <%= pkg.description %> (all in one) | v<%= pkg.version %> | <%= grunt.template.today("yyyy-mm-dd") %> */\n'
|
banner: '/*! <%= pkg.description %> (all in one) | v<%= pkg.version %> | <%= grunt.template.today("yyyy-mm-dd") %> */\n'
|
||||||
|
|
@ -58,6 +65,11 @@ module.exports = function(grunt) {
|
||||||
'dist/jquery.sketchable.memento.min.js': [ 'jquery.sketchable.memento.js' ]
|
'dist/jquery.sketchable.memento.min.js': [ 'jquery.sketchable.memento.js' ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
jqAnimate: {
|
||||||
|
files: {
|
||||||
|
'dist/jquery.sketchable.animate.min.js': [ 'jquery.sketchable.animate.js' ]
|
||||||
|
}
|
||||||
|
},
|
||||||
jqFull: {
|
jqFull: {
|
||||||
options: {
|
options: {
|
||||||
banner: '/*! <%= pkg.description %> (all in one) | v<%= pkg.version %> | <%= grunt.template.today("yyyy-mm-dd") %> */\n'
|
banner: '/*! <%= pkg.description %> (all in one) | v<%= pkg.version %> | <%= grunt.template.today("yyyy-mm-dd") %> */\n'
|
||||||
|
|
@ -84,11 +96,13 @@ module.exports = function(grunt) {
|
||||||
grunt.registerTask('jsketch', [ 'uglify:jsketch', 'clean' ]);
|
grunt.registerTask('jsketch', [ 'uglify:jsketch', 'clean' ]);
|
||||||
grunt.registerTask('sketchable', [ 'uglify:sketchable', 'uglify:jqSketchable', 'clean' ]);
|
grunt.registerTask('sketchable', [ 'uglify:sketchable', 'uglify:jqSketchable', 'clean' ]);
|
||||||
grunt.registerTask('memento', [ 'uglify:memento', 'uglify:jqMemento', 'clean' ]);
|
grunt.registerTask('memento', [ 'uglify:memento', 'uglify:jqMemento', 'clean' ]);
|
||||||
|
grunt.registerTask('animate', [ 'uglify:animate', 'uglify:jqAnimate', 'clean' ]);
|
||||||
|
|
||||||
grunt.registerTask('default', [
|
grunt.registerTask('default', [
|
||||||
'full',
|
'full',
|
||||||
'jsketch',
|
'jsketch',
|
||||||
'sketchable',
|
'sketchable',
|
||||||
'memento',
|
'memento',
|
||||||
|
'animate',
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
!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 f<e.length-1&&(f++,this.restore()),this},this.reset=function(){return e=[],f=-1,this.save()},this.save=function(a){return b.sketchable("handler",function(b,c){a&&a.identifier>0?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;i<h.length;i++)e(h[i]);a.extend(a.fn.sketchable.api,{memento:{undo:function(){var b=a(this).data(c);return b.memento.undo()},redo:function(){var b=a(this).data(c);return b.memento.redo()},save:function(){var b=a(this).data(c);return b.memento.save()},state:function(){var b=a(this).data(c);return b.memento.state()},restore:function(b){var d=a(this).data(c);return d.memento.restore(b)}}}),f.memento=new b(d),f.memento.init()}}(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 f<e.length-1&&(f++,this.restore()),this},this.reset=function(){return e=[],f=-1,this.save()},this.save=function(a){return b.sketchable("handler",function(b,c){a&&a.identifier>0?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.memento$"+a])if(f.options["_bound.memento$"+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;i<h.length;i++)e(h[i]);a.extend(a.fn.sketchable.api,{memento:{undo:function(){var b=a(this).data(c);return b.memento.undo(),d},redo:function(){var b=a(this).data(c);return b.memento.redo(),d},save:function(){var b=a(this).data(c);return b.memento.save(),d},state:function(){var b=a(this).data(c);return b.memento.state(),d},restore:function(b){var e=a(this).data(c);return e.memento.restore(b),d}}}),f.memento=new b(d),f.memento.init()}}(jQuery);
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
!function(a){function b(a){function b(b,c){a.handler(function(a,d){d.sketch.clear(),d.sketch.context.drawImage(b,0,0),d.strokes=c.slice()})}function c(a){if(a.ctrlKey)switch(a.which){case 26:a.shiftKey?f.redo():f.undo();break;case 25:f.redo()}}var d=[],e=-1,f=this;this.undo=function(){return e>0&&(e--,this.restore()),this},this.redo=function(){return e<d.length-1&&(e++,this.restore()),this},this.reset=function(){return d=[],e=-1,this.save()},this.save=function(b){return a.handler(function(a,c){b&&b.identifier>0?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;h<g.length;h++)d(g[h]);deepExtend(a,{memento:{undo:function(){var b=dataBind(a.elem)[c];return b.memento.undo()},redo:function(){var b=dataBind(a.elem)[c];return b.memento.redo()},save:function(){var b=dataBind(a.elem)[c];return b.memento.save()},state:function(){var b=dataBind(a.elem)[c];return b.memento.state()},restore:function(b){var d=dataBind(a.elem)[c];return d.memento.restore(b)}}}),e.memento=new b(a),e.memento.init()}}(this);
|
!function(a){function b(a){function b(b,c){a.handler(function(a,d){d.sketch.clear(),d.sketch.context.drawImage(b,0,0),d.strokes=c.slice()})}function c(a){if(a.ctrlKey)switch(a.which){case 26:a.shiftKey?f.redo():f.undo();break;case 25:f.redo()}}var d=[],e=-1,f=this;this.undo=function(){return e>0&&(e--,this.restore()),this},this.redo=function(){return e<d.length-1&&(e++,this.restore()),this},this.reset=function(){return d=[],e=-1,this.save()},this.save=function(b){return a.handler(function(a,c){b&&b.identifier>0?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.memento$"+b])if(e.options["_bound.memento$"+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;h<g.length;h++)d(g[h]);deepExtend(a,{memento:{undo:function(){var b=dataBind(a.elem)[c];return b.memento.undo(),a},redo:function(){var b=dataBind(a.elem)[c];return b.memento.redo(),a},save:function(){var b=dataBind(a.elem)[c];return b.memento.save(),a},state:function(){var b=dataBind(a.elem)[c];return b.memento.state(),a},restore:function(b){var d=dataBind(a.elem)[c];return d.memento.restore(b),a}}}),e.memento=new b(a),e.memento.init()}}(this);
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*!
|
||||||
|
* An animation plugin for jQuery Sketchable | v1.0 | Luis A. Leiva | MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
||||||
|
/* global jQuery */
|
||||||
|
;(function($) {
|
||||||
|
|
||||||
|
// Custom namespace ID, for private data bindind.
|
||||||
|
var namespace = 'sketchable';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brings animation capabilities to Sketchable elements.
|
||||||
|
* @class
|
||||||
|
* @version 1.0
|
||||||
|
* @param {Sketchable} $instance jQuery Sketchable element.
|
||||||
|
*/
|
||||||
|
function AnimateSketch($instance) {
|
||||||
|
var self = this;
|
||||||
|
var data = $instance.data(namespace);
|
||||||
|
|
||||||
|
// Note: requires strokes to be set in advance.
|
||||||
|
var sketch = data.sketch;
|
||||||
|
var strokes = data.strokes;
|
||||||
|
var events = data.options.events;
|
||||||
|
var graphics = data.options.graphics;
|
||||||
|
|
||||||
|
// Flatten strokes struct to easily handle multistrokes.
|
||||||
|
var fmtStrokes = [];
|
||||||
|
for (var s = 0; s < strokes.length; s++) {
|
||||||
|
var coords = strokes[s];
|
||||||
|
for (var c = 0; c < coords.length; c++) {
|
||||||
|
var pt = toPoint(coords[c]);
|
||||||
|
pt.strokeId = s;
|
||||||
|
fmtStrokes.push(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var raf;
|
||||||
|
var frame = 1;
|
||||||
|
var count = fmtStrokes.length - 1;
|
||||||
|
|
||||||
|
if (typeof events.animationstart === 'function') events.animationstart($instance, data);
|
||||||
|
|
||||||
|
(function loop() {
|
||||||
|
raf = requestAnimationFrame(loop);
|
||||||
|
|
||||||
|
try {
|
||||||
|
drawLine(sketch, fmtStrokes, frame, graphics);
|
||||||
|
frame++;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame == count) {
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
if (typeof events.animationend === 'function') events.animationend($instance, data);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel current animation.
|
||||||
|
*/
|
||||||
|
this.cancel = function() {
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw line on jSketch canvas at time t.
|
||||||
|
* Optionally set graphics options.
|
||||||
|
* @private
|
||||||
|
* @param sketch Object jSketch canvas.
|
||||||
|
* @param coords Array Stroke coordinates.
|
||||||
|
* @param t Int Time iterator.
|
||||||
|
* @param [graphics] Object Graphics options.
|
||||||
|
*/
|
||||||
|
function drawLine(sketch, coords, t, graphics) {
|
||||||
|
var prevPt = coords[t - 1];
|
||||||
|
var currPt = coords[t];
|
||||||
|
|
||||||
|
if (sketch.data.firstPointSize && (t === 1 || currPt.strokeId !== prevPt.strokeId)) {
|
||||||
|
var pt = t > 1 ? currPt : prevPt;
|
||||||
|
sketch.beginFill(sketch.data.strokeStyle).fillCircle(pt.x, pt.y, sketch.data.firstPointSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
sketch.lineStyle(graphics.strokeStyle, graphics.lineWidth).beginPath();
|
||||||
|
if (currPt.strokeId === prevPt.strokeId) {
|
||||||
|
sketch.line(prevPt.x, prevPt.y, currPt.x, currPt.y).stroke();
|
||||||
|
}
|
||||||
|
sketch.closePath();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert point array to object.
|
||||||
|
* @private
|
||||||
|
* @param {Array} p Point, having [x,y,t] items.
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
function toPoint(p) {
|
||||||
|
if (!(p instanceof Array)) return p;
|
||||||
|
return { x: p[0], y: p[1], t: p[2] };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate plugin constructor for jQuery Sketchable instances.
|
||||||
|
* @param {Object} $instance jQuery Sketchable instance.
|
||||||
|
* @memberof $.fn.sketchable.plugins
|
||||||
|
*/
|
||||||
|
$.fn.sketchable.plugins.animate = function($instance) {
|
||||||
|
// Access the instance configuration.
|
||||||
|
var config = $instance.sketchable('config');
|
||||||
|
|
||||||
|
var callbacks = {
|
||||||
|
clear: function(elem, data) {
|
||||||
|
data.animate && data.animate.cancel();
|
||||||
|
},
|
||||||
|
destroy: function(elem, data) {
|
||||||
|
data.animate && data.animate.cancel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// A helper function to override user-defined event listeners.
|
||||||
|
function override(evName) {
|
||||||
|
// Flag event override so that it doesn't get fired more than once.
|
||||||
|
if (config.options['_bound.animate$' + evName]) return;
|
||||||
|
config.options['_bound.animate$' + evName] = true;
|
||||||
|
|
||||||
|
if (config.options.events && typeof config.options.events[evName] === 'function') {
|
||||||
|
// User has defined this event, so wrap it.
|
||||||
|
var fn = config.options.events[evName];
|
||||||
|
config.options.events[evName] = function() {
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: the init event is used to create sketchable instances,
|
||||||
|
// therefore it should NOT be overriden.
|
||||||
|
var events = 'clear destroy'.split(' ');
|
||||||
|
for (var i = 0; i < events.length; i++) {
|
||||||
|
override(events[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose public API: all jQuery sketchable instances will have these methods.
|
||||||
|
$.extend($.fn.sketchable.api, {
|
||||||
|
// Namespace methods to avoid collisions with other plugins.
|
||||||
|
animate: {
|
||||||
|
/**
|
||||||
|
* Animate canvas strokes.
|
||||||
|
* @return {AnimateSketch}
|
||||||
|
* @memberof $.fn.sketchable
|
||||||
|
* @example jqueryElem.sketchable('strokes', strokesArray).sketchable('animate.strokes');
|
||||||
|
* @example
|
||||||
|
* // Accessing event hooks:
|
||||||
|
* jqueryElem.sketchable('config', {
|
||||||
|
* events: {
|
||||||
|
* animationstart: function(elem, data) {
|
||||||
|
* // Animation started.
|
||||||
|
* },
|
||||||
|
* animationend: function(elem, data) {
|
||||||
|
* // Animation ended.
|
||||||
|
* },
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* .sketchable('strokes', strokesArray)
|
||||||
|
* .sketchable('animate.strokes');
|
||||||
|
*/
|
||||||
|
strokes: function() {
|
||||||
|
var data = $(this).data(namespace);
|
||||||
|
data.animate = new AnimateSketch($instance);
|
||||||
|
return $instance;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
||||||
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*!
|
||||||
|
* Animation plugin for Sketchable | v1.0 | Luis A. Leiva | MIT license
|
||||||
|
*/
|
||||||
|
|
||||||
|
// XXX: Requires `sketchable.utils.js` to be loaded first.
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
||||||
|
/* global Event, dataBind, deepExtend */
|
||||||
|
;(function(window) {
|
||||||
|
|
||||||
|
// Custom namespace ID, for private data bindind.
|
||||||
|
var namespace = 'sketchable';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brings animation capabilities to Sketchable elements.
|
||||||
|
* @class
|
||||||
|
* @version 1.0
|
||||||
|
* @param {Sketchable} instance Sketchable element.
|
||||||
|
*/
|
||||||
|
function AnimateSketch(instance) {
|
||||||
|
var self = this;
|
||||||
|
var data = dataBind(instance.elem)[namespace];
|
||||||
|
|
||||||
|
// Note: requires strokes to be set in advance.
|
||||||
|
var sketch = data.sketch;
|
||||||
|
var strokes = data.strokes;
|
||||||
|
var events = data.options.events;
|
||||||
|
var graphics = data.options.graphics;
|
||||||
|
|
||||||
|
// Flatten strokes struct to easily handle multistrokes.
|
||||||
|
var fmtStrokes = [];
|
||||||
|
for (var s = 0; s < strokes.length; s++) {
|
||||||
|
var coords = strokes[s];
|
||||||
|
for (var c = 0; c < coords.length; c++) {
|
||||||
|
var pt = toPoint(coords[c]);
|
||||||
|
pt.strokeId = s;
|
||||||
|
fmtStrokes.push(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var raf;
|
||||||
|
var frame = 1;
|
||||||
|
var count = fmtStrokes.length - 1;
|
||||||
|
|
||||||
|
if (typeof events.animationstart === 'function') events.animationstart(instance.elem, data);
|
||||||
|
|
||||||
|
(function loop() {
|
||||||
|
raf = requestAnimationFrame(loop);
|
||||||
|
|
||||||
|
try {
|
||||||
|
drawLine(sketch, fmtStrokes, frame, graphics);
|
||||||
|
frame++;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame == count) {
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
if (typeof events.animationend === 'function') events.animationend(instance.elem, data);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel current animation.
|
||||||
|
*/
|
||||||
|
this.cancel = function() {
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw line on jSketch canvas at time t.
|
||||||
|
* Optionally set graphics options.
|
||||||
|
* @private
|
||||||
|
* @param sketch Object jSketch canvas.
|
||||||
|
* @param coords Array Stroke coordinates.
|
||||||
|
* @param t Int Time iterator.
|
||||||
|
* @param [graphics] Object Graphics options.
|
||||||
|
*/
|
||||||
|
function drawLine(sketch, coords, t, graphics) {
|
||||||
|
var prevPt = coords[t - 1];
|
||||||
|
var currPt = coords[t];
|
||||||
|
|
||||||
|
if (sketch.data.firstPointSize && (t === 1 || currPt.strokeId !== prevPt.strokeId)) {
|
||||||
|
var pt = t > 1 ? currPt : prevPt;
|
||||||
|
sketch.beginFill(sketch.data.strokeStyle).fillCircle(pt.x, pt.y, sketch.data.firstPointSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
sketch.lineStyle(graphics.strokeStyle, graphics.lineWidth).beginPath();
|
||||||
|
if (currPt.strokeId === prevPt.strokeId) {
|
||||||
|
sketch.line(prevPt.x, prevPt.y, currPt.x, currPt.y).stroke();
|
||||||
|
}
|
||||||
|
sketch.closePath();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert point array to object.
|
||||||
|
* @private
|
||||||
|
* @param {Array} p Point, having [x,y,t] items.
|
||||||
|
* @return {Object}
|
||||||
|
*/
|
||||||
|
function toPoint(p) {
|
||||||
|
if (!(p instanceof Array)) return p;
|
||||||
|
return { x: p[0], y: p[1], t: p[2] };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate plugin constructor for jQuery Sketchable instances.
|
||||||
|
* @param {Sketchable} instance Sketchable element.
|
||||||
|
* @memberof Sketchable#plugins
|
||||||
|
*/
|
||||||
|
Sketchable.prototype.plugins.animate = function(instance) {
|
||||||
|
// Access the instance configuration.
|
||||||
|
var config = instance.config();
|
||||||
|
|
||||||
|
var callbacks = {
|
||||||
|
clear: function(elem, data) {
|
||||||
|
data.animate && data.animate.cancel();
|
||||||
|
},
|
||||||
|
destroy: function(elem, data) {
|
||||||
|
data.animate && data.animate.cancel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// A helper function to override user-defined event listeners.
|
||||||
|
function override(evName) {
|
||||||
|
// Flag event override so that it doesn't get fired more than once.
|
||||||
|
if (config.options['_bound.animate$' + evName]) return;
|
||||||
|
config.options['_bound.animate$' + evName] = true;
|
||||||
|
|
||||||
|
if (config.options.events && typeof config.options.events[evName] === 'function') {
|
||||||
|
// User has defined this event, so wrap it.
|
||||||
|
var fn = config.options.events[evName];
|
||||||
|
config.options.events[evName] = function() {
|
||||||
|
// 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: the init event is used to create sketchable instances,
|
||||||
|
// therefore it should NOT be overriden.
|
||||||
|
var events = 'clear destroy'.split(' ');
|
||||||
|
for (var i = 0; i < events.length; i++) {
|
||||||
|
override(events[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose public API: all Sketchable instances will have these methods.
|
||||||
|
deepExtend(instance, {
|
||||||
|
// Namespace methods to avoid collisions with other plugins.
|
||||||
|
animate: {
|
||||||
|
/**
|
||||||
|
* Animate canvas strokes.
|
||||||
|
* @return {AnimateSketch}
|
||||||
|
* @memberof Sketchable
|
||||||
|
* @example sketchableInstance.strokes(strokeArray).animate.strokes();
|
||||||
|
* @example
|
||||||
|
* // Accessing event hooks:
|
||||||
|
* sketchableInstance.config({
|
||||||
|
* events: {
|
||||||
|
* animationstart: function(elem, data) {
|
||||||
|
* // Animation started.
|
||||||
|
* },
|
||||||
|
* animationend: function(elem, data) {
|
||||||
|
* // Animation finished.
|
||||||
|
* },
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
* .strokes(strokeArray)
|
||||||
|
* .animate.strokes();
|
||||||
|
*/
|
||||||
|
strokes: function() {
|
||||||
|
var data = dataBind(instance.elem)[namespace];
|
||||||
|
data.animate = new AnimateSketch(instance);
|
||||||
|
return instance;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
})(this);
|
||||||
Loading…
Reference in New Issue