281 lines
10 KiB
JavaScript
281 lines
10 KiB
JavaScript
/*!
|
|
* ZUI: 图片裁剪工具 - v1.8.1 - 2018-01-18
|
|
* http://zui.sexy
|
|
* GitHub: https://github.com/easysoft/zui.git
|
|
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
|
|
*/
|
|
|
|
/* ========================================================================
|
|
* ZUI: img-cutter.js
|
|
* http://zui.sexy
|
|
* ========================================================================
|
|
* Copyright (c) 2014-2016 cnezsoft.com; Licensed MIT
|
|
* ======================================================================== */
|
|
|
|
|
|
(function($, Math, undefined) {
|
|
'use strict';
|
|
|
|
if(!$.fn.draggable) console.error('img-cutter requires draggable.js');
|
|
if(!$.zui.imgReady) console.error('img-cutter requires image.ready.js');
|
|
|
|
var NAME = 'zui.imgCutter';
|
|
|
|
var ImgCutter = function(element, options) {
|
|
this.$ = $(element);
|
|
this.initOptions(options);
|
|
this.init();
|
|
};
|
|
|
|
ImgCutter.DEFAULTS = {
|
|
coverColor: '#000',
|
|
coverOpacity: 0.6,
|
|
// fixedRatio: false,
|
|
defaultWidth: 128,
|
|
defaultHeight: 128,
|
|
minWidth: 48,
|
|
minHeight: 48
|
|
}; // default options
|
|
|
|
ImgCutter.prototype.callEvent = function(name, params) {
|
|
var result = this.$.callEvent(name + '.' + NAME, params, this);
|
|
return !(result.result !== undefined && (!result.result));
|
|
};
|
|
|
|
ImgCutter.prototype.initOptions = function(options) {
|
|
this.options = $.extend({}, ImgCutter.DEFAULTS, this.$.data(), options);
|
|
this.options.coverOpacityIE = this.options.coverOpacity * 100;
|
|
this.clipWidth = this.options.defaultWidth;
|
|
this.clipHeight = this.options.defaultHeight;
|
|
};
|
|
|
|
ImgCutter.prototype.init = function() {
|
|
this.initDom();
|
|
this.initSize();
|
|
this.bindEvents();
|
|
};
|
|
|
|
ImgCutter.prototype.initDom = function() {
|
|
this.$canvas = this.$.children('.canvas');
|
|
this.$img = this.$canvas.children('img');
|
|
this.$actions = this.$.children('.actions');
|
|
this.$btn = this.$.find('.img-cutter-submit');
|
|
this.$preview = this.$.find('.img-cutter-preview');
|
|
|
|
this.options.img = this.$img.attr('src');
|
|
|
|
this.$canvas.append('<div class="cover" style="background: {coverColor}; opacity: {coverOpacity}; filter:alpha(opacity={coverOpacityIE});"></div><div class="controller" style="width: {defaultWidth}px; height: {defaultHeight}px"><div class="control" data-direction="top"></div><div class="control" data-direction="right"></div><div class="control" data-direction="bottom"></div><div class="control" data-direction="left"></div><div class="control" data-direction="top-left"></div><div class="control" data-direction="top-right"></div><div class="control" data-direction="bottom-left"></div><div class="control" data-direction="bottom-right"></div></div><div class="cliper"><img src="{img}"/></div>'.format(this.options));
|
|
|
|
this.$cover = this.$canvas.children('.cover');
|
|
this.$controller = this.$canvas.children('.controller');
|
|
this.$cliper = this.$canvas.children('.cliper');
|
|
this.$chipImg = this.$cliper.children('img');
|
|
|
|
if(this.options.fixedRatio) {
|
|
this.$.addClass('fixed-ratio');
|
|
}
|
|
};
|
|
|
|
ImgCutter.prototype.resetImage = function(img) {
|
|
var that = this;
|
|
that.options.img = img;
|
|
that.$img.attr('src', img);
|
|
that.$chipImg.attr('src', img);
|
|
that.imgWidth = undefined;
|
|
that.left = undefined;
|
|
that.initSize();
|
|
};
|
|
|
|
ImgCutter.prototype.initSize = function() {
|
|
var that = this;
|
|
if(!that.imgWidth) {
|
|
$.zui.imgReady(that.options.img, function() {
|
|
that.imgWidth = this.width;
|
|
that.imgHeight = this.height;
|
|
that.callEvent('ready');
|
|
});
|
|
}
|
|
|
|
|
|
var waitImgWidth = setInterval(function() {
|
|
if(that.imgWidth) {
|
|
clearInterval(waitImgWidth);
|
|
|
|
that.width = Math.min(that.imgWidth, that.$.width());
|
|
that.$canvas.css('width', this.width);
|
|
that.$cliper.css('width', this.width);
|
|
that.height = that.$canvas.height();
|
|
|
|
if(that.left === undefined) {
|
|
that.left = Math.floor((that.width - that.$controller.width()) / 2);
|
|
that.top = Math.floor((that.height - that.$controller.height()) / 2);
|
|
}
|
|
|
|
that.refreshSize();
|
|
}
|
|
}, 0);
|
|
};
|
|
|
|
ImgCutter.prototype.refreshSize = function(ratioSide) {
|
|
var options = this.options;
|
|
|
|
this.clipWidth = Math.max(options.minWidth, Math.min(this.width, this.clipWidth));
|
|
this.clipHeight = Math.max(options.minHeight, Math.min(this.height, this.clipHeight));
|
|
|
|
if(options.fixedRatio) {
|
|
if(ratioSide && ratioSide === 'height') {
|
|
this.clipWidth = Math.max(options.minWidth, Math.min(this.width, this.clipHeight * options.defaultWidth / options.defaultHeight));
|
|
this.clipHeight = this.clipWidth * options.defaultHeight / options.defaultWidth;
|
|
} else {
|
|
this.clipHeight = Math.max(options.minHeight, Math.min(this.height, this.clipWidth * options.defaultHeight / options.defaultWidth));
|
|
this.clipWidth = this.clipHeight * options.defaultWidth / options.defaultHeight;
|
|
}
|
|
}
|
|
|
|
this.left = Math.min(this.width - this.clipWidth, Math.max(0, this.left));
|
|
this.top = Math.min(this.height - this.clipHeight, Math.max(0, this.top));
|
|
this.right = this.left + this.clipWidth;
|
|
this.bottom = this.top + this.clipHeight;
|
|
|
|
this.$controller.css({
|
|
left: this.left,
|
|
top: this.top,
|
|
width: this.clipWidth,
|
|
height: this.clipHeight
|
|
});
|
|
this.$cliper.css('clip', 'rect({0}px {1}px {2}px {3}px'.format(this.top, this.left + this.clipWidth, this.top + this.clipHeight, this.left));
|
|
|
|
|
|
this.callEvent('change', {
|
|
top: this.top,
|
|
left: this.left,
|
|
bottom: this.bottom,
|
|
right: this.right,
|
|
width: this.clipWidth,
|
|
height: this.clipHeight
|
|
});
|
|
};
|
|
|
|
ImgCutter.prototype.getData = function() {
|
|
var that = this;
|
|
that.data = {
|
|
originWidth: that.imgWidth,
|
|
originHeight: that.imgHeight,
|
|
scaleWidth: that.width,
|
|
scaleHeight: that.height,
|
|
width: that.right - that.left,
|
|
height: that.bottom - that.top,
|
|
left: that.left,
|
|
top: that.top,
|
|
right: that.right,
|
|
bottom: that.bottom,
|
|
scaled: that.imgWidth != that.width || that.imgHeight != that.height
|
|
};
|
|
return that.data;
|
|
};
|
|
|
|
ImgCutter.prototype.bindEvents = function() {
|
|
var that = this,
|
|
options = this.options;
|
|
this.$.resize($.proxy(this.initSize, this));
|
|
this.$btn.hover(function() {
|
|
that.$.toggleClass('hover');
|
|
}).click(function() {
|
|
var data = that.getData();
|
|
|
|
if(!that.callEvent('before', data)) return;
|
|
|
|
var url = options.post || options.get || options.url || null;
|
|
if(url !== null) {
|
|
$.ajax({
|
|
type: options.post ? 'POST' : 'GET',
|
|
url: url,
|
|
data: data
|
|
})
|
|
.done(function(e) {
|
|
that.callEvent('done', e);
|
|
}).fail(function(e) {
|
|
that.callEvent('fail', e);
|
|
}).always(function(e) {
|
|
that.callEvent('always', e);
|
|
});
|
|
}
|
|
});
|
|
|
|
this.$controller.draggable({
|
|
move: false,
|
|
container: this.$canvas,
|
|
drag: function(e) {
|
|
that.left += e.smallOffset.x;
|
|
that.top += e.smallOffset.y;
|
|
that.refreshSize();
|
|
}
|
|
});
|
|
|
|
this.$controller.children('.control').draggable({
|
|
move: false,
|
|
container: this.$canvas,
|
|
stopPropagation: true,
|
|
drag: function(e) {
|
|
var dr = e.element.data('direction');
|
|
var offset = e.smallOffset;
|
|
var ratioSide = false;
|
|
|
|
switch(dr) {
|
|
case 'left':
|
|
case 'top-left':
|
|
case 'bottom-left':
|
|
that.left += offset.x;
|
|
that.left = Math.min(that.right - options.minWidth, Math.max(0, that.left));
|
|
that.clipWidth = that.right - that.left;
|
|
break;
|
|
case 'right':
|
|
case 'top-right':
|
|
case 'bottom-right':
|
|
that.clipWidth += offset.x;
|
|
that.clipWidth = Math.min(that.width - that.left, Math.max(options.minWidth, that.clipWidth));
|
|
break;
|
|
}
|
|
switch(dr) {
|
|
case 'top':
|
|
case 'top-left':
|
|
case 'top-right':
|
|
that.top += offset.y;
|
|
that.top = Math.min(that.bottom - options.minHeight, Math.max(0, that.top));
|
|
that.clipHeight = that.bottom - that.top;
|
|
ratioSide = true;
|
|
break;
|
|
case 'bottom':
|
|
case 'bottom-left':
|
|
case 'bottom-right':
|
|
that.clipHeight += offset.y;
|
|
that.clipHeight = Math.min(that.height - that.top, Math.max(options.minHeight, that.clipHeight));
|
|
ratioSide = true;
|
|
break;
|
|
}
|
|
|
|
that.refreshSize(ratioSide);
|
|
}
|
|
});
|
|
};
|
|
|
|
$.fn.imgCutter = function(option) {
|
|
return this.each(function() {
|
|
var $this = $(this);
|
|
var data = $this.data(NAME);
|
|
var options = typeof option == 'object' && option;
|
|
|
|
if(!data) $this.data(NAME, (data = new ImgCutter(this, options)));
|
|
|
|
if(typeof option == 'string') data[option]();
|
|
});
|
|
};
|
|
|
|
$.fn.imgCutter.Constructor = ImgCutter;
|
|
|
|
$(function() {
|
|
$('[data-toggle="imgCutter"]').imgCutter();
|
|
});
|
|
}(jQuery, Math, undefined));
|
|
|