croppie_rails 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1038 +1,1148 @@
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
- }));
1
+ /*************************
2
+ * Croppie
3
+ * Copyright 2016
4
+ * Foliotek
5
+ * Version: 2.1.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
+ if (img.src === src) {
128
+ // If image source hasn't changed, return a promise that resolves immediately
129
+ prom = new Promise(function (resolve, reject) {
130
+ resolve(img);
131
+ });
132
+ } else {
133
+ prom = new Promise(function (resolve, reject) {
134
+ if (src.substring(0,4).toLowerCase() === 'http') {
135
+ img.setAttribute('crossOrigin', 'anonymous');
136
+ }
137
+ img.onload = function () {
138
+ setTimeout(function () {
139
+ resolve(img);
140
+ }, 1);
141
+ };
142
+ });
143
+
144
+ img.src = src;
145
+ }
146
+
147
+ img.style.opacity = 0;
148
+
149
+ return prom;
150
+ }
151
+
152
+ /* CSS Transform Prototype */
153
+ var _TRANSLATE = 'translate3d',
154
+ _TRANSLATE_SUFFIX = ', 0px';
155
+ var Transform = function (x, y, scale) {
156
+ this.x = parseFloat(x);
157
+ this.y = parseFloat(y);
158
+ this.scale = parseFloat(scale);
159
+ };
160
+
161
+ Transform.parse = function (v) {
162
+ if (v.style) {
163
+ return Transform.parse(v.style[CSS_TRANSFORM]);
164
+ }
165
+ else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) {
166
+ return Transform.fromMatrix(v);
167
+ }
168
+ else {
169
+ return Transform.fromString(v);
170
+ }
171
+ };
172
+
173
+ Transform.fromMatrix = function (v) {
174
+ var vals = v.substring(7).split(',');
175
+ if (!vals.length || v === 'none') {
176
+ vals = [1, 0, 0, 1, 0, 0];
177
+ }
178
+
179
+ return new Transform(parseInt(vals[4], 10), parseInt(vals[5], 10), parseFloat(vals[0]));
180
+ };
181
+
182
+ Transform.fromString = function (v) {
183
+ var values = v.split(') '),
184
+ translate = values[0].substring(_TRANSLATE.length + 1).split(','),
185
+ scale = values.length > 1 ? values[1].substring(6) : 1,
186
+ x = translate.length > 1 ? translate[0] : 0,
187
+ y = translate.length > 1 ? translate[1] : 0;
188
+
189
+ return new Transform(x, y, scale);
190
+ };
191
+
192
+ Transform.prototype.toString = function () {
193
+ return _TRANSLATE + '(' + this.x + 'px, ' + this.y + 'px' + _TRANSLATE_SUFFIX + ') scale(' + this.scale + ')';
194
+ };
195
+
196
+ var TransformOrigin = function (el) {
197
+ if (!el || !el.style[CSS_TRANS_ORG]) {
198
+ this.x = 0;
199
+ this.y = 0;
200
+ return;
201
+ }
202
+ var css = el.style[CSS_TRANS_ORG].split(' ');
203
+ this.x = parseFloat(css[0]);
204
+ this.y = parseFloat(css[1]);
205
+ };
206
+
207
+ TransformOrigin.prototype.toString = function () {
208
+ return this.x + 'px ' + this.y + 'px';
209
+ };
210
+
211
+ function getExifOrientation (img, cb) {
212
+ if (!window.EXIF) {
213
+ cb(0);
214
+ }
215
+
216
+ EXIF.getData(img, function () {
217
+ var orientation = EXIF.getTag(this, 'Orientation');
218
+ cb(orientation);
219
+ });
220
+ }
221
+
222
+ function drawCanvas(canvas, img, orientation) {
223
+ var width = img.width,
224
+ height = img.height,
225
+ ctx = canvas.getContext('2d');
226
+
227
+ canvas.width = img.width;
228
+ canvas.height = img.height;
229
+
230
+ ctx.save();
231
+ switch (orientation) {
232
+ case 2:
233
+ ctx.translate(width, 0);
234
+ ctx.scale(-1, 1);
235
+ break;
236
+
237
+ case 3:
238
+ ctx.translate(width, height);
239
+ ctx.rotate(180*Math.PI/180);
240
+ break;
241
+
242
+ case 4:
243
+ ctx.translate(0, height);
244
+ ctx.scale(1, -1);
245
+ break;
246
+
247
+ case 5:
248
+ canvas.width = height;
249
+ canvas.height = width;
250
+ ctx.rotate(90*Math.PI/180);
251
+ ctx.scale(1, -1);
252
+ break;
253
+
254
+ case 6:
255
+ canvas.width = height;
256
+ canvas.height = width;
257
+ ctx.rotate(90*Math.PI/180);
258
+ ctx.translate(0, -height);
259
+ break;
260
+
261
+ case 7:
262
+ canvas.width = height;
263
+ canvas.height = width;
264
+ ctx.rotate(-90*Math.PI/180);
265
+ ctx.translate(-width, height);
266
+ ctx.scale(1, -1);
267
+ break;
268
+
269
+ case 8:
270
+ canvas.width = height;
271
+ canvas.height = width;
272
+ ctx.translate(0, width);
273
+ ctx.rotate(-90*Math.PI/180);
274
+ break;
275
+ }
276
+ ctx.drawImage(img, 0,0, width, height);
277
+ ctx.restore();
278
+ }
279
+
280
+ /* Private Methods */
281
+ function _create() {
282
+ var self = this,
283
+ contClass = 'croppie-container',
284
+ customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null,
285
+ boundary, img, viewport, overlay, canvas;
286
+
287
+ self.options.useCanvas = self.options.enableOrientation || _hasExif.call(self);
288
+ // Properties on class
289
+ self.data = {};
290
+ self.elements = {};
291
+
292
+ // Generating Markup
293
+ boundary = self.elements.boundary = document.createElement('div');
294
+ viewport = self.elements.viewport = document.createElement('div');
295
+ img = self.elements.img = document.createElement('img');
296
+ overlay = self.elements.overlay = document.createElement('div');
297
+
298
+ if (self.options.useCanvas) {
299
+ self.elements.canvas = document.createElement('canvas');
300
+ self.elements.preview = self.elements.canvas;
301
+ }
302
+ else {
303
+ self.elements.preview = self.elements.img;
304
+ }
305
+
306
+ addClass(boundary, 'cr-boundary');
307
+ css(boundary, {
308
+ width: self.options.boundary.width + 'px',
309
+ height: self.options.boundary.height + 'px'
310
+ });
311
+
312
+ addClass(viewport, 'cr-viewport');
313
+ if (customViewportClass) {
314
+ addClass(viewport, customViewportClass);
315
+ }
316
+ css(viewport, {
317
+ width: self.options.viewport.width + 'px',
318
+ height: self.options.viewport.height + 'px'
319
+ });
320
+
321
+ addClass(self.elements.preview, 'cr-image');
322
+ addClass(overlay, 'cr-overlay');
323
+
324
+ self.element.appendChild(boundary);
325
+ boundary.appendChild(self.elements.preview);
326
+ boundary.appendChild(viewport);
327
+ boundary.appendChild(overlay);
328
+
329
+ addClass(self.element, contClass);
330
+ if (self.options.customClass) {
331
+ addClass(self.element, self.options.customClass);
332
+ }
333
+
334
+ // Initialize drag & zoom
335
+ _initDraggable.call(this);
336
+
337
+ if (self.options.enableZoom) {
338
+ _initializeZoom.call(self);
339
+ }
340
+
341
+ // if (self.options.enableOrientation) {
342
+ // _initRotationControls.call(self);
343
+ // }
344
+ }
345
+
346
+ function _initRotationControls () {
347
+ // TODO - Not a fan of these controls
348
+ return;
349
+ var self = this,
350
+ wrap, btnLeft, btnRight, iLeft, iRight;
351
+
352
+ wrap = document.createElement('div');
353
+ self.elements.orientationBtnLeft = btnLeft = document.createElement('button');
354
+ self.elements.orientationBtnRight = btnRight = document.createElement('button');
355
+
356
+ wrap.appendChild(btnLeft);
357
+ wrap.appendChild(btnRight);
358
+
359
+ iLeft = document.createElement('i');
360
+ iRight = document.createElement('i');
361
+ btnLeft.appendChild(iLeft);
362
+ btnRight.appendChild(iRight);
363
+
364
+ addClass(wrap, 'cr-rotate-controls');
365
+ addClass(btnLeft, 'cr-rotate-l');
366
+ addClass(btnRight, 'cr-rotate-r');
367
+
368
+ self.elements.boundary.appendChild(wrap);
369
+
370
+ btnLeft.addEventListener('click', function () {
371
+ self.rotate(-90);
372
+ });
373
+ btnRight.addEventListener('click', function () {
374
+ self.rotate(90);
375
+ });
376
+ }
377
+
378
+ function _hasExif() {
379
+ // todo - remove options.exif after deprecation
380
+ return (this.options.enableExif || this.options.exif) && window.EXIF;
381
+ }
382
+
383
+ function _setZoomerVal(v) {
384
+ if (this.options.enableZoom) {
385
+ this.elements.zoomer.value = fix(v, 4);
386
+ }
387
+ }
388
+
389
+ function _initializeZoom() {
390
+ var self = this,
391
+ wrap = self.elements.zoomerWrap = document.createElement('div'),
392
+ zoomer = self.elements.zoomer = document.createElement('input');
393
+
394
+ addClass(wrap, 'cr-slider-wrap');
395
+ addClass(zoomer, 'cr-slider');
396
+ zoomer.type = 'range';
397
+ zoomer.step = '0.01';
398
+ zoomer.value = 1;
399
+ zoomer.style.display = self.options.showZoomer ? '' : 'none';
400
+
401
+ self.element.appendChild(wrap);
402
+ wrap.appendChild(zoomer);
403
+
404
+ self._currentZoom = 1;
405
+
406
+ function change() {
407
+ _onZoom.call(self, {
408
+ value: parseFloat(zoomer.value),
409
+ origin: new TransformOrigin(self.elements.preview),
410
+ viewportRect: self.elements.viewport.getBoundingClientRect(),
411
+ transform: Transform.parse(self.elements.preview)
412
+ });
413
+ }
414
+
415
+ function scroll(ev) {
416
+ var delta, targetZoom;
417
+
418
+ if (ev.wheelDelta) {
419
+ delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2
420
+ } else if (ev.deltaY) {
421
+ delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2
422
+ } else if (ev.detail) {
423
+ delta = ev.detail / -60; //delta min: -3 max: 3 // max x 10 x 2
424
+ } else {
425
+ delta = 0;
426
+ }
427
+
428
+ targetZoom = self._currentZoom + delta;
429
+
430
+ ev.preventDefault();
431
+ _setZoomerVal.call(self, targetZoom);
432
+ change();
433
+ }
434
+
435
+ self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress
436
+ self.elements.zoomer.addEventListener('change', change);
437
+
438
+ if (self.options.mouseWheelZoom) {
439
+ self.elements.boundary.addEventListener('mousewheel', scroll);
440
+ self.elements.boundary.addEventListener('DOMMouseScroll', scroll);
441
+ }
442
+ }
443
+
444
+ function _onZoom(ui) {
445
+ var self = this,
446
+ transform = ui ? ui.transform : Transform.parse(self.elements.preview),
447
+ vpRect = ui ? ui.viewportRect : self.elements.viewport.getBoundingClientRect(),
448
+ origin = ui ? ui.origin : new TransformOrigin(self.elements.preview);
449
+
450
+ self._currentZoom = ui ? ui.value : self._currentZoom;
451
+ transform.scale = self._currentZoom;
452
+
453
+ if (self.options.enforceBoundary) {
454
+ var boundaries = _getVirtualBoundaries.call(self, vpRect),
455
+ transBoundaries = boundaries.translate,
456
+ oBoundaries = boundaries.origin;
457
+
458
+ if (transform.x >= transBoundaries.maxX) {
459
+ origin.x = oBoundaries.minX;
460
+ transform.x = transBoundaries.maxX;
461
+ }
462
+
463
+ if (transform.x <= transBoundaries.minX) {
464
+ origin.x = oBoundaries.maxX;
465
+ transform.x = transBoundaries.minX;
466
+ }
467
+
468
+ if (transform.y >= transBoundaries.maxY) {
469
+ origin.y = oBoundaries.minY;
470
+ transform.y = transBoundaries.maxY;
471
+ }
472
+
473
+ if (transform.y <= transBoundaries.minY) {
474
+ origin.y = oBoundaries.maxY;
475
+ transform.y = transBoundaries.minY;
476
+ }
477
+ }
478
+
479
+ var transCss = {};
480
+ transCss[CSS_TRANSFORM] = transform.toString();
481
+ transCss[CSS_TRANS_ORG] = origin.toString();
482
+ css(self.elements.preview, transCss);
483
+
484
+ _debouncedOverlay.call(self);
485
+ _triggerUpdate.call(self);
486
+ }
487
+
488
+ function _getVirtualBoundaries(viewport) {
489
+ var self = this,
490
+ scale = self._currentZoom,
491
+ vpWidth = viewport.width,
492
+ vpHeight = viewport.height,
493
+ centerFromBoundaryX = self.options.boundary.width / 2,
494
+ centerFromBoundaryY = self.options.boundary.height / 2,
495
+ imgRect = self.elements.preview.getBoundingClientRect(),
496
+ curImgWidth = imgRect.width,
497
+ curImgHeight = imgRect.height,
498
+ halfWidth = vpWidth / 2,
499
+ halfHeight = vpHeight / 2;
500
+
501
+
502
+ var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1;
503
+ var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale)));
504
+
505
+ var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1;
506
+ var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale)));
507
+
508
+ var originMinX = (1 / scale) * halfWidth;
509
+ var originMaxX = (curImgWidth * (1 / scale)) - originMinX;
510
+
511
+ var originMinY = (1 / scale) * halfHeight;
512
+ var originMaxY = (curImgHeight * (1 / scale)) - originMinY;
513
+
514
+ return {
515
+ translate: {
516
+ maxX: maxX,
517
+ minX: minX,
518
+ maxY: maxY,
519
+ minY: minY
520
+ },
521
+ origin: {
522
+ maxX: originMaxX,
523
+ minX: originMinX,
524
+ maxY: originMaxY,
525
+ minY: originMinY
526
+ }
527
+ };
528
+ }
529
+
530
+ function _updateCenterPoint() {
531
+ var self = this,
532
+ scale = self._currentZoom,
533
+ data = self.elements.preview.getBoundingClientRect(),
534
+ vpData = self.elements.viewport.getBoundingClientRect(),
535
+ transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]),
536
+ pc = new TransformOrigin(self.elements.preview),
537
+ top = (vpData.top - data.top) + (vpData.height / 2),
538
+ left = (vpData.left - data.left) + (vpData.width / 2),
539
+ center = {},
540
+ adj = {};
541
+
542
+ center.y = top / scale;
543
+ center.x = left / scale;
544
+
545
+ adj.y = (center.y - pc.y) * (1 - scale);
546
+ adj.x = (center.x - pc.x) * (1 - scale);
547
+
548
+ transform.x -= adj.x;
549
+ transform.y -= adj.y;
550
+
551
+ var newCss = {};
552
+ newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px';
553
+ newCss[CSS_TRANSFORM] = transform.toString();
554
+ css(self.elements.preview, newCss);
555
+ }
556
+
557
+ function _initDraggable() {
558
+ var self = this,
559
+ isDragging = false,
560
+ originalX,
561
+ originalY,
562
+ originalDistance,
563
+ vpRect;
564
+
565
+ function mouseDown(ev) {
566
+ ev.preventDefault();
567
+ if (isDragging) return;
568
+ isDragging = true;
569
+ originalX = ev.pageX;
570
+ originalY = ev.pageY;
571
+
572
+ if (ev.touches) {
573
+ var touches = ev.touches[0];
574
+ originalX = touches.pageX;
575
+ originalY = touches.pageY;
576
+ }
577
+
578
+ transform = Transform.parse(self.elements.preview);
579
+ window.addEventListener('mousemove', mouseMove);
580
+ window.addEventListener('touchmove', mouseMove);
581
+ window.addEventListener('mouseup', mouseUp);
582
+ window.addEventListener('touchend', mouseUp);
583
+ document.body.style[CSS_USERSELECT] = 'none';
584
+ vpRect = self.elements.viewport.getBoundingClientRect();
585
+ }
586
+
587
+ function mouseMove(ev) {
588
+ ev.preventDefault();
589
+ var pageX = ev.pageX,
590
+ pageY = ev.pageY;
591
+
592
+ if (ev.touches) {
593
+ var touches = ev.touches[0];
594
+ pageX = touches.pageX;
595
+ pageY = touches.pageY;
596
+ }
597
+
598
+ var deltaX = pageX - originalX,
599
+ deltaY = pageY - originalY,
600
+ imgRect = self.elements.preview.getBoundingClientRect(),
601
+ top = transform.y + deltaY,
602
+ left = transform.x + deltaX,
603
+ newCss = {};
604
+
605
+ if (ev.type == 'touchmove') {
606
+ if (ev.touches.length > 1) {
607
+ var touch1 = ev.touches[0];
608
+ var touch2 = ev.touches[1];
609
+ var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY));
610
+
611
+ if (!originalDistance) {
612
+ originalDistance = dist / self._currentZoom;
613
+ }
614
+
615
+ var scale = dist / originalDistance;
616
+
617
+ _setZoomerVal.call(self, scale);
618
+ dispatchChange(self.elements.zoomer);
619
+ return;
620
+ }
621
+ }
622
+
623
+ if (self.options.enforceBoundary) {
624
+ if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) {
625
+ transform.y = top;
626
+ }
627
+
628
+ if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) {
629
+ transform.x = left;
630
+ }
631
+ }
632
+ else {
633
+ transform.y = top;
634
+ transform.x = left;
635
+ }
636
+
637
+ newCss[CSS_TRANSFORM] = transform.toString();
638
+ css(self.elements.preview, newCss);
639
+ _updateOverlay.call(self);
640
+ originalY = pageY;
641
+ originalX = pageX;
642
+ }
643
+
644
+ function mouseUp() {
645
+ isDragging = false;
646
+ window.removeEventListener('mousemove', mouseMove);
647
+ window.removeEventListener('touchmove', mouseMove);
648
+ window.removeEventListener('mouseup', mouseUp);
649
+ window.removeEventListener('touchend', mouseUp);
650
+ document.body.style[CSS_USERSELECT] = '';
651
+ _updateCenterPoint.call(self);
652
+ _triggerUpdate.call(self);
653
+ originalDistance = 0;
654
+ }
655
+
656
+ self.elements.overlay.addEventListener('mousedown', mouseDown);
657
+ self.elements.overlay.addEventListener('touchstart', mouseDown);
658
+ }
659
+
660
+ function _updateOverlay() {
661
+ var self = this,
662
+ boundRect = self.elements.boundary.getBoundingClientRect(),
663
+ imgData = self.elements.preview.getBoundingClientRect();
664
+
665
+ css(self.elements.overlay, {
666
+ width: imgData.width + 'px',
667
+ height: imgData.height + 'px',
668
+ top: (imgData.top - boundRect.top) + 'px',
669
+ left: (imgData.left - boundRect.left) + 'px'
670
+ });
671
+ }
672
+ var _debouncedOverlay = debounce(_updateOverlay, 500);
673
+
674
+ function _triggerUpdate() {
675
+ var self = this;
676
+ if (_isVisible.call(self)) {
677
+ self.options.update.call(self, self.get());
678
+ }
679
+ }
680
+
681
+ function _isVisible() {
682
+ return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0;
683
+ }
684
+
685
+ function _updatePropertiesFromImage() {
686
+ var self = this,
687
+ minZoom = 0,
688
+ maxZoom = 1.5,
689
+ initialZoom = 1,
690
+ cssReset = {},
691
+ img = self.elements.preview,
692
+ zoomer = self.elements.zoomer,
693
+ transformReset = new Transform(0, 0, initialZoom),
694
+ originReset = new TransformOrigin(),
695
+ isVisible = _isVisible.call(self),
696
+ imgData,
697
+ vpData,
698
+ boundaryData,
699
+ minW,
700
+ minH;
701
+
702
+ if (!isVisible || self.data.bound) {
703
+ // if the croppie isn't visible or it doesn't need binding
704
+ return;
705
+ }
706
+
707
+ self.data.bound = true;
708
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
709
+ cssReset[CSS_TRANS_ORG] = originReset.toString();
710
+ cssReset['opacity'] = 1;
711
+ css(img, cssReset);
712
+
713
+ imgData = img.getBoundingClientRect();
714
+ vpData = self.elements.viewport.getBoundingClientRect();
715
+ boundaryData = self.elements.boundary.getBoundingClientRect();
716
+ self._originalImageWidth = imgData.width;
717
+ self._originalImageHeight = imgData.height;
718
+
719
+ if (self.options.enableZoom) {
720
+ if (self.options.enforceBoundary) {
721
+ minW = vpData.width / imgData.width;
722
+ minH = vpData.height / imgData.height;
723
+ minZoom = Math.max(minW, minH);
724
+ }
725
+
726
+ if (minZoom >= maxZoom) {
727
+ maxZoom = minZoom + 1;
728
+ }
729
+
730
+ zoomer.min = fix(minZoom, 4);
731
+ zoomer.max = fix(maxZoom, 4);
732
+ initialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height));
733
+ _setZoomerVal.call(self, initialZoom);
734
+ dispatchChange(zoomer);
735
+ }
736
+
737
+ self._currentZoom = transformReset.scale = initialZoom;
738
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
739
+ css(img, cssReset);
740
+
741
+ if (self.data.points.length) {
742
+ _bindPoints.call(self, self.data.points);
743
+ }
744
+ else {
745
+ _centerImage.call(self);
746
+ }
747
+
748
+ _updateCenterPoint.call(self);
749
+ _updateOverlay.call(self);
750
+ }
751
+
752
+ function _bindPoints(points) {
753
+ if (points.length != 4) {
754
+ throw "Croppie - Invalid number of points supplied: " + points;
755
+ }
756
+ var self = this,
757
+ pointsWidth = points[2] - points[0],
758
+ // pointsHeight = points[3] - points[1],
759
+ vpData = self.elements.viewport.getBoundingClientRect(),
760
+ boundRect = self.elements.boundary.getBoundingClientRect(),
761
+ vpOffset = {
762
+ left: vpData.left - boundRect.left,
763
+ top: vpData.top - boundRect.top
764
+ },
765
+ scale = vpData.width / pointsWidth,
766
+ originTop = points[1],
767
+ originLeft = points[0],
768
+ transformTop = (-1 * points[1]) + vpOffset.top,
769
+ transformLeft = (-1 * points[0]) + vpOffset.left,
770
+ newCss = {};
771
+
772
+ newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px';
773
+ newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString();
774
+ css(self.elements.preview, newCss);
775
+
776
+ _setZoomerVal.call(self, scale);
777
+ self._currentZoom = scale;
778
+ }
779
+
780
+ function _centerImage() {
781
+ var self = this,
782
+ imgDim = self.elements.preview.getBoundingClientRect(),
783
+ vpDim = self.elements.viewport.getBoundingClientRect(),
784
+ boundDim = self.elements.boundary.getBoundingClientRect(),
785
+ vpLeft = vpDim.left - boundDim.left,
786
+ vpTop = vpDim.top - boundDim.top,
787
+ w = vpLeft - ((imgDim.width - vpDim.width) / 2),
788
+ h = vpTop - ((imgDim.height - vpDim.height) / 2),
789
+ transform = new Transform(w, h, self._currentZoom);
790
+
791
+ css(self.elements.preview, CSS_TRANSFORM, transform.toString());
792
+ }
793
+
794
+ function _transferImageToCanvas(customOrientation) {
795
+ var self = this,
796
+ canvas = self.elements.canvas,
797
+ img = self.elements.img,
798
+ ctx = canvas.getContext('2d'),
799
+ exif = _hasExif.call(self),
800
+ customOrientation = self.options.enableOrientation && customOrientation;
801
+
802
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
803
+ canvas.width = img.width;
804
+ canvas.height = img.height;
805
+
806
+ if (exif) {
807
+ getExifOrientation(img, function (orientation) {
808
+ drawCanvas(canvas, img, parseInt(orientation));
809
+ if (customOrientation) {
810
+ drawCanvas(canvas, img, customOrientation);
811
+ }
812
+ });
813
+ } else if (customOrientation) {
814
+ drawCanvas(canvas, img, customOrientation);
815
+ }
816
+ }
817
+
818
+ function _getHtmlResult(data) {
819
+ var points = data.points,
820
+ div = document.createElement('div'),
821
+ img = document.createElement('img'),
822
+ width = points[2] - points[0],
823
+ height = points[3] - points[1];
824
+
825
+ addClass(div, 'croppie-result');
826
+ div.appendChild(img);
827
+ css(img, {
828
+ left: (-1 * points[0]) + 'px',
829
+ top: (-1 * points[1]) + 'px'
830
+ });
831
+ img.src = data.url;
832
+ css(div, {
833
+ width: width + 'px',
834
+ height: height + 'px'
835
+ });
836
+
837
+ return div;
838
+ }
839
+
840
+ function _getCanvasResult(img, data) {
841
+ var points = data.points,
842
+ left = points[0],
843
+ top = points[1],
844
+ width = (points[2] - points[0]),
845
+ height = (points[3] - points[1]),
846
+ circle = data.circle,
847
+ canvas = document.createElement('canvas'),
848
+ ctx = canvas.getContext('2d'),
849
+ outWidth = width,
850
+ outHeight = height;
851
+
852
+ if (data.outputWidth && data.outputHeight) {
853
+ outWidth = data.outputWidth;
854
+ outHeight = data.outputHeight;
855
+ }
856
+
857
+ canvas.width = outWidth;
858
+ canvas.height = outHeight;
859
+
860
+ ctx.drawImage(img, left, top, width, height, 0, 0, outWidth, outHeight);
861
+ if (circle) {
862
+ ctx.fillStyle = '#fff';
863
+ ctx.globalCompositeOperation = 'destination-in';
864
+ ctx.beginPath();
865
+ ctx.arc(outWidth / 2, outHeight / 2, outWidth / 2, 0, Math.PI * 2, true);
866
+ ctx.closePath();
867
+ ctx.fill();
868
+ }
869
+ return canvas.toDataURL(data.format, data.quality);
870
+ }
871
+
872
+ function _bind(options, cb) {
873
+ var self = this,
874
+ url,
875
+ points = [];
876
+
877
+ if (typeof (options) === 'string') {
878
+ url = options;
879
+ options = {};
880
+ }
881
+ else if (Array.isArray(options)) {
882
+ points = options.slice();
883
+ }
884
+ else if (typeof (options) == 'undefined' && self.data.url) { //refreshing
885
+ _updatePropertiesFromImage.call(self);
886
+ _triggerUpdate.call(self);
887
+ return null;
888
+ }
889
+ else {
890
+ url = options.url;
891
+ points = options.points || [];
892
+ }
893
+
894
+ self.data.bound = false;
895
+ self.data.url = url || self.data.url;
896
+ self.data.points = (points || self.data.points).map(function (p) {
897
+ return parseFloat(p);
898
+ });
899
+ var prom = loadImage(url, self.elements.img);
900
+ prom.then(function () {
901
+ if (self.options.useCanvas) {
902
+ self.elements.img.exifdata = null;
903
+ _transferImageToCanvas.call(self, options.orientation || 1);
904
+ }
905
+ _updatePropertiesFromImage.call(self);
906
+ _triggerUpdate.call(self);
907
+ if (cb) {
908
+ cb();
909
+ }
910
+ });
911
+ return prom;
912
+ }
913
+
914
+ function fix(v, decimalPoints) {
915
+ return parseFloat(v).toFixed(decimalPoints || 0);
916
+ }
917
+
918
+ function _get() {
919
+ var self = this,
920
+ imgData = self.elements.preview.getBoundingClientRect(),
921
+ vpData = self.elements.viewport.getBoundingClientRect(),
922
+ x1 = vpData.left - imgData.left,
923
+ y1 = vpData.top - imgData.top,
924
+ x2 = x1 + vpData.width,
925
+ y2 = y1 + vpData.height,
926
+ scale = self._currentZoom;
927
+
928
+ if (scale === Infinity || isNaN(scale)) {
929
+ scale = 1;
930
+ }
931
+
932
+ var max = self.options.enforceBoundary ? 0 : Number.NEGATIVE_INFINITY;
933
+ x1 = Math.max(max, x1 / scale);
934
+ y1 = Math.max(max, y1 / scale);
935
+ x2 = Math.max(max, x2 / scale);
936
+ y2 = Math.max(max, y2 / scale);
937
+
938
+ return {
939
+ points: [fix(x1), fix(y1), fix(x2), fix(y2)],
940
+ zoom: scale
941
+ };
942
+ }
943
+
944
+ var RESULT_DEFAULTS = {
945
+ type: 'canvas',
946
+ format: 'png',
947
+ quality: 1
948
+ },
949
+ RESULT_FORMATS = ['jpeg', 'webp', 'png'];
950
+
951
+ function _result(options) {
952
+ var self = this,
953
+ data = _get.call(self),
954
+ opts = deepExtend(RESULT_DEFAULTS, deepExtend({}, options)),
955
+ type = (typeof (options) === 'string' ? options : (opts.type || 'viewport')),
956
+ size = opts.size,
957
+ format = opts.format,
958
+ quality = opts.quality,
959
+ vpRect = self.elements.viewport.getBoundingClientRect(),
960
+ ratio = vpRect.width / vpRect.height,
961
+ prom;
962
+
963
+ if (size === 'viewport') {
964
+ data.outputWidth = vpRect.width;
965
+ data.outputHeight = vpRect.height;
966
+ } else if (typeof size === 'object') {
967
+ if (size.width && size.height) {
968
+ data.outputWidth = size.width;
969
+ data.outputHeight = size.height;
970
+ } else if (size.width) {
971
+ data.outputWidth = size.width;
972
+ data.outputHeight = size.width / ratio;
973
+ } else if (size.height) {
974
+ data.outputWidth = size.height * ratio;
975
+ data.outputHeight = size.height;
976
+ }
977
+ }
978
+
979
+ if (RESULT_FORMATS.indexOf(format) > -1) {
980
+ data.format = 'image/' + format;
981
+ data.quality = quality;
982
+ }
983
+
984
+ data.circle = self.options.viewport.type === 'circle';
985
+ data.url = self.data.url;
986
+
987
+ prom = new Promise(function (resolve, reject) {
988
+ if (type === 'canvas') {
989
+ resolve(_getCanvasResult.call(self, self.elements.preview, data));
990
+ }
991
+ else {
992
+ resolve(_getHtmlResult.call(self, data));
993
+ }
994
+ });
995
+ return prom;
996
+ }
997
+
998
+ function _refresh() {
999
+ _updatePropertiesFromImage.call(this);
1000
+ }
1001
+
1002
+ function _rotate(deg) {
1003
+ if (!this.options.useCanvas) {
1004
+ throw 'Croppie: Cannot rotate without enableOrientation';
1005
+ }
1006
+
1007
+ var self = this,
1008
+ canvas = self.elements.canvas,
1009
+ img = self.elements.img,
1010
+ copy = document.createElement('canvas'),
1011
+ ornt = 1;
1012
+
1013
+ copy.width = canvas.width;
1014
+ copy.height = canvas.height;
1015
+ var ctx = copy.getContext('2d');
1016
+ ctx.drawImage(canvas, 0, 0);
1017
+
1018
+ if (deg === 90 || deg === -270) ornt = 6;
1019
+ if (deg === -90 || deg === 270) ornt = 8;
1020
+ if (deg === 180 || deg === -180) ornt = 3;
1021
+
1022
+ drawCanvas(canvas, copy, ornt);
1023
+ _onZoom.call(self);
1024
+ }
1025
+
1026
+ function _destroy() {
1027
+ var self = this;
1028
+ self.element.removeChild(self.elements.boundary);
1029
+ removeClass(self.element, 'croppie-container');
1030
+ if (self.options.enableZoom) {
1031
+ self.element.removeChild(self.elements.zoomerWrap);
1032
+ }
1033
+ delete self.elements;
1034
+ }
1035
+
1036
+ if (window.jQuery) {
1037
+ var $ = window.jQuery;
1038
+ $.fn.croppie = function (opts) {
1039
+ var ot = typeof opts;
1040
+
1041
+ if (ot === 'string') {
1042
+ var args = Array.prototype.slice.call(arguments, 1);
1043
+ var singleInst = $(this).data('croppie');
1044
+
1045
+ if (opts === 'get') {
1046
+ return singleInst.get();
1047
+ }
1048
+ else if (opts === 'result') {
1049
+ return singleInst.result.apply(singleInst, args);
1050
+ }
1051
+
1052
+ return this.each(function () {
1053
+ var i = $(this).data('croppie');
1054
+ if (!i) return;
1055
+
1056
+ var method = i[opts];
1057
+ if ($.isFunction(method)) {
1058
+ method.apply(i, args);
1059
+ if (opts === 'destroy') {
1060
+ $(this).removeData('croppie');
1061
+ }
1062
+ }
1063
+ else {
1064
+ throw 'Croppie ' + opts + ' method not found';
1065
+ }
1066
+ });
1067
+ }
1068
+ else {
1069
+ return this.each(function () {
1070
+ var i = new Croppie(this, opts);
1071
+ $(this).data('croppie', i);
1072
+ });
1073
+ }
1074
+ };
1075
+ }
1076
+
1077
+ function Croppie(element, opts) {
1078
+ this.element = element;
1079
+ this.options = deepExtend(deepExtend({}, Croppie.defaults), opts);
1080
+
1081
+ _create.call(this);
1082
+ if (this.options.url) {
1083
+ var bindOpts = {
1084
+ url: this.options.url,
1085
+ points: this.options.points
1086
+ };
1087
+ delete this.options['url'];
1088
+ delete this.options['points'];
1089
+ _bind.call(this, bindOpts);
1090
+ }
1091
+ }
1092
+
1093
+ Croppie.defaults = {
1094
+ viewport: {
1095
+ width: 100,
1096
+ height: 100,
1097
+ type: 'square'
1098
+ },
1099
+ boundary: {
1100
+ width: 300,
1101
+ height: 300
1102
+ },
1103
+ orientationControls: {
1104
+ enabled: true,
1105
+ leftClass: '',
1106
+ rightClass: ''
1107
+ },
1108
+ customClass: '',
1109
+ showZoomer: true,
1110
+ enableZoom: true,
1111
+ mouseWheelZoom: true,
1112
+ enableExif: false,
1113
+ enforceBoundary: true,
1114
+ enableOrientation: false,
1115
+ update: function () { }
1116
+ };
1117
+
1118
+ deepExtend(Croppie.prototype, {
1119
+ bind: function (options, cb) {
1120
+ return _bind.call(this, options, cb);
1121
+ },
1122
+ get: function () {
1123
+ return _get.call(this);
1124
+ },
1125
+ result: function (type) {
1126
+ return _result.call(this, type);
1127
+ },
1128
+ refresh: function () {
1129
+ return _refresh.call(this);
1130
+ },
1131
+ setZoom: function (v) {
1132
+ _setZoomerVal.call(this, v);
1133
+ dispatchChange(this.elements.zoomer);
1134
+ },
1135
+ rotate: function (deg) {
1136
+ _rotate.call(this, deg);
1137
+ },
1138
+ destroy: function () {
1139
+ return _destroy.call(this);
1140
+ }
1141
+ });
1142
+
1143
+ exports.Croppie = window.Croppie = Croppie;
1144
+
1145
+ if (typeof module === 'object' && !!module.exports) {
1146
+ module.exports = Croppie;
1147
+ }
1148
+ }));