mirror of https://github.com/luileito/jsketch.git
181 lines
5.5 KiB
JavaScript
181 lines
5.5 KiB
JavaScript
/*!
|
|
* An animation plugin for jQuery Sketchable | v1.1 | 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 {jQuery} $instance - jQuery sketchable element.
|
|
*/
|
|
function AnimateSketch($instance) {
|
|
var self = this;
|
|
var data = $instance.data(namespace);
|
|
|
|
// Note: To animate a sketchable canvas, strokes must be set in advance.
|
|
var sketch = data.sketch;
|
|
var strokes = data.strokes;
|
|
var events = data.options.events;
|
|
var graphics = data.options.graphics;
|
|
|
|
// Reformat strokes to handle multitouch.
|
|
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]);
|
|
// The strokeId is not available in jsketchable < 2.2, so add it.
|
|
if (!pt.strokeId) pt.strokeId = s;
|
|
fmtStrokes.push(pt);
|
|
}
|
|
}
|
|
|
|
if (typeof events.animationstart === 'function')
|
|
events.animationstart($instance, data);
|
|
|
|
var raf;
|
|
var frame = 0;
|
|
|
|
sketch.lineStyle(graphics.strokeStyle, graphics.lineWidth);
|
|
|
|
(function loop() {
|
|
raf = requestAnimationFrame(loop);
|
|
// Here be dragons, thus surround by try/catch.
|
|
try {
|
|
drawLine(sketch, fmtStrokes, frame, graphics);
|
|
} catch (err) {
|
|
console.error(err);
|
|
cancelAnimationFrame(raf);
|
|
}
|
|
// Advance local count and check if current animation should end.
|
|
if (++frame === fmtStrokes.length - 1) {
|
|
cancelAnimationFrame(raf);
|
|
if (typeof events.animationend === 'function')
|
|
events.animationend($instance, data);
|
|
}
|
|
})();
|
|
|
|
/**
|
|
* Cancel current animation.
|
|
* @return {AnimateSketch}.
|
|
*/
|
|
this.cancel = function() {
|
|
cancelAnimationFrame(raf);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Draw line on jSketch canvas at time t.
|
|
* @private
|
|
* @param {object} sketch - jSketch canvas.
|
|
* @param {array} coords - Stroke coordinates.
|
|
* @param {number} t - Time iterator.
|
|
*/
|
|
function drawLine(sketch, coords, t) {
|
|
var currPt = coords[t];
|
|
var nextPt = coords[t + 1];
|
|
|
|
if (t === 0 || currPt.strokeId !== nextPt.strokeId) {
|
|
// Draw first point.
|
|
if (sketch.data.firstPointSize) {
|
|
var pt = t > 0 ? nextPt : currPt;
|
|
sketch.beginFill(sketch.data.strokeStyle)
|
|
.fillCircle(pt.x, pt.y, sketch.data.firstPointSize)
|
|
.endFill();
|
|
}
|
|
// Trigger step event for subsequent strokes.
|
|
if (t > 0 && typeof events.animationstep === 'function')
|
|
events.animationstep($instance, data);
|
|
// Flag stroke change.
|
|
sketch.closePath().beginPath();
|
|
}
|
|
|
|
if (currPt.strokeId === nextPt.strokeId)
|
|
sketch.line(currPt.x, currPt.y, nextPt.x, nextPt.y).stroke();
|
|
}
|
|
|
|
/**
|
|
* Convert point array to object.
|
|
* @private
|
|
* @param {array} p - Point, having at least [x,y,t] items.
|
|
* @return {object}
|
|
*/
|
|
function toPoint(p) {
|
|
if (!(p instanceof Array)) return p;
|
|
// Point coords is an array with 4 items: [x, y, time, is_drawing, strokeId].
|
|
return { x: p[0], y: p[1], time: p[2], strokeId: p[4] };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Animate plugin constructor for jQuery Sketchable instances.
|
|
* @param {jQuery} $instance - jQuery Sketchable instance.
|
|
* @namespace $.fn.sketchable.plugins.animate
|
|
*/
|
|
$.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();
|
|
},
|
|
};
|
|
|
|
// 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++) {
|
|
var evName = events[i];
|
|
$instance.sketchable('decorate', evName, callbacks[evName], 'animate');
|
|
}
|
|
|
|
// 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 {jQuery} jQuery sketchable element.
|
|
* @memberof $.fn.sketchable.plugins.animate
|
|
* @example jqueryElem.sketchable('strokes', strokesArray).sketchable('animate.strokes');
|
|
* @example
|
|
* // Accessing event hooks:
|
|
* jqueryElem.sketchable('config', {
|
|
* events: {
|
|
* animationstart: function(elem, data) {
|
|
* // Animation started: the first stroke is being drawn.
|
|
* },
|
|
* animationstep: function(elem, data) {
|
|
* // Animation steped: a new stroke is being drawn.
|
|
* },
|
|
* animationend: function(elem, data) {
|
|
* // Animation ended: the last stroke has been drawn.
|
|
* },
|
|
* }
|
|
* })
|
|
* .sketchable('strokes', strokesArray)
|
|
* .sketchable('animate.strokes');
|
|
*/
|
|
strokes: function() {
|
|
var data = $(this).data(namespace);
|
|
data.animate = new AnimateSketch($instance);
|
|
return $instance;
|
|
},
|
|
},
|
|
});
|
|
|
|
};
|
|
|
|
})(jQuery);
|