Skip to content

Instantly share code, notes, and snippets.

@maolion
Created November 25, 2017 07:35
Show Gist options
  • Save maolion/97f364d344567c60278833f8db90a12c to your computer and use it in GitHub Desktop.
Save maolion/97f364d344567c60278833f8db90a12c to your computer and use it in GitHub Desktop.
Image Crop
<div class="image-crop-container">
<div class="crop-area">
<div class="dragable"></div>
<div class="mask"></div>
<img class="original-img" src="placeholder.gif" />
</div>
</div>
var $ = require('common:widget/jquery/1.11.3/jquery.js');
var Env = require('common:widget/tool/env.js');
var Utils = require('common:widget/tool/utils.js');
var Event = require('common:widget/tool/event.js');
var TouchDelegate = require('mobile:widget/touch-delegate/touch-delegate.js');
/// @require "common:static/js/load-image.all.min.js"
/// @require "common:static/js/megapix-image.js"
var PLACEHOLDER_SRC = __uri('./placeholder.gif');
var TEMPLATE = __inline('./image-crop-panel.tpl');
var HS = document.documentElement.style;
var BASE_FONTSIZE = 50;
var D_BASE_FONTSIZE = BASE_FONTSIZE;
var DEF_OPTION = {
width : 100,
height : 100,
useMask : true,
useRem : true,
maxScale : Infinity
};
function ImageCrop($el, option) {
Event.call(this);
var $container = $(TEMPLATE);
var _this = this;
this.option = $.extend({}, DEF_OPTION, option);
this._$el = $el;
this._$container = $container;
this._$area = $container.find('.crop-area');
this._$img = $container.find('.original-img');
this._source = null;
this._focal = { x : 0, y : 0 };
this._minScale = 0;
this._curScale = 0;
$el.append($container);
this.option.targetWidth = this.option.targetWidth || 200;
this.option.targetHeight = this.option.targetHeight || 200;
if (this.option.useRem) {
this._$area.css({
width : this.option.targetWidth / BASE_FONT_SIZE + 'rem',
height : this.option.targetHeight / BASE_FONT_SIZE + 'rem'
});
} else {
this._$area.css({
width : this.option.targetWidth,
height : this.option.targetHeight
});
}
if (this.option.useMask) {
$container.addClass('use-mask');
}
if (this._$img.data('source')) {
this.load(this._$img.data('source'));
}
this._$img.data('src', PLACEHOLDER_SRC);
this._$img.data('crop', this);
this._$img.on('load', imageLoadHandler);
this._$img.on('error', imageErrorHandler);
setupImageDragDropHandler(this);
}
var api = ImageCrop.prototype = Utils.create(Event.prototype, ImageCrop);
api.load = function(src, orientation, file) {
var $img = this._$img;
this.fireEvent('loadImageBefore', [src, orientation, $img]);
$img.css('visibility', 'hidden');
$img.attr('src', src);
$img.data('source', src);
$img.data('orientation', orientation);
$img.data('mega-pix-image', file && new MegaPixImage(file));
};
api.zoom = function(scale) {
var $img = this._$img;
var originalSize = $img.data('original-size');
if(scale < this._minScale) {
scale = this._minScale;
}
$img.width(originalSize.width * scale / this.option.targetWidth * 100 + '%');
this._curScale = scale;
this._focusOnCenter();
};
api.move = function (x, y) {
var $img = this._$img;
var originalSize = $img.data('original-size');
var width = originalSize.width * this._curScale;
var height = originalSize.height * this._curScale;
x = fillContainer(x, width, this.option.targetWidth);
y = fillContainer(y, height, this.option.targetHeight);
var styleObj = $img[0].style;
styleObj[Env.CSSPROP.transform] = 'translate(' + (x / width * 100) + '%,'+ (y / height * 100) +'%)';
this._focal.x = (x * -1 + this.option.targetWidth / 2) / this._curScale;
this._focal.y = (y * -1 + this.option.targetHeight / 2) / this._curScale;
};
api.getCropImageData = function(scale) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
var $img = this._$img;
var imgPos = Utils.getComputedPosition($img[0]);
var originalSize = $img.data('original-size');
var width = originalSize.width * this._curScale;
var height = originalSize.height * this._curScale;
var orientation = $img.data('orientation');
var oriImgCanvas = $img[0];
canvas.width = this.option.targetWidth;
canvas.height = this.option.targetHeight;
var canvasFull = document.createElement('canvas');
var mpImg = $img.data('mega-pix-image');
if (mpImg && orientation) {
mpImg.render(canvasFull, { maxWidth: Math.max(width, height), maxHeight: Math.max(width, height), orientation: orientation });
} else {
canvasFull.width = width;
canvasFull.height = height;
canvasFull.getContext('2d').drawImage(
$img[0],
0,
0,
width,
height
);
}
oriImgCanvas = canvasFull;
ctx.drawImage(
oriImgCanvas,
(imgPos.x / $img.width()) * width,
(imgPos.y / $img.height()) * height
);
return scale ? canvas.toDataURL("image/jpeg", scale) : canvas.toDataURL("image/jpg");
};
api.getSource = function() {
return this._$img.data('source');
};
api.isEmpty = function() {
return !this._$img.data('source');
};
api.getScale = function() {
return this._curScale;
};
api.getMinScale = function() {
return this._minScale;
};
api._initDimensions = function() {
var $img = this._$img;
var originalSize = $img.data('original-size');
if (!originalSize) {
$img.data('original-size', originalSize = {});
}
$img.css({
width : 'auto',
height : 'auto'
});
$img.removeAttr('width');
$img.removeAttr('height');
originalSize.width = $img.width();
originalSize.height = $img.height();
var widthRatio = this.option.targetWidth / originalSize.width;
var heightRatio = this.option.targetHeight / originalSize.height;
if (widthRatio >= heightRatio) {
this._minScale = (originalSize.width < this.option.targetWidth) ? (this.option.targetWidth / originalSize.width) : widthRatio;
} else {
this._minScale = (originalSize.height < this.option.targetHeight) ? (this.option.targetHeight / originalSize.height) : heightRatio;
}
this._focal.x = originalSize.width / 2;
this._focal.y = originalSize.height / 2;
this.zoom(this._minScale);
$img.css('visibility', 'visible');
};
api._focusOnCenter = function () {
var $img = this._$img;
var originalSize = $img.data('original-size');
this.move(
(this._focal.x * this._curScale - this.option.targetWidth / 2) * -1,
(this._focal.y * this._curScale - this.option.targetHeight / 2) * -1
);
};
module.exports = ImageCrop;
function imageLoadHandler() {
var crop = $(this).data('crop');
var $img = crop._$img;
var limit = crop._limitSize;
if (!$img.data('source') || $img.data('source') == PLACEHOLDER_SRC) {
return;
}
crop._initDimensions();
crop.fireEvent('loadImageComplete');
}
function imageErrorHandler() {
var $img = $(this);
var crop = $img.data('crop');
if ($img.data('src') == PLACEHOLDER_SRC) {
return;
}
//alert('图片加载失败, 请重试!');
crop._source = null;
$img.data('source', null);
$img.attr('src', PLACEHOLDER_SRC);
$img[0].style[Env.CSSPROP.transform] = 'translate(0, 0)';
crop.fireEvent('loadImageError');
}
function setupImageDragDropHandler(crop) {
var $doc = $(document);
var $img = crop._$img;
var originalSize = null;
var img = $img[0];
var $dragable = crop._$container.find('.dragable');
var x = 0;
var y = 0;
var width = 0;
var height = 0;
var oWidth = 0;
var oHeight = 0;
var touchDelegate = new TouchDelegate.Delegate($dragable, true);
touchDelegate.on(TouchDelegate.Identifier.free, function(e){
if (e.touch.isStart) {
var pos = Utils.getComputedPosition(img);
originalSize = $img.data('original-size')
x = pos.x - e.x;
y = pos.y - e.y;
width = $img.width();
height = $img.height();
oWidth = originalSize.width * crop._curScale;
oHeight = originalSize.height * crop._curScale;
}
crop.move(
(x + e.x) / width * oWidth,
(y + e.y) / height * oHeight
);
});
}
function fillContainer(value, target, container) {
if (value + target < container) {
value = container - target;
}
return value > 0 ? 0 : value;
}
@import "../../../../common/client/static/mobile/lib/css/variable.less";
.image-crop-container{
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
&.use-mask{
background-image: -webkit-linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%), -webkit-linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%);
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%), linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%);
background-size: 16px 16px;
background-position: 0 0, 8px 8px;
.crop-area{
overflow: visible;
.mask{
//display: block;
top:0;
left: 0;
}
}
}
.crop-area{
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
overflow: hidden;
z-index: 2;
}
.dragable{
position: absolute;
width: 100%;
height: 100%;
z-index: 3;
}
.mask{
position: absolute;
top:-9999px;
left:-9999px;
z-index: 2;
width: 100%;
height: 100%;
-webkit-border-radius: 100%;
border-radius: 100%;
-webkit-box-shadow: 0 0 0 100/@REM rgba(0, 0, 0, .6);
box-shadow: 0 0 0 100/@REM rgba(0, 0, 0, .6);
}
.original-img{
position: absolute;
top:0;
left: 0;
z-index: 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment