vendor: 7,927 bytes, lines 1-178
1/************************* 2 * Croppie 3 * Copyright 2019 4 * Foliotek 5 * Version: 2.6.4 6 *************************/ 7(function (root, factory) { 8 if (typeof define === 'function' && define.amd) { 9 // AMD. Register as an anonymous module. 10 define(factory); 11 } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { 12 // CommonJS 13 module.exports = factory(); 14 } else { 15 // Browser globals 16 root.Croppie = factory(); 17 } 18}(typeof self !== 'undefined' ? self : this, function () { 19 20 /* Polyfills */ 21 if (typeof Promise !== 'function') { 22 /*! promise-polyfill 3.1.0 */ 23 !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); 24 } 25 26 if ( typeof window.CustomEvent !== "function" ) { 27 (function(){ 28 function CustomEvent ( event, params ) { 29 params = params || { bubbles: false, cancelable: false, detail: undefined }; 30 var evt = document.createEvent( 'CustomEvent' ); 31 evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); 32 return evt; 33 } 34 CustomEvent.prototype = window.Event.prototype; 35 window.CustomEvent = CustomEvent; 36 }()); 37 } 38 39 if (!HTMLCanvasElement.prototype.toBlob) { 40 Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { 41 value: function (callback, type, quality) { 42 var binStr = atob( this.toDataURL(type, quality).split(',')[1] ), 43 len = binStr.length, 44 arr = new Uint8Array(len); 45 46 for (var i=0; i<len; i++ ) { 47 arr[i] = binStr.charCodeAt(i); 48 } 49 50 callback( new Blob( [arr], {type: type || 'image/png'} ) ); 51 } 52 }); 53 } 54 /* End Polyfills */ 55 56 var cssPrefixes = ['Webkit', 'Moz', 'ms'], 57 emptyStyles = document.createElement('div').style, 58 EXIF_NORM = [1,8,3,6], 59 EXIF_FLIP = [2,7,4,5], 60 CSS_TRANS_ORG, 61 CSS_TRANSFORM, 62 CSS_USERSELECT; 63 64 function vendorPrefix(prop) { 65 if (prop in emptyStyles) { 66 return prop; 67 } 68 69 var capProp = prop[0].toUpperCase() + prop.slice(1), 70 i = cssPrefixes.length; 71 72 while (i--) { 73 prop = cssPrefixes[i] + capProp; 74 if (prop in emptyStyles) { 75 return prop; 76 } 77 } 78 } 79 80 CSS_TRANSFORM = vendorPrefix('transform'); 81 CSS_TRANS_ORG = vendorPrefix('transformOrigin'); 82 CSS_USERSELECT = vendorPrefix('userSelect'); 83 84 function getExifOffset(ornt, rotate) { 85 var arr = EXIF_NORM.indexOf(ornt) > -1 ? EXIF_NORM : EXIF_FLIP, 86 index = arr.indexOf(ornt), 87 offset = (rotate / 90) % arr.length;// 180 = 2%4 = 2 shift exif by 2 indexes 88 89 return arr[(arr.length + index + (offset % arr.length)) % arr.length]; 90 } 91 92 // Credits to : Andrew Dupont - http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/ 93 function deepExtend(destination, source) { 94 destination = destination || {}; 95 for (var property in source) { 96 if (source[property] && source[property].constructor && source[property].constructor === Object) { 97 destination[property] = destination[property] || {}; 98 deepExtend(destination[property], source[property]); 99 } else { 100 destination[property] = source[property]; 101 } 102 } 103 return destination; 104 } 105 106 function clone(object) { 107 return deepExtend({}, object); 108 } 109 110 function debounce(func, wait, immediate) { 111 var timeout; 112 return function () { 113 var context = this, args = arguments; 114 var later = function () { 115 timeout = null; 116 if (!immediate) func.apply(context, args); 117 }; 118 var callNow = immediate && !timeout; 119 clearTimeout(timeout); 120 timeout = setTimeout(later, wait); 121 if (callNow) func.apply(context, args); 122 }; 123 } 124 125 function dispatchChange(element) { 126 if ("createEvent" in document) { 127 var evt = document.createEvent("HTMLEvents"); 128 evt.initEvent("change", false, true); 129 element.dispatchEvent(evt); 130 } 131 else { 132 element.fireEvent("onchange"); 133 } 134 } 135 136 //http://jsperf.com/vanilla-css 137 function css(el, styles, val) { 138 if (typeof (styles) === 'string') { 139 var tmp = styles; 140 styles = {}; 141 styles[tmp] = val; 142 } 143 144 for (var prop in styles) { 145 el.style[prop] = styles[prop]; 146 } 147 } 148 149 function addClass(el, c) { 150 if (el.classList) { 151 el.classList.add(c); 152 } 153 else { 154 el.className += ' ' + c; 155 } 156 } 157 158 function removeClass(el, c) { 159 if (el.classList) { 160 el.classList.remove(c); 161 } 162 else { 163 el.className = el.className.replace(c, ''); 164 } 165 } 166 167 function setAttributes(el, attrs) { 168 for (var key in attrs) { 169 el.setAttribute(key, attrs[key]); 170 } 171 } 172 173 function num(v) { 174 return parseInt(v, 10); 175 } 176 177 /* Utilities */ 178 function loadImage(src, doExif) {
vendor: 15,047 bytes, lines 178-640
178 179 var img = new Image(); 180 img.style.opacity = '0'; 181 return new Promise(function (resolve, reject) { 182 function _resolve() { 183 img.style.opacity = '1'; 184 setTimeout(function () { 185 resolve(img); 186 }, 1); 187 } 188 189 img.removeAttribute('crossOrigin'); 190 if (src.match(/^https?:\/\/|^\/\//)) { 191 img.setAttribute('crossOrigin', 'anonymous'); 192 } 193 194 img.onload = function () { 195 if (doExif) { 196 EXIF.getData(img, function () { 197 _resolve(); 198 }); 199 } 200 else { 201 _resolve(); 202 } 203 }; 204 img.onerror = function (ev) { 205 img.style.opacity = 1; 206 setTimeout(function () { 207 reject(ev); 208 }, 1); 209 }; 210 img.src = src; 211 }); 212 } 213 214 function naturalImageDimensions(img, ornt) { 215 var w = img.naturalWidth; 216 var h = img.naturalHeight; 217 var orient = ornt || getExifOrientation(img); 218 if (orient && orient >= 5) { 219 var x= w; 220 w = h; 221 h = x; 222 } 223 return { width: w, height: h }; 224 } 225 226 /* CSS Transform Prototype */ 227 var TRANSLATE_OPTS = { 228 'translate3d': { 229 suffix: ', 0px' 230 }, 231 'translate': { 232 suffix: '' 233 } 234 }; 235 var Transform = function (x, y, scale) { 236 this.x = parseFloat(x); 237 this.y = parseFloat(y); 238 this.scale = parseFloat(scale); 239 }; 240 241 Transform.parse = function (v) { 242 if (v.style) { 243 return Transform.parse(v.style[CSS_TRANSFORM]); 244 } 245 else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) { 246 return Transform.fromMatrix(v); 247 } 248 else { 249 return Transform.fromString(v); 250 } 251 }; 252 253 Transform.fromMatrix = function (v) { 254 var vals = v.substring(7).split(','); 255 if (!vals.length || v === 'none') { 256 vals = [1, 0, 0, 1, 0, 0]; 257 } 258 259 return new Transform(num(vals[4]), num(vals[5]), parseFloat(vals[0])); 260 }; 261 262 Transform.fromString = function (v) { 263 var values = v.split(') '), 264 translate = values[0].substring(Croppie.globals.translate.length + 1).split(','), 265 scale = values.length > 1 ? values[1].substring(6) : 1, 266 x = translate.length > 1 ? translate[0] : 0, 267 y = translate.length > 1 ? translate[1] : 0; 268 269 return new Transform(x, y, scale); 270 }; 271 272 Transform.prototype.toString = function () { 273 var suffix = TRANSLATE_OPTS[Croppie.globals.translate].suffix || ''; 274 return Croppie.globals.translate + '(' + this.x + 'px, ' + this.y + 'px' + suffix + ') scale(' + this.scale + ')'; 275 }; 276 277 var TransformOrigin = function (el) { 278 if (!el || !el.style[CSS_TRANS_ORG]) { 279 this.x = 0; 280 this.y = 0; 281 return; 282 } 283 var css = el.style[CSS_TRANS_ORG].split(' '); 284 this.x = parseFloat(css[0]); 285 this.y = parseFloat(css[1]); 286 }; 287 288 TransformOrigin.prototype.toString = function () { 289 return this.x + 'px ' + this.y + 'px'; 290 }; 291 292 function getExifOrientation (img) { 293 return img.exifdata && img.exifdata.Orientation ? num(img.exifdata.Orientation) : 1; 294 } 295 296 function drawCanvas(canvas, img, orientation) { 297 var width = img.width, 298 height = img.height, 299 ctx = canvas.getContext('2d'); 300 301 canvas.width = img.width; 302 canvas.height = img.height; 303 304 ctx.save(); 305 switch (orientation) { 306 case 2: 307 ctx.translate(width, 0); 308 ctx.scale(-1, 1); 309 break; 310 311 case 3: 312 ctx.translate(width, height); 313 ctx.rotate(180*Math.PI/180); 314 break; 315 316 case 4: 317 ctx.translate(0, height); 318 ctx.scale(1, -1); 319 break; 320 321 case 5: 322 canvas.width = height; 323 canvas.height = width; 324 ctx.rotate(90*Math.PI/180); 325 ctx.scale(1, -1); 326 break; 327 328 case 6: 329 canvas.width = height; 330 canvas.height = width; 331 ctx.rotate(90*Math.PI/180); 332 ctx.translate(0, -height); 333 break; 334 335 case 7: 336 canvas.width = height; 337 canvas.height = width; 338 ctx.rotate(-90*Math.PI/180); 339 ctx.translate(-width, height); 340 ctx.scale(1, -1); 341 break; 342 343 case 8: 344 canvas.width = height; 345 canvas.height = width; 346 ctx.translate(0, width); 347 ctx.rotate(-90*Math.PI/180); 348 break; 349 } 350 ctx.drawImage(img, 0,0, width, height); 351 ctx.restore(); 352 } 353 354 /* Private Methods */ 355 function _create() { 356 var self = this, 357 contClass = 'croppie-container', 358 customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null, 359 boundary, img, viewport, overlay, bw, bh; 360 361 self.options.useCanvas = self.options.enableOrientation || _hasExif.call(self); 362 // Properties on class 363 self.data = {}; 364 self.elements = {}; 365 366 boundary = self.elements.boundary = document.createElement('div'); 367 viewport = self.elements.viewport = document.createElement('div'); 368 img = self.elements.img = document.createElement('img'); 369 overlay = self.elements.overlay = document.createElement('div'); 370 371 if (self.options.useCanvas) { 372 self.elements.canvas = document.createElement('canvas'); 373 self.elements.preview = self.elements.canvas; 374 } 375 else { 376 self.elements.preview = img; 377 } 378 379 addClass(boundary, 'cr-boundary'); 380 boundary.setAttribute('aria-dropeffect', 'none'); 381 bw = self.options.boundary.width; 382 bh = self.options.boundary.height; 383 css(boundary, { 384 width: (bw + (isNaN(bw) ? '' : 'px')), 385 height: (bh + (isNaN(bh) ? '' : 'px')) 386 }); 387 388 addClass(viewport, 'cr-viewport'); 389 if (customViewportClass) { 390 addClass(viewport, customViewportClass); 391 } 392 css(viewport, { 393 width: self.options.viewport.width + 'px', 394 height: self.options.viewport.height + 'px' 395 }); 396 viewport.setAttribute('tabindex', 0); 397 398 addClass(self.elements.preview, 'cr-image'); 399 setAttributes(self.elements.preview, { 'alt': 'preview', 'aria-grabbed': 'false' }); 400 addClass(overlay, 'cr-overlay'); 401 402 self.element.appendChild(boundary); 403 boundary.appendChild(self.elements.preview); 404 boundary.appendChild(viewport); 405 boundary.appendChild(overlay); 406 407 addClass(self.element, contClass); 408 if (self.options.customClass) { 409 addClass(self.element, self.options.customClass); 410 } 411 412 _initDraggable.call(this); 413 414 if (self.options.enableZoom) { 415 _initializeZoom.call(self); 416 } 417 418 // if (self.options.enableOrientation) { 419 // _initRotationControls.call(self); 420 // } 421 422 if (self.options.enableResize) { 423 _initializeResize.call(self); 424 } 425 } 426 427 // function _initRotationControls () { 428 // var self = this, 429 // wrap, btnLeft, btnRight, iLeft, iRight; 430 431 // wrap = document.createElement('div'); 432 // self.elements.orientationBtnLeft = btnLeft = document.createElement('button'); 433 // self.elements.orientationBtnRight = btnRight = document.createElement('button'); 434 435 // wrap.appendChild(btnLeft); 436 // wrap.appendChild(btnRight); 437 438 // iLeft = document.createElement('i'); 439 // iRight = document.createElement('i'); 440 // btnLeft.appendChild(iLeft); 441 // btnRight.appendChild(iRight); 442 443 // addClass(wrap, 'cr-rotate-controls'); 444 // addClass(btnLeft, 'cr-rotate-l'); 445 // addClass(btnRight, 'cr-rotate-r'); 446 447 // self.elements.boundary.appendChild(wrap); 448 449 // btnLeft.addEventListener('click', function () { 450 // self.rotate(-90); 451 // }); 452 // btnRight.addEventListener('click', function () { 453 // self.rotate(90); 454 // }); 455 // } 456 457 function _hasExif() { 458 return this.options.enableExif && window.EXIF; 459 } 460 461 function _initializeResize () { 462 var self = this; 463 var wrap = document.createElement('div'); 464 var isDragging = false; 465 var direction; 466 var originalX; 467 var originalY; 468 var minSize = 50; 469 var maxWidth; 470 var maxHeight; 471 var vr; 472 var hr; 473 474 addClass(wrap, 'cr-resizer'); 475 css(wrap, { 476 width: this.options.viewport.width + 'px', 477 height: this.options.viewport.height + 'px' 478 }); 479 480 if (this.options.resizeControls.height) { 481 vr = document.createElement('div'); 482 addClass(vr, 'cr-resizer-vertical'); 483 wrap.appendChild(vr); 484 } 485 486 if (this.options.resizeControls.width) { 487 hr = document.createElement('div'); 488 addClass(hr, 'cr-resizer-horisontal'); 489 wrap.appendChild(hr); 490 } 491 492 function mouseDown(ev) { 493 if (ev.button !== undefined && ev.button !== 0) return; 494 495 ev.preventDefault(); 496 if (isDragging) { 497 return; 498 } 499 500 var overlayRect = self.elements.overlay.getBoundingClientRect(); 501 502 isDragging = true; 503 originalX = ev.pageX; 504 originalY = ev.pageY; 505 direction = ev.currentTarget.className.indexOf('vertical') !== -1 ? 'v' : 'h'; 506 maxWidth = overlayRect.width; 507 maxHeight = overlayRect.height; 508 509 if (ev.touches) { 510 var touches = ev.touches[0]; 511 originalX = touches.pageX; 512 originalY = touches.pageY; 513 } 514 515 window.addEventListener('mousemove', mouseMove); 516 window.addEventListener('touchmove', mouseMove); 517 window.addEventListener('mouseup', mouseUp); 518 window.addEventListener('touchend', mouseUp); 519 document.body.style[CSS_USERSELECT] = 'none'; 520 } 521 522 function mouseMove(ev) { 523 var pageX = ev.pageX; 524 var pageY = ev.pageY; 525 526 ev.preventDefault(); 527 528 if (ev.touches) { 529 var touches = ev.touches[0]; 530 pageX = touches.pageX; 531 pageY = touches.pageY; 532 } 533 534 var deltaX = pageX - originalX; 535 var deltaY = pageY - originalY; 536 var newHeight = self.options.viewport.height + deltaY; 537 var newWidth = self.options.viewport.width + deltaX; 538 539 if (direction === 'v' && newHeight >= minSize && newHeight <= maxHeight) { 540 css(wrap, { 541 height: newHeight + 'px' 542 }); 543 544 self.options.boundary.height += deltaY; 545 css(self.elements.boundary, { 546 height: self.options.boundary.height + 'px' 547 }); 548 549 self.options.viewport.height += deltaY; 550 css(self.elements.viewport, { 551 height: self.options.viewport.height + 'px' 552 }); 553 } 554 else if (direction === 'h' && newWidth >= minSize && newWidth <= maxWidth) { 555 css(wrap, { 556 width: newWidth + 'px' 557 }); 558 559 self.options.boundary.width += deltaX; 560 css(self.elements.boundary, { 561 width: self.options.boundary.width + 'px' 562 }); 563 564 self.options.viewport.width += deltaX; 565 css(self.elements.viewport, { 566 width: self.options.viewport.width + 'px' 567 }); 568 } 569 570 _updateOverlay.call(self); 571 _updateZoomLimits.call(self); 572 _updateCenterPoint.call(self); 573 _triggerUpdate.call(self); 574 originalY = pageY; 575 originalX = pageX; 576 } 577 578 function mouseUp() { 579 isDragging = false; 580 window.removeEventListener('mousemove', mouseMove); 581 window.removeEventListener('touchmove', mouseMove); 582 window.removeEventListener('mouseup', mouseUp); 583 window.removeEventListener('touchend', mouseUp); 584 document.body.style[CSS_USERSELECT] = ''; 585 } 586 587 if (vr) { 588 vr.addEventListener('mousedown', mouseDown); 589 vr.addEventListener('touchstart', mouseDown); 590 } 591 592 if (hr) { 593 hr.addEventListener('mousedown', mouseDown); 594 hr.addEventListener('touchstart', mouseDown); 595 } 596 597 this.elements.boundary.appendChild(wrap); 598 } 599 600 function _setZoomerVal(v) { 601 if (this.options.enableZoom) { 602 var z = this.elements.zoomer, 603 val = fix(v, 4); 604 605 z.value = Math.max(parseFloat(z.min), Math.min(parseFloat(z.max), val)).toString(); 606 } 607 } 608 609 function _initializeZoom() { 610 var self = this, 611 wrap = self.elements.zoomerWrap = document.createElement('div'), 612 zoomer = self.elements.zoomer = document.createElement('input'); 613 614 addClass(wrap, 'cr-slider-wrap'); 615 addClass(zoomer, 'cr-slider'); 616 zoomer.type = 'range'; 617 zoomer.step = '0.0001'; 618 zoomer.value = '1'; 619 zoomer.style.display = self.options.showZoomer ? '' : 'none'; 620 zoomer.setAttribute('aria-label', 'zoom'); 621 622 self.element.appendChild(wrap); 623 wrap.appendChild(zoomer); 624 625 self._currentZoom = 1; 626 627 function change() { 628 _onZoom.call(self, { 629 value: parseFloat(zoomer.value), 630 origin: new TransformOrigin(self.elements.preview), 631 viewportRect: self.elements.viewport.getBoundingClientRect(), 632 transform: Transform.parse(self.elements.preview) 633 }); 634 } 635 636 function scroll(ev) { 637 var delta, targetZoom; 638 639 if(self.options.mouseWheelZoom === 'ctrl' && ev.ctrlKey !== true){ 640 return 0;
640
vendor: 14,569 bytes, lines 640-1038
640 641 } else if (ev.wheelDelta) { 642 delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2 643 } else if (ev.deltaY) { 644 delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2 645 } else if (ev.detail) { 646 delta = ev.detail / -60; //delta min: -3 max: 3 // max x 10 x 2 647 } else { 648 delta = 0; 649 } 650 651 targetZoom = self._currentZoom + (delta * self._currentZoom); 652 653 ev.preventDefault(); 654 _setZoomerVal.call(self, targetZoom); 655 change.call(self); 656 } 657 658 self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress 659 self.elements.zoomer.addEventListener('change', change); 660 661 if (self.options.mouseWheelZoom) { 662 self.elements.boundary.addEventListener('mousewheel', scroll); 663 self.elements.boundary.addEventListener('DOMMouseScroll', scroll); 664 } 665 } 666 667 function _onZoom(ui) { 668 var self = this, 669 transform = ui ? ui.transform : Transform.parse(self.elements.preview), 670 vpRect = ui ? ui.viewportRect : self.elements.viewport.getBoundingClientRect(), 671 origin = ui ? ui.origin : new TransformOrigin(self.elements.preview); 672 673 function applyCss() { 674 var transCss = {}; 675 transCss[CSS_TRANSFORM] = transform.toString(); 676 transCss[CSS_TRANS_ORG] = origin.toString(); 677 css(self.elements.preview, transCss); 678 } 679 680 self._currentZoom = ui ? ui.value : self._currentZoom; 681 transform.scale = self._currentZoom; 682 self.elements.zoomer.setAttribute('aria-valuenow', self._currentZoom); 683 applyCss(); 684 685 if (self.options.enforceBoundary) { 686 var boundaries = _getVirtualBoundaries.call(self, vpRect), 687 transBoundaries = boundaries.translate, 688 oBoundaries = boundaries.origin; 689 690 if (transform.x >= transBoundaries.maxX) { 691 origin.x = oBoundaries.minX; 692 transform.x = transBoundaries.maxX; 693 } 694 695 if (transform.x <= transBoundaries.minX) { 696 origin.x = oBoundaries.maxX; 697 transform.x = transBoundaries.minX; 698 } 699 700 if (transform.y >= transBoundaries.maxY) { 701 origin.y = oBoundaries.minY; 702 transform.y = transBoundaries.maxY; 703 } 704 705 if (transform.y <= transBoundaries.minY) { 706 origin.y = oBoundaries.maxY; 707 transform.y = transBoundaries.minY; 708 } 709 } 710 applyCss(); 711 _debouncedOverlay.call(self); 712 _triggerUpdate.call(self); 713 } 714 715 function _getVirtualBoundaries(viewport) { 716 var self = this, 717 scale = self._currentZoom, 718 vpWidth = viewport.width, 719 vpHeight = viewport.height, 720 centerFromBoundaryX = self.elements.boundary.clientWidth / 2, 721 centerFromBoundaryY = self.elements.boundary.clientHeight / 2, 722 imgRect = self.elements.preview.getBoundingClientRect(), 723 curImgWidth = imgRect.width, 724 curImgHeight = imgRect.height, 725 halfWidth = vpWidth / 2, 726 halfHeight = vpHeight / 2; 727 728 var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1; 729 var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale))); 730 731 var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1; 732 var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale))); 733 734 var originMinX = (1 / scale) * halfWidth; 735 var originMaxX = (curImgWidth * (1 / scale)) - originMinX; 736 737 var originMinY = (1 / scale) * halfHeight; 738 var originMaxY = (curImgHeight * (1 / scale)) - originMinY; 739 740 return { 741 translate: { 742 maxX: maxX, 743 minX: minX, 744 maxY: maxY, 745 minY: minY 746 }, 747 origin: { 748 maxX: originMaxX, 749 minX: originMinX, 750 maxY: originMaxY, 751 minY: originMinY 752 } 753 }; 754 } 755 756 function _updateCenterPoint(rotate) { 757 var self = this, 758 scale = self._currentZoom, 759 data = self.elements.preview.getBoundingClientRect(), 760 vpData = self.elements.viewport.getBoundingClientRect(), 761 transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]), 762 pc = new TransformOrigin(self.elements.preview), 763 top = (vpData.top - data.top) + (vpData.height / 2), 764 left = (vpData.left - data.left) + (vpData.width / 2), 765 center = {}, 766 adj = {}; 767 768 if (rotate) { 769 var cx = pc.x; 770 var cy = pc.y; 771 var tx = transform.x; 772 var ty = transform.y; 773 774 center.y = cx; 775 center.x = cy; 776 transform.y = tx; 777 transform.x = ty; 778 } 779 else { 780 center.y = top / scale; 781 center.x = left / scale; 782 783 adj.y = (center.y - pc.y) * (1 - scale); 784 adj.x = (center.x - pc.x) * (1 - scale); 785 786 transform.x -= adj.x; 787 transform.y -= adj.y; 788 } 789 790 var newCss = {}; 791 newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px'; 792 newCss[CSS_TRANSFORM] = transform.toString(); 793 css(self.elements.preview, newCss); 794 } 795 796 function _initDraggable() { 797 var self = this, 798 isDragging = false, 799 originalX, 800 originalY, 801 originalDistance, 802 vpRect, 803 transform; 804 805 function assignTransformCoordinates(deltaX, deltaY) { 806 var imgRect = self.elements.preview.getBoundingClientRect(), 807 top = transform.y + deltaY, 808 left = transform.x + deltaX; 809 810 if (self.options.enforceBoundary) { 811 if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) { 812 transform.y = top; 813 } 814 815 if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) { 816 transform.x = left; 817 } 818 } 819 else { 820 transform.y = top; 821 transform.x = left; 822 } 823 } 824 825 function toggleGrabState(isDragging) { 826 self.elements.preview.setAttribute('aria-grabbed', isDragging); 827 self.elements.boundary.setAttribute('aria-dropeffect', isDragging? 'move': 'none'); 828 } 829 830 function keyDown(ev) { 831 var LEFT_ARROW = 37, 832 UP_ARROW = 38, 833 RIGHT_ARROW = 39, 834 DOWN_ARROW = 40; 835 836 if (ev.shiftKey && (ev.keyCode === UP_ARROW || ev.keyCode === DOWN_ARROW)) { 837 var zoom; 838 if (ev.keyCode === UP_ARROW) { 839 zoom = parseFloat(self.elements.zoomer.value) + parseFloat(self.elements.zoomer.step) 840 } 841 else { 842 zoom = parseFloat(self.elements.zoomer.value) - parseFloat(self.elements.zoomer.step) 843 } 844 self.setZoom(zoom); 845 } 846 else if (self.options.enableKeyMovement && (ev.keyCode >= 37 && ev.keyCode <= 40)) { 847 ev.preventDefault(); 848 var movement = parseKeyDown(ev.keyCode); 849 850 transform = Transform.parse(self.elements.preview); 851 document.body.style[CSS_USERSELECT] = 'none'; 852 vpRect = self.elements.viewport.getBoundingClientRect(); 853 keyMove(movement); 854 } 855 856 function parseKeyDown(key) { 857 switch (key) { 858 case LEFT_ARROW: 859 return [1, 0]; 860 case UP_ARROW: 861 return [0, 1]; 862 case RIGHT_ARROW: 863 return [-1, 0]; 864 case DOWN_ARROW: 865 return [0, -1]; 866 } 867 } 868 } 869 870 function keyMove(movement) { 871 var deltaX = movement[0], 872 deltaY = movement[1], 873 newCss = {}; 874 875 assignTransformCoordinates(deltaX, deltaY); 876 877 newCss[CSS_TRANSFORM] = transform.toString(); 878 css(self.elements.preview, newCss); 879 _updateOverlay.call(self); 880 document.body.style[CSS_USERSELECT] = ''; 881 _updateCenterPoint.call(self); 882 _triggerUpdate.call(self); 883 originalDistance = 0; 884 } 885 886 function mouseDown(ev) { 887 if (ev.button !== undefined && ev.button !== 0) return; 888 889 ev.preventDefault(); 890 if (isDragging) return; 891 isDragging = true; 892 originalX = ev.pageX; 893 originalY = ev.pageY; 894 895 if (ev.touches) { 896 var touches = ev.touches[0]; 897 originalX = touches.pageX; 898 originalY = touches.pageY; 899 } 900 toggleGrabState(isDragging); 901 transform = Transform.parse(self.elements.preview); 902 window.addEventListener('mousemove', mouseMove); 903 window.addEventListener('touchmove', mouseMove); 904 window.addEventListener('mouseup', mouseUp); 905 window.addEventListener('touchend', mouseUp); 906 document.body.style[CSS_USERSELECT] = 'none'; 907 vpRect = self.elements.viewport.getBoundingClientRect(); 908 } 909 910 function mouseMove(ev) { 911 ev.preventDefault(); 912 var pageX = ev.pageX, 913 pageY = ev.pageY; 914 915 if (ev.touches) { 916 var touches = ev.touches[0]; 917 pageX = touches.pageX; 918 pageY = touches.pageY; 919 } 920 921 var deltaX = pageX - originalX, 922 deltaY = pageY - originalY, 923 newCss = {}; 924 925 if (ev.type === 'touchmove') { 926 if (ev.touches.length > 1) { 927 var touch1 = ev.touches[0]; 928 var touch2 = ev.touches[1]; 929 var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY)); 930 931 if (!originalDistance) { 932 originalDistance = dist / self._currentZoom; 933 } 934 935 var scale = dist / originalDistance; 936 937 _setZoomerVal.call(self, scale); 938 dispatchChange(self.elements.zoomer); 939 return; 940 } 941 } 942 943 assignTransformCoordinates(deltaX, deltaY); 944 945 newCss[CSS_TRANSFORM] = transform.toString(); 946 css(self.elements.preview, newCss); 947 _updateOverlay.call(self); 948 originalY = pageY; 949 originalX = pageX; 950 } 951 952 function mouseUp() { 953 isDragging = false; 954 toggleGrabState(isDragging); 955 window.removeEventListener('mousemove', mouseMove); 956 window.removeEventListener('touchmove', mouseMove); 957 window.removeEventListener('mouseup', mouseUp); 958 window.removeEventListener('touchend', mouseUp); 959 document.body.style[CSS_USERSELECT] = ''; 960 _updateCenterPoint.call(self); 961 _triggerUpdate.call(self); 962 originalDistance = 0; 963 } 964 965 self.elements.overlay.addEventListener('mousedown', mouseDown); 966 self.elements.viewport.addEventListener('keydown', keyDown); 967 self.elements.overlay.addEventListener('touchstart', mouseDown); 968 } 969 970 function _updateOverlay() { 971 if (!this.elements) return; // since this is debounced, it can be fired after destroy 972 var self = this, 973 boundRect = self.elements.boundary.getBoundingClientRect(), 974 imgData = self.elements.preview.getBoundingClientRect(); 975 976 css(self.elements.overlay, { 977 width: imgData.width + 'px', 978 height: imgData.height + 'px', 979 top: (imgData.top - boundRect.top) + 'px', 980 left: (imgData.left - boundRect.left) + 'px' 981 }); 982 } 983 var _debouncedOverlay = debounce(_updateOverlay, 500); 984 985 function _triggerUpdate() { 986 var self = this, 987 data = self.get(); 988 989 if (!_isVisible.call(self)) { 990 return; 991 } 992 993 self.options.update.call(self, data); 994 if (self.$ && typeof Prototype === 'undefined') { 995 self.$(self.element).trigger('update.croppie', data); 996 } 997 else { 998 var ev; 999 if (window.CustomEvent) { 1000 ev = new CustomEvent('update', { detail: data }); 1001 } else { 1002 ev = document.createEvent('CustomEvent'); 1003 ev.initCustomEvent('update', true, true, data); 1004 } 1005 1006 self.element.dispatchEvent(ev); 1007 } 1008 } 1009 1010 function _isVisible() { 1011 return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0; 1012 } 1013 1014 function _updatePropertiesFromImage() { 1015 var self = this, 1016 initialZoom = 1, 1017 cssReset = {}, 1018 img = self.elements.preview, 1019 imgData, 1020 transformReset = new Transform(0, 0, initialZoom), 1021 originReset = new TransformOrigin(), 1022 isVisible = _isVisible.call(self); 1023 1024 if (!isVisible || self.data.bound) {// if the croppie isn't visible or it doesn't need binding 1025 return; 1026 } 1027 1028 self.data.bound = true; 1029 cssReset[CSS_TRANSFORM] = transformReset.toString(); 1030 cssReset[CSS_TRANS_ORG] = originReset.toString(); 1031 cssReset['opacity'] = 1; 1032 css(img, cssReset); 1033 1034 imgData = self.elements.preview.getBoundingClientRect(); 1035 1036 self._originalImageWidth = imgData.width; 1037 self._originalImageHeight = imgData.height; 1038 self.data.orientation =
vendor: 1,602 bytes, lines 1038-1087
1038getExifOrientation(self.elements.img); 1039 1040 if (self.options.enableZoom) { 1041 _updateZoomLimits.call(self, true); 1042 } 1043 else { 1044 self._currentZoom = initialZoom; 1045 } 1046 1047 transformReset.scale = self._currentZoom; 1048 cssReset[CSS_TRANSFORM] = transformReset.toString(); 1049 css(img, cssReset); 1050 1051 if (self.data.points.length) { 1052 _bindPoints.call(self, self.data.points); 1053 } 1054 else { 1055 _centerImage.call(self); 1056 } 1057 1058 _updateCenterPoint.call(self); 1059 _updateOverlay.call(self); 1060 } 1061 1062 function _updateZoomLimits (initial) { 1063 var self = this, 1064 minZoom = Math.max(self.options.minZoom, 0) || 0, 1065 maxZoom = self.options.maxZoom || 1.5, 1066 initialZoom, 1067 defaultInitialZoom, 1068 zoomer = self.elements.zoomer, 1069 scale = parseFloat(zoomer.value), 1070 boundaryData = self.elements.boundary.getBoundingClientRect(), 1071 imgData = naturalImageDimensions(self.elements.img, self.data.orientation), 1072 vpData = self.elements.viewport.getBoundingClientRect(), 1073 minW, 1074 minH; 1075 if (self.options.enforceBoundary) { 1076 minW = vpData.width / imgData.width; 1077 minH = vpData.height / imgData.height; 1078 minZoom = Math.max(minW, minH); 1079 } 1080 1081 if (minZoom >= maxZoom) { 1082 maxZoom = minZoom + 1; 1083 } 1084 1085 zoomer.min = fix(minZoom, 4); 1086 zoomer.max = fix(maxZoom, 4); 1087
vendor: 9,518 bytes, lines 1087-1345
1087 1088 if (!initial && (scale < zoomer.min || scale > zoomer.max)) { 1089 _setZoomerVal.call(self, scale < zoomer.min ? zoomer.min : zoomer.max); 1090 } 1091 else if (initial) { 1092 defaultInitialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height)); 1093 initialZoom = self.data.boundZoom !== null ? self.data.boundZoom : defaultInitialZoom; 1094 _setZoomerVal.call(self, initialZoom); 1095 } 1096 1097 dispatchChange(zoomer); 1098 } 1099 1100 function _bindPoints(points) { 1101 if (points.length !== 4) { 1102 throw "Croppie - Invalid number of points supplied: " + points; 1103 } 1104 var self = this, 1105 pointsWidth = points[2] - points[0], 1106 // pointsHeight = points[3] - points[1], 1107 vpData = self.elements.viewport.getBoundingClientRect(), 1108 boundRect = self.elements.boundary.getBoundingClientRect(), 1109 vpOffset = { 1110 left: vpData.left - boundRect.left, 1111 top: vpData.top - boundRect.top 1112 }, 1113 scale = vpData.width / pointsWidth, 1114 originTop = points[1], 1115 originLeft = points[0], 1116 transformTop = (-1 * points[1]) + vpOffset.top, 1117 transformLeft = (-1 * points[0]) + vpOffset.left, 1118 newCss = {}; 1119 1120 newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px'; 1121 newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString(); 1122 css(self.elements.preview, newCss); 1123 1124 _setZoomerVal.call(self, scale); 1125 self._currentZoom = scale; 1126 } 1127 1128 function _centerImage() { 1129 var self = this, 1130 imgDim = self.elements.preview.getBoundingClientRect(), 1131 vpDim = self.elements.viewport.getBoundingClientRect(), 1132 boundDim = self.elements.boundary.getBoundingClientRect(), 1133 vpLeft = vpDim.left - boundDim.left, 1134 vpTop = vpDim.top - boundDim.top, 1135 w = vpLeft - ((imgDim.width - vpDim.width) / 2), 1136 h = vpTop - ((imgDim.height - vpDim.height) / 2), 1137 transform = new Transform(w, h, self._currentZoom); 1138 1139 css(self.elements.preview, CSS_TRANSFORM, transform.toString()); 1140 } 1141 1142 function _transferImageToCanvas(customOrientation) { 1143 var self = this, 1144 canvas = self.elements.canvas, 1145 img = self.elements.img, 1146 ctx = canvas.getContext('2d'); 1147 1148 ctx.clearRect(0, 0, canvas.width, canvas.height); 1149 canvas.width = img.width; 1150 canvas.height = img.height; 1151 1152 var orientation = self.options.enableOrientation && customOrientation || getExifOrientation(img); 1153 drawCanvas(canvas, img, orientation); 1154 } 1155 1156 function _getCanvas(data) { 1157 var self = this, 1158 points = data.points, 1159 left = num(points[0]), 1160 top = num(points[1]), 1161 right = num(points[2]), 1162 bottom = num(points[3]), 1163 width = right-left, 1164 height = bottom-top, 1165 circle = data.circle, 1166 canvas = document.createElement('canvas'), 1167 ctx = canvas.getContext('2d'), 1168 startX = 0, 1169 startY = 0, 1170 canvasWidth = data.outputWidth || width, 1171 canvasHeight = data.outputHeight || height; 1172 1173 canvas.width = canvasWidth; 1174 canvas.height = canvasHeight; 1175 1176 if (data.backgroundColor) { 1177 ctx.fillStyle = data.backgroundColor; 1178 ctx.fillRect(0, 0, canvasWidth, canvasHeight); 1179 } 1180 1181 // By default assume we're going to draw the entire 1182 // source image onto the destination canvas. 1183 var sx = left, 1184 sy = top, 1185 sWidth = width, 1186 sHeight = height, 1187 dx = 0, 1188 dy = 0, 1189 dWidth = canvasWidth, 1190 dHeight = canvasHeight; 1191 1192 // 1193 // Do not go outside of the original image's bounds along the x-axis. 1194 // Handle translations when projecting onto the destination canvas. 1195 // 1196 1197 // The smallest possible source x-position is 0. 1198 if (left < 0) { 1199 sx = 0; 1200 dx = (Math.abs(left) / width) * canvasWidth; 1201 } 1202 1203 // The largest possible source width is the original image's width. 1204 if (sWidth + sx > self._originalImageWidth) { 1205 sWidth = self._originalImageWidth - sx; 1206 dWidth = (sWidth / width) * canvasWidth; 1207 } 1208 1209 // 1210 // Do not go outside of the original image's bounds along the y-axis. 1211 // 1212 1213 // The smallest possible source y-position is 0. 1214 if (top < 0) { 1215 sy = 0; 1216 dy = (Math.abs(top) / height) * canvasHeight; 1217 } 1218 1219 // The largest possible source height is the original image's height. 1220 if (sHeight + sy > self._originalImageHeight) { 1221 sHeight = self._originalImageHeight - sy; 1222 dHeight = (sHeight / height) * canvasHeight; 1223 } 1224 1225 // console.table({ left, right, top, bottom, canvasWidth, canvasHeight, width, height, startX, startY, circle, sx, sy, dx, dy, sWidth, sHeight, dWidth, dHeight }); 1226 1227 ctx.drawImage(this.elements.preview, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); 1228 if (circle) { 1229 ctx.fillStyle = '#fff'; 1230 ctx.globalCompositeOperation = 'destination-in'; 1231 ctx.beginPath(); 1232 ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true); 1233 ctx.closePath(); 1234 ctx.fill(); 1235 } 1236 return canvas; 1237 } 1238 1239 function _getHtmlResult(data) { 1240 var points = data.points, 1241 div = document.createElement('div'), 1242 img = document.createElement('img'), 1243 width = points[2] - points[0], 1244 height = points[3] - points[1]; 1245 1246 addClass(div, 'croppie-result'); 1247 div.appendChild(img); 1248 css(img, { 1249 left: (-1 * points[0]) + 'px', 1250 top: (-1 * points[1]) + 'px' 1251 }); 1252 img.src = data.url; 1253 css(div, { 1254 width: width + 'px', 1255 height: height + 'px' 1256 }); 1257 1258 return div; 1259 } 1260 1261 function _getBase64Result(data) { 1262 return _getCanvas.call(this, data).toDataURL(data.format, data.quality); 1263 } 1264 1265 function _getBlobResult(data) { 1266 var self = this; 1267 return new Promise(function (resolve) { 1268 _getCanvas.call(self, data).toBlob(function (blob) { 1269 resolve(blob); 1270 }, data.format, data.quality); 1271 }); 1272 } 1273 1274 function _replaceImage(img) { 1275 if (this.elements.img.parentNode) { 1276 Array.prototype.forEach.call(this.elements.img.classList, function(c) { img.classList.add(c); }); 1277 this.elements.img.parentNode.replaceChild(img, this.elements.img); 1278 this.elements.preview = img; // if the img is attached to the DOM, they're not using the canvas 1279 } 1280 this.elements.img = img; 1281 } 1282 1283 function _bind(options, cb) { 1284 var self = this, 1285 url, 1286 points = [], 1287 zoom = null, 1288 hasExif = _hasExif.call(self); 1289 1290 if (typeof (options) === 'string') { 1291 url = options; 1292 options = {}; 1293 } 1294 else if (Array.isArray(options)) { 1295 points = options.slice(); 1296 } 1297 else if (typeof (options) === 'undefined' && self.data.url) { //refreshing 1298 _updatePropertiesFromImage.call(self); 1299 _triggerUpdate.call(self); 1300 return null; 1301 } 1302 else { 1303 url = options.url; 1304 points = options.points || []; 1305 zoom = typeof(options.zoom) === 'undefined' ? null : options.zoom; 1306 } 1307 1308 self.data.bound = false; 1309 self.data.url = url || self.data.url; 1310 self.data.boundZoom = zoom; 1311 1312 return loadImage(url, hasExif).then(function (img) { 1313 _replaceImage.call(self, img); 1314 if (!points.length) { 1315 var natDim = naturalImageDimensions(img); 1316 var rect = self.elements.viewport.getBoundingClientRect(); 1317 var aspectRatio = rect.width / rect.height; 1318 var imgAspectRatio = natDim.width / natDim.height; 1319 var width, height; 1320 1321 if (imgAspectRatio > aspectRatio) { 1322 height = natDim.height; 1323 width = height * aspectRatio; 1324 } 1325 else { 1326 width = natDim.width; 1327 height = natDim.height / aspectRatio; 1328 } 1329 1330 var x0 = (natDim.width - width) / 2; 1331 var y0 = (natDim.height - height) / 2; 1332 var x1 = x0 + width; 1333 var y1 = y0 + height; 1334 self.data.points = [x0, y0, x1, y1]; 1335 } 1336 else if (self.options.relative) { 1337 points = [ 1338 points[0] * img.naturalWidth / 100, 1339 points[1] * img.naturalHeight / 100, 1340 points[2] * img.naturalWidth / 100, 1341 points[3] * img.naturalHeight / 100 1342 ]; 1343 } 1344 1345 self.data.
vendor: 5,012 bytes, lines 1345-1485
1345points = points.map(function (p) { 1346 return parseFloat(p); 1347 }); 1348 if (self.options.useCanvas) { 1349 _transferImageToCanvas.call(self, options.orientation); 1350 } 1351 _updatePropertiesFromImage.call(self); 1352 _triggerUpdate.call(self); 1353 cb && cb(); 1354 }); 1355 } 1356 1357 function fix(v, decimalPoints) { 1358 return parseFloat(v).toFixed(decimalPoints || 0); 1359 } 1360 1361 function _get() { 1362 var self = this, 1363 imgData = self.elements.preview.getBoundingClientRect(), 1364 vpData = self.elements.viewport.getBoundingClientRect(), 1365 x1 = vpData.left - imgData.left, 1366 y1 = vpData.top - imgData.top, 1367 widthDiff = (vpData.width - self.elements.viewport.offsetWidth) / 2, //border 1368 heightDiff = (vpData.height - self.elements.viewport.offsetHeight) / 2, 1369 x2 = x1 + self.elements.viewport.offsetWidth + widthDiff, 1370 y2 = y1 + self.elements.viewport.offsetHeight + heightDiff, 1371 scale = self._currentZoom; 1372 1373 if (scale === Infinity || isNaN(scale)) { 1374 scale = 1; 1375 } 1376 1377 var max = self.options.enforceBoundary ? 0 : Number.NEGATIVE_INFINITY; 1378 x1 = Math.max(max, x1 / scale); 1379 y1 = Math.max(max, y1 / scale); 1380 x2 = Math.max(max, x2 / scale); 1381 y2 = Math.max(max, y2 / scale); 1382 1383 return { 1384 points: [fix(x1), fix(y1), fix(x2), fix(y2)], 1385 zoom: scale, 1386 orientation: self.data.orientation 1387 }; 1388 } 1389 1390 var RESULT_DEFAULTS = { 1391 type: 'canvas', 1392 format: 'png', 1393 quality: 1 1394 }, 1395 RESULT_FORMATS = ['jpeg', 'webp', 'png']; 1396 1397 function _result(options) { 1398 var self = this, 1399 data = _get.call(self), 1400 opts = deepExtend(clone(RESULT_DEFAULTS), clone(options)), 1401 resultType = (typeof (options) === 'string' ? options : (opts.type || 'base64')), 1402 size = opts.size || 'viewport', 1403 format = opts.format, 1404 quality = opts.quality, 1405 backgroundColor = opts.backgroundColor, 1406 circle = typeof opts.circle === 'boolean' ? opts.circle : (self.options.viewport.type === 'circle'), 1407 vpRect = self.elements.viewport.getBoundingClientRect(), 1408 ratio = vpRect.width / vpRect.height, 1409 prom; 1410 1411 if (size === 'viewport') { 1412 data.outputWidth = vpRect.width; 1413 data.outputHeight = vpRect.height; 1414 } else if (typeof size === 'object') { 1415 if (size.width && size.height) { 1416 data.outputWidth = size.width; 1417 data.outputHeight = size.height; 1418 } else if (size.width) { 1419 data.outputWidth = size.width; 1420 data.outputHeight = size.width / ratio; 1421 } else if (size.height) { 1422 data.outputWidth = size.height * ratio; 1423 data.outputHeight = size.height; 1424 } 1425 } 1426 1427 if (RESULT_FORMATS.indexOf(format) > -1) { 1428 data.format = 'image/' + format; 1429 data.quality = quality; 1430 } 1431 1432 data.circle = circle; 1433 data.url = self.data.url; 1434 data.backgroundColor = backgroundColor; 1435 1436 prom = new Promise(function (resolve) { 1437 switch(resultType.toLowerCase()) 1438 { 1439 case 'rawcanvas': 1440 resolve(_getCanvas.call(self, data)); 1441 break; 1442 case 'canvas': 1443 case 'base64': 1444 resolve(_getBase64Result.call(self, data)); 1445 break; 1446 case 'blob': 1447 _getBlobResult.call(self, data).then(resolve); 1448 break; 1449 default: 1450 resolve(_getHtmlResult.call(self, data)); 1451 break; 1452 } 1453 }); 1454 return prom; 1455 } 1456 1457 function _refresh() { 1458 _updatePropertiesFromImage.call(this); 1459 } 1460 1461 function _rotate(deg) { 1462 if (!this.options.useCanvas || !this.options.enableOrientation) { 1463 throw 'Croppie: Cannot rotate without enableOrientation && EXIF.js included'; 1464 } 1465 1466 var self = this, 1467 canvas = self.elements.canvas; 1468 1469 self.data.orientation = getExifOffset(self.data.orientation, deg); 1470 drawCanvas(canvas, self.elements.img, self.data.orientation); 1471 _updateCenterPoint.call(self, true); 1472 _updateZoomLimits.call(self); 1473 } 1474 1475 function _destroy() { 1476 var self = this; 1477 self.element.removeChild(self.elements.boundary); 1478 removeClass(self.element, 'croppie-container'); 1479 if (self.options.enableZoom) { 1480 self.element.removeChild(self.elements.zoomerWrap); 1481 } 1482 delete self.elements; 1483 } 1484 1485 if (
vendor: 4,616 bytes, lines 1485-1625
1485window.jQuery) { 1486 var $ = window.jQuery; 1487 $.fn.croppie = function (opts) { 1488 var ot = typeof opts; 1489 1490 if (ot === 'string') { 1491 var args = Array.prototype.slice.call(arguments, 1); 1492 var singleInst = $(this).data('croppie'); 1493 1494 if (opts === 'get') { 1495 return singleInst.get(); 1496 } 1497 else if (opts === 'result') { 1498 return singleInst.result.apply(singleInst, args); 1499 } 1500 else if (opts === 'bind') { 1501 return singleInst.bind.apply(singleInst, args); 1502 } 1503 1504 return this.each(function () { 1505 var i = $(this).data('croppie'); 1506 if (!i) return; 1507 1508 var method = i[opts]; 1509 if ($.isFunction(method)) { 1510 method.apply(i, args); 1511 if (opts === 'destroy') { 1512 $(this).removeData('croppie'); 1513 } 1514 } 1515 else { 1516 throw 'Croppie ' + opts + ' method not found'; 1517 } 1518 }); 1519 } 1520 else { 1521 return this.each(function () { 1522 var i = new Croppie(this, opts); 1523 i.$ = $; 1524 $(this).data('croppie', i); 1525 }); 1526 } 1527 }; 1528 } 1529 1530 function Croppie(element, opts) { 1531 if (element.className.indexOf('croppie-container') > -1) { 1532 throw new Error("Croppie: Can't initialize croppie more than once"); 1533 } 1534 this.element = element; 1535 this.options = deepExtend(clone(Croppie.defaults), opts); 1536 1537 if (this.element.tagName.toLowerCase() === 'img') { 1538 var origImage = this.element; 1539 addClass(origImage, 'cr-original-image'); 1540 setAttributes(origImage, {'aria-hidden' : 'true', 'alt' : '' }); 1541 var replacementDiv = document.createElement('div'); 1542 this.element.parentNode.appendChild(replacementDiv); 1543 replacementDiv.appendChild(origImage); 1544 this.element = replacementDiv; 1545 this.options.url = this.options.url || origImage.src; 1546 } 1547 1548 _create.call(this); 1549 if (this.options.url) { 1550 var bindOpts = { 1551 url: this.options.url, 1552 points: this.options.points 1553 }; 1554 delete this.options['url']; 1555 delete this.options['points']; 1556 _bind.call(this, bindOpts); 1557 } 1558 } 1559 1560 Croppie.defaults = { 1561 viewport: { 1562 width: 100, 1563 height: 100, 1564 type: 'square' 1565 }, 1566 boundary: { }, 1567 orientationControls: { 1568 enabled: true, 1569 leftClass: '', 1570 rightClass: '' 1571 }, 1572 resizeControls: { 1573 width: true, 1574 height: true 1575 }, 1576 customClass: '', 1577 showZoomer: true, 1578 enableZoom: true, 1579 enableResize: false, 1580 mouseWheelZoom: true, 1581 enableExif: false, 1582 enforceBoundary: true, 1583 enableOrientation: false, 1584 enableKeyMovement: true, 1585 update: function () { } 1586 }; 1587 1588 Croppie.globals = { 1589 translate: 'translate3d' 1590 }; 1591 1592 deepExtend(Croppie.prototype, { 1593 bind: function (options, cb) { 1594 return _bind.call(this, options, cb); 1595 }, 1596 get: function () { 1597 var data = _get.call(this); 1598 var points = data.points; 1599 if (this.options.relative) { 1600 points[0] /= this.elements.img.naturalWidth / 100; 1601 points[1] /= this.elements.img.naturalHeight / 100; 1602 points[2] /= this.elements.img.naturalWidth / 100; 1603 points[3] /= this.elements.img.naturalHeight / 100; 1604 } 1605 return data; 1606 }, 1607 result: function (type) { 1608 return _result.call(this, type); 1609 }, 1610 refresh: function () { 1611 return _refresh.call(this); 1612 }, 1613 setZoom: function (v) { 1614 _setZoomerVal.call(this, v); 1615 dispatchChange(this.elements.zoomer); 1616 }, 1617 rotate: function (deg) { 1618 _rotate.call(this, deg); 1619 }, 1620 destroy: function () { 1621 return _destroy.call(this); 1622 } 1623 }); 1624 return Croppie; 1625}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.