croppie_rails 0.1.1

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,1038 @@
1
+ /*************************
2
+ * Croppie
3
+ * Copyright 2016
4
+ * Foliotek
5
+ * Version: 2.0.1
6
+ *************************/
7
+ (function (root, factory) {
8
+ if (typeof define === 'function' && define.amd) {
9
+ // AMD. Register as an anonymous module.
10
+ define(['exports'], factory);
11
+ } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
12
+ // CommonJS
13
+ factory(exports);
14
+ } else {
15
+ // Browser globals
16
+ factory((root.commonJsStrict = {}));
17
+ }
18
+ }(this, function (exports) {
19
+
20
+ if (typeof Promise !== 'function') {
21
+ /*! promise-polyfill 3.1.0 */
22
+ !function(a){function b(a,b){return function(){a.apply(b,arguments)}}function c(a){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof a)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],i(a,b(e,this),b(f,this))}function d(a){var b=this;return null===this._state?void this._deferreds.push(a):void k(function(){var c=b._state?a.onFulfilled:a.onRejected;if(null===c)return void(b._state?a.resolve:a.reject)(b._value);var d;try{d=c(b._value)}catch(e){return void a.reject(e)}a.resolve(d)})}function e(a){try{if(a===this)throw new TypeError("A promise cannot be resolved with itself.");if(a&&("object"==typeof a||"function"==typeof a)){var c=a.then;if("function"==typeof c)return void i(b(c,a),b(e,this),b(f,this))}this._state=!0,this._value=a,g.call(this)}catch(d){f.call(this,d)}}function f(a){this._state=!1,this._value=a,g.call(this)}function g(){for(var a=0,b=this._deferreds.length;b>a;a++)d.call(this,this._deferreds[a]);this._deferreds=null}function h(a,b,c,d){this.onFulfilled="function"==typeof a?a:null,this.onRejected="function"==typeof b?b:null,this.resolve=c,this.reject=d}function i(a,b,c){var d=!1;try{a(function(a){d||(d=!0,b(a))},function(a){d||(d=!0,c(a))})}catch(e){if(d)return;d=!0,c(e)}}var j=setTimeout,k="function"==typeof setImmediate&&setImmediate||function(a){j(a,1)},l=Array.isArray||function(a){return"[object Array]"===Object.prototype.toString.call(a)};c.prototype["catch"]=function(a){return this.then(null,a)},c.prototype.then=function(a,b){var e=this;return new c(function(c,f){d.call(e,new h(a,b,c,f))})},c.all=function(){var a=Array.prototype.slice.call(1===arguments.length&&l(arguments[0])?arguments[0]:arguments);return new c(function(b,c){function d(f,g){try{if(g&&("object"==typeof g||"function"==typeof g)){var h=g.then;if("function"==typeof h)return void h.call(g,function(a){d(f,a)},c)}a[f]=g,0===--e&&b(a)}catch(i){c(i)}}if(0===a.length)return b([]);for(var e=a.length,f=0;f<a.length;f++)d(f,a[f])})},c.resolve=function(a){return a&&"object"==typeof a&&a.constructor===c?a:new c(function(b){b(a)})},c.reject=function(a){return new c(function(b,c){c(a)})},c.race=function(a){return new c(function(b,c){for(var d=0,e=a.length;e>d;d++)a[d].then(b,c)})},c._setImmediateFn=function(a){k=a},"undefined"!=typeof module&&module.exports?module.exports=c:a.Promise||(a.Promise=c)}(this);
23
+ }
24
+
25
+ var cssPrefixes = ['Webkit', 'Moz', 'ms'],
26
+ emptyStyles = document.createElement('div').style,
27
+ CSS_TRANS_ORG,
28
+ CSS_TRANSFORM,
29
+ CSS_USERSELECT;
30
+
31
+ function vendorPrefix(prop) {
32
+ if (prop in emptyStyles) {
33
+ return prop;
34
+ }
35
+
36
+ var capProp = prop[0].toUpperCase() + prop.slice(1),
37
+ i = cssPrefixes.length;
38
+
39
+ while (i--) {
40
+ prop = cssPrefixes[i] + capProp;
41
+ if (prop in emptyStyles) {
42
+ return prop;
43
+ }
44
+ }
45
+ }
46
+
47
+ CSS_TRANSFORM = vendorPrefix('transform');
48
+ CSS_TRANS_ORG = vendorPrefix('transformOrigin');
49
+ CSS_USERSELECT = vendorPrefix('userSelect');
50
+
51
+ // Credits to : Andrew Dupont - http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
52
+ function deepExtend(destination, source) {
53
+ destination = destination || {};
54
+ for (var property in source) {
55
+ if (source[property] && source[property].constructor && source[property].constructor === Object) {
56
+ destination[property] = destination[property] || {};
57
+ arguments.callee(destination[property], source[property]);
58
+ } else {
59
+ destination[property] = source[property];
60
+ }
61
+ }
62
+ return destination;
63
+ }
64
+
65
+ function debounce(func, wait, immediate) {
66
+ var timeout;
67
+ return function () {
68
+ var context = this, args = arguments;
69
+ var later = function () {
70
+ timeout = null;
71
+ if (!immediate) func.apply(context, args);
72
+ };
73
+ var callNow = immediate && !timeout;
74
+ clearTimeout(timeout);
75
+ timeout = setTimeout(later, wait);
76
+ if (callNow) func.apply(context, args);
77
+ };
78
+ }
79
+
80
+ function dispatchChange(element) {
81
+ if ("createEvent" in document) {
82
+ var evt = document.createEvent("HTMLEvents");
83
+ evt.initEvent("change", false, true);
84
+ element.dispatchEvent(evt);
85
+ }
86
+ else {
87
+ element.fireEvent("onchange");
88
+ }
89
+ }
90
+
91
+ //http://jsperf.com/vanilla-css
92
+ function css(el, styles, val) {
93
+ if (typeof (styles) === 'string') {
94
+ var tmp = styles;
95
+ styles = {};
96
+ styles[tmp] = val;
97
+ }
98
+
99
+ for (var prop in styles) {
100
+ el.style[prop] = styles[prop];
101
+ }
102
+ }
103
+
104
+ function addClass(el, c) {
105
+ if (el.classList) {
106
+ el.classList.add(c);
107
+ }
108
+ else {
109
+ el.className += ' ' + c;
110
+ }
111
+ }
112
+
113
+ function removeClass(el, c) {
114
+ if (el.classList) {
115
+ el.classList.remove(c);
116
+ }
117
+ else {
118
+ el.className = el.className.replace(c, '');
119
+ }
120
+ }
121
+
122
+ /* Utilities */
123
+ function loadImage(src, imageEl) {
124
+ var img = imageEl || new Image(),
125
+ prom;
126
+
127
+ prom = new Promise(function (resolve, reject) {
128
+ if (src.substring(0,4).toLowerCase() === 'http') {
129
+ img.setAttribute('crossOrigin', 'anonymous');
130
+ }
131
+ img.onload = function () {
132
+ setTimeout(function () {
133
+ resolve(img);
134
+ }, 1);
135
+ };
136
+ });
137
+
138
+ img.style.opacity = 0;
139
+ img.src = src;
140
+ return prom;
141
+ }
142
+
143
+ /* CSS Transform Prototype */
144
+ var _TRANSLATE = 'translate3d',
145
+ _TRANSLATE_SUFFIX = ', 0px';
146
+ var Transform = function (x, y, scale) {
147
+ this.x = parseFloat(x);
148
+ this.y = parseFloat(y);
149
+ this.scale = parseFloat(scale);
150
+ };
151
+
152
+ Transform.parse = function (v) {
153
+ if (v.style) {
154
+ return Transform.parse(v.style[CSS_TRANSFORM]);
155
+ }
156
+ else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) {
157
+ return Transform.fromMatrix(v);
158
+ }
159
+ else {
160
+ return Transform.fromString(v);
161
+ }
162
+ };
163
+
164
+ Transform.fromMatrix = function (v) {
165
+ var vals = v.substring(7).split(',');
166
+ if (!vals.length || v === 'none') {
167
+ vals = [1, 0, 0, 1, 0, 0];
168
+ }
169
+
170
+ return new Transform(parseInt(vals[4], 10), parseInt(vals[5], 10), parseFloat(vals[0]));
171
+ };
172
+
173
+ Transform.fromString = function (v) {
174
+ var values = v.split(') '),
175
+ translate = values[0].substring(_TRANSLATE.length + 1).split(','),
176
+ scale = values.length > 1 ? values[1].substring(6) : 1,
177
+ x = translate.length > 1 ? translate[0] : 0,
178
+ y = translate.length > 1 ? translate[1] : 0;
179
+
180
+ return new Transform(x, y, scale);
181
+ };
182
+
183
+ Transform.prototype.toString = function () {
184
+ return _TRANSLATE + '(' + this.x + 'px, ' + this.y + 'px' + _TRANSLATE_SUFFIX + ') scale(' + this.scale + ')';
185
+ };
186
+
187
+ var TransformOrigin = function (el) {
188
+ if (!el || !el.style[CSS_TRANS_ORG]) {
189
+ this.x = 0;
190
+ this.y = 0;
191
+ return;
192
+ }
193
+ var css = el.style[CSS_TRANS_ORG].split(' ');
194
+ this.x = parseFloat(css[0]);
195
+ this.y = parseFloat(css[1]);
196
+ };
197
+
198
+ TransformOrigin.prototype.toString = function () {
199
+ return this.x + 'px ' + this.y + 'px';
200
+ };
201
+
202
+ function getExifOrientation (img, cb) {
203
+ if (!window.EXIF) {
204
+ cb(0);
205
+ }
206
+
207
+ EXIF.getData(img, function () {
208
+ var orientation = EXIF.getTag(this, 'Orientation');
209
+ cb(orientation);
210
+ });
211
+ }
212
+
213
+ function rotateCanvas(canvas, ctx, img, orientation) {
214
+ var width = img.width,
215
+ height = img.height;
216
+
217
+ canvas.width = img.width;
218
+ canvas.height = img.height;
219
+
220
+ ctx.save();
221
+ switch (orientation) {
222
+ case 2:
223
+ ctx.translate(width, 0);
224
+ ctx.scale(-1, 1);
225
+ break;
226
+
227
+ case 3:
228
+ ctx.translate(width, height);
229
+ ctx.rotate(180*Math.PI/180);
230
+ break;
231
+
232
+ case 4:
233
+ ctx.translate(0, height);
234
+ ctx.scale(1, -1);
235
+ break;
236
+
237
+ case 5:
238
+ canvas.width = height;
239
+ canvas.height = width;
240
+ ctx.rotate(90*Math.PI/180);
241
+ ctx.scale(1, -1);
242
+ break;
243
+
244
+ case 6:
245
+ canvas.width = height;
246
+ canvas.height = width;
247
+ ctx.rotate(90*Math.PI/180);
248
+ ctx.translate(0, -height);
249
+ break;
250
+
251
+ case 7:
252
+ canvas.width = height;
253
+ canvas.height = width;
254
+ ctx.rotate(-90*Math.PI/180);
255
+ ctx.translate(-width, height);
256
+ ctx.scale(1, -1);
257
+ break;
258
+
259
+ case 8:
260
+ canvas.width = height;
261
+ canvas.height = width;
262
+ ctx.translate(0, width);
263
+ ctx.rotate(-90*Math.PI/180);
264
+ break;
265
+ }
266
+ ctx.drawImage(img, 0,0, width, height);
267
+ ctx.restore();
268
+ }
269
+
270
+ /* Private Methods */
271
+ function _create() {
272
+ var self = this,
273
+ contClass = 'croppie-container',
274
+ customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null,
275
+ boundary, img, viewport, overlay, canvas;
276
+
277
+ self.options.useCanvas = self.options.exif && window.EXIF;
278
+ // Properties on class
279
+ self.data = {};
280
+ self.elements = {};
281
+
282
+ // Generating Markup
283
+ boundary = self.elements.boundary = document.createElement('div');
284
+ viewport = self.elements.viewport = document.createElement('div');
285
+ img = self.elements.img = document.createElement('img');
286
+ overlay = self.elements.overlay = document.createElement('div');
287
+
288
+ if (self.options.useCanvas) {
289
+ self.elements.canvas = document.createElement('canvas');
290
+ self.elements.preview = self.elements.canvas;
291
+ }
292
+ else {
293
+ self.elements.preview = self.elements.img;
294
+ }
295
+
296
+ addClass(boundary, 'cr-boundary');
297
+ css(boundary, {
298
+ width: self.options.boundary.width + 'px',
299
+ height: self.options.boundary.height + 'px'
300
+ });
301
+
302
+ addClass(viewport, 'cr-viewport');
303
+ if (customViewportClass) {
304
+ addClass(viewport, customViewportClass);
305
+ }
306
+ css(viewport, {
307
+ width: self.options.viewport.width + 'px',
308
+ height: self.options.viewport.height + 'px'
309
+ });
310
+
311
+ addClass(self.elements.preview, 'cr-image');
312
+ addClass(overlay, 'cr-overlay');
313
+
314
+ self.element.appendChild(boundary);
315
+ boundary.appendChild(self.elements.preview);
316
+ boundary.appendChild(viewport);
317
+ boundary.appendChild(overlay);
318
+
319
+ addClass(self.element, contClass);
320
+ if (self.options.customClass) {
321
+ addClass(self.element, self.options.customClass);
322
+ }
323
+
324
+ // Initialize drag & zoom
325
+ _initDraggable.call(this);
326
+
327
+ if (self.options.enableZoom) {
328
+ _initializeZoom.call(self);
329
+ }
330
+ }
331
+
332
+ function _setZoomerVal(v) {
333
+ if (this.options.enableZoom) {
334
+ this.elements.zoomer.value = fix(v, 4);
335
+ }
336
+ }
337
+
338
+ function _initializeZoom() {
339
+ var self = this,
340
+ wrap = self.elements.zoomerWrap = document.createElement('div'),
341
+ zoomer = self.elements.zoomer = document.createElement('input'),
342
+ origin,
343
+ viewportRect,
344
+ transform;
345
+
346
+ addClass(wrap, 'cr-slider-wrap');
347
+ addClass(zoomer, 'cr-slider');
348
+ zoomer.type = 'range';
349
+ zoomer.step = '0.01';
350
+ zoomer.value = 1;
351
+ zoomer.style.display = self.options.showZoomer ? '' : 'none';
352
+
353
+ self.element.appendChild(wrap);
354
+ wrap.appendChild(zoomer);
355
+
356
+ self._currentZoom = 1;
357
+ function start() {
358
+ _updateCenterPoint.call(self);
359
+ origin = new TransformOrigin(self.elements.preview);
360
+ viewportRect = self.elements.viewport.getBoundingClientRect();
361
+ transform = Transform.parse(self.elements.preview);
362
+ }
363
+
364
+ function change() {
365
+ _onZoom.call(self, {
366
+ value: parseFloat(zoomer.value),
367
+ origin: origin || new TransformOrigin(self.elements.preview),
368
+ viewportRect: viewportRect || self.elements.viewport.getBoundingClientRect(),
369
+ transform: transform || Transform.parse(self.elements.preview)
370
+ });
371
+ }
372
+
373
+ function scroll(ev) {
374
+ var delta, targetZoom;
375
+
376
+ if (ev.wheelDelta) {
377
+ delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2
378
+ } else if (ev.deltaY) {
379
+ delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2
380
+ } else if (ev.detail) {
381
+ delta = ev.detail / 60; //delta min: -3 max: 3 // max x 10 x 2
382
+ } else {
383
+ delta = 0;
384
+ }
385
+
386
+ targetZoom = self._currentZoom + delta;
387
+
388
+ ev.preventDefault();
389
+ start();
390
+ _setZoomerVal.call(self, targetZoom);
391
+ change();
392
+ }
393
+
394
+ self.elements.zoomer.addEventListener('mousedown', start);
395
+ self.elements.zoomer.addEventListener('touchstart', start);
396
+
397
+ self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress
398
+ self.elements.zoomer.addEventListener('change', change);
399
+
400
+ if (self.options.mouseWheelZoom) {
401
+ self.elements.boundary.addEventListener('mousewheel', scroll);
402
+ self.elements.boundary.addEventListener('DOMMouseScroll', scroll);
403
+ }
404
+ }
405
+
406
+ function _onZoom(ui) {
407
+ var self = this,
408
+ transform = ui.transform,
409
+ vpRect = ui.viewportRect,
410
+ origin = ui.origin;
411
+
412
+ self._currentZoom = ui.value;
413
+ transform.scale = self._currentZoom;
414
+
415
+ var boundaries = _getVirtualBoundaries.call(self, vpRect),
416
+ transBoundaries = boundaries.translate,
417
+ oBoundaries = boundaries.origin;
418
+
419
+ if (transform.x >= transBoundaries.maxX) {
420
+ origin.x = oBoundaries.minX;
421
+ transform.x = transBoundaries.maxX;
422
+ }
423
+
424
+ if (transform.x <= transBoundaries.minX) {
425
+ origin.x = oBoundaries.maxX;
426
+ transform.x = transBoundaries.minX;
427
+ }
428
+
429
+ if (transform.y >= transBoundaries.maxY) {
430
+ origin.y = oBoundaries.minY;
431
+ transform.y = transBoundaries.maxY;
432
+ }
433
+
434
+ if (transform.y <= transBoundaries.minY) {
435
+ origin.y = oBoundaries.maxY;
436
+ transform.y = transBoundaries.minY;
437
+ }
438
+
439
+ var transCss = {};
440
+ transCss[CSS_TRANSFORM] = transform.toString();
441
+ transCss[CSS_TRANS_ORG] = origin.toString();
442
+ css(self.elements.preview, transCss);
443
+
444
+ _debouncedOverlay.call(self);
445
+ _triggerUpdate.call(self);
446
+ }
447
+
448
+ function _getVirtualBoundaries(viewport) {
449
+ var self = this,
450
+ scale = self._currentZoom,
451
+ vpWidth = viewport.width,
452
+ vpHeight = viewport.height,
453
+ centerFromBoundaryX = self.options.boundary.width / 2,
454
+ centerFromBoundaryY = self.options.boundary.height / 2,
455
+ originalImgWidth = self._originalImageWidth,
456
+ originalImgHeight = self._originalImageHeight,
457
+ curImgWidth = originalImgWidth * scale,
458
+ curImgHeight = originalImgHeight * scale,
459
+ halfWidth = vpWidth / 2,
460
+ halfHeight = vpHeight / 2;
461
+
462
+
463
+ var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1;
464
+ var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale)));
465
+
466
+ var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1;
467
+ var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale)));
468
+
469
+ var originMinX = (1 / scale) * halfWidth;
470
+ var originMaxX = (curImgWidth * (1 / scale)) - originMinX;
471
+
472
+ var originMinY = (1 / scale) * halfHeight;
473
+ var originMaxY = (curImgHeight * (1 / scale)) - originMinY;
474
+
475
+ return {
476
+ translate: {
477
+ maxX: maxX,
478
+ minX: minX,
479
+ maxY: maxY,
480
+ minY: minY
481
+ },
482
+ origin: {
483
+ maxX: originMaxX,
484
+ minX: originMinX,
485
+ maxY: originMaxY,
486
+ minY: originMinY
487
+ }
488
+ };
489
+ }
490
+
491
+ function _updateCenterPoint() {
492
+ var self = this,
493
+ scale = self._currentZoom,
494
+ data = self.elements.preview.getBoundingClientRect(),
495
+ vpData = self.elements.viewport.getBoundingClientRect(),
496
+ transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]),
497
+ pc = new TransformOrigin(self.elements.preview),
498
+ top = (vpData.top - data.top) + (vpData.height / 2),
499
+ left = (vpData.left - data.left) + (vpData.width / 2),
500
+ center = {},
501
+ adj = {};
502
+
503
+ center.y = top / scale;
504
+ center.x = left / scale;
505
+
506
+ adj.y = (center.y - pc.y) * (1 - scale);
507
+ adj.x = (center.x - pc.x) * (1 - scale);
508
+
509
+ transform.x -= adj.x;
510
+ transform.y -= adj.y;
511
+
512
+ var newCss = {};
513
+ newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px';
514
+ newCss[CSS_TRANSFORM] = transform.toString();
515
+ css(self.elements.preview, newCss);
516
+ }
517
+
518
+ function _initDraggable() {
519
+ var self = this,
520
+ isDragging = false,
521
+ originalX,
522
+ originalY,
523
+ originalDistance,
524
+ vpRect;
525
+
526
+ function mouseDown(ev) {
527
+ ev.preventDefault();
528
+ if (isDragging) return;
529
+ isDragging = true;
530
+ originalX = ev.pageX;
531
+ originalY = ev.pageY;
532
+
533
+ if (ev.touches) {
534
+ var touches = ev.touches[0];
535
+ originalX = touches.pageX;
536
+ originalY = touches.pageY;
537
+ }
538
+
539
+ transform = Transform.parse(self.elements.preview);
540
+ window.addEventListener('mousemove', mouseMove);
541
+ window.addEventListener('touchmove', mouseMove);
542
+ window.addEventListener('mouseup', mouseUp);
543
+ window.addEventListener('touchend', mouseUp);
544
+ document.body.style[CSS_USERSELECT] = 'none';
545
+ vpRect = self.elements.viewport.getBoundingClientRect();
546
+ }
547
+
548
+ function mouseMove(ev) {
549
+ ev.preventDefault();
550
+ var pageX = ev.pageX,
551
+ pageY = ev.pageY;
552
+
553
+ if (ev.touches) {
554
+ var touches = ev.touches[0];
555
+ pageX = touches.pageX;
556
+ pageY = touches.pageY;
557
+ }
558
+
559
+ var deltaX = pageX - originalX,
560
+ deltaY = pageY - originalY,
561
+ imgRect = self.elements.preview.getBoundingClientRect(),
562
+ top = transform.y + deltaY,
563
+ left = transform.x + deltaX,
564
+ newCss = {};
565
+
566
+ if (ev.type == 'touchmove') {
567
+ if (ev.touches.length > 1) {
568
+ var touch1 = ev.touches[0];
569
+ var touch2 = ev.touches[1];
570
+ var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY));
571
+
572
+ if (!originalDistance) {
573
+ originalDistance = dist / self._currentZoom;
574
+ }
575
+
576
+ var scale = dist / originalDistance;
577
+
578
+ _setZoomerVal.call(self, scale);
579
+ dispatchChange(self.elements.zoomer);
580
+ return;
581
+ }
582
+ }
583
+
584
+ if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) {
585
+ transform.y = top;
586
+ }
587
+
588
+ if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) {
589
+ transform.x = left;
590
+ }
591
+
592
+ newCss[CSS_TRANSFORM] = transform.toString();
593
+ css(self.elements.preview, newCss);
594
+ _updateOverlay.call(self);
595
+ originalY = pageY;
596
+ originalX = pageX;
597
+ }
598
+
599
+ function mouseUp() {
600
+ isDragging = false;
601
+ window.removeEventListener('mousemove', mouseMove);
602
+ window.removeEventListener('touchmove', mouseMove);
603
+ window.removeEventListener('mouseup', mouseUp);
604
+ window.removeEventListener('touchend', mouseUp);
605
+ document.body.style[CSS_USERSELECT] = '';
606
+ _updateCenterPoint.call(self);
607
+ _triggerUpdate.call(self);
608
+ originalDistance = 0;
609
+ }
610
+
611
+ self.elements.overlay.addEventListener('mousedown', mouseDown);
612
+ self.elements.overlay.addEventListener('touchstart', mouseDown);
613
+ }
614
+
615
+ function _updateOverlay() {
616
+ var self = this,
617
+ boundRect = self.elements.boundary.getBoundingClientRect(),
618
+ imgData = self.elements.preview.getBoundingClientRect();
619
+
620
+ css(self.elements.overlay, {
621
+ width: imgData.width + 'px',
622
+ height: imgData.height + 'px',
623
+ top: (imgData.top - boundRect.top) + 'px',
624
+ left: (imgData.left - boundRect.left) + 'px'
625
+ });
626
+ }
627
+ var _debouncedOverlay = debounce(_updateOverlay, 500);
628
+
629
+ function _triggerUpdate() {
630
+ var self = this;
631
+ if (_isVisible.call(self)) {
632
+ self.options.update.call(self, self.get());
633
+ }
634
+ }
635
+
636
+ function _isVisible() {
637
+ return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0;
638
+ }
639
+
640
+ function _updatePropertiesFromImage() {
641
+ var self = this,
642
+ minZoom = 0,
643
+ maxZoom = 1.5,
644
+ initialZoom = 1,
645
+ cssReset = {},
646
+ img = self.elements.preview,
647
+ zoomer = self.elements.zoomer,
648
+ transformReset = new Transform(0, 0, initialZoom),
649
+ originReset = new TransformOrigin(),
650
+ isVisible = _isVisible.call(self),
651
+ imgData,
652
+ vpData,
653
+ boundaryData,
654
+ minW,
655
+ minH;
656
+
657
+ if (!isVisible || self.data.bound) {
658
+ // if the croppie isn't visible or it doesn't need binding
659
+ return;
660
+ }
661
+
662
+ self.data.bound = true;
663
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
664
+ cssReset[CSS_TRANS_ORG] = originReset.toString();
665
+ cssReset['opacity'] = 1;
666
+ css(img, cssReset);
667
+
668
+ imgData = img.getBoundingClientRect();
669
+ vpData = self.elements.viewport.getBoundingClientRect();
670
+ boundaryData = self.elements.boundary.getBoundingClientRect();
671
+ self._originalImageWidth = imgData.width;
672
+ self._originalImageHeight = imgData.height;
673
+
674
+ if (self.options.enableZoom) {
675
+ minW = vpData.width / imgData.width;
676
+ minH = vpData.height / imgData.height;
677
+ minZoom = Math.max(minW, minH);
678
+
679
+ if (minZoom >= maxZoom) {
680
+ maxZoom = minZoom + 1;
681
+ }
682
+
683
+ zoomer.min = fix(minZoom, 4);
684
+ zoomer.max = fix(maxZoom, 4);
685
+ initialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height));
686
+ _setZoomerVal.call(self, initialZoom);
687
+ dispatchChange(zoomer);
688
+ }
689
+
690
+ self._currentZoom = transformReset.scale = initialZoom;
691
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
692
+ css(img, cssReset);
693
+
694
+ if (self.data.points.length) {
695
+ _bindPoints.call(self, self.data.points);
696
+ }
697
+ else {
698
+ _centerImage.call(self);
699
+ }
700
+
701
+
702
+ _updateOverlay.call(self);
703
+ }
704
+
705
+ function _bindPoints(points) {
706
+ if (points.length != 4) {
707
+ throw "Croppie - Invalid number of points supplied: " + points;
708
+ }
709
+ var self = this,
710
+ pointsWidth = points[2] - points[0],
711
+ // pointsHeight = points[3] - points[1],
712
+ vpData = self.elements.viewport.getBoundingClientRect(),
713
+ boundRect = self.elements.boundary.getBoundingClientRect(),
714
+ vpOffset = {
715
+ left: vpData.left - boundRect.left,
716
+ top: vpData.top - boundRect.top
717
+ },
718
+ scale = vpData.width / pointsWidth,
719
+ originTop = points[1],
720
+ originLeft = points[0],
721
+ transformTop = (-1 * points[1]) + vpOffset.top,
722
+ transformLeft = (-1 * points[0]) + vpOffset.left,
723
+ newCss = {};
724
+
725
+ newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px';
726
+ newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString();
727
+ css(self.elements.preview, newCss);
728
+
729
+ _setZoomerVal.call(self, scale);
730
+ self._currentZoom = scale;
731
+ }
732
+
733
+ function _centerImage() {
734
+ var self = this,
735
+ imgDim = self.elements.preview.getBoundingClientRect(),
736
+ vpDim = self.elements.viewport.getBoundingClientRect(),
737
+ boundDim = self.elements.boundary.getBoundingClientRect(),
738
+ vpLeft = vpDim.left - boundDim.left,
739
+ vpTop = vpDim.top - boundDim.top,
740
+ w = vpLeft - ((imgDim.width - vpDim.width) / 2),
741
+ h = vpTop - ((imgDim.height - vpDim.height) / 2),
742
+ transform = new Transform(w, h, self._currentZoom);
743
+
744
+ css(self.elements.preview, CSS_TRANSFORM, transform.toString());
745
+ }
746
+
747
+ function _transferImageToCanvas() {
748
+ var self = this,
749
+ canvas = self.elements.canvas,
750
+ img = self.elements.img,
751
+ ctx = canvas.getContext('2d');
752
+
753
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
754
+ canvas.width = img.width;
755
+ canvas.height = img.height;
756
+
757
+ getExifOrientation(img, function (orientation) {
758
+ rotateCanvas(canvas, ctx, img, parseInt(orientation));
759
+ });
760
+ }
761
+
762
+ function _getHtmlResult(data) {
763
+ var points = data.points,
764
+ div = document.createElement('div'),
765
+ img = document.createElement('img'),
766
+ width = points[2] - points[0],
767
+ height = points[3] - points[1];
768
+
769
+ addClass(div, 'croppie-result');
770
+ div.appendChild(img);
771
+ css(img, {
772
+ left: (-1 * points[0]) + 'px',
773
+ top: (-1 * points[1]) + 'px'
774
+ });
775
+ img.src = data.url;
776
+ css(div, {
777
+ width: width + 'px',
778
+ height: height + 'px'
779
+ });
780
+
781
+ return div;
782
+ }
783
+
784
+ function _getCanvasResult(img, data) {
785
+ var points = data.points,
786
+ left = points[0],
787
+ top = points[1],
788
+ width = (points[2] - points[0]),
789
+ height = (points[3] - points[1]),
790
+ circle = data.circle,
791
+ canvas = document.createElement('canvas'),
792
+ ctx = canvas.getContext('2d'),
793
+ outWidth = width,
794
+ outHeight = height;
795
+
796
+ if (data.outputWidth && data.outputHeight) {
797
+ outWidth = data.outputWidth;
798
+ outHeight = data.outputHeight;
799
+ }
800
+
801
+ canvas.width = outWidth;
802
+ canvas.height = outHeight;
803
+
804
+ ctx.drawImage(img, left, top, width, height, 0, 0, outWidth, outHeight);
805
+ if (circle) {
806
+ ctx.fillStyle = '#fff';
807
+ ctx.globalCompositeOperation = 'destination-in';
808
+ ctx.beginPath();
809
+ ctx.arc(outWidth / 2, outHeight / 2, outWidth / 2, 0, Math.PI * 2, true);
810
+ ctx.closePath();
811
+ ctx.fill();
812
+ }
813
+ return canvas.toDataURL(data.format, data.quality);
814
+ }
815
+
816
+ function _bind(options, cb) {
817
+ var self = this,
818
+ url,
819
+ points = [];
820
+
821
+ if (typeof (options) === 'string') {
822
+ url = options;
823
+ options = {};
824
+ }
825
+ else if (Array.isArray(options)) {
826
+ points = options.slice();
827
+ }
828
+ else if (typeof (options) == 'undefined' && self.data.url) { //refreshing
829
+ _updatePropertiesFromImage.call(self);
830
+ _triggerUpdate.call(self);
831
+ return null;
832
+ }
833
+ else {
834
+ url = options.url;
835
+ points = options.points || [];
836
+ }
837
+
838
+ self.data.bound = false;
839
+ self.data.url = url || self.data.url;
840
+ self.data.points = (points || self.data.points).map(function (p) {
841
+ return parseFloat(p);
842
+ });
843
+ var prom = loadImage(url, self.elements.img);
844
+ prom.then(function () {
845
+ if (self.options.useCanvas) {
846
+ self.elements.img.exifdata = null;
847
+ _transferImageToCanvas.call(self);
848
+ }
849
+ _updatePropertiesFromImage.call(self);
850
+ _triggerUpdate.call(self);
851
+ if (cb) {
852
+ cb();
853
+ }
854
+ });
855
+ return prom;
856
+ }
857
+
858
+ function fix(v, decimalPoints) {
859
+ return parseFloat(v).toFixed(decimalPoints || 0);
860
+ }
861
+
862
+ function _get() {
863
+ var self = this,
864
+ imgData = self.elements.preview.getBoundingClientRect(),
865
+ vpData = self.elements.viewport.getBoundingClientRect(),
866
+ x1 = vpData.left - imgData.left,
867
+ y1 = vpData.top - imgData.top,
868
+ x2 = x1 + vpData.width,
869
+ y2 = y1 + vpData.height,
870
+ scale = self._currentZoom;
871
+
872
+ if (scale === Infinity || isNaN(scale)) {
873
+ scale = 1;
874
+ }
875
+
876
+ x1 = Math.max(0, x1 / scale);
877
+ y1 = Math.max(0, y1 / scale);
878
+ x2 = Math.max(0, x2 / scale);
879
+ y2 = Math.max(0, y2 / scale);
880
+
881
+ return {
882
+ points: [fix(x1), fix(y1), fix(x2), fix(y2)],
883
+ zoom: scale
884
+ };
885
+ }
886
+
887
+ var RESULT_DEFAULTS = {
888
+ type: 'canvas',
889
+ size: 'viewport',
890
+ format: 'png',
891
+ quality: 1
892
+ },
893
+ RESULT_FORMATS = ['jpeg', 'webp', 'png'];
894
+
895
+ function _result(options) {
896
+ var self = this,
897
+ data = _get.call(self),
898
+ opts = deepExtend(RESULT_DEFAULTS, deepExtend({}, options)),
899
+ type = (typeof (options) === 'string' ? options : opts.type),
900
+ size = opts.size,
901
+ format = opts.format,
902
+ quality = opts.quality,
903
+ vpRect,
904
+ prom;
905
+
906
+ if (size === 'viewport') {
907
+ vpRect = self.elements.viewport.getBoundingClientRect();
908
+ data.outputWidth = vpRect.width;
909
+ data.outputHeight = vpRect.height;
910
+ }
911
+
912
+ if (RESULT_FORMATS.indexOf(format) > -1) {
913
+ data.format = 'image/' + format;
914
+ data.quality = quality;
915
+ }
916
+
917
+ data.circle = self.options.viewport.type === 'circle';
918
+ data.url = self.data.url;
919
+
920
+ prom = new Promise(function (resolve, reject) {
921
+ if (type === 'canvas') {
922
+ resolve(_getCanvasResult.call(self, self.elements.preview, data));
923
+ }
924
+ else {
925
+ resolve(_getHtmlResult.call(self, data));
926
+ }
927
+ });
928
+ return prom;
929
+ }
930
+
931
+ function _refresh() {
932
+ _updatePropertiesFromImage.call(this);
933
+ }
934
+
935
+ function _destroy() {
936
+ var self = this;
937
+ self.element.removeChild(self.elements.boundary);
938
+ removeClass(self.element, 'croppie-container');
939
+ if (self.options.enableZoom) {
940
+ self.element.removeChild(self.elements.zoomerWrap);
941
+ }
942
+ delete self.elements;
943
+ }
944
+
945
+ if (this.jQuery) {
946
+ var $ = this.jQuery;
947
+ $.fn.croppie = function (opts) {
948
+ var ot = typeof opts;
949
+
950
+ if (ot === 'string') {
951
+ var args = Array.prototype.slice.call(arguments, 1);
952
+ var singleInst = $(this).data('croppie');
953
+
954
+ if (opts === 'get') {
955
+ return singleInst.get();
956
+ }
957
+ else if (opts === 'result') {
958
+ return singleInst.result.apply(singleInst, args);
959
+ }
960
+
961
+ return this.each(function () {
962
+ var i = $(this).data('croppie');
963
+ if (!i) return;
964
+
965
+ var method = i[opts];
966
+ if ($.isFunction(method)) {
967
+ method.apply(i, args);
968
+ if (opts === 'destroy') {
969
+ $(this).removeData('croppie');
970
+ }
971
+ }
972
+ else {
973
+ throw 'Croppie ' + opts + ' method not found';
974
+ }
975
+ });
976
+ }
977
+ else {
978
+ return this.each(function () {
979
+ var i = new Croppie(this, opts);
980
+ $(this).data('croppie', i);
981
+ });
982
+ }
983
+ };
984
+ }
985
+
986
+ function Croppie(element, opts) {
987
+ this.element = element;
988
+ this.options = deepExtend(deepExtend({}, Croppie.defaults), opts);
989
+
990
+ _create.call(this);
991
+ }
992
+
993
+ Croppie.defaults = {
994
+ viewport: {
995
+ width: 100,
996
+ height: 100,
997
+ type: 'square'
998
+ },
999
+ boundary: {
1000
+ width: 300,
1001
+ height: 300
1002
+ },
1003
+ customClass: '',
1004
+ showZoomer: true,
1005
+ enableZoom: true,
1006
+ mouseWheelZoom: true,
1007
+ exif: false,
1008
+ update: function () { }
1009
+ };
1010
+
1011
+ deepExtend(Croppie.prototype, {
1012
+ bind: function (options, cb) {
1013
+ return _bind.call(this, options, cb);
1014
+ },
1015
+ get: function () {
1016
+ return _get.call(this);
1017
+ },
1018
+ result: function (type) {
1019
+ return _result.call(this, type);
1020
+ },
1021
+ refresh: function () {
1022
+ return _refresh.call(this);
1023
+ },
1024
+ setZoom: function (v) {
1025
+ _setZoomerVal.call(this, v);
1026
+ dispatchChange(this.elements.zoomer);
1027
+ },
1028
+ destroy: function () {
1029
+ return _destroy.call(this);
1030
+ }
1031
+ });
1032
+
1033
+ exports.Croppie = window.Croppie = Croppie;
1034
+
1035
+ if (typeof module === 'object' && !!module.exports) {
1036
+ module.exports = Croppie;
1037
+ }
1038
+ }));