ele-signature-rails 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,828 @@
1
+ /**
2
+ * Usage for accepting signatures:
3
+ * $('.sigPad').signaturePad()
4
+ *
5
+ * Usage for displaying previous signatures:
6
+ * $('.sigPad').signaturePad({displayOnly:true}).regenerate(sig)
7
+ * or
8
+ * var api = $('.sigPad').signaturePad({displayOnly:true})
9
+ * api.regenerate(sig)
10
+ */
11
+ ;(function ($) {
12
+ function SignaturePad (selector, options) {
13
+ /**
14
+ * Reference to the object for use in public methods
15
+ *
16
+ * @private
17
+ *
18
+ * @type {Object}
19
+ */
20
+ var self = this,
21
+
22
+ /**
23
+ * Holds the merged default settings and user passed settings
24
+ *
25
+ * @private
26
+ *
27
+ * @type {Object}
28
+ */
29
+ settings = $.extend({}, $.fn.signaturePad.defaults, options),
30
+
31
+ /**
32
+ * The current context, as passed by jQuery, of selected items
33
+ *
34
+ * @private
35
+ *
36
+ * @type {Object}
37
+ */
38
+ context = $(selector),
39
+
40
+ /**
41
+ * jQuery reference to the canvas element inside the signature pad
42
+ *
43
+ * @private
44
+ *
45
+ * @type {Object}
46
+ */
47
+ canvas = $(settings.canvas, context),
48
+
49
+ /**
50
+ * Dom reference to the canvas element inside the signature pad
51
+ *
52
+ * @private
53
+ *
54
+ * @type {Object}
55
+ */
56
+ element = canvas.get(0),
57
+
58
+ /**
59
+ * The drawing context for the signature canvas
60
+ *
61
+ * @private
62
+ *
63
+ * @type {Object}
64
+ */
65
+ canvasContext = null,
66
+
67
+ /**
68
+ * Holds the previous point of drawing
69
+ * Disallows drawing over the same location to make lines more delicate
70
+ *
71
+ * @private
72
+ *
73
+ * @type {Object}
74
+ */
75
+ previous = {'x': null, 'y': null},
76
+
77
+ /**
78
+ * An array holding all the points and lines to generate the signature
79
+ * Each item is an object like:
80
+ * {
81
+ * mx: moveTo x coordinate
82
+ * my: moveTo y coordinate
83
+ * lx: lineTo x coordinate
84
+ * lx: lineTo y coordinate
85
+ * }
86
+ *
87
+ * @private
88
+ *
89
+ * @type {Array}
90
+ */
91
+ output = [],
92
+
93
+ /**
94
+ * Stores a timeout for when the mouse leaves the canvas
95
+ * If the mouse has left the canvas for a specific amount of time
96
+ * Stops drawing on the canvas
97
+ *
98
+ * @private
99
+ *
100
+ * @type {Object}
101
+ */
102
+ mouseLeaveTimeout = false,
103
+
104
+ /**
105
+ * Whether the mouse button is currently pressed down or not
106
+ *
107
+ * @private
108
+ *
109
+ * @type {Boolean}
110
+ */
111
+ mouseButtonDown = false,
112
+
113
+ /**
114
+ * Whether the browser is a touch event browser or not
115
+ *
116
+ * @private
117
+ *
118
+ * @type {Boolean}
119
+ */
120
+ touchable = false,
121
+
122
+ /**
123
+ * Whether events have already been bound to the canvas or not
124
+ *
125
+ * @private
126
+ *
127
+ * @type {Boolean}
128
+ */
129
+ eventsBound = false,
130
+
131
+ /**
132
+ * Remembers the default font-size when typing, and will allow it to be scaled for bigger/smaller names
133
+ *
134
+ * @private
135
+ *
136
+ * @type {Number}
137
+ */
138
+ typeItDefaultFontSize = 30,
139
+
140
+ /**
141
+ * Remembers the current font-size when typing
142
+ *
143
+ * @private
144
+ *
145
+ * @type {Number}
146
+ */
147
+ typeItCurrentFontSize = typeItDefaultFontSize,
148
+
149
+ /**
150
+ * Remembers how many characters are in the name field, to help with the scaling feature
151
+ *
152
+ * @private
153
+ *
154
+ * @type {Number}
155
+ */
156
+ typeItNumChars = 0
157
+
158
+ /**
159
+ * Clears the mouseLeaveTimeout
160
+ * Resets some other variables that may be active
161
+ *
162
+ * @private
163
+ */
164
+ function clearMouseLeaveTimeout () {
165
+ clearTimeout(mouseLeaveTimeout)
166
+ mouseLeaveTimeout = false
167
+ mouseButtonDown = false
168
+ }
169
+
170
+ /**
171
+ * Draws a line on canvas using the mouse position
172
+ * Checks previous position to not draw over top of previous drawing
173
+ * (makes the line really thick and poorly anti-aliased)
174
+ *
175
+ * @private
176
+ *
177
+ * @param {Object} e The event object
178
+ * @param {Number} newYOffset A pixel value for drawing the newY, used for drawing a single dot on click
179
+ */
180
+ function drawLine (e, newYOffset) {
181
+ var offset, newX, newY
182
+
183
+ e.preventDefault()
184
+
185
+ offset = $(e.target).offset()
186
+
187
+ clearTimeout(mouseLeaveTimeout)
188
+ mouseLeaveTimeout = false
189
+
190
+ if (typeof e.targetTouches !== 'undefined') {
191
+ newX = Math.floor(e.targetTouches[0].pageX - offset.left)
192
+ newY = Math.floor(e.targetTouches[0].pageY - offset.top)
193
+ } else {
194
+ newX = Math.floor(e.pageX - offset.left)
195
+ newY = Math.floor(e.pageY - offset.top)
196
+ }
197
+
198
+ if (previous.x === newX && previous.y === newY)
199
+ return true
200
+
201
+ if (previous.x === null)
202
+ previous.x = newX
203
+
204
+ if (previous.y === null)
205
+ previous.y = newY
206
+
207
+ if (newYOffset)
208
+ newY += newYOffset
209
+
210
+ canvasContext.beginPath()
211
+ canvasContext.moveTo(previous.x, previous.y)
212
+ canvasContext.lineTo(newX, newY)
213
+ canvasContext.lineCap = settings.penCap
214
+ canvasContext.stroke()
215
+ canvasContext.closePath()
216
+
217
+ output.push({
218
+ 'lx': newX, 'ly': newY, 'mx': previous.x, 'my': previous.y
219
+ })
220
+
221
+ previous.x = newX
222
+ previous.y = newY
223
+
224
+ if (settings.onDraw && typeof settings.onDraw === 'function')
225
+ settings.onDraw.apply(self)
226
+ }
227
+
228
+ /**
229
+ * Callback wrapper for executing stopDrawing without the event
230
+ * Put up here so that it can be removed at a later time
231
+ *
232
+ * @private
233
+ */
234
+ function stopDrawingWrapper () {
235
+ stopDrawing()
236
+ }
237
+
238
+ /**
239
+ * Callback registered to mouse/touch events of the canvas
240
+ * Stops the drawing abilities
241
+ *
242
+ * @private
243
+ *
244
+ * @param {Object} e The event object
245
+ */
246
+ function stopDrawing (e) {
247
+ if (!!e) {
248
+ drawLine(e, 1)
249
+ } else {
250
+ if (touchable) {
251
+ canvas.each(function () {
252
+ this.removeEventListener('touchmove', drawLine)
253
+ // this.removeEventListener('MSPointerMove', drawLine)
254
+ })
255
+ } else {
256
+ canvas.unbind('mousemove.signaturepad')
257
+ }
258
+
259
+ if (output.length > 0 && settings.onDrawEnd && typeof settings.onDrawEnd === 'function')
260
+ settings.onDrawEnd.apply(self)
261
+ }
262
+
263
+ previous.x = null
264
+ previous.y = null
265
+
266
+ if (settings.output && output.length > 0)
267
+ $(settings.output, context).val(JSON.stringify(output))
268
+ }
269
+
270
+ /**
271
+ * Draws the signature line
272
+ *
273
+ * @private
274
+ */
275
+ function drawSigLine () {
276
+ if (!settings.lineWidth)
277
+ return false
278
+
279
+ canvasContext.beginPath()
280
+ canvasContext.lineWidth = settings.lineWidth
281
+ canvasContext.strokeStyle = settings.lineColour
282
+ canvasContext.moveTo(settings.lineMargin, settings.lineTop)
283
+ canvasContext.lineTo(element.width - settings.lineMargin, settings.lineTop)
284
+ canvasContext.stroke()
285
+ canvasContext.closePath()
286
+ }
287
+
288
+ /**
289
+ * Clears all drawings off the canvas and redraws the signature line
290
+ *
291
+ * @private
292
+ */
293
+ function clearCanvas () {
294
+ canvasContext.clearRect(0, 0, element.width, element.height)
295
+ canvasContext.fillStyle = settings.bgColour
296
+ canvasContext.fillRect(0, 0, element.width, element.height)
297
+
298
+ if (!settings.displayOnly)
299
+ drawSigLine()
300
+
301
+ canvasContext.lineWidth = settings.penWidth
302
+ canvasContext.strokeStyle = settings.penColour
303
+
304
+ $(settings.output, context).val('')
305
+ output = []
306
+
307
+ stopDrawing()
308
+ }
309
+
310
+ /**
311
+ * Callback registered to mouse/touch events of the canvas
312
+ * Draws a line at the mouse cursor location, starting a new line if necessary
313
+ *
314
+ * @private
315
+ *
316
+ * @param {Object} e The event object
317
+ * @param {Object} o The object context registered to the event; canvas
318
+ */
319
+ function onMouseMove (e, o) {
320
+ if (previous.x == null) {
321
+ drawLine(e, 1)
322
+ } else {
323
+ drawLine(e, o)
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Callback registered to mouse/touch events of canvas
329
+ * Triggers the drawLine function
330
+ *
331
+ * @private
332
+ *
333
+ * @param {Object} e The event object
334
+ * @param {Object} touchObject The object context registered to the event; canvas
335
+ */
336
+ function startDrawing (e, touchObject) {
337
+ if (touchable) {
338
+ touchObject.addEventListener('touchmove', onMouseMove, false)
339
+ // touchObject.addEventListener('MSPointerMove', onMouseMove, false)
340
+ } else {
341
+ canvas.bind('mousemove.signaturepad', onMouseMove)
342
+ }
343
+
344
+ // Draws a single point on initial mouse down, for people with periods in their name
345
+ drawLine(e, 1)
346
+ }
347
+
348
+ /**
349
+ * Removes all the mouse events from the canvas
350
+ *
351
+ * @private
352
+ */
353
+ function disableCanvas () {
354
+ eventsBound = false
355
+
356
+ canvas.each(function () {
357
+ if (this.removeEventListener) {
358
+ this.removeEventListener('touchend', stopDrawingWrapper)
359
+ this.removeEventListener('touchcancel', stopDrawingWrapper)
360
+ this.removeEventListener('touchmove', drawLine)
361
+ // this.removeEventListener('MSPointerUp', stopDrawingWrapper)
362
+ // this.removeEventListener('MSPointerCancel', stopDrawingWrapper)
363
+ // this.removeEventListener('MSPointerMove', drawLine)
364
+ }
365
+
366
+ if (this.ontouchstart)
367
+ this.ontouchstart = null
368
+ })
369
+
370
+ $(document).unbind('mouseup.signaturepad')
371
+ canvas.unbind('mousedown.signaturepad')
372
+ canvas.unbind('mousemove.signaturepad')
373
+ canvas.unbind('mouseleave.signaturepad')
374
+
375
+ $(settings.clear, context).unbind('click.signaturepad')
376
+ }
377
+
378
+ /**
379
+ * Lazy touch event detection
380
+ * Uses the first press on the canvas to detect either touch or mouse reliably
381
+ * Will then bind other events as needed
382
+ *
383
+ * @private
384
+ *
385
+ * @param {Object} e The event object
386
+ */
387
+ function initDrawEvents (e) {
388
+ if (eventsBound)
389
+ return false
390
+
391
+ eventsBound = true
392
+
393
+ // Closes open keyboards to free up space
394
+ $('input').blur()
395
+
396
+ if (typeof e.targetTouches !== 'undefined')
397
+ touchable = true
398
+
399
+ if (touchable) {
400
+ canvas.each(function () {
401
+ this.addEventListener('touchend', stopDrawingWrapper, false)
402
+ this.addEventListener('touchcancel', stopDrawingWrapper, false)
403
+ // this.addEventListener('MSPointerUp', stopDrawingWrapper, false)
404
+ // this.addEventListener('MSPointerCancel', stopDrawingWrapper, false)
405
+ })
406
+
407
+ canvas.unbind('mousedown.signaturepad')
408
+ } else {
409
+ $(document).bind('mouseup.signaturepad', function () {
410
+ if (mouseButtonDown) {
411
+ stopDrawing()
412
+ clearMouseLeaveTimeout()
413
+ }
414
+ })
415
+ canvas.bind('mouseleave.signaturepad', function (e) {
416
+ if (mouseButtonDown) stopDrawing(e)
417
+
418
+ if (mouseButtonDown && !mouseLeaveTimeout) {
419
+ mouseLeaveTimeout = setTimeout(function () {
420
+ stopDrawing()
421
+ clearMouseLeaveTimeout()
422
+ }, 500)
423
+ }
424
+ })
425
+
426
+ canvas.each(function () {
427
+ this.ontouchstart = null
428
+ })
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Triggers the abilities to draw on the canvas
434
+ * Sets up mouse/touch events, hides and shows descriptions and sets current classes
435
+ *
436
+ * @private
437
+ */
438
+ function drawIt () {
439
+ $(settings.typed, context).hide()
440
+ clearCanvas()
441
+
442
+ canvas.each(function () {
443
+ this.ontouchstart = function (e) {
444
+ e.preventDefault()
445
+ mouseButtonDown = true
446
+ initDrawEvents(e)
447
+ startDrawing(e, this)
448
+ }
449
+ })
450
+
451
+ canvas.bind('mousedown.signaturepad', function (e) {
452
+ e.preventDefault()
453
+
454
+ // Only allow left mouse clicks to trigger signature drawing
455
+ if (e.which > 1) return false
456
+
457
+ mouseButtonDown = true
458
+ initDrawEvents(e)
459
+ startDrawing(e)
460
+ })
461
+
462
+ $(settings.clear, context).bind('click.signaturepad', function (e) { e.preventDefault(); clearCanvas() })
463
+
464
+ $(settings.typeIt, context).bind('click.signaturepad', function (e) { e.preventDefault(); typeIt() })
465
+ $(settings.drawIt, context).unbind('click.signaturepad')
466
+ $(settings.drawIt, context).bind('click.signaturepad', function (e) { e.preventDefault() })
467
+
468
+ $(settings.typeIt, context).removeClass(settings.currentClass)
469
+ $(settings.drawIt, context).addClass(settings.currentClass)
470
+ $(settings.sig, context).addClass(settings.currentClass)
471
+
472
+ $(settings.typeItDesc, context).hide()
473
+ $(settings.drawItDesc, context).show()
474
+ $(settings.clear, context).show()
475
+ }
476
+
477
+ /**
478
+ * Triggers the abilities to type in the input for generating a signature
479
+ * Sets up mouse events, hides and shows descriptions and sets current classes
480
+ *
481
+ * @private
482
+ */
483
+ function typeIt () {
484
+ clearCanvas()
485
+ disableCanvas()
486
+ $(settings.typed, context).show()
487
+
488
+ $(settings.drawIt, context).bind('click.signaturepad', function (e) { e.preventDefault(); drawIt() })
489
+ $(settings.typeIt, context).unbind('click.signaturepad')
490
+ $(settings.typeIt, context).bind('click.signaturepad', function (e) { e.preventDefault() })
491
+
492
+ $(settings.output, context).val('')
493
+
494
+ $(settings.drawIt, context).removeClass(settings.currentClass)
495
+ $(settings.typeIt, context).addClass(settings.currentClass)
496
+ $(settings.sig, context).removeClass(settings.currentClass)
497
+
498
+ $(settings.drawItDesc, context).hide()
499
+ $(settings.clear, context).hide()
500
+ $(settings.typeItDesc, context).show()
501
+
502
+ typeItCurrentFontSize = typeItDefaultFontSize = $(settings.typed, context).css('font-size').replace(/px/, '')
503
+ }
504
+
505
+ /**
506
+ * Callback registered on key up and blur events for input field
507
+ * Writes the text fields value as Html into an element
508
+ *
509
+ * @private
510
+ *
511
+ * @param {String} val The value of the input field
512
+ */
513
+ function type (val) {
514
+ var typed = $(settings.typed, context),
515
+ cleanedVal = $.trim(val.replace(/>/g, '&gt;').replace(/</g, '&lt;')),
516
+ oldLength = typeItNumChars,
517
+ edgeOffset = typeItCurrentFontSize * 0.5
518
+
519
+ typeItNumChars = cleanedVal.length
520
+ typed.html(cleanedVal)
521
+
522
+ if (!cleanedVal) {
523
+ typed.css('font-size', typeItDefaultFontSize + 'px')
524
+ return
525
+ }
526
+
527
+ if (typeItNumChars > oldLength && typed.outerWidth() > element.width) {
528
+ while (typed.outerWidth() > element.width) {
529
+ typeItCurrentFontSize--
530
+ typed.css('font-size', typeItCurrentFontSize + 'px')
531
+ }
532
+ }
533
+
534
+ if (typeItNumChars < oldLength && typed.outerWidth() + edgeOffset < element.width && typeItCurrentFontSize < typeItDefaultFontSize) {
535
+ while (typed.outerWidth() + edgeOffset < element.width && typeItCurrentFontSize < typeItDefaultFontSize) {
536
+ typeItCurrentFontSize++
537
+ typed.css('font-size', typeItCurrentFontSize + 'px')
538
+ }
539
+ }
540
+ }
541
+
542
+ /**
543
+ * Default onBeforeValidate function to clear errors
544
+ *
545
+ * @private
546
+ *
547
+ * @param {Object} context current context object
548
+ * @param {Object} settings provided settings
549
+ */
550
+ function onBeforeValidate (context, settings) {
551
+ $('p.' + settings.errorClass, context).remove()
552
+ context.removeClass(settings.errorClass)
553
+ $('input, label', context).removeClass(settings.errorClass)
554
+ }
555
+
556
+ /**
557
+ * Default onFormError function to show errors
558
+ *
559
+ * @private
560
+ *
561
+ * @param {Object} errors object contains validation errors (e.g. nameInvalid=true)
562
+ * @param {Object} context current context object
563
+ * @param {Object} settings provided settings
564
+ */
565
+ function onFormError (errors, context, settings) {
566
+ if (errors.nameInvalid) {
567
+ context.prepend(['<p class="', settings.errorClass, '">', settings.errorMessage, '</p>'].join(''))
568
+ $(settings.name, context).focus()
569
+ $(settings.name, context).addClass(settings.errorClass)
570
+ $('label[for=' + $(settings.name).attr('id') + ']', context).addClass(settings.errorClass)
571
+ }
572
+
573
+ if (errors.drawInvalid)
574
+ context.prepend(['<p class="', settings.errorClass, '">', settings.errorMessageDraw, '</p>'].join(''))
575
+ }
576
+
577
+ /**
578
+ * Validates the form to confirm a name was typed in the field
579
+ * If drawOnly also confirms that the user drew a signature
580
+ *
581
+ * @private
582
+ *
583
+ * @return {Boolean}
584
+ */
585
+ function validateForm () {
586
+ var valid = true,
587
+ errors = {drawInvalid: false, nameInvalid: false},
588
+ onBeforeArguments = [context, settings],
589
+ onErrorArguments = [errors, context, settings]
590
+
591
+ if (settings.onBeforeValidate && typeof settings.onBeforeValidate === 'function') {
592
+ settings.onBeforeValidate.apply(self, onBeforeArguments)
593
+ } else {
594
+ onBeforeValidate.apply(self, onBeforeArguments)
595
+ }
596
+
597
+ if (settings.drawOnly && output.length < 1) {
598
+ errors.drawInvalid = true
599
+ valid = false
600
+ }
601
+
602
+ if ($(settings.name, context).val() === '') {
603
+ errors.nameInvalid = true
604
+ valid = false
605
+ }
606
+
607
+ if (settings.onFormError && typeof settings.onFormError === 'function') {
608
+ settings.onFormError.apply(self, onErrorArguments)
609
+ } else {
610
+ onFormError.apply(self, onErrorArguments)
611
+ }
612
+
613
+ return valid
614
+ }
615
+
616
+ /**
617
+ * Redraws the signature on a specific canvas
618
+ *
619
+ * @private
620
+ *
621
+ * @param {Array} paths the signature JSON
622
+ * @param {Object} context the canvas context to draw on
623
+ * @param {Boolean} saveOutput whether to write the path to the output array or not
624
+ */
625
+ function drawSignature (paths, context, saveOutput) {
626
+ for (var i in paths) {
627
+ if (typeof paths[i] === 'object') {
628
+ context.beginPath()
629
+ context.moveTo(paths[i].mx, paths[i].my)
630
+ context.lineTo(paths[i].lx, paths[i].ly)
631
+ context.lineCap = settings.penCap
632
+ context.stroke()
633
+ context.closePath()
634
+
635
+ if (saveOutput) {
636
+ output.push({
637
+ 'lx': paths[i].lx, 'ly': paths[i].ly, 'mx': paths[i].mx, 'my': paths[i].my
638
+ })
639
+ }
640
+ }
641
+ }
642
+ }
643
+
644
+ /**
645
+ * Initialisation function, called immediately after all declarations
646
+ * Technically public, but only should be used internally
647
+ *
648
+ * @private
649
+ */
650
+ function init () {
651
+ // Fixes the jQuery.fn.offset() function for Mobile Safari Browsers i.e. iPod Touch, iPad and iPhone
652
+ // https://gist.github.com/661844
653
+ // http://bugs.jquery.com/ticket/6446
654
+ if (parseFloat(((/CPU.+OS ([0-9_]{3}).*AppleWebkit.*Mobile/i.exec(navigator.userAgent)) || [0, '4_2'])[1].replace('_', '.')) < 4.1) {
655
+ $.fn.Oldoffset = $.fn.offset
656
+ $.fn.offset = function () {
657
+ var result = $(this).Oldoffset()
658
+ result.top -= window.scrollY
659
+ result.left -= window.scrollX
660
+
661
+ return result
662
+ }
663
+ }
664
+
665
+ // Disable selection on the typed div and canvas
666
+ $(settings.typed, context).bind('selectstart.signaturepad', function (e) { return $(e.target).is(':input') })
667
+ canvas.bind('selectstart.signaturepad', function (e) { return $(e.target).is(':input') })
668
+
669
+ if (!element.getContext && FlashCanvas)
670
+ FlashCanvas.initElement(element)
671
+
672
+ if (element.getContext) {
673
+ canvasContext = element.getContext('2d')
674
+
675
+ $(settings.sig, context).show()
676
+
677
+ if (!settings.displayOnly) {
678
+ if (!settings.drawOnly) {
679
+ $(settings.name, context).bind('keyup.signaturepad', function () {
680
+ type($(this).val())
681
+ })
682
+
683
+ $(settings.name, context).bind('blur.signaturepad', function () {
684
+ type($(this).val())
685
+ })
686
+
687
+ $(settings.drawIt, context).bind('click.signaturepad', function (e) {
688
+ e.preventDefault()
689
+ drawIt()
690
+ })
691
+ }
692
+
693
+ if (settings.drawOnly || settings.defaultAction === 'drawIt') {
694
+ drawIt()
695
+ } else {
696
+ typeIt()
697
+ }
698
+
699
+ if (settings.validateFields) {
700
+ if ($(selector).is('form')) {
701
+ $(selector).bind('submit.signaturepad', function () { return validateForm() })
702
+ } else {
703
+ $(selector).parents('form').bind('submit.signaturepad', function () { return validateForm() })
704
+ }
705
+ }
706
+
707
+ $(settings.sigNav, context).show()
708
+ }
709
+ }
710
+ }
711
+
712
+ $.extend(self, {
713
+ /**
714
+ * A property to store the current version of Signature Pad
715
+ */
716
+ signaturePad: '{{version}}', /**
717
+ * Initializes SignaturePad
718
+ */ init: function () { init() }, /**
719
+ * Allows options to be updated after initialization
720
+ *
721
+ * @param {Object} options An object containing the options to be changed
722
+ */ updateOptions: function (options) {
723
+ $.extend(settings, options)
724
+ }, /**
725
+ * Regenerates a signature on the canvas using an array of objects
726
+ * Follows same format as object property
727
+ * @see var object
728
+ *
729
+ * @param {Array} paths An array of the lines and points
730
+ */ regenerate: function (paths) {
731
+ self.clearCanvas()
732
+ $(settings.typed, context).hide()
733
+
734
+ if (typeof paths === 'string')
735
+ paths = JSON.parse(paths)
736
+
737
+ drawSignature(paths, canvasContext, true)
738
+
739
+ if (settings.output && $(settings.output, context).length > 0)
740
+ $(settings.output, context).val(JSON.stringify(output))
741
+ }, /**
742
+ * Clears the canvas
743
+ * Redraws the background colour and the signature line
744
+ */ clearCanvas: function () { clearCanvas() }, /**
745
+ * Returns the signature as a Js array
746
+ *
747
+ * @return {Array}
748
+ */ getSignature: function () { return output }, /**
749
+ * Returns the signature as a Json string
750
+ *
751
+ * @return {String}
752
+ */ getSignatureString: function () { return JSON.stringify(output) }, /**
753
+ * Returns the signature as an image
754
+ * Re-draws the signature in a shadow canvas to create a clean version
755
+ *
756
+ * @return {String}
757
+ */ getSignatureImage: function () {
758
+ var tmpCanvas = document.createElement('canvas'),
759
+ tmpContext = null,
760
+ data = null
761
+
762
+ tmpCanvas.style.position = 'absolute'
763
+ tmpCanvas.style.top = '-999em'
764
+ tmpCanvas.width = element.width
765
+ tmpCanvas.height = element.height
766
+ document.body.appendChild(tmpCanvas)
767
+
768
+ if (!tmpCanvas.getContext && FlashCanvas)
769
+ FlashCanvas.initElement(tmpCanvas)
770
+
771
+ tmpContext = tmpCanvas.getContext('2d')
772
+
773
+ tmpContext.fillStyle = settings.bgColour
774
+ tmpContext.fillRect(0, 0, element.width, element.height)
775
+ tmpContext.lineWidth = settings.penWidth
776
+ tmpContext.strokeStyle = settings.penColour
777
+
778
+ drawSignature(output, tmpContext)
779
+ data = tmpCanvas.toDataURL.apply(tmpCanvas, arguments)
780
+
781
+ document.body.removeChild(tmpCanvas)
782
+ tmpCanvas = null
783
+
784
+ return data
785
+ }, /**
786
+ * The form validation function
787
+ * Validates that the signature has been filled in properly
788
+ * Allows it to be hooked into another validation function and called at a different time
789
+ *
790
+ * @return {Boolean}
791
+ */ validateForm: function () { return validateForm() }
792
+ })
793
+ }
794
+
795
+ /**
796
+ * Create the plugin
797
+ * Returns an Api which can be used to call specific methods
798
+ *
799
+ * @param {Object} options The options array
800
+ *
801
+ * @return {Object} The Api for controlling the instance
802
+ */
803
+ $.fn.signaturePad = function (options) {
804
+ var api = null
805
+
806
+ this.each(function () {
807
+ if (!$.data(this, 'plugin-signaturePad')) {
808
+ api = new SignaturePad(this, options)
809
+ api.init()
810
+ $.data(this, 'plugin-signaturePad', api)
811
+ } else {
812
+ api = $.data(this, 'plugin-signaturePad')
813
+ api.updateOptions(options)
814
+ }
815
+ })
816
+
817
+ return api
818
+ }
819
+
820
+ /**
821
+ * Expose the defaults so they can be overwritten for multiple instances
822
+ *
823
+ * @type {Object}
824
+ */
825
+ $.fn.signaturePad.defaults = {
826
+ defaultAction: 'typeIt', // What action should be highlighted first: typeIt or drawIt displayOnly: false, // Initialize canvas for signature display only; ignore buttons and inputs drawOnly: false, // Whether the to allow a typed signature or not canvas: 'canvas', // Selector for selecting the canvas element sig: '.sig', // Parts of the signature form that require Javascript (hidden by default) sigNav: '.sigNav', // The TypeIt/DrawIt navigation (hidden by default) bgColour: '#ffffff', // The colour fill for the background of the canvas; or transparent penColour: '#145394', // Colour of the drawing ink penWidth: 2, // Thickness of the pen penCap: 'round', // Determines how the end points of each line are drawn (values: 'butt', 'round', 'square') lineColour: '#ccc', // Colour of the signature line lineWidth: 2, // Thickness of the signature line lineMargin: 5, // Margin on right and left of signature line lineTop: 35, // Distance to draw the line from the top name: '.name', // The input field for typing a name typed: '.typed', // The Html element to accept the printed name clear: '.clearButton', // Button for clearing the canvas typeIt: '.typeIt a', // Button to trigger name typing actions (current by default) drawIt: '.drawIt a', // Button to trigger name drawing actions typeItDesc: '.typeItDesc', // The description for TypeIt actions drawItDesc: '.drawItDesc', // The description for DrawIt actions (hidden by default) output: '.output', // The hidden input field for remembering line coordinates currentClass: 'current', // The class used to mark items as being currently active validateFields: true, // Whether the name, draw fields should be validated errorClass: 'error', // The class applied to the new error Html element errorMessage: 'Please enter your name', // The error message displayed on invalid submission errorMessageDraw: 'Please sign the document', // The error message displayed when drawOnly and no signature is drawn onBeforeValidate: null, // Pass a callback to be used instead of the built-in function onFormError: null, // Pass a callback to be used instead of the built-in function onDraw: null, // Pass a callback to be used to capture the drawing process onDrawEnd: null // Pass a callback to be exectued after the drawing process
827
+ }
828
+ }(jQuery))