|
|
(function($) { // Hide scope, no $ conflict
var signatureOverrides = {
// Global defaults for signature
options: { background: '#ffffff', // Colour of the background
color: '#000000', // Colour of the signature
thickness: 2, // Thickness of the lines
guideline: false, // Add a guide line or not?
guidelineColor: '#a0a0a0', // Guide line colour
guidelineOffset: 50, // Guide line offset from the bottom
guidelineIndent: 10, // Guide line indent from the edges
notAvailable: 'Your browser doesn\'t support signing', // Error message when no canvas
syncField: null, // Selector for synchronised text field
change: null, // Callback when signature changed
width: 170, height: 50 },
/* Initialise a new signature area. */ _create: function() { this.element.addClass(this.widgetFullName || this.widgetBaseClass); try { this.canvas = $('<canvas width="' + this.options.width + '" height="' + this.options.height + '">' + '' + '</canvas>')[0]; this.element.prepend(this.canvas); this.element.find('img').remove(); this.ctx = this.canvas.getContext('2d'); } catch (e) { $(this.canvas).remove(); this.resize = true; this.canvas = document.createElement('canvas'); this.canvas.setAttribute('width', this.element.width()); this.canvas.setAttribute('height', this.element.height()); this.canvas.innerHTML = this.options.notAvailable; this.element.append(this.canvas); if (G_vmlCanvasManager) { // Requires excanvas.js
G_vmlCanvasManager.initElement(this.canvas); } this.ctx = this.canvas.getContext('2d'); } this._refresh(true); this._mouseInit(); },
/* Refresh the appearance of the signature area. @param init (boolean, internal) true if initialising */ _refresh: function(init) { if (this.resize) { var parent = $(this.canvas); $('div', this.canvas).css({width: parent.width(), height: parent.height()}); } this.ctx.fillStyle = this.options.background; this.ctx.strokeStyle = this.options.color; this.ctx.lineWidth = this.options.thickness; this.ctx.lineCap = 'round'; this.ctx.lineJoin = 'round'; this.clear(init); },
/* Clear the signature area. @param init (boolean, internal) true if initialising */ clear: function(init) { this.ctx.fillRect(0, 0, this.element.width(), this.element.height()); if (this.options.guideline) { this.ctx.save(); this.ctx.strokeStyle = this.options.guidelineColor; this.ctx.lineWidth = 1; this.ctx.beginPath(); this.ctx.moveTo(this.options.guidelineIndent, this.element.height() - this.options.guidelineOffset); this.ctx.lineTo(this.element.width() - this.options.guidelineIndent, this.element.height() - this.options.guidelineOffset); this.ctx.stroke(); this.ctx.restore(); } this.lines = []; if (!init) { this._changed(); } },
/* Synchronise changes and trigger change event. @param event (Event) the triggering event */ _changed: function(event) { if (this.options.syncField) { $(this.options.syncField).val(this.toJSON()); } this._trigger('change', event, {}); },
/* Custom options handling. @param options (object) the new option values */ _setOptions: function(options) { if (this._superApply) { this._superApply(arguments); // Base widget handling
} else { $.Widget.prototype._setOptions.apply(this, arguments); // Base widget handling
} this._refresh(); },
/* Determine if dragging can start. @param event (Event) the triggering mouse event @return (boolean) true if allowed, false if not */ _mouseCapture: function(event) { return !this.options.disabled; },
/* Start a new line. @param event (Event) the triggering mouse event */ _mouseStart: function(event) { this.offset = this.element.offset(); this.offset.left -= document.documentElement.scrollLeft || document.body.scrollLeft; this.offset.top -= document.documentElement.scrollTop || document.body.scrollTop; this.lastPoint = [this._round(event.clientX - this.offset.left), this._round(event.clientY - this.offset.top)]; this.curLine = [this.lastPoint]; this.lines.push(this.curLine); },
/* Track the mouse. @param event (Event) the triggering mouse event */ _mouseDrag: function(event) { var point = [this._round(event.clientX - this.offset.left), this._round(event.clientY - this.offset.top)]; this.curLine.push(point); this.ctx.beginPath(); this.ctx.moveTo(this.lastPoint[0], this.lastPoint[1]); this.ctx.lineTo(point[0], point[1]); this.ctx.stroke(); this.lastPoint = point; },
/* End a line. @param event (Event) the triggering mouse event */ _mouseStop: function(event) { this.lastPoint = null; this.curLine = null; this._changed(event); },
/* Round to two decimal points. @param value (number) the value to round @return (number) the rounded value */ _round: function(value) { return Math.round(value * 100) / 100; },
/* Convert the captured lines to JSON text. @return (string) the JSON text version of the lines */ toJSON: function() { return '{"lines":[' + $.map(this.lines, function(line) { return '[' + $.map(line, function(point) { return '[' + point + ']'; }) + ']'; }) + ']}'; },
/* Convert the captured lines to SVG text. @return (string) the SVG text version of the lines */ toSVG: function() { return '<?xml version="1.0"?>\n<!DOCTYPE svg PUBLIC ' + '"-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + '<svg xmlns="http://www.w3.org/2000/svg" width="15cm" height="15cm">\n' + ' <g fill="' + this.options.background + '">\n' + ' <rect x="0" y="0" width="' + this.canvas.width + '" height="' + this.canvas.height + '"/>\n' + ' <g fill="none" stroke="' + this.options.color + '" stroke-width="' + this.options.thickness + '">\n'+ $.map(this.lines, function(line) { return ' <polyline points="' + $.map(line, function(point) { return point + ''; }).join(' ') + '"/>\n'; }).join('') + ' </g>\n </g>\n</svg>\n'; },
/* Draw a signature from its JSON description. @param sigJSON (object) object with attribute lines being an array of arrays of points or (string) text version of the JSON */ draw: function(sigJSON) { this.clear(true); if (typeof sigJSON === 'string') { sigJSON = $.parseJSON(sigJSON); } this.lines = sigJSON.lines || []; var ctx = this.ctx; $.each(this.lines, function() { ctx.beginPath(); $.each(this, function(i) { ctx[i === 0 ? 'moveTo' : 'lineTo'](this[0], this[1]); }); ctx.stroke(); }); this._changed(); },
/* Determine whether or not any drawing has occurred. @return (boolean) true if not signed, false if signed */ isEmpty: function() { return this.lines.length === 0; },
/* Remove the signature functionality. */ _destroy: function() { this.element.removeClass(this.widgetFullName || this.widgetBaseClass); $(this.canvas).remove(); this.canvas = this.ctx = this.lines = null; this._mouseDestroy(); } };
if (!$.Widget.prototype._destroy) { $.extend(signatureOverrides, { /* Remove the signature functionality. */ destroy: function() { this._destroy(); $.Widget.prototype.destroy.call(this); // Base widget handling
} }); }
if($.Widget.prototype._getCreateOptions === $.noop) { $.extend(signatureOverrides, { /* Restore the metadata functionality. */ _getCreateOptions: function() { return $.metadata && $.metadata.get(this.element[0])[this.widgetName]; } }); }
/* Signature capture and display. Depends on jquery.ui.widget, jquery.ui.mouse. */ $.widget('kbw.signature', $.ui.mouse, signatureOverrides);
// Make some things more accessible
$.kbw.signature.options = $.kbw.signature.prototype.options;
})(jQuery);
|