| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /*
- * cropit - v0.2.0
- * Customizable crop and zoom.
- * https://github.com/scottcheng/cropit
- *
- * Made by Scott Cheng
- * Based on https://github.com/yufeiliu/simple_image_uploader
- * Under MIT License
- */
- (function($) {
- var Zoomer;
- Zoomer = function() {
- function Zoomer() {}
- Zoomer.prototype.setup = function(imageSize, previewSize, exportZoom, options) {
- var heightRatio, widthRatio;
- if (exportZoom == null) {
- exportZoom = 1;
- }
- widthRatio = previewSize.w / imageSize.w;
- heightRatio = previewSize.h / imageSize.h;
- if ((options != null ? options.minZoom : void 0) === "fit") {
- this.minZoom = widthRatio < heightRatio ? widthRatio : heightRatio;
- } else {
- this.minZoom = widthRatio < heightRatio ? heightRatio : widthRatio;
- }
- return this.maxZoom = this.minZoom < 1 / exportZoom ? 1 / exportZoom : this.minZoom;
- };
- Zoomer.prototype.getZoom = function(sliderPos) {
- if (!(this.minZoom && this.maxZoom)) {
- return null;
- }
- return sliderPos * (this.maxZoom - this.minZoom) + this.minZoom;
- };
- Zoomer.prototype.getSliderPos = function(zoom) {
- if (!(this.minZoom && this.maxZoom)) {
- return null;
- }
- if (this.minZoom === this.maxZoom) {
- return 0;
- } else {
- return (zoom - this.minZoom) / (this.maxZoom - this.minZoom);
- }
- };
- Zoomer.prototype.isZoomable = function() {
- if (!(this.minZoom && this.maxZoom)) {
- return null;
- }
- return this.minZoom !== this.maxZoom;
- };
- Zoomer.prototype.fixZoom = function(zoom) {
- if (zoom < this.minZoom) {
- return this.minZoom;
- }
- if (zoom > this.maxZoom) {
- return this.maxZoom;
- }
- return zoom;
- };
- return Zoomer;
- }();
- var Cropit;
- Cropit = function() {
- Cropit._DEFAULTS = {
- exportZoom: 1,
- imageBackground: false,
- imageBackgroundBorderWidth: 0,
- imageState: null,
- allowCrossOrigin: false,
- allowDragNDrop: true,
- freeMove: false,
- minZoom: "fill"
- };
- Cropit.PREVIEW_EVENTS = function() {
- return [ "mousedown", "mouseup", "mouseleave", "touchstart", "touchend", "touchcancel", "touchleave" ].map(function(type) {
- return "" + type + ".cropit";
- }).join(" ");
- }();
- Cropit.PREVIEW_MOVE_EVENTS = "mousemove.cropit touchmove.cropit";
- Cropit.ZOOM_INPUT_EVENTS = function() {
- return [ "mousemove", "touchmove", "change" ].map(function(type) {
- return "" + type + ".cropit";
- }).join(" ");
- }();
- function Cropit(element, options) {
- var dynamicDefaults;
- this.element = element;
- this.$el = $(this.element);
- dynamicDefaults = {
- $fileInput: this.$("input.cropit-image-input"),
- $preview: this.$(".cropit-image-preview"),
- $zoomSlider: this.$("input.cropit-image-zoom-input"),
- $previewContainer: this.$(".cropit-image-preview-container")
- };
- this.options = $.extend({}, Cropit._DEFAULTS, dynamicDefaults, options);
- this.init();
- }
- Cropit.prototype.init = function() {
- var $previewContainer, _ref, _ref1, _ref2;
- this.image = new Image();
- if (this.options.allowCrossOrigin) {
- this.image.crossOrigin = "Anonymous";
- }
- this.$fileInput = this.options.$fileInput.attr({
- accept: "image/*"
- });
- this.$preview = this.options.$preview.css({
- backgroundRepeat: "no-repeat"
- });
- this.$zoomSlider = this.options.$zoomSlider.attr({
- min: 0,
- max: 1,
- step: .01
- });
- this.previewSize = {
- w: this.options.width || this.$preview.width(),
- h: this.options.height || this.$preview.height()
- };
- if (this.options.width) {
- this.$preview.width(this.previewSize.w);
- }
- if (this.options.height) {
- this.$preview.height(this.previewSize.h);
- }
- if (this.options.imageBackground) {
- if ($.isArray(this.options.imageBackgroundBorderWidth)) {
- this.imageBgBorderWidthArray = this.options.imageBackgroundBorderWidth;
- } else {
- this.imageBgBorderWidthArray = [];
- [ 0, 1, 2, 3 ].forEach(function(_this) {
- return function(i) {
- return _this.imageBgBorderWidthArray[i] = _this.options.imageBackgroundBorderWidth;
- };
- }(this));
- }
- $previewContainer = this.options.$previewContainer;
- this.$imageBg = $("<img />").addClass("cropit-image-background").attr("alt", "").css("position", "absolute");
- this.$imageBgContainer = $("<div />").addClass("cropit-image-background-container").css({
- position: "absolute",
- zIndex: 0,
- left: -this.imageBgBorderWidthArray[3] + window.parseInt(this.$preview.css("border-left-width")),
- top: -this.imageBgBorderWidthArray[0] + window.parseInt(this.$preview.css("border-top-width")),
- width: this.previewSize.w + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
- height: this.previewSize.h + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
- }).append(this.$imageBg);
- if (this.imageBgBorderWidthArray[0] > 0) {
- this.$imageBgContainer.css({
- overflow: "hidden"
- });
- }
- $previewContainer.css("position", "relative").prepend(this.$imageBgContainer);
- this.$preview.css("position", "relative");
- this.$preview.hover(function(_this) {
- return function() {
- return _this.$imageBg.addClass("cropit-preview-hovered");
- };
- }(this), function(_this) {
- return function() {
- return _this.$imageBg.removeClass("cropit-preview-hovered");
- };
- }(this));
- }
- this.initialOffset = {
- x: 0,
- y: 0
- };
- this.initialZoom = 0;
- this.initialZoomSliderPos = 0;
- this.imageLoaded = false;
- this.moveContinue = false;
- this.zoomer = new Zoomer();
- if (this.options.allowDragNDrop) {
- jQuery.event.props.push("dataTransfer");
- }
- this.bindListeners();
- this.$zoomSlider.val(this.initialZoomSliderPos);
- this.setOffset(((_ref = this.options.imageState) != null ? _ref.offset : void 0) || this.initialOffset);
- this.zoom = ((_ref1 = this.options.imageState) != null ? _ref1.zoom : void 0) || this.initialZoom;
- return this.loadImage(((_ref2 = this.options.imageState) != null ? _ref2.src : void 0) || null);
- };
- Cropit.prototype.bindListeners = function() {
- this.$fileInput.on("change.cropit", this.onFileChange.bind(this));
- this.$preview.on(Cropit.PREVIEW_EVENTS, this.onPreviewEvent.bind(this));
- this.$zoomSlider.on(Cropit.ZOOM_INPUT_EVENTS, this.onZoomSliderChange.bind(this));
- if (this.options.allowDragNDrop) {
- this.$preview.on("dragover.cropit dragleave.cropit", this.onDragOver.bind(this));
- return this.$preview.on("drop.cropit", this.onDrop.bind(this));
- }
- };
- Cropit.prototype.unbindListeners = function() {
- this.$fileInput.off("change.cropit");
- this.$preview.off(Cropit.PREVIEW_EVENTS);
- this.$preview.off("dragover.cropit dragleave.cropit drop.cropit");
- return this.$zoomSlider.off(Cropit.ZOOM_INPUT_EVENTS);
- };
- Cropit.prototype.reset = function() {
- this.zoom = this.initialZoom;
- return this.offset = this.initialOffset;
- };
- Cropit.prototype.onFileChange = function() {
- var _base;
- if (typeof (_base = this.options).onFileChange === "function") {
- _base.onFileChange();
- }
- return this.loadFileReader(this.$fileInput.get(0).files[0]);
- };
- Cropit.prototype.loadFileReader = function(file) {
- var fileReader;
- fileReader = new FileReader();
- if (file != null ? file.type.match("image") : void 0) {
- this.setImageLoadingClass();
- fileReader.readAsDataURL(file);
- fileReader.onload = this.onFileReaderLoaded.bind(this);
- return fileReader.onerror = this.onFileReaderError.bind(this);
- } else if (file != null) {
- return this.onFileReaderError();
- }
- };
- Cropit.prototype.onFileReaderLoaded = function(e) {
- this.reset();
- return this.loadImage(e.target.result);
- };
- Cropit.prototype.onFileReaderError = function() {
- var _base;
- return typeof (_base = this.options).onFileReaderError === "function" ? _base.onFileReaderError() : void 0;
- };
- Cropit.prototype.onDragOver = function(e) {
- e.preventDefault();
- e.dataTransfer.dropEffect = "copy";
- return this.$preview.toggleClass("cropit-drag-hovered", e.type === "dragover");
- };
- Cropit.prototype.onDrop = function(e) {
- var files;
- e.preventDefault();
- e.stopPropagation();
- files = Array.prototype.slice.call(e.dataTransfer.files, 0);
- files.some(function(_this) {
- return function(file) {
- if (file.type.match("image")) {
- _this.loadFileReader(file);
- return true;
- }
- };
- }(this));
- return this.$preview.removeClass("cropit-drag-hovered");
- };
- Cropit.prototype.loadImage = function(imageSrc) {
- var _base;
- this.imageSrc = imageSrc;
- if (!this.imageSrc) {
- return;
- }
- if (typeof (_base = this.options).onImageLoading === "function") {
- _base.onImageLoading();
- }
- this.setImageLoadingClass();
- this.image.onload = this.onImageLoaded.bind(this);
- this.image.onerror = this.onImageError.bind(this);
- return this.image.src = this.imageSrc;
- };
- Cropit.prototype.onImageLoaded = function() {
- var _base;
- this.setImageLoadedClass();
- this.setOffset(this.offset);
- this.$preview.css("background-image", "url(" + this.imageSrc + ")");
- if (this.options.imageBackground) {
- this.$imageBg.attr("src", this.imageSrc);
- }
- this.imageSize = {
- w: this.image.width,
- h: this.image.height
- };
- this.setupZoomer();
- this.imageLoaded = true;
- return typeof (_base = this.options).onImageLoaded === "function" ? _base.onImageLoaded() : void 0;
- };
- Cropit.prototype.onImageError = function() {
- var _base;
- return typeof (_base = this.options).onImageError === "function" ? _base.onImageError() : void 0;
- };
- Cropit.prototype.setImageLoadingClass = function() {
- return this.$preview.removeClass("cropit-image-loaded").addClass("cropit-image-loading");
- };
- Cropit.prototype.setImageLoadedClass = function() {
- return this.$preview.removeClass("cropit-image-loading").addClass("cropit-image-loaded");
- };
- Cropit.prototype.getEventPosition = function(e) {
- var _ref, _ref1, _ref2, _ref3;
- if ((_ref = e.originalEvent) != null ? (_ref1 = _ref.touches) != null ? _ref1[0] : void 0 : void 0) {
- e = (_ref2 = e.originalEvent) != null ? (_ref3 = _ref2.touches) != null ? _ref3[0] : void 0 : void 0;
- }
- if (e.clientX && e.clientY) {
- return {
- x: e.clientX,
- y: e.clientY
- };
- }
- };
- Cropit.prototype.onPreviewEvent = function(e) {
- if (!this.imageLoaded) {
- return;
- }
- this.moveContinue = false;
- this.$preview.off(Cropit.PREVIEW_MOVE_EVENTS);
- if (e.type === "mousedown" || e.type === "touchstart") {
- this.origin = this.getEventPosition(e);
- this.moveContinue = true;
- this.$preview.on(Cropit.PREVIEW_MOVE_EVENTS, this.onMove.bind(this));
- } else {
- $(document.body).focus();
- }
- e.stopPropagation();
- return false;
- };
- Cropit.prototype.onMove = function(e) {
- var eventPosition;
- eventPosition = this.getEventPosition(e);
- if (this.moveContinue && eventPosition) {
- this.setOffset({
- x: this.offset.x + eventPosition.x - this.origin.x,
- y: this.offset.y + eventPosition.y - this.origin.y
- });
- }
- this.origin = eventPosition;
- e.stopPropagation();
- return false;
- };
- Cropit.prototype.setOffset = function(position) {
- this.offset = this.fixOffset(position);
- this.$preview.css("background-position", "" + this.offset.x + "px " + this.offset.y + "px");
- if (this.options.imageBackground) {
- return this.$imageBg.css({
- left: this.offset.x + this.imageBgBorderWidthArray[3],
- top: this.offset.y + this.imageBgBorderWidthArray[0]
- });
- }
- };
- Cropit.prototype.fixOffset = function(offset) {
- var ret;
- if (!this.imageLoaded) {
- return offset;
- }
- ret = {
- x: offset.x,
- y: offset.y
- };
- if (!this.options.freeMove) {
- if (this.imageSize.w * this.zoom >= this.previewSize.w) {
- ret.x = Math.min(0, Math.max(ret.x, this.previewSize.w - this.imageSize.w * this.zoom));
- } else {
- ret.x = Math.max(0, Math.min(ret.x, this.previewSize.w - this.imageSize.w * this.zoom));
- }
- if (this.imageSize.h * this.zoom >= this.previewSize.h) {
- ret.y = Math.min(0, Math.max(ret.y, this.previewSize.h - this.imageSize.h * this.zoom));
- } else {
- ret.y = Math.max(0, Math.min(ret.y, this.previewSize.h - this.imageSize.h * this.zoom));
- }
- }
- ret.x = this.round(ret.x);
- ret.y = this.round(ret.y);
- return ret;
- };
- Cropit.prototype.onZoomSliderChange = function() {
- var newZoom;
- if (!this.imageLoaded) {
- return;
- }
- this.zoomSliderPos = Number(this.$zoomSlider.val());
- newZoom = this.zoomer.getZoom(this.zoomSliderPos);
- return this.setZoom(newZoom);
- };
- Cropit.prototype.enableZoomSlider = function() {
- var _base;
- this.$zoomSlider.removeAttr("disabled");
- return typeof (_base = this.options).onZoomEnabled === "function" ? _base.onZoomEnabled() : void 0;
- };
- Cropit.prototype.disableZoomSlider = function() {
- var _base;
- this.$zoomSlider.attr("disabled", true);
- return typeof (_base = this.options).onZoomDisabled === "function" ? _base.onZoomDisabled() : void 0;
- };
- Cropit.prototype.setupZoomer = function() {
- this.zoomer.setup(this.imageSize, this.previewSize, this.options.exportZoom, this.options);
- this.zoom = this.fixZoom(this.zoom);
- this.setZoom(this.zoom);
- if (this.isZoomable()) {
- return this.enableZoomSlider();
- } else {
- return this.disableZoomSlider();
- }
- };
- Cropit.prototype.setZoom = function(newZoom) {
- var newX, newY, oldZoom, updatedHeight, updatedWidth;
- newZoom = this.fixZoom(newZoom);
- updatedWidth = this.round(this.imageSize.w * newZoom);
- updatedHeight = this.round(this.imageSize.h * newZoom);
- oldZoom = this.zoom;
- newX = this.previewSize.w / 2 - (this.previewSize.w / 2 - this.offset.x) * newZoom / oldZoom;
- newY = this.previewSize.h / 2 - (this.previewSize.h / 2 - this.offset.y) * newZoom / oldZoom;
- this.zoom = newZoom;
- this.setOffset({
- x: newX,
- y: newY
- });
- this.zoomSliderPos = this.zoomer.getSliderPos(this.zoom);
- this.$zoomSlider.val(this.zoomSliderPos);
- this.$preview.css("background-size", "" + updatedWidth + "px " + updatedHeight + "px");
- if (this.options.imageBackground) {
- return this.$imageBg.css({
- width: updatedWidth,
- height: updatedHeight
- });
- }
- };
- Cropit.prototype.fixZoom = function(zoom) {
- return this.zoomer.fixZoom(zoom);
- };
- Cropit.prototype.isZoomable = function() {
- return this.zoomer.isZoomable();
- };
- Cropit.prototype.getCroppedImageData = function(exportOptions) {
- var canvas, canvasContext, croppedSize, exportDefaults, exportZoom;
- if (!this.imageSrc) {
- return null;
- }
- exportDefaults = {
- type: "image/png",
- quality: .75,
- originalSize: false,
- fillBg: "#fff"
- };
- exportOptions = $.extend({}, exportDefaults, exportOptions);
- croppedSize = {
- w: this.previewSize.w,
- h: this.previewSize.h
- };
- exportZoom = exportOptions.originalSize ? 1 / this.zoom : this.options.exportZoom;
- canvas = $("<canvas />").attr({
- width: croppedSize.w * exportZoom,
- height: croppedSize.h * exportZoom
- }).get(0);
- canvasContext = canvas.getContext("2d");
- if (exportOptions.type === "image/jpeg") {
- canvasContext.fillStyle = exportOptions.fillBg;
- canvasContext.fillRect(0, 0, canvas.width, canvas.height);
- }
- canvasContext.drawImage(this.image, this.offset.x * exportZoom, this.offset.y * exportZoom, this.zoom * exportZoom * this.imageSize.w, this.zoom * exportZoom * this.imageSize.h);
- return canvas.toDataURL(exportOptions.type, exportOptions.quality);
- };
- Cropit.prototype.getImageState = function() {
- return {
- src: this.imageSrc,
- offset: this.offset,
- zoom: this.zoom
- };
- };
- Cropit.prototype.getImageSrc = function() {
- return this.imageSrc;
- };
- Cropit.prototype.getOffset = function() {
- return this.offset;
- };
- Cropit.prototype.getZoom = function() {
- return this.zoom;
- };
- Cropit.prototype.getImageSize = function() {
- if (!this.imageSize) {
- return null;
- }
- return {
- width: this.imageSize.w,
- height: this.imageSize.h
- };
- };
- Cropit.prototype.getPreviewSize = function() {
- return {
- width: this.previewSize.w,
- height: this.previewSize.h
- };
- };
- Cropit.prototype.setPreviewSize = function(size) {
- if (!((size != null ? size.width : void 0) > 0 && (size != null ? size.height : void 0) > 0)) {
- return;
- }
- this.previewSize = {
- w: size.width,
- h: size.height
- };
- this.$preview.css({
- width: this.previewSize.w,
- height: this.previewSize.h
- });
- if (this.options.imageBackground) {
- this.$imageBgContainer.css({
- width: this.previewSize.w + this.imageBgBorderWidthArray[1] + this.imageBgBorderWidthArray[3],
- height: this.previewSize.h + this.imageBgBorderWidthArray[0] + this.imageBgBorderWidthArray[2]
- });
- }
- if (this.imageLoaded) {
- return this.setupZoomer();
- }
- };
- Cropit.prototype.disable = function() {
- this.unbindListeners();
- this.disableZoomSlider();
- return this.$el.addClass("cropit-disabled");
- };
- Cropit.prototype.reenable = function() {
- this.bindListeners();
- this.enableZoomSlider();
- return this.$el.removeClass("cropit-disabled");
- };
- Cropit.prototype.round = function(x) {
- return +(Math.round(x * 100) + "e-2");
- };
- Cropit.prototype.$ = function(selector) {
- if (!this.$el) {
- return null;
- }
- return this.$el.find(selector);
- };
- return Cropit;
- }();
- var dataKey, methods;
- dataKey = "cropit";
- methods = {
- init: function(options) {
- return this.each(function() {
- var cropit;
- if (!$.data(this, dataKey)) {
- cropit = new Cropit(this, options);
- return $.data(this, dataKey, cropit);
- }
- });
- },
- destroy: function() {
- return this.each(function() {
- return $.removeData(this, dataKey);
- });
- },
- isZoomable: function() {
- var cropit;
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.isZoomable() : void 0;
- },
- "export": function(options) {
- var cropit;
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getCroppedImageData(options) : void 0;
- },
- imageState: function() {
- var cropit;
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getImageState() : void 0;
- },
- imageSrc: function(newImageSrc) {
- var cropit;
- if (newImageSrc != null) {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- if (cropit != null) {
- cropit.reset();
- }
- return cropit != null ? cropit.loadImage(newImageSrc) : void 0;
- });
- } else {
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getImageSrc() : void 0;
- }
- },
- offset: function(newOffset) {
- var cropit;
- if (newOffset != null && newOffset.x != null && newOffset.y != null) {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- return cropit != null ? cropit.setOffset(newOffset) : void 0;
- });
- } else {
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getOffset() : void 0;
- }
- },
- zoom: function(newZoom) {
- var cropit;
- if (newZoom != null) {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- return cropit != null ? cropit.setZoom(newZoom) : void 0;
- });
- } else {
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getZoom() : void 0;
- }
- },
- imageSize: function() {
- var cropit;
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getImageSize() : void 0;
- },
- previewSize: function(newSize) {
- var cropit;
- if (newSize != null) {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- return cropit != null ? cropit.setPreviewSize(newSize) : void 0;
- });
- } else {
- cropit = this.first().data(dataKey);
- return cropit != null ? cropit.getPreviewSize() : void 0;
- }
- },
- disable: function() {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- return cropit.disable();
- });
- },
- reenable: function() {
- return this.each(function() {
- var cropit;
- cropit = $.data(this, dataKey);
- return cropit.reenable();
- });
- }
- };
- $.fn.cropit = function(method) {
- if (methods[method]) {
- return methods[method].apply(this, [].slice.call(arguments, 1));
- } else {
- return methods.init.apply(this, arguments);
- }
- };
- })(window.jQuery);
|