john_hancock 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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