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 +4 -4
- data/app/assets/javascript/john_hancock.js +11 -0
- data/app/assets/javascript/signature_pad.js +498 -351
- data/lib/john_hancock/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5c86cd0cd56dacbaa94c80c2f621242b064de68
|
4
|
+
data.tar.gz: 8ed3c9db346b544dd7f6521e5ca07c4985ccd925
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
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
|
+
};
|
data/lib/john_hancock/version.rb
CHANGED
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.
|
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:
|
12
|
+
date: 2017-02-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sqlite3
|