john_hancock 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f5a5c2680aba0b53a5f20fdef9c392bab937ff3
4
- data.tar.gz: 948112f9245c0816c45f55ed38db12f1e81b3632
3
+ metadata.gz: e5c86cd0cd56dacbaa94c80c2f621242b064de68
4
+ data.tar.gz: 8ed3c9db346b544dd7f6521e5ca07c4985ccd925
5
5
  SHA512:
6
- metadata.gz: 07c96186acc9a025e686ec8755c3e0b325fa1fffa7680a4c9bc5e6ee5e7c3b22ed45d79104e5ce8d80272c92ecefb1538eace03bd20692b4b491de19cf6e7d7f
7
- data.tar.gz: 163fab1062cda7ce48c7dd32cea0eb442dd15809efddaddfeccfea38486079b051a48e1deeacdc20dfce3ed4f6a4656474949851717035e04d2067ee76926dd7
6
+ metadata.gz: c1d5f61fe79c6eff9f06b1c66a9a9c8053230eac95a1d32546358541c12e515792ae230fa0eacbac03163893623688b02721eed93ba012b15624d406b5433b4e
7
+ data.tar.gz: e545eff5ac35058a39ea8fdeba264df105fd0a69e882b4782e4ec78f38a7e7106041a1ec56add779e9eeb6df830ce63af70b08faf6ceaaff6b56d279d13b02a6
@@ -11,5 +11,16 @@ $( document ).ready(function() {
11
11
  $(parent_form).submit(function(e) {
12
12
  $(hidden_field).val(signaturePad.toDataURL());
13
13
  });
14
+
15
+ function resizeCanvas() {
16
+ var ratio = Math.max(window.devicePixelRatio || 1, 1);
17
+ canvas.width = canvas.offsetWidth * ratio;
18
+ canvas.height = canvas.offsetHeight * ratio;
19
+ canvas.getContext("2d").scale(ratio, ratio);
20
+ signaturePad.clear(); // otherwise isEmpty() might return incorrect value
21
+ }
22
+
23
+ window.addEventListener("resize", resizeCanvas);
24
+ resizeCanvas();
14
25
  }
15
26
  })
@@ -1,352 +1,499 @@
1
- var SignaturePad = (function (document) {
2
- "use strict";
3
-
4
- var SignaturePad = function (canvas, options) {
5
- var self = this,
6
- opts = options || {};
7
-
8
- this.velocityFilterWeight = opts.velocityFilterWeight || 0.7;
9
- this.minWidth = opts.minWidth || 0.5;
10
- this.maxWidth = opts.maxWidth || 2.5;
11
- this.dotSize = opts.dotSize || function () {
12
- return (this.minWidth + this.maxWidth) / 2;
13
- };
14
- this.penColor = opts.penColor || "black";
15
- this.backgroundColor = opts.backgroundColor || "rgba(0,0,0,0)";
16
- this.onEnd = opts.onEnd;
17
- this.onBegin = opts.onBegin;
18
-
19
- this._canvas = canvas;
20
- this._ctx = canvas.getContext("2d");
21
- this.clear();
22
-
23
- // we need add these inline so they are available to unbind while still having
24
- // access to 'self' we could use _.bind but it's not worth adding a dependency
25
- this._handleMouseDown = function (event) {
26
- if (event.which === 1) {
27
- self._mouseButtonDown = true;
28
- self._strokeBegin(event);
29
- }
30
- };
31
-
32
- this._handleMouseMove = function (event) {
33
- if (self._mouseButtonDown) {
34
- self._strokeUpdate(event);
35
- }
36
- };
37
-
38
- this._handleMouseUp = function (event) {
39
- if (event.which === 1 && self._mouseButtonDown) {
40
- self._mouseButtonDown = false;
41
- self._strokeEnd(event);
42
- }
43
- };
44
-
45
- this._handleTouchStart = function (event) {
46
- if (event.targetTouches.length == 1) {
47
- var touch = event.changedTouches[0];
48
- self._strokeBegin(touch);
49
- }
50
- };
51
-
52
- this._handleTouchMove = function (event) {
53
- // Prevent scrolling.
54
- event.preventDefault();
55
-
56
- var touch = event.targetTouches[0];
57
- self._strokeUpdate(touch);
58
- };
59
-
60
- this._handleTouchEnd = function (event) {
61
- var wasCanvasTouched = event.target === self._canvas;
62
- if (wasCanvasTouched) {
63
- event.preventDefault();
64
- self._strokeEnd(event);
65
- }
66
- };
67
-
68
- this._handleMouseEvents();
69
- this._handleTouchEvents();
70
- };
71
-
72
- SignaturePad.prototype.clear = function () {
73
- var ctx = this._ctx,
74
- canvas = this._canvas;
75
-
76
- ctx.fillStyle = this.backgroundColor;
77
- ctx.clearRect(0, 0, canvas.width, canvas.height);
78
- ctx.fillRect(0, 0, canvas.width, canvas.height);
79
- this._reset();
80
- };
81
-
82
- SignaturePad.prototype.toDataURL = function (imageType, quality) {
83
- var canvas = this._canvas;
84
- return canvas.toDataURL.apply(canvas, arguments);
85
- };
86
-
87
- SignaturePad.prototype.fromDataURL = function (dataUrl) {
88
- var self = this,
89
- image = new Image(),
90
- ratio = window.devicePixelRatio || 1,
91
- width = this._canvas.width / ratio,
92
- height = this._canvas.height / ratio;
93
-
94
- this._reset();
95
- image.src = dataUrl;
96
- image.onload = function () {
97
- self._ctx.drawImage(image, 0, 0, width, height);
98
- };
99
- this._isEmpty = false;
100
- };
101
-
102
- SignaturePad.prototype._strokeUpdate = function (event) {
103
- var point = this._createPoint(event);
104
- this._addPoint(point);
105
- };
106
-
107
- SignaturePad.prototype._strokeBegin = function (event) {
108
- this._reset();
109
- this._strokeUpdate(event);
110
- if (typeof this.onBegin === 'function') {
111
- this.onBegin(event);
1
+ function Point(x, y, time) {
2
+ this.x = x;
3
+ this.y = y;
4
+ this.time = time || new Date().getTime();
5
+ }
6
+
7
+ Point.prototype.velocityFrom = function (start) {
8
+ return (this.time !== start.time) ? this.distanceTo(start) / (this.time - start.time) : 1;
9
+ };
10
+
11
+ Point.prototype.distanceTo = function (start) {
12
+ return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
13
+ };
14
+
15
+ function Bezier(startPoint, control1, control2, endPoint) {
16
+ this.startPoint = startPoint;
17
+ this.control1 = control1;
18
+ this.control2 = control2;
19
+ this.endPoint = endPoint;
20
+ }
21
+
22
+ // Returns approximated length.
23
+ Bezier.prototype.length = function () {
24
+ const steps = 10;
25
+ let length = 0;
26
+ let px;
27
+ let py;
28
+
29
+ for (let i = 0; i <= steps; i += 1) {
30
+ const t = i / steps;
31
+ const cx = this._point(
32
+ t,
33
+ this.startPoint.x,
34
+ this.control1.x,
35
+ this.control2.x,
36
+ this.endPoint.x
37
+ );
38
+ const cy = this._point(
39
+ t,
40
+ this.startPoint.y,
41
+ this.control1.y,
42
+ this.control2.y,
43
+ this.endPoint.y
44
+ );
45
+ if (i > 0) {
46
+ const xdiff = cx - px;
47
+ const ydiff = cy - py;
48
+ length += Math.sqrt((xdiff * xdiff) + (ydiff * ydiff));
49
+ }
50
+ px = cx;
51
+ py = cy;
52
+ }
53
+
54
+ return length;
55
+ };
56
+
57
+ /* eslint-disable no-multi-spaces, space-in-parens */
58
+ Bezier.prototype._point = function (t, start, c1, c2, end) {
59
+ return ( start * (1.0 - t) * (1.0 - t) * (1.0 - t))
60
+ + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
61
+ + (3.0 * c2 * (1.0 - t) * t * t)
62
+ + ( end * t * t * t);
63
+ };
64
+ /* eslint-enable no-multi-spaces, space-in-parens */
65
+
66
+ function SignaturePad(canvas, options) {
67
+ const self = this;
68
+ const opts = options || {};
69
+
70
+ this.velocityFilterWeight = opts.velocityFilterWeight || 0.7;
71
+ this.minWidth = opts.minWidth || 0.5;
72
+ this.maxWidth = opts.maxWidth || 2.5;
73
+ this.dotSize = opts.dotSize || function () {
74
+ return (this.minWidth + this.maxWidth) / 2;
75
+ };
76
+ this.penColor = opts.penColor || 'black';
77
+ this.backgroundColor = opts.backgroundColor || 'rgba(0,0,0,0)';
78
+ this.onBegin = opts.onBegin;
79
+ this.onEnd = opts.onEnd;
80
+
81
+ this._canvas = canvas;
82
+ this._ctx = canvas.getContext('2d');
83
+ this.clear();
84
+
85
+ // We need add these inline so they are available to unbind while still having
86
+ // access to 'self' we could use _.bind but it's not worth adding a dependency.
87
+ this._handleMouseDown = function (event) {
88
+ if (event.which === 1) {
89
+ self._mouseButtonDown = true;
90
+ self._strokeBegin(event);
91
+ }
92
+ };
93
+
94
+ this._handleMouseMove = function (event) {
95
+ if (self._mouseButtonDown) {
96
+ self._strokeUpdate(event);
97
+ }
98
+ };
99
+
100
+ this._handleMouseUp = function (event) {
101
+ if (event.which === 1 && self._mouseButtonDown) {
102
+ self._mouseButtonDown = false;
103
+ self._strokeEnd(event);
104
+ }
105
+ };
106
+
107
+ this._handleTouchStart = function (event) {
108
+ if (event.targetTouches.length === 1) {
109
+ const touch = event.changedTouches[0];
110
+ self._strokeBegin(touch);
111
+ }
112
+ };
113
+
114
+ this._handleTouchMove = function (event) {
115
+ // Prevent scrolling.
116
+ event.preventDefault();
117
+
118
+ const touch = event.targetTouches[0];
119
+ self._strokeUpdate(touch);
120
+ };
121
+
122
+ this._handleTouchEnd = function (event) {
123
+ const wasCanvasTouched = event.target === self._canvas;
124
+ if (wasCanvasTouched) {
125
+ event.preventDefault();
126
+ self._strokeEnd(event);
127
+ }
128
+ };
129
+
130
+ // Enable mouse and touch event handlers
131
+ this.on();
132
+ }
133
+
134
+ // Public methods
135
+ SignaturePad.prototype.clear = function () {
136
+ const ctx = this._ctx;
137
+ const canvas = this._canvas;
138
+
139
+ ctx.fillStyle = this.backgroundColor;
140
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
141
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
142
+
143
+ this._data = [];
144
+ this._reset();
145
+ this._isEmpty = true;
146
+ };
147
+
148
+ SignaturePad.prototype.fromDataURL = function (dataUrl) {
149
+ const image = new Image();
150
+ const ratio = window.devicePixelRatio || 1;
151
+ const width = this._canvas.width / ratio;
152
+ const height = this._canvas.height / ratio;
153
+
154
+ this._reset();
155
+ image.src = dataUrl;
156
+ image.onload = () => {
157
+ this._ctx.drawImage(image, 0, 0, width, height);
158
+ };
159
+ this._isEmpty = false;
160
+ };
161
+
162
+ SignaturePad.prototype.toDataURL = function (type, ...options) {
163
+ switch (type) {
164
+ case 'image/svg+xml':
165
+ return this._toSVG();
166
+ default:
167
+ return this._canvas.toDataURL(type, ...options);
168
+ }
169
+ };
170
+
171
+ SignaturePad.prototype.on = function () {
172
+ this._handleMouseEvents();
173
+ this._handleTouchEvents();
174
+ };
175
+
176
+ SignaturePad.prototype.off = function () {
177
+ this._canvas.removeEventListener('mousedown', this._handleMouseDown);
178
+ this._canvas.removeEventListener('mousemove', this._handleMouseMove);
179
+ document.removeEventListener('mouseup', this._handleMouseUp);
180
+
181
+ this._canvas.removeEventListener('touchstart', this._handleTouchStart);
182
+ this._canvas.removeEventListener('touchmove', this._handleTouchMove);
183
+ this._canvas.removeEventListener('touchend', this._handleTouchEnd);
184
+ };
185
+
186
+ SignaturePad.prototype.isEmpty = function () {
187
+ return this._isEmpty;
188
+ };
189
+
190
+ // Private methods
191
+ SignaturePad.prototype._strokeBegin = function (event) {
192
+ this._data.push([]);
193
+ this._reset();
194
+ this._strokeUpdate(event);
195
+
196
+ if (typeof this.onBegin === 'function') {
197
+ this.onBegin(event);
198
+ }
199
+ };
200
+
201
+ SignaturePad.prototype._strokeUpdate = function (event) {
202
+ const x = event.clientX;
203
+ const y = event.clientY;
204
+
205
+ const point = this._createPoint(x, y);
206
+ const { curve, widths } = this._addPoint(point);
207
+
208
+ if (curve && widths) {
209
+ this._drawCurve(curve, widths.start, widths.end);
210
+ }
211
+
212
+ this._data[this._data.length - 1].push({
213
+ x: point.x,
214
+ y: point.y,
215
+ time: point.time,
216
+ });
217
+ };
218
+
219
+ SignaturePad.prototype._strokeEnd = function (event) {
220
+ const canDrawCurve = this.points.length > 2;
221
+ const point = this.points[0];
222
+
223
+ if (!canDrawCurve && point) {
224
+ this._drawDot(point);
225
+ }
226
+
227
+ if (typeof this.onEnd === 'function') {
228
+ this.onEnd(event);
229
+ }
230
+ };
231
+
232
+ SignaturePad.prototype._handleMouseEvents = function () {
233
+ this._mouseButtonDown = false;
234
+
235
+ this._canvas.addEventListener('mousedown', this._handleMouseDown);
236
+ this._canvas.addEventListener('mousemove', this._handleMouseMove);
237
+ document.addEventListener('mouseup', this._handleMouseUp);
238
+ };
239
+
240
+ SignaturePad.prototype._handleTouchEvents = function () {
241
+ // Pass touch events to canvas element on mobile IE11 and Edge.
242
+ this._canvas.style.msTouchAction = 'none';
243
+ this._canvas.style.touchAction = 'none';
244
+
245
+ this._canvas.addEventListener('touchstart', this._handleTouchStart);
246
+ this._canvas.addEventListener('touchmove', this._handleTouchMove);
247
+ this._canvas.addEventListener('touchend', this._handleTouchEnd);
248
+ };
249
+
250
+ SignaturePad.prototype._reset = function () {
251
+ this.points = [];
252
+ this._lastVelocity = 0;
253
+ this._lastWidth = (this.minWidth + this.maxWidth) / 2;
254
+ this._ctx.fillStyle = this.penColor;
255
+ };
256
+
257
+ SignaturePad.prototype._createPoint = function (x, y, time) {
258
+ const rect = this._canvas.getBoundingClientRect();
259
+
260
+ return new Point(
261
+ x - rect.left,
262
+ y - rect.top,
263
+ time || new Date().getTime()
264
+ );
265
+ };
266
+
267
+ SignaturePad.prototype._addPoint = function (point) {
268
+ const points = this.points;
269
+ let tmp;
270
+
271
+ points.push(point);
272
+
273
+ if (points.length > 2) {
274
+ // To reduce the initial lag make it work with 3 points
275
+ // by copying the first point to the beginning.
276
+ if (points.length === 3) points.unshift(points[0]);
277
+
278
+ tmp = this._calculateCurveControlPoints(points[0], points[1], points[2]);
279
+ const c2 = tmp.c2;
280
+ tmp = this._calculateCurveControlPoints(points[1], points[2], points[3]);
281
+ const c3 = tmp.c1;
282
+ const curve = new Bezier(points[1], c2, c3, points[2]);
283
+ const widths = this._calculateCurveWidths(curve);
284
+
285
+ // Remove the first element from the list,
286
+ // so that we always have no more than 4 points in points array.
287
+ points.shift();
288
+
289
+ return { curve, widths };
290
+ }
291
+
292
+ return {};
293
+ };
294
+
295
+ SignaturePad.prototype._calculateCurveControlPoints = function (s1, s2, s3) {
296
+ const dx1 = s1.x - s2.x;
297
+ const dy1 = s1.y - s2.y;
298
+ const dx2 = s2.x - s3.x;
299
+ const dy2 = s2.y - s3.y;
300
+
301
+ const m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
302
+ const m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
303
+
304
+ const l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
305
+ const l2 = Math.sqrt((dx2 * dx2) + (dy2 * dy2));
306
+
307
+ const dxm = (m1.x - m2.x);
308
+ const dym = (m1.y - m2.y);
309
+
310
+ const k = l2 / (l1 + l2);
311
+ const cm = { x: m2.x + (dxm * k), y: m2.y + (dym * k) };
312
+
313
+ const tx = s2.x - cm.x;
314
+ const ty = s2.y - cm.y;
315
+
316
+ return {
317
+ c1: new Point(m1.x + tx, m1.y + ty),
318
+ c2: new Point(m2.x + tx, m2.y + ty),
319
+ };
320
+ };
321
+
322
+ SignaturePad.prototype._calculateCurveWidths = function (curve) {
323
+ const startPoint = curve.startPoint;
324
+ const endPoint = curve.endPoint;
325
+ const widths = { start: null, end: null };
326
+
327
+ const velocity = (this.velocityFilterWeight * endPoint.velocityFrom(startPoint))
328
+ + ((1 - this.velocityFilterWeight) * this._lastVelocity);
329
+
330
+ const newWidth = this._strokeWidth(velocity);
331
+
332
+ widths.start = this._lastWidth;
333
+ widths.end = newWidth;
334
+
335
+ this._lastVelocity = velocity;
336
+ this._lastWidth = newWidth;
337
+
338
+ return widths;
339
+ };
340
+
341
+ SignaturePad.prototype._strokeWidth = function (velocity) {
342
+ return Math.max(this.maxWidth / (velocity + 1), this.minWidth);
343
+ };
344
+
345
+ SignaturePad.prototype._drawPoint = function (x, y, size) {
346
+ const ctx = this._ctx;
347
+
348
+ ctx.moveTo(x, y);
349
+ ctx.arc(x, y, size, 0, 2 * Math.PI, false);
350
+ this._isEmpty = false;
351
+ };
352
+
353
+ SignaturePad.prototype._drawCurve = function (curve, startWidth, endWidth) {
354
+ const ctx = this._ctx;
355
+ const widthDelta = endWidth - startWidth;
356
+ const drawSteps = Math.floor(curve.length());
357
+
358
+ ctx.beginPath();
359
+
360
+ for (let i = 0; i < drawSteps; i += 1) {
361
+ // Calculate the Bezier (x, y) coordinate for this step.
362
+ const t = i / drawSteps;
363
+ const tt = t * t;
364
+ const ttt = tt * t;
365
+ const u = 1 - t;
366
+ const uu = u * u;
367
+ const uuu = uu * u;
368
+
369
+ let x = uuu * curve.startPoint.x;
370
+ x += 3 * uu * t * curve.control1.x;
371
+ x += 3 * u * tt * curve.control2.x;
372
+ x += ttt * curve.endPoint.x;
373
+
374
+ let y = uuu * curve.startPoint.y;
375
+ y += 3 * uu * t * curve.control1.y;
376
+ y += 3 * u * tt * curve.control2.y;
377
+ y += ttt * curve.endPoint.y;
378
+
379
+ const width = startWidth + (ttt * widthDelta);
380
+ this._drawPoint(x, y, width);
381
+ }
382
+
383
+ ctx.closePath();
384
+ ctx.fill();
385
+ };
386
+
387
+ SignaturePad.prototype._drawDot = function (point) {
388
+ const ctx = this._ctx;
389
+ const width = (typeof this.dotSize) === 'function' ? this.dotSize() : this.dotSize;
390
+
391
+ ctx.beginPath();
392
+ this._drawPoint(point.x, point.y, width);
393
+ ctx.closePath();
394
+ ctx.fill();
395
+ };
396
+
397
+ SignaturePad.prototype._fromData = function (pointGroups, drawCurve, drawDot) {
398
+ for (let i = 0; i < pointGroups.length; i += 1) {
399
+ const group = pointGroups[i];
400
+
401
+ if (group.length > 1) {
402
+ for (let j = 0; j < group.length; j += 1) {
403
+ const rawPoint = group[j];
404
+ const point = new Point(rawPoint.x, rawPoint.y, rawPoint.time);
405
+
406
+ if (j === 0) {
407
+ // First point in a group. Nothing to draw yet.
408
+ this._reset();
409
+ this._addPoint(point);
410
+ } else if (j !== group.length - 1) {
411
+ // Middle point in a group.
412
+ const { curve, widths } = this._addPoint(point);
413
+ if (curve && widths) {
414
+ drawCurve(curve, widths);
415
+ }
416
+ } else {
417
+ // Last point in a group. Do nothing.
112
418
  }
113
- };
114
-
115
- SignaturePad.prototype._strokeDraw = function (point) {
116
- var ctx = this._ctx,
117
- dotSize = typeof(this.dotSize) === 'function' ? this.dotSize() : this.dotSize;
118
-
119
- ctx.beginPath();
120
- this._drawPoint(point.x, point.y, dotSize);
121
- ctx.closePath();
122
- ctx.fill();
123
- };
124
-
125
- SignaturePad.prototype._strokeEnd = function (event) {
126
- var canDrawCurve = this.points.length > 2,
127
- point = this.points[0];
128
-
129
- if (!canDrawCurve && point) {
130
- this._strokeDraw(point);
131
- }
132
- if (typeof this.onEnd === 'function') {
133
- this.onEnd(event);
134
- }
135
- };
136
-
137
- SignaturePad.prototype._handleMouseEvents = function () {
138
- this._mouseButtonDown = false;
139
-
140
- this._canvas.addEventListener("mousedown", this._handleMouseDown);
141
- this._canvas.addEventListener("mousemove", this._handleMouseMove);
142
- document.addEventListener("mouseup", this._handleMouseUp);
143
- };
144
-
145
- SignaturePad.prototype._handleTouchEvents = function () {
146
- // Pass touch events to canvas element on mobile IE11 and Edge.
147
- this._canvas.style.msTouchAction = 'none';
148
- this._canvas.style.touchAction = 'none';
149
-
150
- this._canvas.addEventListener("touchstart", this._handleTouchStart);
151
- this._canvas.addEventListener("touchmove", this._handleTouchMove);
152
- this._canvas.addEventListener("touchend", this._handleTouchEnd);
153
- };
154
-
155
- SignaturePad.prototype.on = function () {
156
- this._handleMouseEvents();
157
- this._handleTouchEvents();
158
- };
159
-
160
- SignaturePad.prototype.off = function () {
161
- this._canvas.removeEventListener("mousedown", this._handleMouseDown);
162
- this._canvas.removeEventListener("mousemove", this._handleMouseMove);
163
- document.removeEventListener("mouseup", this._handleMouseUp);
164
-
165
- this._canvas.removeEventListener("touchstart", this._handleTouchStart);
166
- this._canvas.removeEventListener("touchmove", this._handleTouchMove);
167
- this._canvas.removeEventListener("touchend", this._handleTouchEnd);
168
- };
169
-
170
- SignaturePad.prototype.isEmpty = function () {
171
- return this._isEmpty;
172
- };
173
-
174
- SignaturePad.prototype._reset = function () {
175
- this.points = [];
176
- this._lastVelocity = 0;
177
- this._lastWidth = (this.minWidth + this.maxWidth) / 2;
178
- this._isEmpty = true;
179
- this._ctx.fillStyle = this.penColor;
180
- };
181
-
182
- SignaturePad.prototype._createPoint = function (event) {
183
- var rect = this._canvas.getBoundingClientRect();
184
- return new Point(
185
- event.clientX - rect.left,
186
- event.clientY - rect.top
187
- );
188
- };
189
-
190
- SignaturePad.prototype._addPoint = function (point) {
191
- var points = this.points,
192
- c2, c3,
193
- curve, tmp;
194
-
195
- points.push(point);
196
-
197
- if (points.length > 2) {
198
- // To reduce the initial lag make it work with 3 points
199
- // by copying the first point to the beginning.
200
- if (points.length === 3) points.unshift(points[0]);
201
-
202
- tmp = this._calculateCurveControlPoints(points[0], points[1], points[2]);
203
- c2 = tmp.c2;
204
- tmp = this._calculateCurveControlPoints(points[1], points[2], points[3]);
205
- c3 = tmp.c1;
206
- curve = new Bezier(points[1], c2, c3, points[2]);
207
- this._addCurve(curve);
208
-
209
- // Remove the first element from the list,
210
- // so that we always have no more than 4 points in points array.
211
- points.shift();
212
- }
213
- };
214
-
215
- SignaturePad.prototype._calculateCurveControlPoints = function (s1, s2, s3) {
216
- var dx1 = s1.x - s2.x, dy1 = s1.y - s2.y,
217
- dx2 = s2.x - s3.x, dy2 = s2.y - s3.y,
218
-
219
- m1 = {x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0},
220
- m2 = {x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0},
221
-
222
- l1 = Math.sqrt(dx1*dx1 + dy1*dy1),
223
- l2 = Math.sqrt(dx2*dx2 + dy2*dy2),
224
-
225
- dxm = (m1.x - m2.x),
226
- dym = (m1.y - m2.y),
227
-
228
- k = l2 / (l1 + l2),
229
- cm = {x: m2.x + dxm*k, y: m2.y + dym*k},
230
-
231
- tx = s2.x - cm.x,
232
- ty = s2.y - cm.y;
233
-
234
- return {
235
- c1: new Point(m1.x + tx, m1.y + ty),
236
- c2: new Point(m2.x + tx, m2.y + ty)
237
- };
238
- };
239
-
240
- SignaturePad.prototype._addCurve = function (curve) {
241
- var startPoint = curve.startPoint,
242
- endPoint = curve.endPoint,
243
- velocity, newWidth;
244
-
245
- velocity = endPoint.velocityFrom(startPoint);
246
- velocity = this.velocityFilterWeight * velocity
247
- + (1 - this.velocityFilterWeight) * this._lastVelocity;
248
-
249
- newWidth = this._strokeWidth(velocity);
250
- this._drawCurve(curve, this._lastWidth, newWidth);
251
-
252
- this._lastVelocity = velocity;
253
- this._lastWidth = newWidth;
254
- };
255
-
256
- SignaturePad.prototype._drawPoint = function (x, y, size) {
257
- var ctx = this._ctx;
258
-
259
- ctx.moveTo(x, y);
260
- ctx.arc(x, y, size, 0, 2 * Math.PI, false);
261
- this._isEmpty = false;
262
- };
263
-
264
- SignaturePad.prototype._drawCurve = function (curve, startWidth, endWidth) {
265
- var ctx = this._ctx,
266
- widthDelta = endWidth - startWidth,
267
- drawSteps, width, i, t, tt, ttt, u, uu, uuu, x, y;
268
-
269
- drawSteps = Math.floor(curve.length());
270
- ctx.beginPath();
271
- for (i = 0; i < drawSteps; i++) {
272
- // Calculate the Bezier (x, y) coordinate for this step.
273
- t = i / drawSteps;
274
- tt = t * t;
275
- ttt = tt * t;
276
- u = 1 - t;
277
- uu = u * u;
278
- uuu = uu * u;
279
-
280
- x = uuu * curve.startPoint.x;
281
- x += 3 * uu * t * curve.control1.x;
282
- x += 3 * u * tt * curve.control2.x;
283
- x += ttt * curve.endPoint.x;
284
-
285
- y = uuu * curve.startPoint.y;
286
- y += 3 * uu * t * curve.control1.y;
287
- y += 3 * u * tt * curve.control2.y;
288
- y += ttt * curve.endPoint.y;
289
-
290
- width = startWidth + ttt * widthDelta;
291
- this._drawPoint(x, y, width);
292
- }
293
- ctx.closePath();
294
- ctx.fill();
295
- };
296
-
297
- SignaturePad.prototype._strokeWidth = function (velocity) {
298
- return Math.max(this.maxWidth / (velocity + 1), this.minWidth);
299
- };
300
-
301
-
302
- var Point = function (x, y, time) {
303
- this.x = x;
304
- this.y = y;
305
- this.time = time || new Date().getTime();
306
- };
307
-
308
- Point.prototype.velocityFrom = function (start) {
309
- return (this.time !== start.time) ? this.distanceTo(start) / (this.time - start.time) : 1;
310
- };
311
-
312
- Point.prototype.distanceTo = function (start) {
313
- return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
314
- };
315
-
316
- var Bezier = function (startPoint, control1, control2, endPoint) {
317
- this.startPoint = startPoint;
318
- this.control1 = control1;
319
- this.control2 = control2;
320
- this.endPoint = endPoint;
321
- };
322
-
323
- // Returns approximated length.
324
- Bezier.prototype.length = function () {
325
- var steps = 10,
326
- length = 0,
327
- i, t, cx, cy, px, py, xdiff, ydiff;
328
-
329
- for (i = 0; i <= steps; i++) {
330
- t = i / steps;
331
- cx = this._point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
332
- cy = this._point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
333
- if (i > 0) {
334
- xdiff = cx - px;
335
- ydiff = cy - py;
336
- length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
337
- }
338
- px = cx;
339
- py = cy;
340
- }
341
- return length;
342
- };
343
-
344
- Bezier.prototype._point = function (t, start, c1, c2, end) {
345
- return start * (1.0 - t) * (1.0 - t) * (1.0 - t)
346
- + 3.0 * c1 * (1.0 - t) * (1.0 - t) * t
347
- + 3.0 * c2 * (1.0 - t) * t * t
348
- + end * t * t * t;
349
- };
350
-
351
- return SignaturePad;
352
- })(document);
419
+ }
420
+ } else {
421
+ this._reset();
422
+ const rawPoint = group[0];
423
+ drawDot(rawPoint);
424
+ }
425
+ }
426
+ };
427
+
428
+ SignaturePad.prototype._toSVG = function () {
429
+ const pointGroups = this._data;
430
+ const canvas = this._canvas;
431
+ const minX = 0;
432
+ const minY = 0;
433
+ const maxX = canvas.width;
434
+ const maxY = canvas.height;
435
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
436
+
437
+ svg.setAttributeNS(null, 'width', canvas.width);
438
+ svg.setAttributeNS(null, 'height', canvas.height);
439
+
440
+ this._fromData(
441
+ pointGroups,
442
+ (curve, widths) => {
443
+ const path = document.createElementNS('http;//www.w3.org/2000/svg', 'path');
444
+
445
+ // Need to check curve for NaN values, these pop up when drawing
446
+ // lines on the canvas that are not continuous. E.g. Sharp corners
447
+ // or stopping mid-stroke and than continuing without lifting mouse.
448
+ if (!isNaN(curve.control1.x) &&
449
+ !isNaN(curve.control1.y) &&
450
+ !isNaN(curve.control2.x) &&
451
+ !isNaN(curve.control2.y)) {
452
+ const attr = `M ${curve.startPoint.x.toFixed(3)},${curve.startPoint.y.toFixed(3)} `
453
+ + `C ${curve.control1.x.toFixed(3)},${curve.control1.y.toFixed(3)} `
454
+ + `${curve.control2.x.toFixed(3)},${curve.control2.y.toFixed(3)} `
455
+ + `${curve.endPoint.x.toFixed(3)},${curve.endPoint.y.toFixed(3)}`;
456
+
457
+ path.setAttribute('d', attr);
458
+ path.setAttributeNS(null, 'stroke-width', (widths.end * 2.25).toFixed(3));
459
+ path.setAttributeNS(null, 'stroke', this.penColor);
460
+ path.setAttributeNS(null, 'fill', 'none');
461
+ path.setAttributeNS(null, 'stroke-linecap', 'round');
462
+
463
+ svg.appendChild(path);
464
+ }
465
+ },
466
+ (rawPoint) => {
467
+ const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
468
+ const dotSize = (typeof this.dotSize) === 'function' ? this.dotSize() : this.dotSize;
469
+ circle.setAttributeNS(null, 'r', dotSize);
470
+ circle.setAttributeNS(null, 'cx', rawPoint.x);
471
+ circle.setAttributeNS(null, 'cy', rawPoint.y);
472
+ circle.setAttributeNS(null, 'fill', this.penColor);
473
+
474
+ svg.appendChild(circle);
475
+ }
476
+ );
477
+
478
+ const prefix = 'data:image/svg+xml;base64,';
479
+ const header = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="${minX} ${minY} ${maxX} ${maxY}">`;
480
+ const body = svg.innerHTML;
481
+ const footer = '</svg>';
482
+ const data = header + body + footer;
483
+
484
+ return prefix + btoa(data);
485
+ };
486
+
487
+ SignaturePad.prototype.fromData = function (pointGroups) {
488
+ this.clear();
489
+
490
+ this._fromData(
491
+ pointGroups,
492
+ (curve, widths) => this._drawCurve(curve, widths.start, widths.end),
493
+ rawPoint => this._drawDot(rawPoint)
494
+ )
495
+ };
496
+
497
+ SignaturePad.prototype.toData = function () {
498
+ return this._data;
499
+ };
@@ -1,3 +1,3 @@
1
1
  module JohnHancock
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: john_hancock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Lawrence
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-07-05 00:00:00.000000000 Z
12
+ date: 2017-02-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sqlite3