Created
November 25, 2017 07:35
-
-
Save maolion/97f364d344567c60278833f8db90a12c to your computer and use it in GitHub Desktop.
Image Crop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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