From 238e4a9566a5834ba8ed14a79e0ea9ec7bf601ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vin=C3=ADcius=20Gustavo=20Grandi?=
<93281527+vinicius-grandi@users.noreply.github.com>
Date: Fri, 3 Dec 2021 17:46:05 -0300
Subject: [PATCH] Making a profile cropper
---
public/css/croppie.css | 250 +++
public/css/main.css | 43 +
public/js/croppie.js | 1636 +++++++++++++++++++
public/js/profilecropper/profile.js | 118 ++
resources/views/components/master.blade.php | 4 +-
resources/views/profiles/edit.blade.php | 41 +-
6 files changed, 2087 insertions(+), 5 deletions(-)
create mode 100644 public/css/croppie.css
create mode 100644 public/js/croppie.js
create mode 100644 public/js/profilecropper/profile.js
diff --git a/public/css/croppie.css b/public/css/croppie.css
new file mode 100644
index 0000000..0af2e2c
--- /dev/null
+++ b/public/css/croppie.css
@@ -0,0 +1,250 @@
+.croppie-container {
+ width: 100%;
+ height: 100%;
+}
+
+.croppie-container .cr-image {
+ z-index: -1;
+ position: absolute;
+ top: 0;
+ left: 0;
+ transform-origin: 0 0;
+ max-height: none;
+ max-width: none;
+}
+
+.croppie-container .cr-boundary {
+ position: relative;
+ overflow: hidden;
+ margin: 0 auto;
+ z-index: 1;
+ width: 100%;
+ height: 100%;
+}
+
+.croppie-container .cr-viewport,
+.croppie-container .cr-resizer {
+ position: absolute;
+ border: 2px solid #fff;
+ margin: auto;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ box-shadow: 0 0 2000px 2000px rgba(0, 0, 0, 0.5);
+ z-index: 0;
+}
+
+.croppie-container .cr-resizer {
+ z-index: 2;
+ box-shadow: none;
+ pointer-events: none;
+}
+
+.croppie-container .cr-resizer-vertical,
+.croppie-container .cr-resizer-horisontal {
+ position: absolute;
+ pointer-events: all;
+}
+
+.croppie-container .cr-resizer-vertical::after,
+.croppie-container .cr-resizer-horisontal::after {
+ display: block;
+ position: absolute;
+ box-sizing: border-box;
+ border: 1px solid black;
+ background: #fff;
+ width: 10px;
+ height: 10px;
+ content: '';
+}
+
+.croppie-container .cr-resizer-vertical {
+ bottom: -5px;
+ cursor: row-resize;
+ width: 100%;
+ height: 10px;
+}
+
+.croppie-container .cr-resizer-vertical::after {
+ left: 50%;
+ margin-left: -5px;
+}
+
+.croppie-container .cr-resizer-horisontal {
+ right: -5px;
+ cursor: col-resize;
+ width: 10px;
+ height: 100%;
+}
+
+.croppie-container .cr-resizer-horisontal::after {
+ top: 50%;
+ margin-top: -5px;
+}
+
+.croppie-container .cr-original-image {
+ display: none;
+}
+
+.croppie-container .cr-vp-circle {
+ border-radius: 50%;
+}
+
+.croppie-container .cr-overlay {
+ z-index: 1;
+ position: absolute;
+ cursor: move;
+ touch-action: none;
+}
+
+.croppie-container .cr-slider-wrap {
+ width: 75%;
+ margin: 15px auto;
+ text-align: center;
+}
+
+.croppie-result {
+ position: relative;
+ overflow: hidden;
+}
+
+.croppie-result img {
+ position: absolute;
+}
+
+.croppie-container .cr-image,
+.croppie-container .cr-overlay,
+.croppie-container .cr-viewport {
+ -webkit-transform: translateZ(0);
+ -moz-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ transform: translateZ(0);
+}
+
+/*************************************/
+/***** STYLING RANGE INPUT ***********/
+/*************************************/
+/*http://brennaobrien.com/blog/2014/05/style-input-type-range-in-every-browser.html */
+/*************************************/
+
+.cr-slider {
+ -webkit-appearance: none;
+/*removes default webkit styles*/
+ /*border: 1px solid white; *//*fix for FF unable to apply focus style bug */
+ width: 300px;
+/*required for proper track sizing in FF*/
+ max-width: 100%;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ background-color: transparent;
+}
+
+.cr-slider::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 3px;
+ background: rgba(0, 0, 0, 0.5);
+ border: 0;
+ border-radius: 3px;
+}
+
+.cr-slider::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ border: none;
+ height: 16px;
+ width: 16px;
+ border-radius: 50%;
+ background: #ddd;
+ margin-top: -6px;
+}
+
+.cr-slider:focus {
+ outline: none;
+}
+/*
+.cr-slider:focus::-webkit-slider-runnable-track {
+background: #ccc;
+}
+*/
+
+.cr-slider::-moz-range-track {
+ width: 100%;
+ height: 3px;
+ background: rgba(0, 0, 0, 0.5);
+ border: 0;
+ border-radius: 3px;
+}
+
+.cr-slider::-moz-range-thumb {
+ border: none;
+ height: 16px;
+ width: 16px;
+ border-radius: 50%;
+ background: #ddd;
+ margin-top: -6px;
+}
+
+/*hide the outline behind the border*/
+.cr-slider:-moz-focusring {
+ outline: 1px solid white;
+ outline-offset: -1px;
+}
+
+.cr-slider::-ms-track {
+ width: 100%;
+ height: 5px;
+ background: transparent;
+/*remove bg colour from the track, we'll use ms-fill-lower and ms-fill-upper instead */
+ border-color: transparent;/*leave room for the larger thumb to overflow with a transparent border */
+ border-width: 6px 0;
+ color: transparent;/*remove default tick marks*/
+}
+.cr-slider::-ms-fill-lower {
+ background: rgba(0, 0, 0, 0.5);
+ border-radius: 10px;
+}
+.cr-slider::-ms-fill-upper {
+ background: rgba(0, 0, 0, 0.5);
+ border-radius: 10px;
+}
+.cr-slider::-ms-thumb {
+ border: none;
+ height: 16px;
+ width: 16px;
+ border-radius: 50%;
+ background: #ddd;
+ margin-top:1px;
+}
+.cr-slider:focus::-ms-fill-lower {
+ background: rgba(0, 0, 0, 0.5);
+}
+.cr-slider:focus::-ms-fill-upper {
+ background: rgba(0, 0, 0, 0.5);
+}
+/*******************************************/
+
+/***********************************/
+/* Rotation Tools */
+/***********************************/
+.cr-rotate-controls {
+ position: absolute;
+ bottom: 5px;
+ left: 5px;
+ z-index: 1;
+}
+.cr-rotate-controls button {
+ border: 0;
+ background: none;
+}
+.cr-rotate-controls i:before {
+ display: inline-block;
+ font-style: normal;
+ font-weight: 900;
+ font-size: 22px;
+}
+.cr-rotate-l i:before {
+ content: '↺';
+}
+.cr-rotate-r i:before {
+ content: '↻';
+}
diff --git a/public/css/main.css b/public/css/main.css
index 9758775..b1c9fa1 100755
--- a/public/css/main.css
+++ b/public/css/main.css
@@ -21175,6 +21175,49 @@ video {
}
}
+.fade-out-bck {
+ -webkit-animation: fade-out-bck 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
+ animation: fade-out-bck 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
+}
+
+/* ----------------------------------------------
+ * Generated by Animista on 2021-12-2 16:47:57
+ * Licensed under FreeBSD License.
+ * See http://animista.net/license for more info.
+ * w: http://animista.net, t: @cssanimista
+ * ---------------------------------------------- */
+
+/**
+ * ----------------------------------------
+ * animation fade-out-bck
+ * ----------------------------------------
+ */
+ @-webkit-keyframes fade-out-bck {
+ 0% {
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateZ(-80px);
+ transform: translateZ(-80px);
+ opacity: 0;
+ }
+}
+@keyframes fade-out-bck {
+ 0% {
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateZ(-80px);
+ transform: translateZ(-80px);
+ opacity: 0;
+ }
+}
+
+
@-webkit-keyframes bounce {
0%, 100% {
transform: translateY(-25%);
diff --git a/public/js/croppie.js b/public/js/croppie.js
new file mode 100644
index 0000000..98cb9b2
--- /dev/null
+++ b/public/js/croppie.js
@@ -0,0 +1,1636 @@
+/*************************
+ * Croppie
+ * Copyright 2019
+ * Foliotek
+ * Version: 2.6.5
+ *************************/
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
+ // CommonJS
+ module.exports = factory();
+ } else {
+ // Browser globals
+ root.Croppie = factory();
+ }
+}(typeof self !== 'undefined' ? self : this, function () {
+
+ /* Polyfills */
+ if (typeof Promise !== 'function') {
+ /*! promise-polyfill 3.1.0 */
+ !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;fd;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);
+ }
+
+ if (typeof window !== 'undefined' && typeof window.CustomEvent !== "function") {
+ (function(){
+ function CustomEvent ( event, params ) {
+ params = params || { bubbles: false, cancelable: false, detail: undefined };
+ var evt = document.createEvent( 'CustomEvent' );
+ evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
+ return evt;
+ }
+ CustomEvent.prototype = window.Event.prototype;
+ window.CustomEvent = CustomEvent;
+ }());
+ }
+
+ if (typeof HTMLCanvasElement !== 'undefined' && !HTMLCanvasElement.prototype.toBlob) {
+ Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
+ value: function (callback, type, quality) {
+ var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
+ len = binStr.length,
+ arr = new Uint8Array(len);
+
+ for (var i=0; i -1 ? EXIF_NORM : EXIF_FLIP,
+ index = arr.indexOf(ornt),
+ offset = (rotate / 90) % arr.length;// 180 = 2%4 = 2 shift exif by 2 indexes
+
+ return arr[(arr.length + index + (offset % arr.length)) % arr.length];
+ }
+
+ // Credits to : Andrew Dupont - http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/
+ function deepExtend(destination, source) {
+ destination = destination || {};
+ for (var property in source) {
+ if (source[property] && source[property].constructor && source[property].constructor === Object) {
+ destination[property] = destination[property] || {};
+ deepExtend(destination[property], source[property]);
+ } else {
+ destination[property] = source[property];
+ }
+ }
+ return destination;
+ }
+
+ function clone(object) {
+ return deepExtend({}, object);
+ }
+
+ function debounce(func, wait, immediate) {
+ var timeout;
+ return function () {
+ var context = this, args = arguments;
+ var later = function () {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) func.apply(context, args);
+ };
+ }
+
+ function dispatchChange(element) {
+ if ("createEvent" in document) {
+ var evt = document.createEvent("HTMLEvents");
+ evt.initEvent("change", false, true);
+ element.dispatchEvent(evt);
+ }
+ else {
+ element.fireEvent("onchange");
+ }
+ }
+
+ //http://jsperf.com/vanilla-css
+ function css(el, styles, val) {
+ if (typeof (styles) === 'string') {
+ var tmp = styles;
+ styles = {};
+ styles[tmp] = val;
+ }
+
+ for (var prop in styles) {
+ el.style[prop] = styles[prop];
+ }
+ }
+
+ function addClass(el, c) {
+ if (el.classList) {
+ el.classList.add(c);
+ }
+ else {
+ el.className += ' ' + c;
+ }
+ }
+
+ function removeClass(el, c) {
+ if (el.classList) {
+ el.classList.remove(c);
+ }
+ else {
+ el.className = el.className.replace(c, '');
+ }
+ }
+
+ function setAttributes(el, attrs) {
+ for (var key in attrs) {
+ el.setAttribute(key, attrs[key]);
+ }
+ }
+
+ function num(v) {
+ return parseInt(v, 10);
+ }
+
+ /* Utilities */
+ function loadImage(src, doExif) {
+ if (!src) { throw 'Source image missing'; }
+
+ var img = new Image();
+ img.style.opacity = '0';
+ return new Promise(function (resolve, reject) {
+ function _resolve() {
+ img.style.opacity = '1';
+ setTimeout(function () {
+ resolve(img);
+ }, 1);
+ }
+
+ img.removeAttribute('crossOrigin');
+ if (src.match(/^https?:\/\/|^\/\//)) {
+ img.setAttribute('crossOrigin', 'anonymous');
+ }
+
+ img.onload = function () {
+ if (doExif) {
+ EXIF.getData(img, function () {
+ _resolve();
+ });
+ }
+ else {
+ _resolve();
+ }
+ };
+ img.onerror = function (ev) {
+ img.style.opacity = 1;
+ setTimeout(function () {
+ reject(ev);
+ }, 1);
+ };
+ img.src = src;
+ });
+ }
+
+ function naturalImageDimensions(img, ornt) {
+ var w = img.naturalWidth;
+ var h = img.naturalHeight;
+ var orient = ornt || getExifOrientation(img);
+ if (orient && orient >= 5) {
+ var x= w;
+ w = h;
+ h = x;
+ }
+ return { width: w, height: h };
+ }
+
+ /* CSS Transform Prototype */
+ var TRANSLATE_OPTS = {
+ 'translate3d': {
+ suffix: ', 0px'
+ },
+ 'translate': {
+ suffix: ''
+ }
+ };
+ var Transform = function (x, y, scale) {
+ this.x = parseFloat(x);
+ this.y = parseFloat(y);
+ this.scale = parseFloat(scale);
+ };
+
+ Transform.parse = function (v) {
+ if (v.style) {
+ return Transform.parse(v.style[CSS_TRANSFORM]);
+ }
+ else if (v.indexOf('matrix') > -1 || v.indexOf('none') > -1) {
+ return Transform.fromMatrix(v);
+ }
+ else {
+ return Transform.fromString(v);
+ }
+ };
+
+ Transform.fromMatrix = function (v) {
+ var vals = v.substring(7).split(',');
+ if (!vals.length || v === 'none') {
+ vals = [1, 0, 0, 1, 0, 0];
+ }
+
+ return new Transform(num(vals[4]), num(vals[5]), parseFloat(vals[0]));
+ };
+
+ Transform.fromString = function (v) {
+ var values = v.split(') '),
+ translate = values[0].substring(Croppie.globals.translate.length + 1).split(','),
+ scale = values.length > 1 ? values[1].substring(6) : 1,
+ x = translate.length > 1 ? translate[0] : 0,
+ y = translate.length > 1 ? translate[1] : 0;
+
+ return new Transform(x, y, scale);
+ };
+
+ Transform.prototype.toString = function () {
+ var suffix = TRANSLATE_OPTS[Croppie.globals.translate].suffix || '';
+ return Croppie.globals.translate + '(' + this.x + 'px, ' + this.y + 'px' + suffix + ') scale(' + this.scale + ')';
+ };
+
+ var TransformOrigin = function (el) {
+ if (!el || !el.style[CSS_TRANS_ORG]) {
+ this.x = 0;
+ this.y = 0;
+ return;
+ }
+ var css = el.style[CSS_TRANS_ORG].split(' ');
+ this.x = parseFloat(css[0]);
+ this.y = parseFloat(css[1]);
+ };
+
+ TransformOrigin.prototype.toString = function () {
+ return this.x + 'px ' + this.y + 'px';
+ };
+
+ function getExifOrientation (img) {
+ return img.exifdata && img.exifdata.Orientation ? num(img.exifdata.Orientation) : 1;
+ }
+
+ function drawCanvas(canvas, img, orientation) {
+ var width = img.width,
+ height = img.height,
+ ctx = canvas.getContext('2d');
+
+ canvas.width = img.width;
+ canvas.height = img.height;
+
+ ctx.save();
+ switch (orientation) {
+ case 2:
+ ctx.translate(width, 0);
+ ctx.scale(-1, 1);
+ break;
+
+ case 3:
+ ctx.translate(width, height);
+ ctx.rotate(180*Math.PI/180);
+ break;
+
+ case 4:
+ ctx.translate(0, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 5:
+ canvas.width = height;
+ canvas.height = width;
+ ctx.rotate(90*Math.PI/180);
+ ctx.scale(1, -1);
+ break;
+
+ case 6:
+ canvas.width = height;
+ canvas.height = width;
+ ctx.rotate(90*Math.PI/180);
+ ctx.translate(0, -height);
+ break;
+
+ case 7:
+ canvas.width = height;
+ canvas.height = width;
+ ctx.rotate(-90*Math.PI/180);
+ ctx.translate(-width, height);
+ ctx.scale(1, -1);
+ break;
+
+ case 8:
+ canvas.width = height;
+ canvas.height = width;
+ ctx.translate(0, width);
+ ctx.rotate(-90*Math.PI/180);
+ break;
+ }
+ ctx.drawImage(img, 0,0, width, height);
+ ctx.restore();
+ }
+
+ /* Private Methods */
+ function _create() {
+ var self = this,
+ contClass = 'croppie-container',
+ customViewportClass = self.options.viewport.type ? 'cr-vp-' + self.options.viewport.type : null,
+ boundary, img, viewport, overlay, bw, bh;
+
+ self.options.useCanvas = self.options.enableOrientation || _hasExif.call(self);
+ // Properties on class
+ self.data = {};
+ self.elements = {};
+
+ boundary = self.elements.boundary = document.createElement('div');
+ viewport = self.elements.viewport = document.createElement('div');
+ img = self.elements.img = document.createElement('img');
+ overlay = self.elements.overlay = document.createElement('div');
+
+ if (self.options.useCanvas) {
+ self.elements.canvas = document.createElement('canvas');
+ self.elements.preview = self.elements.canvas;
+ }
+ else {
+ self.elements.preview = img;
+ }
+
+ addClass(boundary, 'cr-boundary');
+ boundary.setAttribute('aria-dropeffect', 'none');
+ bw = self.options.boundary.width;
+ bh = self.options.boundary.height;
+ css(boundary, {
+ width: (bw + (isNaN(bw) ? '' : 'px')),
+ height: (bh + (isNaN(bh) ? '' : 'px'))
+ });
+
+ addClass(viewport, 'cr-viewport');
+ if (customViewportClass) {
+ addClass(viewport, customViewportClass);
+ }
+ css(viewport, {
+ width: self.options.viewport.width + 'px',
+ height: self.options.viewport.height + 'px'
+ });
+ viewport.setAttribute('tabindex', 0);
+
+ addClass(self.elements.preview, 'cr-image');
+ setAttributes(self.elements.preview, { 'alt': 'preview', 'aria-grabbed': 'false' });
+ addClass(overlay, 'cr-overlay');
+
+ self.element.appendChild(boundary);
+ boundary.appendChild(self.elements.preview);
+ boundary.appendChild(viewport);
+ boundary.appendChild(overlay);
+
+ addClass(self.element, contClass);
+ if (self.options.customClass) {
+ addClass(self.element, self.options.customClass);
+ }
+
+ _initDraggable.call(this);
+
+ if (self.options.enableZoom) {
+ _initializeZoom.call(self);
+ }
+
+ // if (self.options.enableOrientation) {
+ // _initRotationControls.call(self);
+ // }
+
+ if (self.options.enableResize) {
+ _initializeResize.call(self);
+ }
+ }
+
+ // function _initRotationControls () {
+ // var self = this,
+ // wrap, btnLeft, btnRight, iLeft, iRight;
+
+ // wrap = document.createElement('div');
+ // self.elements.orientationBtnLeft = btnLeft = document.createElement('button');
+ // self.elements.orientationBtnRight = btnRight = document.createElement('button');
+
+ // wrap.appendChild(btnLeft);
+ // wrap.appendChild(btnRight);
+
+ // iLeft = document.createElement('i');
+ // iRight = document.createElement('i');
+ // btnLeft.appendChild(iLeft);
+ // btnRight.appendChild(iRight);
+
+ // addClass(wrap, 'cr-rotate-controls');
+ // addClass(btnLeft, 'cr-rotate-l');
+ // addClass(btnRight, 'cr-rotate-r');
+
+ // self.elements.boundary.appendChild(wrap);
+
+ // btnLeft.addEventListener('click', function () {
+ // self.rotate(-90);
+ // });
+ // btnRight.addEventListener('click', function () {
+ // self.rotate(90);
+ // });
+ // }
+
+ function _hasExif() {
+ return this.options.enableExif && window.EXIF;
+ }
+
+ function _initializeResize () {
+ var self = this;
+ var wrap = document.createElement('div');
+ var isDragging = false;
+ var direction;
+ var originalX;
+ var originalY;
+ var minSize = 50;
+ var maxWidth;
+ var maxHeight;
+ var vr;
+ var hr;
+
+ addClass(wrap, 'cr-resizer');
+ css(wrap, {
+ width: this.options.viewport.width + 'px',
+ height: this.options.viewport.height + 'px'
+ });
+
+ if (this.options.resizeControls.height) {
+ vr = document.createElement('div');
+ addClass(vr, 'cr-resizer-vertical');
+ wrap.appendChild(vr);
+ }
+
+ if (this.options.resizeControls.width) {
+ hr = document.createElement('div');
+ addClass(hr, 'cr-resizer-horisontal');
+ wrap.appendChild(hr);
+ }
+
+ function mouseDown(ev) {
+ if (ev.button !== undefined && ev.button !== 0) return;
+
+ ev.preventDefault();
+ if (isDragging) {
+ return;
+ }
+
+ var overlayRect = self.elements.overlay.getBoundingClientRect();
+
+ isDragging = true;
+ originalX = ev.pageX;
+ originalY = ev.pageY;
+ direction = ev.currentTarget.className.indexOf('vertical') !== -1 ? 'v' : 'h';
+ maxWidth = overlayRect.width;
+ maxHeight = overlayRect.height;
+
+ if (ev.touches) {
+ var touches = ev.touches[0];
+ originalX = touches.pageX;
+ originalY = touches.pageY;
+ }
+
+ window.addEventListener('mousemove', mouseMove);
+ window.addEventListener('touchmove', mouseMove);
+ window.addEventListener('mouseup', mouseUp);
+ window.addEventListener('touchend', mouseUp);
+ document.body.style[CSS_USERSELECT] = 'none';
+ }
+
+ function mouseMove(ev) {
+ var pageX = ev.pageX;
+ var pageY = ev.pageY;
+
+ ev.preventDefault();
+
+ if (ev.touches) {
+ var touches = ev.touches[0];
+ pageX = touches.pageX;
+ pageY = touches.pageY;
+ }
+
+ var deltaX = pageX - originalX;
+ var deltaY = pageY - originalY;
+ var newHeight = self.options.viewport.height + deltaY;
+ var newWidth = self.options.viewport.width + deltaX;
+
+ if (direction === 'v' && newHeight >= minSize && newHeight <= maxHeight) {
+ css(wrap, {
+ height: newHeight + 'px'
+ });
+
+ self.options.boundary.height += deltaY;
+ css(self.elements.boundary, {
+ height: self.options.boundary.height + 'px'
+ });
+
+ self.options.viewport.height += deltaY;
+ css(self.elements.viewport, {
+ height: self.options.viewport.height + 'px'
+ });
+ }
+ else if (direction === 'h' && newWidth >= minSize && newWidth <= maxWidth) {
+ css(wrap, {
+ width: newWidth + 'px'
+ });
+
+ self.options.boundary.width += deltaX;
+ css(self.elements.boundary, {
+ width: self.options.boundary.width + 'px'
+ });
+
+ self.options.viewport.width += deltaX;
+ css(self.elements.viewport, {
+ width: self.options.viewport.width + 'px'
+ });
+ }
+
+ _updateOverlay.call(self);
+ _updateZoomLimits.call(self);
+ _updateCenterPoint.call(self);
+ _triggerUpdate.call(self);
+ originalY = pageY;
+ originalX = pageX;
+ }
+
+ function mouseUp() {
+ isDragging = false;
+ window.removeEventListener('mousemove', mouseMove);
+ window.removeEventListener('touchmove', mouseMove);
+ window.removeEventListener('mouseup', mouseUp);
+ window.removeEventListener('touchend', mouseUp);
+ document.body.style[CSS_USERSELECT] = '';
+ }
+
+ if (vr) {
+ vr.addEventListener('mousedown', mouseDown);
+ vr.addEventListener('touchstart', mouseDown);
+ }
+
+ if (hr) {
+ hr.addEventListener('mousedown', mouseDown);
+ hr.addEventListener('touchstart', mouseDown);
+ }
+
+ this.elements.boundary.appendChild(wrap);
+ }
+
+ function _setZoomerVal(v) {
+ if (this.options.enableZoom) {
+ var z = this.elements.zoomer,
+ val = fix(v, 4);
+
+ z.value = Math.max(parseFloat(z.min), Math.min(parseFloat(z.max), val)).toString();
+ }
+ }
+
+ function _initializeZoom() {
+ var self = this,
+ wrap = self.elements.zoomerWrap = document.createElement('div'),
+ zoomer = self.elements.zoomer = document.createElement('input');
+
+ addClass(wrap, 'cr-slider-wrap');
+ addClass(zoomer, 'cr-slider');
+ zoomer.type = 'range';
+ zoomer.step = '0.0001';
+ zoomer.value = '1';
+ zoomer.style.display = self.options.showZoomer ? '' : 'none';
+ zoomer.setAttribute('aria-label', 'zoom');
+
+ self.element.appendChild(wrap);
+ wrap.appendChild(zoomer);
+
+ self._currentZoom = 1;
+
+ function change() {
+ _onZoom.call(self, {
+ value: parseFloat(zoomer.value),
+ origin: new TransformOrigin(self.elements.preview),
+ viewportRect: self.elements.viewport.getBoundingClientRect(),
+ transform: Transform.parse(self.elements.preview)
+ });
+ }
+
+ function scroll(ev) {
+ var delta, targetZoom;
+
+ if(self.options.mouseWheelZoom === 'ctrl' && ev.ctrlKey !== true){
+ return 0;
+ } else if (ev.wheelDelta) {
+ delta = ev.wheelDelta / 1200; //wheelDelta min: -120 max: 120 // max x 10 x 2
+ } else if (ev.deltaY) {
+ delta = ev.deltaY / 1060; //deltaY min: -53 max: 53 // max x 10 x 2
+ } else if (ev.detail) {
+ delta = ev.detail / -60; //delta min: -3 max: 3 // max x 10 x 2
+ } else {
+ delta = 0;
+ }
+
+ targetZoom = self._currentZoom + (delta * self._currentZoom);
+
+ ev.preventDefault();
+ _setZoomerVal.call(self, targetZoom);
+ change.call(self);
+ }
+
+ self.elements.zoomer.addEventListener('input', change);// this is being fired twice on keypress
+ self.elements.zoomer.addEventListener('change', change);
+
+ if (self.options.mouseWheelZoom) {
+ self.elements.boundary.addEventListener('mousewheel', scroll);
+ self.elements.boundary.addEventListener('DOMMouseScroll', scroll);
+ }
+ }
+
+ function _onZoom(ui) {
+ var self = this,
+ transform = ui ? ui.transform : Transform.parse(self.elements.preview),
+ vpRect = ui ? ui.viewportRect : self.elements.viewport.getBoundingClientRect(),
+ origin = ui ? ui.origin : new TransformOrigin(self.elements.preview);
+
+ function applyCss() {
+ var transCss = {};
+ transCss[CSS_TRANSFORM] = transform.toString();
+ transCss[CSS_TRANS_ORG] = origin.toString();
+ css(self.elements.preview, transCss);
+ }
+
+ self._currentZoom = ui ? ui.value : self._currentZoom;
+ transform.scale = self._currentZoom;
+ self.elements.zoomer.setAttribute('aria-valuenow', self._currentZoom);
+ applyCss();
+
+ if (self.options.enforceBoundary) {
+ var boundaries = _getVirtualBoundaries.call(self, vpRect),
+ transBoundaries = boundaries.translate,
+ oBoundaries = boundaries.origin;
+
+ if (transform.x >= transBoundaries.maxX) {
+ origin.x = oBoundaries.minX;
+ transform.x = transBoundaries.maxX;
+ }
+
+ if (transform.x <= transBoundaries.minX) {
+ origin.x = oBoundaries.maxX;
+ transform.x = transBoundaries.minX;
+ }
+
+ if (transform.y >= transBoundaries.maxY) {
+ origin.y = oBoundaries.minY;
+ transform.y = transBoundaries.maxY;
+ }
+
+ if (transform.y <= transBoundaries.minY) {
+ origin.y = oBoundaries.maxY;
+ transform.y = transBoundaries.minY;
+ }
+ }
+ applyCss();
+ _debouncedOverlay.call(self);
+ _triggerUpdate.call(self);
+ }
+
+ function _getVirtualBoundaries(viewport) {
+ var self = this,
+ scale = self._currentZoom,
+ vpWidth = viewport.width,
+ vpHeight = viewport.height,
+ centerFromBoundaryX = self.elements.boundary.clientWidth / 2,
+ centerFromBoundaryY = self.elements.boundary.clientHeight / 2,
+ imgRect = self.elements.preview.getBoundingClientRect(),
+ curImgWidth = imgRect.width,
+ curImgHeight = imgRect.height,
+ halfWidth = vpWidth / 2,
+ halfHeight = vpHeight / 2;
+
+ var maxX = ((halfWidth / scale) - centerFromBoundaryX) * -1;
+ var minX = maxX - ((curImgWidth * (1 / scale)) - (vpWidth * (1 / scale)));
+
+ var maxY = ((halfHeight / scale) - centerFromBoundaryY) * -1;
+ var minY = maxY - ((curImgHeight * (1 / scale)) - (vpHeight * (1 / scale)));
+
+ var originMinX = (1 / scale) * halfWidth;
+ var originMaxX = (curImgWidth * (1 / scale)) - originMinX;
+
+ var originMinY = (1 / scale) * halfHeight;
+ var originMaxY = (curImgHeight * (1 / scale)) - originMinY;
+
+ return {
+ translate: {
+ maxX: maxX,
+ minX: minX,
+ maxY: maxY,
+ minY: minY
+ },
+ origin: {
+ maxX: originMaxX,
+ minX: originMinX,
+ maxY: originMaxY,
+ minY: originMinY
+ }
+ };
+ }
+
+ function _updateCenterPoint(rotate) {
+ var self = this,
+ scale = self._currentZoom,
+ data = self.elements.preview.getBoundingClientRect(),
+ vpData = self.elements.viewport.getBoundingClientRect(),
+ transform = Transform.parse(self.elements.preview.style[CSS_TRANSFORM]),
+ pc = new TransformOrigin(self.elements.preview),
+ top = (vpData.top - data.top) + (vpData.height / 2),
+ left = (vpData.left - data.left) + (vpData.width / 2),
+ center = {},
+ adj = {};
+
+ if (rotate) {
+ var cx = pc.x;
+ var cy = pc.y;
+ var tx = transform.x;
+ var ty = transform.y;
+
+ center.y = cx;
+ center.x = cy;
+ transform.y = tx;
+ transform.x = ty;
+ }
+ else {
+ center.y = top / scale;
+ center.x = left / scale;
+
+ adj.y = (center.y - pc.y) * (1 - scale);
+ adj.x = (center.x - pc.x) * (1 - scale);
+
+ transform.x -= adj.x;
+ transform.y -= adj.y;
+ }
+
+ var newCss = {};
+ newCss[CSS_TRANS_ORG] = center.x + 'px ' + center.y + 'px';
+ newCss[CSS_TRANSFORM] = transform.toString();
+ css(self.elements.preview, newCss);
+ }
+
+ function _initDraggable() {
+ var self = this,
+ isDragging = false,
+ originalX,
+ originalY,
+ originalDistance,
+ vpRect,
+ transform;
+
+ function assignTransformCoordinates(deltaX, deltaY) {
+ var imgRect = self.elements.preview.getBoundingClientRect(),
+ top = transform.y + deltaY,
+ left = transform.x + deltaX;
+
+ if (self.options.enforceBoundary) {
+ if (vpRect.top > imgRect.top + deltaY && vpRect.bottom < imgRect.bottom + deltaY) {
+ transform.y = top;
+ }
+
+ if (vpRect.left > imgRect.left + deltaX && vpRect.right < imgRect.right + deltaX) {
+ transform.x = left;
+ }
+ }
+ else {
+ transform.y = top;
+ transform.x = left;
+ }
+ }
+
+ function toggleGrabState(isDragging) {
+ self.elements.preview.setAttribute('aria-grabbed', isDragging);
+ self.elements.boundary.setAttribute('aria-dropeffect', isDragging? 'move': 'none');
+ }
+
+ function keyDown(ev) {
+ var LEFT_ARROW = 37,
+ UP_ARROW = 38,
+ RIGHT_ARROW = 39,
+ DOWN_ARROW = 40;
+
+ if (ev.shiftKey && (ev.keyCode === UP_ARROW || ev.keyCode === DOWN_ARROW)) {
+ var zoom;
+ if (ev.keyCode === UP_ARROW) {
+ zoom = parseFloat(self.elements.zoomer.value) + parseFloat(self.elements.zoomer.step)
+ }
+ else {
+ zoom = parseFloat(self.elements.zoomer.value) - parseFloat(self.elements.zoomer.step)
+ }
+ self.setZoom(zoom);
+ }
+ else if (self.options.enableKeyMovement && (ev.keyCode >= 37 && ev.keyCode <= 40)) {
+ ev.preventDefault();
+ var movement = parseKeyDown(ev.keyCode);
+
+ transform = Transform.parse(self.elements.preview);
+ document.body.style[CSS_USERSELECT] = 'none';
+ vpRect = self.elements.viewport.getBoundingClientRect();
+ keyMove(movement);
+ }
+
+ function parseKeyDown(key) {
+ switch (key) {
+ case LEFT_ARROW:
+ return [1, 0];
+ case UP_ARROW:
+ return [0, 1];
+ case RIGHT_ARROW:
+ return [-1, 0];
+ case DOWN_ARROW:
+ return [0, -1];
+ }
+ }
+ }
+
+ function keyMove(movement) {
+ var deltaX = movement[0],
+ deltaY = movement[1],
+ newCss = {};
+
+ assignTransformCoordinates(deltaX, deltaY);
+
+ newCss[CSS_TRANSFORM] = transform.toString();
+ css(self.elements.preview, newCss);
+ _updateOverlay.call(self);
+ document.body.style[CSS_USERSELECT] = '';
+ _updateCenterPoint.call(self);
+ _triggerUpdate.call(self);
+ originalDistance = 0;
+ }
+
+ function mouseDown(ev) {
+ if (ev.button !== undefined && ev.button !== 0) return;
+
+ ev.preventDefault();
+ if (isDragging) return;
+ isDragging = true;
+ originalX = ev.pageX;
+ originalY = ev.pageY;
+
+ if (ev.touches) {
+ var touches = ev.touches[0];
+ originalX = touches.pageX;
+ originalY = touches.pageY;
+ }
+ toggleGrabState(isDragging);
+ transform = Transform.parse(self.elements.preview);
+ window.addEventListener('mousemove', mouseMove);
+ window.addEventListener('touchmove', mouseMove);
+ window.addEventListener('mouseup', mouseUp);
+ window.addEventListener('touchend', mouseUp);
+ document.body.style[CSS_USERSELECT] = 'none';
+ vpRect = self.elements.viewport.getBoundingClientRect();
+ }
+
+ function mouseMove(ev) {
+ ev.preventDefault();
+ var pageX = ev.pageX,
+ pageY = ev.pageY;
+
+ if (ev.touches) {
+ var touches = ev.touches[0];
+ pageX = touches.pageX;
+ pageY = touches.pageY;
+ }
+
+ var deltaX = pageX - originalX,
+ deltaY = pageY - originalY,
+ newCss = {};
+
+ if (ev.type === 'touchmove') {
+ if (ev.touches.length > 1) {
+ var touch1 = ev.touches[0];
+ var touch2 = ev.touches[1];
+ var dist = Math.sqrt((touch1.pageX - touch2.pageX) * (touch1.pageX - touch2.pageX) + (touch1.pageY - touch2.pageY) * (touch1.pageY - touch2.pageY));
+
+ if (!originalDistance) {
+ originalDistance = dist / self._currentZoom;
+ }
+
+ var scale = dist / originalDistance;
+
+ _setZoomerVal.call(self, scale);
+ dispatchChange(self.elements.zoomer);
+ return;
+ }
+ }
+
+ assignTransformCoordinates(deltaX, deltaY);
+
+ newCss[CSS_TRANSFORM] = transform.toString();
+ css(self.elements.preview, newCss);
+ _updateOverlay.call(self);
+ originalY = pageY;
+ originalX = pageX;
+ }
+
+ function mouseUp() {
+ isDragging = false;
+ toggleGrabState(isDragging);
+ window.removeEventListener('mousemove', mouseMove);
+ window.removeEventListener('touchmove', mouseMove);
+ window.removeEventListener('mouseup', mouseUp);
+ window.removeEventListener('touchend', mouseUp);
+ document.body.style[CSS_USERSELECT] = '';
+ _updateCenterPoint.call(self);
+ _triggerUpdate.call(self);
+ originalDistance = 0;
+ }
+
+ self.elements.overlay.addEventListener('mousedown', mouseDown);
+ self.elements.viewport.addEventListener('keydown', keyDown);
+ self.elements.overlay.addEventListener('touchstart', mouseDown);
+ }
+
+ function _updateOverlay() {
+ if (!this.elements) return; // since this is debounced, it can be fired after destroy
+ var self = this,
+ boundRect = self.elements.boundary.getBoundingClientRect(),
+ imgData = self.elements.preview.getBoundingClientRect();
+
+ css(self.elements.overlay, {
+ width: imgData.width + 'px',
+ height: imgData.height + 'px',
+ top: (imgData.top - boundRect.top) + 'px',
+ left: (imgData.left - boundRect.left) + 'px'
+ });
+ }
+ var _debouncedOverlay = debounce(_updateOverlay, 500);
+
+ function _triggerUpdate() {
+ var self = this,
+ data = self.get();
+
+ if (!_isVisible.call(self)) {
+ return;
+ }
+
+ self.options.update.call(self, data);
+ if (self.$ && typeof Prototype === 'undefined') {
+ self.$(self.element).trigger('update.croppie', data);
+ }
+ else {
+ var ev;
+ if (window.CustomEvent) {
+ ev = new CustomEvent('update', { detail: data });
+ } else {
+ ev = document.createEvent('CustomEvent');
+ ev.initCustomEvent('update', true, true, data);
+ }
+
+ self.element.dispatchEvent(ev);
+ }
+ }
+
+ function _isVisible() {
+ return this.elements.preview.offsetHeight > 0 && this.elements.preview.offsetWidth > 0;
+ }
+
+ function _updatePropertiesFromImage() {
+ var self = this,
+ initialZoom = 1,
+ cssReset = {},
+ img = self.elements.preview,
+ imgData,
+ transformReset = new Transform(0, 0, initialZoom),
+ originReset = new TransformOrigin(),
+ isVisible = _isVisible.call(self);
+
+ if (!isVisible || self.data.bound) {// if the croppie isn't visible or it doesn't need binding
+ return;
+ }
+
+ self.data.bound = true;
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
+ cssReset[CSS_TRANS_ORG] = originReset.toString();
+ cssReset['opacity'] = 1;
+ css(img, cssReset);
+
+ imgData = self.elements.preview.getBoundingClientRect();
+
+ self._originalImageWidth = imgData.width;
+ self._originalImageHeight = imgData.height;
+ self.data.orientation = _hasExif.call(self) ? getExifOrientation(self.elements.img) : self.data.orientation;
+
+ if (self.options.enableZoom) {
+ _updateZoomLimits.call(self, true);
+ }
+ else {
+ self._currentZoom = initialZoom;
+ }
+
+ transformReset.scale = self._currentZoom;
+ cssReset[CSS_TRANSFORM] = transformReset.toString();
+ css(img, cssReset);
+
+ if (self.data.points.length) {
+ _bindPoints.call(self, self.data.points);
+ }
+ else {
+ _centerImage.call(self);
+ }
+
+ _updateCenterPoint.call(self);
+ _updateOverlay.call(self);
+ }
+
+ function _updateZoomLimits (initial) {
+ var self = this,
+ minZoom = Math.max(self.options.minZoom, 0) || 0,
+ maxZoom = self.options.maxZoom || 1.5,
+ initialZoom,
+ defaultInitialZoom,
+ zoomer = self.elements.zoomer,
+ scale = parseFloat(zoomer.value),
+ boundaryData = self.elements.boundary.getBoundingClientRect(),
+ imgData = naturalImageDimensions(self.elements.img, self.data.orientation),
+ vpData = self.elements.viewport.getBoundingClientRect(),
+ minW,
+ minH;
+ if (self.options.enforceBoundary) {
+ minW = vpData.width / imgData.width;
+ minH = vpData.height / imgData.height;
+ minZoom = Math.max(minW, minH);
+ }
+
+ if (minZoom >= maxZoom) {
+ maxZoom = minZoom + 1;
+ }
+
+ zoomer.min = fix(minZoom, 4);
+ zoomer.max = fix(maxZoom, 4);
+
+ if (!initial && (scale < zoomer.min || scale > zoomer.max)) {
+ _setZoomerVal.call(self, scale < zoomer.min ? zoomer.min : zoomer.max);
+ }
+ else if (initial) {
+ defaultInitialZoom = Math.max((boundaryData.width / imgData.width), (boundaryData.height / imgData.height));
+ initialZoom = self.data.boundZoom !== null ? self.data.boundZoom : defaultInitialZoom;
+ _setZoomerVal.call(self, initialZoom);
+ }
+
+ dispatchChange(zoomer);
+ }
+
+ function _bindPoints(points) {
+ if (points.length !== 4) {
+ throw "Croppie - Invalid number of points supplied: " + points;
+ }
+ var self = this,
+ pointsWidth = points[2] - points[0],
+ // pointsHeight = points[3] - points[1],
+ vpData = self.elements.viewport.getBoundingClientRect(),
+ boundRect = self.elements.boundary.getBoundingClientRect(),
+ vpOffset = {
+ left: vpData.left - boundRect.left,
+ top: vpData.top - boundRect.top
+ },
+ scale = vpData.width / pointsWidth,
+ originTop = points[1],
+ originLeft = points[0],
+ transformTop = (-1 * points[1]) + vpOffset.top,
+ transformLeft = (-1 * points[0]) + vpOffset.left,
+ newCss = {};
+
+ newCss[CSS_TRANS_ORG] = originLeft + 'px ' + originTop + 'px';
+ newCss[CSS_TRANSFORM] = new Transform(transformLeft, transformTop, scale).toString();
+ css(self.elements.preview, newCss);
+
+ _setZoomerVal.call(self, scale);
+ self._currentZoom = scale;
+ }
+
+ function _centerImage() {
+ var self = this,
+ imgDim = self.elements.preview.getBoundingClientRect(),
+ vpDim = self.elements.viewport.getBoundingClientRect(),
+ boundDim = self.elements.boundary.getBoundingClientRect(),
+ vpLeft = vpDim.left - boundDim.left,
+ vpTop = vpDim.top - boundDim.top,
+ w = vpLeft - ((imgDim.width - vpDim.width) / 2),
+ h = vpTop - ((imgDim.height - vpDim.height) / 2),
+ transform = new Transform(w, h, self._currentZoom);
+
+ css(self.elements.preview, CSS_TRANSFORM, transform.toString());
+ }
+
+ function _transferImageToCanvas(customOrientation) {
+ var self = this,
+ canvas = self.elements.canvas,
+ img = self.elements.img,
+ ctx = canvas.getContext('2d');
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ canvas.width = img.width;
+ canvas.height = img.height;
+
+ var orientation = self.options.enableOrientation && customOrientation || getExifOrientation(img);
+ drawCanvas(canvas, img, orientation);
+ }
+
+ function _getCanvas(data) {
+ var self = this,
+ points = data.points,
+ left = num(points[0]),
+ top = num(points[1]),
+ right = num(points[2]),
+ bottom = num(points[3]),
+ width = right-left,
+ height = bottom-top,
+ circle = data.circle,
+ canvas = document.createElement('canvas'),
+ ctx = canvas.getContext('2d'),
+ startX = 0,
+ startY = 0,
+ canvasWidth = data.outputWidth || width,
+ canvasHeight = data.outputHeight || height;
+
+ canvas.width = canvasWidth;
+ canvas.height = canvasHeight;
+
+ if (data.backgroundColor) {
+ ctx.fillStyle = data.backgroundColor;
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+ }
+
+ // By default assume we're going to draw the entire
+ // source image onto the destination canvas.
+ var sx = left,
+ sy = top,
+ sWidth = width,
+ sHeight = height,
+ dx = 0,
+ dy = 0,
+ dWidth = canvasWidth,
+ dHeight = canvasHeight;
+
+ //
+ // Do not go outside of the original image's bounds along the x-axis.
+ // Handle translations when projecting onto the destination canvas.
+ //
+
+ // The smallest possible source x-position is 0.
+ if (left < 0) {
+ sx = 0;
+ dx = (Math.abs(left) / width) * canvasWidth;
+ }
+
+ // The largest possible source width is the original image's width.
+ if (sWidth + sx > self._originalImageWidth) {
+ sWidth = self._originalImageWidth - sx;
+ dWidth = (sWidth / width) * canvasWidth;
+ }
+
+ //
+ // Do not go outside of the original image's bounds along the y-axis.
+ //
+
+ // The smallest possible source y-position is 0.
+ if (top < 0) {
+ sy = 0;
+ dy = (Math.abs(top) / height) * canvasHeight;
+ }
+
+ // The largest possible source height is the original image's height.
+ if (sHeight + sy > self._originalImageHeight) {
+ sHeight = self._originalImageHeight - sy;
+ dHeight = (sHeight / height) * canvasHeight;
+ }
+
+ // console.table({ left, right, top, bottom, canvasWidth, canvasHeight, width, height, startX, startY, circle, sx, sy, dx, dy, sWidth, sHeight, dWidth, dHeight });
+
+ ctx.drawImage(this.elements.preview, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
+ if (circle) {
+ ctx.fillStyle = '#fff';
+ ctx.globalCompositeOperation = 'destination-in';
+ ctx.beginPath();
+ ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2, true);
+ ctx.closePath();
+ ctx.fill();
+ }
+ return canvas;
+ }
+
+ function _getHtmlResult(data) {
+ var points = data.points,
+ div = document.createElement('div'),
+ img = document.createElement('img'),
+ width = points[2] - points[0],
+ height = points[3] - points[1];
+
+ addClass(div, 'croppie-result');
+ div.appendChild(img);
+ css(img, {
+ left: (-1 * points[0]) + 'px',
+ top: (-1 * points[1]) + 'px'
+ });
+ img.src = data.url;
+ css(div, {
+ width: width + 'px',
+ height: height + 'px'
+ });
+
+ return div;
+ }
+
+ function _getBase64Result(data) {
+ return _getCanvas.call(this, data).toDataURL(data.format, data.quality);
+ }
+
+ function _getBlobResult(data) {
+ var self = this;
+ return new Promise(function (resolve) {
+ _getCanvas.call(self, data).toBlob(function (blob) {
+ resolve(blob);
+ }, data.format, data.quality);
+ });
+ }
+
+ function _replaceImage(img) {
+ if (this.elements.img.parentNode) {
+ Array.prototype.forEach.call(this.elements.img.classList, function(c) { img.classList.add(c); });
+ this.elements.img.parentNode.replaceChild(img, this.elements.img);
+ this.elements.preview = img; // if the img is attached to the DOM, they're not using the canvas
+ }
+ this.elements.img = img;
+ }
+
+ function _bind(options, cb) {
+ var self = this,
+ url,
+ points = [],
+ zoom = null,
+ hasExif = _hasExif.call(self);
+
+ if (typeof (options) === 'string') {
+ url = options;
+ options = {};
+ }
+ else if (Array.isArray(options)) {
+ points = options.slice();
+ }
+ else if (typeof (options) === 'undefined' && self.data.url) { //refreshing
+ _updatePropertiesFromImage.call(self);
+ _triggerUpdate.call(self);
+ return null;
+ }
+ else {
+ url = options.url;
+ points = options.points || [];
+ zoom = typeof(options.zoom) === 'undefined' ? null : options.zoom;
+ }
+
+ self.data.bound = false;
+ self.data.url = url || self.data.url;
+ self.data.boundZoom = zoom;
+
+ return loadImage(url, hasExif).then(function (img) {
+ _replaceImage.call(self, img);
+ if (!points.length) {
+ var natDim = naturalImageDimensions(img);
+ var rect = self.elements.viewport.getBoundingClientRect();
+ var aspectRatio = rect.width / rect.height;
+ var imgAspectRatio = natDim.width / natDim.height;
+ var width, height;
+
+ if (imgAspectRatio > aspectRatio) {
+ height = natDim.height;
+ width = height * aspectRatio;
+ }
+ else {
+ width = natDim.width;
+ height = natDim.height / aspectRatio;
+ }
+
+ var x0 = (natDim.width - width) / 2;
+ var y0 = (natDim.height - height) / 2;
+ var x1 = x0 + width;
+ var y1 = y0 + height;
+ self.data.points = [x0, y0, x1, y1];
+ }
+ else if (self.options.relative) {
+ points = [
+ points[0] * img.naturalWidth / 100,
+ points[1] * img.naturalHeight / 100,
+ points[2] * img.naturalWidth / 100,
+ points[3] * img.naturalHeight / 100
+ ];
+ }
+
+ self.data.orientation = options.orientation || 1;
+ self.data.points = points.map(function (p) {
+ return parseFloat(p);
+ });
+ if (self.options.useCanvas) {
+ _transferImageToCanvas.call(self, self.data.orientation);
+ }
+ _updatePropertiesFromImage.call(self);
+ _triggerUpdate.call(self);
+ cb && cb();
+ });
+ }
+
+ function fix(v, decimalPoints) {
+ return parseFloat(v).toFixed(decimalPoints || 0);
+ }
+
+ function _get() {
+ var self = this,
+ imgData = self.elements.preview.getBoundingClientRect(),
+ vpData = self.elements.viewport.getBoundingClientRect(),
+ x1 = vpData.left - imgData.left,
+ y1 = vpData.top - imgData.top,
+ widthDiff = (vpData.width - self.elements.viewport.offsetWidth) / 2, //border
+ heightDiff = (vpData.height - self.elements.viewport.offsetHeight) / 2,
+ x2 = x1 + self.elements.viewport.offsetWidth + widthDiff,
+ y2 = y1 + self.elements.viewport.offsetHeight + heightDiff,
+ scale = self._currentZoom;
+
+ if (scale === Infinity || isNaN(scale)) {
+ scale = 1;
+ }
+
+ var max = self.options.enforceBoundary ? 0 : Number.NEGATIVE_INFINITY;
+ x1 = Math.max(max, x1 / scale);
+ y1 = Math.max(max, y1 / scale);
+ x2 = Math.max(max, x2 / scale);
+ y2 = Math.max(max, y2 / scale);
+
+ return {
+ points: [fix(x1), fix(y1), fix(x2), fix(y2)],
+ zoom: scale,
+ orientation: self.data.orientation
+ };
+ }
+
+ var RESULT_DEFAULTS = {
+ type: 'canvas',
+ format: 'png',
+ quality: 1
+ },
+ RESULT_FORMATS = ['jpeg', 'webp', 'png'];
+
+ function _result(options) {
+ var self = this,
+ data = _get.call(self),
+ opts = deepExtend(clone(RESULT_DEFAULTS), clone(options)),
+ resultType = (typeof (options) === 'string' ? options : (opts.type || 'base64')),
+ size = opts.size || 'viewport',
+ format = opts.format,
+ quality = opts.quality,
+ backgroundColor = opts.backgroundColor,
+ circle = typeof opts.circle === 'boolean' ? opts.circle : (self.options.viewport.type === 'circle'),
+ vpRect = self.elements.viewport.getBoundingClientRect(),
+ ratio = vpRect.width / vpRect.height,
+ prom;
+
+ if (size === 'viewport') {
+ data.outputWidth = vpRect.width;
+ data.outputHeight = vpRect.height;
+ } else if (typeof size === 'object') {
+ if (size.width && size.height) {
+ data.outputWidth = size.width;
+ data.outputHeight = size.height;
+ } else if (size.width) {
+ data.outputWidth = size.width;
+ data.outputHeight = size.width / ratio;
+ } else if (size.height) {
+ data.outputWidth = size.height * ratio;
+ data.outputHeight = size.height;
+ }
+ }
+
+ if (RESULT_FORMATS.indexOf(format) > -1) {
+ data.format = 'image/' + format;
+ data.quality = quality;
+ }
+
+ data.circle = circle;
+ data.url = self.data.url;
+ data.backgroundColor = backgroundColor;
+
+ prom = new Promise(function (resolve) {
+ switch(resultType.toLowerCase())
+ {
+ case 'rawcanvas':
+ resolve(_getCanvas.call(self, data));
+ break;
+ case 'canvas':
+ case 'base64':
+ resolve(_getBase64Result.call(self, data));
+ break;
+ case 'blob':
+ _getBlobResult.call(self, data).then(resolve);
+ break;
+ default:
+ resolve(_getHtmlResult.call(self, data));
+ break;
+ }
+ });
+ return prom;
+ }
+
+ function _refresh() {
+ _updatePropertiesFromImage.call(this);
+ }
+
+ function _rotate(deg) {
+ if (!this.options.useCanvas || !this.options.enableOrientation) {
+ throw 'Croppie: Cannot rotate without enableOrientation && EXIF.js included';
+ }
+
+ var self = this,
+ canvas = self.elements.canvas;
+
+ self.data.orientation = getExifOffset(self.data.orientation, deg);
+ drawCanvas(canvas, self.elements.img, self.data.orientation);
+ _updateCenterPoint.call(self, true);
+ _updateZoomLimits.call(self);
+
+ // Reverses image dimensions if the degrees of rotation is not divisible by 180.
+ if ((Math.abs(deg) / 90) % 2 === 1) {
+ var oldHeight = self._originalImageHeight;
+ var oldWidth = self._originalImageWidth;
+ self._originalImageWidth = oldHeight;
+ self._originalImageHeight = oldWidth;
+ }
+ }
+
+ function _destroy() {
+ var self = this;
+ self.element.removeChild(self.elements.boundary);
+ removeClass(self.element, 'croppie-container');
+ if (self.options.enableZoom) {
+ self.element.removeChild(self.elements.zoomerWrap);
+ }
+ delete self.elements;
+ }
+
+ if (typeof window !== 'undefined' && window.jQuery) {
+ var $ = window.jQuery;
+ $.fn.croppie = function (opts) {
+ var ot = typeof opts;
+
+ if (ot === 'string') {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var singleInst = $(this).data('croppie');
+
+ if (opts === 'get') {
+ return singleInst.get();
+ }
+ else if (opts === 'result') {
+ return singleInst.result.apply(singleInst, args);
+ }
+ else if (opts === 'bind') {
+ return singleInst.bind.apply(singleInst, args);
+ }
+
+ return this.each(function () {
+ var i = $(this).data('croppie');
+ if (!i) return;
+
+ var method = i[opts];
+ if ($.isFunction(method)) {
+ method.apply(i, args);
+ if (opts === 'destroy') {
+ $(this).removeData('croppie');
+ }
+ }
+ else {
+ throw 'Croppie ' + opts + ' method not found';
+ }
+ });
+ }
+ else {
+ return this.each(function () {
+ var i = new Croppie(this, opts);
+ i.$ = $;
+ $(this).data('croppie', i);
+ });
+ }
+ };
+ }
+
+ function Croppie(element, opts) {
+ if (element.className.indexOf('croppie-container') > -1) {
+ throw new Error("Croppie: Can't initialize croppie more than once");
+ }
+ this.element = element;
+ this.options = deepExtend(clone(Croppie.defaults), opts);
+
+ if (this.element.tagName.toLowerCase() === 'img') {
+ var origImage = this.element;
+ addClass(origImage, 'cr-original-image');
+ setAttributes(origImage, {'aria-hidden' : 'true', 'alt' : '' });
+ var replacementDiv = document.createElement('div');
+ this.element.parentNode.appendChild(replacementDiv);
+ replacementDiv.appendChild(origImage);
+ this.element = replacementDiv;
+ this.options.url = this.options.url || origImage.src;
+ }
+
+ _create.call(this);
+ if (this.options.url) {
+ var bindOpts = {
+ url: this.options.url,
+ points: this.options.points
+ };
+ delete this.options['url'];
+ delete this.options['points'];
+ _bind.call(this, bindOpts);
+ }
+ }
+
+ Croppie.defaults = {
+ viewport: {
+ width: 100,
+ height: 100,
+ type: 'square'
+ },
+ boundary: { },
+ orientationControls: {
+ enabled: true,
+ leftClass: '',
+ rightClass: ''
+ },
+ resizeControls: {
+ width: true,
+ height: true
+ },
+ customClass: '',
+ showZoomer: true,
+ enableZoom: true,
+ enableResize: false,
+ mouseWheelZoom: true,
+ enableExif: false,
+ enforceBoundary: true,
+ enableOrientation: false,
+ enableKeyMovement: true,
+ update: function () { }
+ };
+
+ Croppie.globals = {
+ translate: 'translate3d'
+ };
+
+ deepExtend(Croppie.prototype, {
+ bind: function (options, cb) {
+ return _bind.call(this, options, cb);
+ },
+ get: function () {
+ var data = _get.call(this);
+ var points = data.points;
+ if (this.options.relative) {
+ points[0] /= this.elements.img.naturalWidth / 100;
+ points[1] /= this.elements.img.naturalHeight / 100;
+ points[2] /= this.elements.img.naturalWidth / 100;
+ points[3] /= this.elements.img.naturalHeight / 100;
+ }
+ return data;
+ },
+ result: function (type) {
+ return _result.call(this, type);
+ },
+ refresh: function () {
+ return _refresh.call(this);
+ },
+ setZoom: function (v) {
+ _setZoomerVal.call(this, v);
+ dispatchChange(this.elements.zoomer);
+ },
+ rotate: function (deg) {
+ _rotate.call(this, deg);
+ },
+ destroy: function () {
+ return _destroy.call(this);
+ }
+ });
+ return Croppie;
+}));
\ No newline at end of file
diff --git a/public/js/profilecropper/profile.js b/public/js/profilecropper/profile.js
new file mode 100644
index 0000000..064a410
--- /dev/null
+++ b/public/js/profilecropper/profile.js
@@ -0,0 +1,118 @@
+let el = document.querySelector('#cropper')
+let banner = document.querySelector('#banner')
+let avatar = document.querySelector('#avatar')
+let preview = document.querySelector('#preview')
+let modal = document.querySelector('#modal')
+let profilefiles = document.querySelectorAll('.profilefiles')
+let pcontainer = document.querySelector('#preview-container')
+
+function showModal() {
+ if(modal.classList.contains('hidden')) {
+ modal.classList.remove('hidden')
+ modal.classList.remove('fade-out-bck')
+ } else {
+ modal.classList.add('hidden')
+ modal.classList.add('fade-out-bck')
+ }
+}
+
+class Crop {
+ createBanner() {
+ this.vanilla = new Croppie(el, {
+ viewport: { width: 300, height: 100 },
+ boundary: { width: 300, height: 300 },
+ })
+ return this.vanilla
+ }
+
+ createAvatar() {
+ this.vanilla = new Croppie(el, {
+ viewport: {
+ width: 300,
+ height: 300,
+ type: 'circle'
+ },
+ boundary: {
+ width: 300,
+ height: 300
+ },
+ })
+ return this.vanilla
+ }
+}
+
+profilefiles.forEach(function(element) {
+ element.addEventListener('change', () => {
+ showModal()
+
+ // croppie instance
+ const [file] = element.files
+
+ let vanilla
+ let teste = new Crop
+
+ if(element.id == 'banner') {
+ vanilla = teste.createBanner()
+ } else {
+ vanilla = teste.createAvatar()
+ }
+
+// set banner
+
+document.querySelector('#show-result').addEventListener('click', ()=> {
+
+
+ let res = result(vanilla, element)
+
+ // result
+ res.then(function(blob) {
+ if(element.id == 'banner') {
+ bimg.src = URL.createObjectURL(blob)
+ } else {
+ pcontainer.classList.remove('hidden')
+ preview.src = URL.createObjectURL(blob)
+ }
+
+ // blob to image
+ let bimage = new File([blob], "image",{
+ type:"image/jpeg", lastModified:new Date().getTime()
+ })
+ let container = new DataTransfer()
+ container.items.add(bimage)
+ element.files = container.files
+
+ // modal fade out
+ modal.classList.add('fade-out-bck')
+ setTimeout(() => {
+ modal.classList.add('hidden')
+ }, 500)
+
+})})
+
+vanilla.bind({
+ url: URL.createObjectURL(file),
+})
+
+banner.addEventListener('click', ()=> {
+ vanilla.destroy()})
+
+avatar.addEventListener('click', ()=> {
+ vanilla.destroy()})
+});
+});
+
+async function result(vanilla, element) {
+ let res
+ if(element.id == 'banner'){
+ res = await vanilla.result({
+ type: 'blob',
+ size: {width: 1500, height: 500},
+ })
+ } else {
+ res = await vanilla.result({
+ type: 'blob',
+ size: {width: 200, height: 200},
+ })
+ }
+ return res
+}
\ No newline at end of file
diff --git a/resources/views/components/master.blade.php b/resources/views/components/master.blade.php
index ff33f3c..01fa194 100755
--- a/resources/views/components/master.blade.php
+++ b/resources/views/components/master.blade.php
@@ -2,7 +2,7 @@
-
+
@@ -11,6 +11,7 @@
+
@@ -19,6 +20,7 @@
+
diff --git a/resources/views/profiles/edit.blade.php b/resources/views/profiles/edit.blade.php
index ef2fdda..d340d08 100755
--- a/resources/views/profiles/edit.blade.php
+++ b/resources/views/profiles/edit.blade.php
@@ -9,10 +9,20 @@
-
+
+
+ New Picture Preview
+
+

+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file