<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!--
Credits to http://fengyuanchen.github.io/cropper
-->
<!-- Content -->
<div class="container">
<div class="row">
<div class="col-md-9">
<!-- <h3 class="page-header">Demo:</h3> -->
<div class="img-container">
<img src="https://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/t31.0-8/134618_418890451497724_216755457_o.jpg" alt="Picture">
</div>
</div>
<div class="col-md-3">
<!-- <h3 class="page-header">Preview:</h3> -->
<div class="docs-preview clearfix">
<div class="img-preview preview-lg"></div>
<div class="img-preview preview-md"></div>
<div class="img-preview preview-sm"></div>
<div class="img-preview preview-xs"></div>
</div>
<!-- <h3 class="page-header">Data:</h3> -->
<div class="docs-data">
<div class="input-group">
<label class="input-group-addon" for="dataX">X</label>
<input class="form-control" id="dataX" type="text" placeholder="x">
<span class="input-group-addon">px</span>
</div>
<div class="input-group">
<label class="input-group-addon" for="dataY">Y</label>
<input class="form-control" id="dataY" type="text" placeholder="y">
<span class="input-group-addon">px</span>
</div>
<div class="input-group">
<label class="input-group-addon" for="dataWidth">Width</label>
<input class="form-control" id="dataWidth" type="text" placeholder="width">
<span class="input-group-addon">px</span>
</div>
<div class="input-group">
<label class="input-group-addon" for="dataHeight">Height</label>
<input class="form-control" id="dataHeight" type="text" placeholder="height">
<span class="input-group-addon">px</span>
</div>
<div class="input-group">
<label class="input-group-addon" for="dataRotate">Rotate</label>
<input class="form-control" id="dataRotate" type="text" placeholder="rotate">
<span class="input-group-addon">deg</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-9 docs-buttons">
<!-- <h3 class="page-header">Toolbar:</h3> -->
<div class="btn-group">
<button class="btn btn-primary" data-method="setDragMode" data-option="move" type="button" title="Move">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setDragMode", "move")">
<span class="icon icon-move"></span>
</span>
</button>
<button class="btn btn-primary" data-method="setDragMode" data-option="crop" type="button" title="Crop">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setDragMode", "crop")">
<span class="icon icon-crop"></span>
</span>
</button>
<button class="btn btn-primary" data-method="zoom" data-option="0.1" type="button" title="Zoom In">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("zoom", 0.1)">
<span class="icon icon-zoom-in"></span>
</span>
</button>
<button class="btn btn-primary" data-method="zoom" data-option="-0.1" type="button" title="Zoom Out">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("zoom", -0.1)">
<span class="icon icon-zoom-out"></span>
</span>
</button>
<button class="btn btn-primary" data-method="rotate" data-option="-45" type="button" title="Rotate Left">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("rotate", -45)">
<span class="icon icon-rotate-left"></span>
</span>
</button>
<button class="btn btn-primary" data-method="rotate" data-option="45" type="button" title="Rotate Right">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("rotate", 45)">
<span class="icon icon-rotate-right"></span>
</span>
</button>
</div>
<div class="btn-group">
<button class="btn btn-primary" data-method="crop" type="button" title="Crop">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("crop")">
<span class="icon icon-ok"></span>
</span>
</button>
<button class="btn btn-primary" data-method="clear" type="button" title="Clear">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("clear")">
<span class="icon icon-remove"></span>
</span>
</button>
<button class="btn btn-primary" data-method="disable" type="button" title="Disable">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("disable")">
<span class="icon icon-lock"></span>
</span>
</button>
<button class="btn btn-primary" data-method="enable" type="button" title="Enable">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("enable")">
<span class="icon icon-unlock"></span>
</span>
</button>
<button class="btn btn-primary" data-method="reset" type="button" title="Reset">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("reset")">
<span class="icon icon-refresh"></span>
</span>
</button>
<label class="btn btn-primary btn-upload" for="inputImage" title="Upload image file">
<input class="sr-only" id="inputImage" name="file" type="file" accept="image/*">
<span class="docs-tooltip" data-toggle="tooltip" title="Import image with Blob URLs">
<span class="icon icon-upload"></span>
</span>
</label>
<button class="btn btn-primary" data-method="destroy" type="button" title="Destroy">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("destroy")">
<span class="icon icon-off"></span>
</span>
</button>
</div>
<div class="btn-group btn-group-crop">
<button class="btn btn-primary" data-method="getCroppedCanvas" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getCroppedCanvas")">
Get Cropped Canvas
</span>
</button>
<button class="btn btn-primary" data-method="getCroppedCanvas" data-option="{ "width": 160, "height": 90 }" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getCroppedCanvas", { width: 160, height: 90 })">
160×90
</span>
</button>
<button class="btn btn-primary" data-method="getCroppedCanvas" data-option="{ "width": 320, "height": 180 }" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getCroppedCanvas", { width: 320, height: 180 })">
320×180
</span>
</button>
</div>
<!-- Show the cropped image in modal -->
<div class="modal fade docs-cropped" id="getCroppedCanvasModal" aria-hidden="true" aria-labelledby="getCroppedCanvasTitle" role="dialog" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button" aria-hidden="true">×</button>
<h4 class="modal-title" id="getCroppedCanvasTitle">Cropped</h4>
</div>
<div class="modal-body"></div>
<!-- <div class="modal-footer">
<button class="btn btn-primary" data-dismiss="modal" type="button">Close</button>
</div> -->
</div>
</div>
</div><!-- /.modal -->
<button class="btn btn-primary" data-method="getData" data-option="" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getData")">
Get Data
</span>
</button>
<button class="btn btn-primary" data-method="setData" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setData", data)">
Set Data
</span>
</button>
<button class="btn btn-primary" data-method="getContainerData" data-option="" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getContainerData")">
Get Container Data
</span>
</button>
<button class="btn btn-primary" data-method="getImageData" data-option="" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getImageData")">
Get Image Data
</span>
</button>
<button class="btn btn-primary" data-method="getCanvasData" data-option="" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getCanvasData")">
Get Canvas Data
</span>
</button>
<button class="btn btn-primary" data-method="setCanvasData" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setCanvasData", data)">
Set Canvas Data
</span>
</button>
<button class="btn btn-primary" data-method="getCropBoxData" data-option="" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("getCropBoxData")">
Get Crop Box Data
</span>
</button>
<button class="btn btn-primary" data-method="setCropBoxData" data-target="#putData" type="button">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setCropBoxData", data)">
Set Crop Box Data
</span>
</button>
<input class="form-control" id="putData" type="text" placeholder="Get data to here or set data with this value">
</div><!-- /.docs-buttons -->
<div class="col-md-3 docs-toggles">
<!-- <h3 class="page-header">Toggles:</h3> -->
<div class="btn-group btn-group-justified" data-toggle="buttons">
<label class="btn btn-primary active" data-method="setAspectRatio" data-option="1.7777777777777777" title="Set Aspect Ratio">
<input class="sr-only" id="aspestRatio1" name="aspestRatio" value="1.7777777777777777" type="radio">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setAspectRatio", 16 / 9)">
16:9
</span>
</label>
<label class="btn btn-primary" data-method="setAspectRatio" data-option="1.3333333333333333" title="Set Aspect Ratio">
<input class="sr-only" id="aspestRatio2" name="aspestRatio" value="1.3333333333333333" type="radio">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setAspectRatio", 4 / 3)">
4:3
</span>
</label>
<label class="btn btn-primary" data-method="setAspectRatio" data-option="1" title="Set Aspect Ratio">
<input class="sr-only" id="aspestRatio3" name="aspestRatio" value="1" type="radio">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setAspectRatio", 1 / 1)">
1:1
</span>
</label>
<label class="btn btn-primary" data-method="setAspectRatio" data-option="0.6666666666666666" title="Set Aspect Ratio">
<input class="sr-only" id="aspestRatio4" name="aspestRatio" value="0.6666666666666666" type="radio">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setAspectRatio", 2 / 3)">
2:3
</span>
</label>
<label class="btn btn-primary" data-method="setAspectRatio" data-option="NaN" title="Set Aspect Ratio">
<input class="sr-only" id="aspestRatio5" name="aspestRatio" value="NaN" type="radio">
<span class="docs-tooltip" data-toggle="tooltip" title="$().cropper("setAspectRatio", NaN)">
Free
</span>
</label>
</div>
<div class="dropdown dropup docs-options">
<button class="btn btn-primary btn-block dropdown-toggle" id="toggleOptions" type="button" data-toggle="dropdown" aria-expanded="true">
Toggle Options
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="toggleOptions">
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="strict" checked>
strict
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="responsive" checked>
responsive
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="checkImageOrigin" checked>
checkImageOrigin
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="modal" checked>
modal
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="guides" checked>
guides
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="highlight" checked>
highlight
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="background" checked>
background
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="autoCrop" checked>
autoCrop
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="dragCrop" checked>
dragCrop
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="movable" checked>
movable
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="resizable" checked>
resizable
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="rotatable" checked>
rotatable
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="zoomable" checked>
zoomable
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="touchDragZoom" checked>
touchDragZoom
</label>
</li>
<li role="presentation">
<label class="checkbox-inline">
<input type="checkbox" name="option" value="mouseWheelZoom" checked>
mouseWheelZoom
</label>
</li>
</ul>
</div><!-- /.dropdown -->
</div><!-- /.docs-toggles -->
</div>
</div>
<!-- Alert -->
<div class="docs-alert"><span class="warning message"></span></div>
.cropper-container {
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
}
.cropper-container img {
display: block;
width: 100%;
min-width: 0 !important;
max-width: none !important;
height: 100%;
min-height: 0 !important;
max-height: none !important;
image-orientation: 0deg !important;
}
.cropper-canvas,
.cropper-drag-box,
.cropper-crop-box,
.cropper-modal {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.cropper-drag-box {
background-color: #fff;
filter: alpha(opacity=0);
opacity: 0;
}
.cropper-modal {
background-color: #000;
filter: alpha(opacity=50);
opacity: .5;
}
.cropper-view-box {
display: block;
width: 100%;
height: 100%;
overflow: hidden;
outline: 1px solid #69f;
outline-color: rgba(102, 153, 255, .75);
}
.cropper-dashed {
position: absolute;
display: block;
filter: alpha(opacity=50);
border: 0 dashed #fff;
opacity: .5;
}
.cropper-dashed.dashed-h {
top: 33.33333333%;
left: 0;
width: 100%;
height: 33.33333333%;
border-top-width: 1px;
border-bottom-width: 1px;
}
.cropper-dashed.dashed-v {
top: 0;
left: 33.33333333%;
width: 33.33333333%;
height: 100%;
border-right-width: 1px;
border-left-width: 1px;
}
.cropper-face,
.cropper-line,
.cropper-point {
position: absolute;
display: block;
width: 100%;
height: 100%;
filter: alpha(opacity=10);
opacity: .1;
}
.cropper-face {
top: 0;
left: 0;
cursor: move;
background-color: #fff;
}
.cropper-line {
background-color: #69f;
}
.cropper-line.line-e {
top: 0;
right: -3px;
width: 5px;
cursor: e-resize;
}
.cropper-line.line-n {
top: -3px;
left: 0;
height: 5px;
cursor: n-resize;
}
.cropper-line.line-w {
top: 0;
left: -3px;
width: 5px;
cursor: w-resize;
}
.cropper-line.line-s {
bottom: -3px;
left: 0;
height: 5px;
cursor: s-resize;
}
.cropper-point {
width: 5px;
height: 5px;
background-color: #69f;
filter: alpha(opacity=75);
opacity: .75;
}
.cropper-point.point-e {
top: 50%;
right: -3px;
margin-top: -3px;
cursor: e-resize;
}
.cropper-point.point-n {
top: -3px;
left: 50%;
margin-left: -3px;
cursor: n-resize;
}
.cropper-point.point-w {
top: 50%;
left: -3px;
margin-top: -3px;
cursor: w-resize;
}
.cropper-point.point-s {
bottom: -3px;
left: 50%;
margin-left: -3px;
cursor: s-resize;
}
.cropper-point.point-ne {
top: -3px;
right: -3px;
cursor: ne-resize;
}
.cropper-point.point-nw {
top: -3px;
left: -3px;
cursor: nw-resize;
}
.cropper-point.point-sw {
bottom: -3px;
left: -3px;
cursor: sw-resize;
}
.cropper-point.point-se {
right: -3px;
bottom: -3px;
width: 20px;
height: 20px;
cursor: se-resize;
filter: alpha(opacity=100);
opacity: 1;
}
.cropper-point.point-se:before {
position: absolute;
right: -50%;
bottom: -50%;
display: block;
width: 200%;
height: 200%;
content: " ";
background-color: #69f;
filter: alpha(opacity=0);
opacity: 0;
}
@media (min-width: 768px) {
.cropper-point.point-se {
width: 15px;
height: 15px;
}
}
@media (min-width: 992px) {
.cropper-point.point-se {
width: 10px;
height: 10px;
}
}
@media (min-width: 1200px) {
.cropper-point.point-se {
width: 5px;
height: 5px;
filter: alpha(opacity=75);
opacity: .75;
}
}
.cropper-bg {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
}
.cropper-invisible {
filter: alpha(opacity=0);
opacity: 0;
}
.cropper-hide {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: auto!important;
min-width: 0!important;
max-width: none!important;
height: auto!important;
min-height: 0!important;
max-height: none!important;
filter: alpha(opacity=0);
opacity: 0;
}
.cropper-hidden {
display: none !important;
}
.cropper-move {
cursor: move;
}
.cropper-crop {
cursor: crosshair;
}
.cropper-disabled .cropper-drag-box,
.cropper-disabled .cropper-face,
.cropper-disabled .cropper-line,
.cropper-disabled .cropper-point {
cursor: not-allowed;
}
/*Main CSS*/
.icon {
display: inline-block;
width: 20px;
height: 20px;
background-image: url("http://fengyuanchen.github.io/cropper/img/icons.png");
vertical-align: middle;
}
.icon-move {
background-position: 0 0;
}
.icon-crop {
background-position: -30px 0;
}
.icon-zoom-in {
background-position: -60px 0;
}
.icon-zoom-out {
background-position: -90px 0;
}
.icon-rotate-left {
background-position: -120px 0;
}
.icon-rotate-right {
background-position: -150px 0;
}
.icon-lock {
background-position: -180px 0;
}
.icon-unlock {
background-position: -210px 0;
}
.icon-remove {
background-position: -240px 0;
}
.icon-refresh {
background-position: -270px 0;
}
.icon-upload {
background-position: -300px 0;
}
.icon-off {
background-position: -330px 0;
}
.icon-info {
background-position: -360px 0;
}
.icon-ok {
background-position: -390px 0;
}
/* Alerts
* -------------------------------------------------------------------------- */
.docs-alert {
display: none;
position: fixed;
top: 20px;
left: 0;
right: 0;
height: 0;
text-align: center;
opacity: 0.9;
}
.docs-alert .message {
display: inline-block;
padding: 5px 10px;
border-radius: 2px;
background-color: #aaa;
color: #fff;
}
.docs-alert .primary {
background-color: #0074d9;
}
.docs-alert .success {
background-color: #2ecc40;
}
.docs-alert .info {
background-color: #39cccc;
}
.docs-alert .warning {
background-color: #ff851b;
}
.docs-alert .danger {
background-color: #ff4136;
}
/* Button
* -------------------------------------------------------------------------- */
.btn-primary {
border-color: #003973; /* hsb(210, 100%, 45%) */
background-color: #00468c; /* hsb(210, 100%, 55%) */
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active,
.btn-primary.active,
.btn-primary.active:focus,
.btn-primary.active:hover {
border-color: #00264d; /* hsb(208, 100%, 10%) */
background-color: #003366; /* hsb(208, 100%, 40%) */
}
/* Basic style
* -------------------------------------------------------------------------- */
body {
overflow-x: hidden;
}
/* Header */
.docs-header {
border-color: #003973;
background-color: #00468c;
color: #fff;
}
.docs-header .navbar-brand {
color: #eee;
}
.docs-header .navbar-toggle {
border-color: #003973;
background-color: #00468c;
}
.docs-header .navbar-toggle:hover,
.docs-header .navbar-toggle:focus {
border-color: #003366;
background-color: #003973;
}
.docs-header .navbar-collapse {
border-color: #003973;
}
.docs-header .navbar-text {
color: #ddd;
}
.docs-header .navbar-nav > li > a {
color: #eee;
}
/* Content */
.img-container,
.img-preview {
background-color: #f7f7f7;
overflow: hidden;
width: 100%;
text-align: center;
}
.img-container {
min-height: 200px;
max-height: 466px;
margin-bottom: 20px;
}
@media (min-width: 768px) {
.img-container {
min-height: 466px;
}
}
.img-container > img {
max-width: 100%;
}
.docs-preview {
margin-right: -15px;
margin-bottom: 10px;
}
.img-preview {
float: left;
margin-right: 10px;
margin-bottom: 10px;
}
.img-preview > img {
max-width: 100%;
}
.preview-lg {
width: 263px;
height: 148px;
}
.preview-md {
width: 139px;
height: 78px;
}
.preview-sm {
width: 69px;
height: 39px;
}
.preview-xs {
width: 35px;
height: 20px;
margin-right: 0;
}
.docs-data > .input-group {
margin-bottom: 10px;
}
.docs-data > .input-group > label {
min-width: 80px;
}
.docs-data > .input-group > span {
min-width: 50px;
}
.docs-buttons > .btn,
.docs-buttons > .btn-group,
.docs-buttons > .form-control {
margin-right: 5px;
margin-bottom: 10px;
}
.docs-toggles > .btn,
.docs-toggles > .btn-group,
.docs-toggles > .dropdown {
margin-bottom: 10px;
}
.docs-tooltip {
display: block;
margin: -6px -12px;
padding: 6px 12px;
}
.docs-tooltip > .icon {
margin: 0 -3px;
vertical-align: top;
}
.tooltip-inner {
white-space: normal;
}
.btn-upload .tooltip-inner {
white-space: nowrap;
}
@media (max-width: 400px) {
.btn-group-crop {
margin-right: -15px!important;
}
.btn-group-crop > .btn {
padding-left: 5px;
padding-right: 5px;
}
.btn-group-crop .docs-tooltip {
margin-left: -5px;
margin-right: -5px;
padding-left: 5px;
padding-right: 5px;
}
}
.docs-options .dropdown-menu {
width: 100%;
}
.docs-options .dropdown-menu > li {
padding: 3px 20px;
}
.docs-options .dropdown-menu > li:hover {
background-color: #f7f7f7;
}
.docs-options .dropdown-menu > li > label {
display: block;
}
.docs-cropped .modal-body {
text-align: center;
}
.docs-cropped .modal-body > img,
.docs-cropped .modal-body > canvas {
max-width: 100%;
}
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node / CommonJS
factory(require('jquery'));
} else {
// Browser globals.
factory(jQuery);
}
})(function ($) {
'use strict';
var $window = $(window),
$document = $(document),
location = window.location,
// Constants
CROPPER_NAMESPACE = '.cropper',
CROPPER_PREVIEW = 'preview' + CROPPER_NAMESPACE,
// RegExps
REGEXP_DRAG_TYPES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,
// Classes
CLASS_MODAL = 'cropper-modal',
CLASS_HIDE = 'cropper-hide',
CLASS_HIDDEN = 'cropper-hidden',
CLASS_INVISIBLE = 'cropper-invisible',
CLASS_MOVE = 'cropper-move',
CLASS_CROP = 'cropper-crop',
CLASS_DISABLED = 'cropper-disabled',
CLASS_BG = 'cropper-bg',
// Events
EVENT_MOUSE_DOWN = 'mousedown touchstart',
EVENT_MOUSE_MOVE = 'mousemove touchmove',
EVENT_MOUSE_UP = 'mouseup mouseleave touchend touchleave touchcancel',
EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll',
EVENT_DBLCLICK = 'dblclick',
EVENT_RESIZE = 'resize' + CROPPER_NAMESPACE, // Bind to window with namespace
EVENT_BUILD = 'build' + CROPPER_NAMESPACE,
EVENT_BUILT = 'built' + CROPPER_NAMESPACE,
EVENT_DRAG_START = 'dragstart' + CROPPER_NAMESPACE,
EVENT_DRAG_MOVE = 'dragmove' + CROPPER_NAMESPACE,
EVENT_DRAG_END = 'dragend' + CROPPER_NAMESPACE,
EVENT_ZOOM_IN = 'zoomin' + CROPPER_NAMESPACE,
EVENT_ZOOM_OUT = 'zoomout' + CROPPER_NAMESPACE,
// Supports
SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext),
// Others
sqrt = Math.sqrt,
min = Math.min,
max = Math.max,
abs = Math.abs,
sin = Math.sin,
cos = Math.cos,
num = parseFloat,
// Prototype
prototype = {};
function isNumber(n) {
return typeof n === 'number' && !isNaN(n);
}
function isUndefined(n) {
return typeof n === 'undefined';
}
function toArray(obj, offset) {
var args = [];
if (isNumber(offset)) { // It's necessary for IE8
args.push(offset);
}
return args.slice.apply(obj, args);
}
// Custom proxy to avoid jQuery's guid
function proxy(fn, context) {
var args = toArray(arguments, 2);
return function () {
return fn.apply(context, args.concat(toArray(arguments)));
};
}
function isCrossOriginURL(url) {
var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
}
function addTimestamp(url) {
var timestamp = 'timestamp=' + (new Date()).getTime();
return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
}
function getRotateValue(degree) {
return degree ? 'rotate(' + degree + 'deg)' : 'none';
}
function getRotatedSizes(data, reverse) {
var deg = abs(data.degree) % 180,
arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180,
sinArc = sin(arc),
cosArc = cos(arc),
width = data.width,
height = data.height,
aspectRatio = data.aspectRatio,
newWidth,
newHeight;
if (!reverse) {
newWidth = width * cosArc + height * sinArc;
newHeight = width * sinArc + height * cosArc;
} else {
newWidth = width / (cosArc + sinArc / aspectRatio);
newHeight = newWidth / aspectRatio;
}
return {
width: newWidth,
height: newHeight
};
}
function getSourceCanvas(image, data) {
var canvas = $('<canvas>')[0],
context = canvas.getContext('2d'),
width = data.naturalWidth,
height = data.naturalHeight,
rotate = data.rotate,
rotated = getRotatedSizes({
width: width,
height: height,
degree: rotate
});
if (rotate) {
canvas.width = rotated.width;
canvas.height = rotated.height;
context.save();
context.translate(rotated.width / 2, rotated.height / 2);
context.rotate(rotate * Math.PI / 180);
context.drawImage(image, -width / 2, -height / 2, width, height);
context.restore();
} else {
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
}
return canvas;
}
function Cropper(element, options) {
this.$element = $(element);
this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
this.ready = false;
this.built = false;
this.rotated = false;
this.cropped = false;
this.disabled = false;
this.canvas = null;
this.cropBox = null;
this.load();
}
prototype.load = function (url) {
var options = this.options,
$this = this.$element,
crossOrigin,
bustCacheUrl,
buildEvent,
$clone;
if (!url) {
if ($this.is('img')) {
if (!$this.attr('src')) {
return;
}
url = $this.prop('src');
} else if ($this.is('canvas') && SUPPORT_CANVAS) {
url = $this[0].toDataURL();
}
}
if (!url) {
return;
}
buildEvent = $.Event(EVENT_BUILD);
$this.one(EVENT_BUILD, options.build).trigger(buildEvent); // Only trigger once
if (buildEvent.isDefaultPrevented()) {
return;
}
if (options.checkImageOrigin && isCrossOriginURL(url)) {
crossOrigin = 'anonymous';
if (!$this.prop('crossOrigin')) { // Only when there was not a "crossOrigin" property
bustCacheUrl = addTimestamp(url); // Bust cache (#148)
}
}
this.$clone = $clone = $('<img>');
$clone.one('load', $.proxy(function () {
var naturalWidth = $clone.prop('naturalWidth') || $clone.width(),
naturalHeight = $clone.prop('naturalHeight') || $clone.height();
this.image = {
naturalWidth: naturalWidth,
naturalHeight: naturalHeight,
aspectRatio: naturalWidth / naturalHeight,
rotate: 0
};
this.url = url;
this.ready = true;
this.build();
}, this)).one('error', function () {
$clone.remove();
}).attr({
crossOrigin: crossOrigin, // "crossOrigin" must before "src" (#271)
src: bustCacheUrl || url
});
// Hide and insert into the document
$clone.addClass(CLASS_HIDE).insertAfter($this);
};
prototype.build = function () {
var $this = this.$element,
$clone = this.$clone,
options = this.options,
$cropper,
$cropBox;
if (!this.ready) {
return;
}
if (this.built) {
this.unbuild();
}
// Create cropper elements
this.$cropper = $cropper = $(Cropper.TEMPLATE);
// Hide the original image
$this.addClass(CLASS_HIDDEN);
// Show the clone iamge
$clone.removeClass(CLASS_HIDE);
this.$container = $this.parent().append($cropper);
this.$canvas = $cropper.find('.cropper-canvas').append($clone);
this.$dragBox = $cropper.find('.cropper-drag-box');
this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
this.$viewBox = $cropper.find('.cropper-view-box');
this.addListeners();
this.initPreview();
// Format aspect ratio
options.aspectRatio = num(options.aspectRatio) || NaN; // 0 -> NaN
if (options.autoCrop) {
this.cropped = true;
if (options.modal) {
this.$dragBox.addClass(CLASS_MODAL);
}
} else {
$cropBox.addClass(CLASS_HIDDEN);
}
if (options.background) {
$cropper.addClass(CLASS_BG);
}
if (!options.highlight) {
$cropBox.find('.cropper-face').addClass(CLASS_INVISIBLE);
}
if (!options.guides) {
$cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
}
if (!options.movable) {
$cropBox.find('.cropper-face').data('drag', 'move');
}
if (!options.resizable) {
$cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
}
this.setDragMode(options.dragCrop ? 'crop' : 'move');
this.built = true;
this.render();
this.setData(options.data);
$this.one(EVENT_BUILT, options.built).trigger(EVENT_BUILT); // Only trigger once
};
prototype.unbuild = function () {
if (!this.built) {
return;
}
this.built = false;
this.initialImage = null;
this.initialCanvas = null; // This is necessary when replace
this.initialCropBox = null;
this.container = null;
this.canvas = null;
this.cropBox = null; // This is necessary when replace
this.removeListeners();
this.resetPreview();
this.$preview = null;
this.$viewBox = null;
this.$cropBox = null;
this.$dragBox = null;
this.$canvas = null;
this.$container = null;
this.$cropper.remove();
this.$cropper = null;
};
$.extend(prototype, {
render: function () {
this.initContainer();
this.initCanvas();
this.initCropBox();
this.renderCanvas();
if (this.cropped) {
this.renderCropBox();
}
},
initContainer: function () {
var $this = this.$element,
$container = this.$container,
$cropper = this.$cropper,
options = this.options;
$cropper.addClass(CLASS_HIDDEN);
$this.removeClass(CLASS_HIDDEN);
$cropper.css((this.container = {
width: max($container.width(), num(options.minContainerWidth) || 200),
height: max($container.height(), num(options.minContainerHeight) || 100)
}));
$this.addClass(CLASS_HIDDEN);
$cropper.removeClass(CLASS_HIDDEN);
},
// image box (wrapper)
initCanvas: function () {
var container = this.container,
containerWidth = container.width,
containerHeight = container.height,
image = this.image,
aspectRatio = image.aspectRatio,
canvas = {
aspectRatio: aspectRatio,
width: containerWidth,
height: containerHeight
};
if (containerHeight * aspectRatio > containerWidth) {
canvas.height = containerWidth / aspectRatio;
} else {
canvas.width = containerHeight * aspectRatio;
}
canvas.oldLeft = canvas.left = (containerWidth - canvas.width) / 2;
canvas.oldTop = canvas.top = (containerHeight - canvas.height) / 2;
this.canvas = canvas;
this.limitCanvas(true, true);
this.initialImage = $.extend({}, image);
this.initialCanvas = $.extend({}, canvas);
},
limitCanvas: function (size, position) {
var options = this.options,
strict = options.strict,
container = this.container,
containerWidth = container.width,
containerHeight = container.height,
canvas = this.canvas,
aspectRatio = canvas.aspectRatio,
cropBox = this.cropBox,
cropped = this.cropped && cropBox,
initialCanvas = this.initialCanvas || canvas,
initialCanvasWidth = initialCanvas.width,
initialCanvasHeight = initialCanvas.height,
minCanvasWidth,
minCanvasHeight;
if (size) {
minCanvasWidth = num(options.minCanvasWidth) || 0;
minCanvasHeight = num(options.minCanvasHeight) || 0;
if (minCanvasWidth) {
if (strict) {
minCanvasWidth = max(cropped ? cropBox.width : initialCanvasWidth, minCanvasWidth);
}
minCanvasHeight = minCanvasWidth / aspectRatio;
} else if (minCanvasHeight) {
if (strict) {
minCanvasHeight = max(cropped ? cropBox.height : initialCanvasHeight, minCanvasHeight);
}
minCanvasWidth = minCanvasHeight * aspectRatio;
} else if (strict) {
if (cropped) {
minCanvasWidth = cropBox.width;
minCanvasHeight = cropBox.height;
if (minCanvasHeight * aspectRatio > minCanvasWidth) {
minCanvasWidth = minCanvasHeight * aspectRatio;
} else {
minCanvasHeight = minCanvasWidth / aspectRatio;
}
} else {
minCanvasWidth = initialCanvasWidth;
minCanvasHeight = initialCanvasHeight;
}
}
$.extend(canvas, {
minWidth: minCanvasWidth,
minHeight: minCanvasHeight,
maxWidth: Infinity,
maxHeight: Infinity
});
}
if (position) {
if (strict) {
if (cropped) {
canvas.minLeft = min(cropBox.left, (cropBox.left + cropBox.width) - canvas.width);
canvas.minTop = min(cropBox.top, (cropBox.top + cropBox.height) - canvas.height);
canvas.maxLeft = cropBox.left;
canvas.maxTop = cropBox.top;
} else {
canvas.minLeft = min(0, containerWidth - canvas.width);
canvas.minTop = min(0, containerHeight - canvas.height);
canvas.maxLeft = max(0, containerWidth - canvas.width);
canvas.maxTop = max(0, containerHeight - canvas.height);
}
} else {
canvas.minLeft = -canvas.width;
canvas.minTop = -canvas.height;
canvas.maxLeft = containerWidth;
canvas.maxTop = containerHeight;
}
}
},
renderCanvas: function (changed) {
var options = this.options,
canvas = this.canvas,
image = this.image,
aspectRatio,
rotated;
if (this.rotated) {
this.rotated = false;
// Computes rotatation sizes with image sizes
rotated = getRotatedSizes({
width: image.width,
height: image.height,
degree: image.rotate
});
aspectRatio = rotated.width / rotated.height;
if (aspectRatio !== canvas.aspectRatio) {
canvas.left -= (rotated.width - canvas.width) / 2;
canvas.top -= (rotated.height - canvas.height) / 2;
canvas.width = rotated.width;
canvas.height = rotated.height;
canvas.aspectRatio = aspectRatio;
this.limitCanvas(true, false);
}
}
if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) {
canvas.left = canvas.oldLeft;
}
if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) {
canvas.top = canvas.oldTop;
}
canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth);
canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight);
this.limitCanvas(false, true);
canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft);
canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop);
this.$canvas.css({
width: canvas.width,
height: canvas.height,
left: canvas.left,
top: canvas.top
});
this.renderImage();
if (this.cropped && options.strict) {
this.limitCropBox(true, true);
}
if (changed) {
this.output();
}
},
renderImage: function () {
var canvas = this.canvas,
image = this.image,
reversed;
if (image.rotate) {
reversed = getRotatedSizes({
width: canvas.width,
height: canvas.height,
degree: image.rotate,
aspectRatio: image.aspectRatio
}, true);
}
$.extend(image, reversed ? {
width: reversed.width,
height: reversed.height,
left: (canvas.width - reversed.width) / 2,
top: (canvas.height - reversed.height) / 2
} : {
width: canvas.width,
height: canvas.height,
left: 0,
top: 0
});
this.$clone.css({
width: image.width,
height: image.height,
marginLeft: image.left,
marginTop: image.top,
transform: getRotateValue(image.rotate)
});
},
initCropBox: function () {
var options = this.options,
canvas = this.canvas,
aspectRatio = options.aspectRatio,
autoCropArea = num(options.autoCropArea) || 0.8,
cropBox = {
width: canvas.width,
height: canvas.height
};
if (aspectRatio) {
if (canvas.height * aspectRatio > canvas.width) {
cropBox.height = cropBox.width / aspectRatio;
} else {
cropBox.width = cropBox.height * aspectRatio;
}
}
this.cropBox = cropBox;
this.limitCropBox(true, true);
// Initialize auto crop area
cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);
// The width of auto crop area must large than "minWidth", and the height too. (#164)
cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea);
cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea);
cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2;
cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2;
this.initialCropBox = $.extend({}, cropBox);
},
limitCropBox: function (size, position) {
var options = this.options,
strict = options.strict,
container = this.container,
containerWidth = container.width,
containerHeight = container.height,
canvas = this.canvas,
cropBox = this.cropBox,
aspectRatio = options.aspectRatio,
minCropBoxWidth,
minCropBoxHeight;
if (size) {
minCropBoxWidth = num(options.minCropBoxWidth) || 0;
minCropBoxHeight = num(options.minCropBoxHeight) || 0;
// min/maxCropBoxWidth/Height must less than conatiner width/height
cropBox.minWidth = min(containerWidth, minCropBoxWidth);
cropBox.minHeight = min(containerHeight, minCropBoxHeight);
cropBox.maxWidth = min(containerWidth, strict ? canvas.width : containerWidth);
cropBox.maxHeight = min(containerHeight, strict ? canvas.height : containerHeight);
if (aspectRatio) {
// compare crop box size with container first
if (cropBox.maxHeight * aspectRatio > cropBox.maxWidth) {
cropBox.minHeight = cropBox.minWidth / aspectRatio;
cropBox.maxHeight = cropBox.maxWidth / aspectRatio;
} else {
cropBox.minWidth = cropBox.minHeight * aspectRatio;
cropBox.maxWidth = cropBox.maxHeight * aspectRatio;
}
}
// The "minWidth" must be less than "maxWidth", and the "minHeight" too.
cropBox.minWidth = min(cropBox.maxWidth, cropBox.minWidth);
cropBox.minHeight = min(cropBox.maxHeight, cropBox.minHeight);
}
if (position) {
if (strict) {
cropBox.minLeft = max(0, canvas.left);
cropBox.minTop = max(0, canvas.top);
cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height;
} else {
cropBox.minLeft = 0;
cropBox.minTop = 0;
cropBox.maxLeft = containerWidth - cropBox.width;
cropBox.maxTop = containerHeight - cropBox.height;
}
}
},
renderCropBox: function () {
var options = this.options,
container = this.container,
containerWidth = container.width,
containerHeight = container.height,
$cropBox = this.$cropBox,
cropBox = this.cropBox;
if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
cropBox.left = cropBox.oldLeft;
}
if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) {
cropBox.top = cropBox.oldTop;
}
cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);
this.limitCropBox(false, true);
cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft);
cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);
if (options.movable) {
$cropBox.find('.cropper-face').data('drag', (cropBox.width === containerWidth && cropBox.height === containerHeight) ? 'move' : 'all');
}
$cropBox.css({
width: cropBox.width,
height: cropBox.height,
left: cropBox.left,
top: cropBox.top
});
if (this.cropped && options.strict) {
this.limitCanvas(true, true);
}
if (!this.disabled) {
this.output();
}
},
output: function () {
var options = this.options;
this.preview();
if (options.crop) {
options.crop.call(this.$element, this.getData());
}
}
});
prototype.initPreview = function () {
var url = this.url;
this.$preview = $(this.options.preview);
this.$viewBox.html('<img src="' + url + '">');
// Override img element styles
// Add `display:block` to avoid margin top issue (Occur only when margin-top <= -height)
this.$preview.each(function () {
var $this = $(this);
$this.data(CROPPER_PREVIEW, {
width: $this.width(),
height: $this.height(),
original: $this.html()
}).html('<img src="' + url + '" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation: 0deg!important">');
});
};
prototype.resetPreview = function () {
this.$preview.each(function () {
var $this = $(this);
$this.html($this.data(CROPPER_PREVIEW).original).removeData(CROPPER_PREVIEW);
});
};
prototype.preview = function () {
var image = this.image,
canvas = this.canvas,
cropBox = this.cropBox,
width = image.width,
height = image.height,
left = cropBox.left - canvas.left - image.left,
top = cropBox.top - canvas.top - image.top,
rotate = image.rotate;
if (!this.cropped || this.disabled) {
return;
}
this.$viewBox.find('img').css({
width: width,
height: height,
marginLeft: -left,
marginTop: -top,
transform: getRotateValue(rotate)
});
this.$preview.each(function () {
var $this = $(this),
data = $this.data(CROPPER_PREVIEW),
ratio = data.width / cropBox.width,
newWidth = data.width,
newHeight = cropBox.height * ratio;
if (newHeight > data.height) {
ratio = data.height / cropBox.height;
newWidth = cropBox.width * ratio;
newHeight = data.height;
}
$this.width(newWidth).height(newHeight).find('img').css({
width: width * ratio,
height: height * ratio,
marginLeft: -left * ratio,
marginTop: -top * ratio,
transform: getRotateValue(rotate)
});
});
};
prototype.addListeners = function () {
var options = this.options;
this.$element.on(EVENT_DRAG_START, options.dragstart).on(EVENT_DRAG_MOVE, options.dragmove).on(EVENT_DRAG_END, options.dragend).on(EVENT_ZOOM_IN, options.zoomin).on(EVENT_ZOOM_OUT, options.zoomout);
this.$cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this)).on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
if (options.zoomable && options.mouseWheelZoom) {
this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
}
$document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this)));
if (options.responsive) {
$window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
}
};
prototype.removeListeners = function () {
var options = this.options;
this.$element.off(EVENT_DRAG_START, options.dragstart).off(EVENT_DRAG_MOVE, options.dragmove).off(EVENT_DRAG_END, options.dragend).off(EVENT_ZOOM_IN, options.zoomin).off(EVENT_ZOOM_OUT, options.zoomout);
this.$cropper.off(EVENT_MOUSE_DOWN, this.dragstart).off(EVENT_DBLCLICK, this.dblclick);
if (options.zoomable && options.mouseWheelZoom) {
this.$cropper.off(EVENT_WHEEL, this.wheel);
}
$document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend);
if (options.responsive) {
$window.off(EVENT_RESIZE, this._resize);
}
};
$.extend(prototype, {
resize: function () {
var $container = this.$container,
container = this.container,
canvasData,
cropBoxData,
ratio;
if (this.disabled) {
return;
}
ratio = $container.width() / container.width;
if (ratio !== 1 || $container.height() !== container.height) {
canvasData = this.getCanvasData();
cropBoxData = this.getCropBoxData();
this.render();
this.setCanvasData($.each(canvasData, function (i, n) {
canvasData[i] = n * ratio;
}));
this.setCropBoxData($.each(cropBoxData, function (i, n) {
cropBoxData[i] = n * ratio;
}));
}
},
dblclick: function () {
if (this.disabled) {
return;
}
if (this.$dragBox.hasClass(CLASS_CROP)) {
this.setDragMode('move');
} else {
this.setDragMode('crop');
}
},
wheel: function (event) {
var e = event.originalEvent,
delta = 1;
if (this.disabled) {
return;
}
event.preventDefault();
if (e.deltaY) {
delta = e.deltaY > 0 ? 1 : -1;
} else if (e.wheelDelta) {
delta = -e.wheelDelta / 120;
} else if (e.detail) {
delta = e.detail > 0 ? 1 : -1;
}
this.zoom(-delta * 0.1);
},
dragstart: function (event) {
var options = this.options,
originalEvent = event.originalEvent,
touches = originalEvent && originalEvent.touches,
e = event,
dragType,
dragStartEvent,
touchesLength;
if (this.disabled) {
return;
}
if (touches) {
touchesLength = touches.length;
if (touchesLength > 1) {
if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
e = touches[1];
this.startX2 = e.pageX;
this.startY2 = e.pageY;
dragType = 'zoom';
} else {
return;
}
}
e = touches[0];
}
dragType = dragType || $(e.target).data('drag');
if (REGEXP_DRAG_TYPES.test(dragType)) {
event.preventDefault();
dragStartEvent = $.Event(EVENT_DRAG_START, {
originalEvent: originalEvent,
dragType: dragType
});
this.$element.trigger(dragStartEvent);
if (dragStartEvent.isDefaultPrevented()) {
return;
}
this.dragType = dragType;
this.cropping = false;
this.startX = e.pageX;
this.startY = e.pageY;
if (dragType === 'crop') {
this.cropping = true;
this.$dragBox.addClass(CLASS_MODAL);
}
}
},
dragmove: function (event) {
var options = this.options,
originalEvent = event.originalEvent,
touches = originalEvent && originalEvent.touches,
e = event,
dragType = this.dragType,
dragMoveEvent,
touchesLength;
if (this.disabled) {
return;
}
if (touches) {
touchesLength = touches.length;
if (touchesLength > 1) {
if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
e = touches[1];
this.endX2 = e.pageX;
this.endY2 = e.pageY;
} else {
return;
}
}
e = touches[0];
}
if (dragType) {
event.preventDefault();
dragMoveEvent = $.Event(EVENT_DRAG_MOVE, {
originalEvent: originalEvent,
dragType: dragType
});
this.$element.trigger(dragMoveEvent);
if (dragMoveEvent.isDefaultPrevented()) {
return;
}
this.endX = e.pageX;
this.endY = e.pageY;
this.change();
}
},
dragend: function (event) {
var dragType = this.dragType,
dragEndEvent;
if (this.disabled) {
return;
}
if (dragType) {
event.preventDefault();
dragEndEvent = $.Event(EVENT_DRAG_END, {
originalEvent: event.originalEvent,
dragType: dragType
});
this.$element.trigger(dragEndEvent);
if (dragEndEvent.isDefaultPrevented()) {
return;
}
if (this.cropping) {
this.cropping = false;
this.$dragBox.toggleClass(CLASS_MODAL, this.cropped && this.options.modal);
}
this.dragType = '';
}
}
});
$.extend(prototype, {
crop: function () {
if (!this.built || this.disabled) {
return;
}
if (!this.cropped) {
this.cropped = true;
this.limitCropBox(true, true);
if (this.options.modal) {
this.$dragBox.addClass(CLASS_MODAL);
}
this.$cropBox.removeClass(CLASS_HIDDEN);
}
this.setCropBoxData(this.initialCropBox);
},
reset: function () {
if (!this.built || this.disabled) {
return;
}
this.image = $.extend({}, this.initialImage);
this.canvas = $.extend({}, this.initialCanvas);
this.cropBox = $.extend({}, this.initialCropBox); // required for strict mode
this.renderCanvas();
if (this.cropped) {
this.renderCropBox();
}
},
clear: function () {
if (!this.cropped || this.disabled) {
return;
}
$.extend(this.cropBox, {
left: 0,
top: 0,
width: 0,
height: 0
});
this.cropped = false;
this.renderCropBox();
this.limitCanvas();
this.renderCanvas(); // Render canvas after render crop box
this.$dragBox.removeClass(CLASS_MODAL);
this.$cropBox.addClass(CLASS_HIDDEN);
},
destroy: function () {
var $this = this.$element;
if (this.ready) {
this.unbuild();
$this.removeClass(CLASS_HIDDEN);
} else if (this.$clone) {
this.$clone.remove();
}
$this.removeData('cropper');
},
replace: function (url) {
if (!this.disabled && url) {
this.load(url);
}
},
enable: function () {
if (this.built) {
this.disabled = false;
this.$cropper.removeClass(CLASS_DISABLED);
}
},
disable: function () {
if (this.built) {
this.disabled = true;
this.$cropper.addClass(CLASS_DISABLED);
}
},
move: function (offsetX, offsetY) {
var canvas = this.canvas;
if (this.built && !this.disabled && isNumber(offsetX) && isNumber(offsetY)) {
canvas.left += offsetX;
canvas.top += offsetY;
this.renderCanvas(true);
}
},
zoom: function (delta) {
var canvas = this.canvas,
zoomEvent,
width,
height;
delta = num(delta);
if (delta && this.built && !this.disabled && this.options.zoomable) {
zoomEvent = delta > 0 ? $.Event(EVENT_ZOOM_IN) : $.Event(EVENT_ZOOM_OUT);
this.$element.trigger(zoomEvent);
if (zoomEvent.isDefaultPrevented()) {
return;
}
delta = delta <= -1 ? 1 / (1 - delta) : delta <= 1 ? (1 + delta) : delta;
width = canvas.width * delta;
height = canvas.height * delta;
canvas.left -= (width - canvas.width) / 2;
canvas.top -= (height - canvas.height) / 2;
canvas.width = width;
canvas.height = height;
this.renderCanvas(true);
this.setDragMode('move');
}
},
rotate: function (degree) {
var image = this.image;
degree = num(degree);
if (degree && this.built && !this.disabled && this.options.rotatable) {
image.rotate = (image.rotate + degree) % 360;
this.rotated = true;
this.renderCanvas(true);
}
},
getData: function () {
var cropBox = this.cropBox,
canvas = this.canvas,
image = this.image,
ratio,
data;
if (this.built && this.cropped) {
data = {
x: cropBox.left - canvas.left,
y: cropBox.top - canvas.top,
width: cropBox.width,
height: cropBox.height
};
ratio = image.width / image.naturalWidth;
$.each(data, function (i, n) {
n = n / ratio;
data[i] = n;
});
} else {
data = {
x: 0,
y: 0,
width: 0,
height: 0
};
}
data.rotate = this.ready ? image.rotate : 0;
return data;
},
setData: function (data) {
var image = this.image,
canvas = this.canvas,
cropBoxData = {},
ratio;
if (this.built && !this.disabled && $.isPlainObject(data)) {
if (isNumber(data.rotate) && data.rotate !== image.rotate && this.options.rotatable) {
image.rotate = data.rotate;
this.rotated = true;
this.renderCanvas(true);
}
ratio = image.width / image.naturalWidth;
if (isNumber(data.x)) {
cropBoxData.left = data.x * ratio + canvas.left;
}
if (isNumber(data.y)) {
cropBoxData.top = data.y * ratio + canvas.top;
}
if (isNumber(data.width)) {
cropBoxData.width = data.width * ratio;
}
if (isNumber(data.height)) {
cropBoxData.height = data.height * ratio;
}
this.setCropBoxData(cropBoxData);
}
},
getContainerData: function () {
return this.built ? this.container : {};
},
getImageData: function () {
return this.ready ? this.image : {};
},
getCanvasData: function () {
var canvas = this.canvas,
data;
if (this.built) {
data = {
left: canvas.left,
top: canvas.top,
width: canvas.width,
height: canvas.height
};
}
return data || {};
},
setCanvasData: function (data) {
var canvas = this.canvas,
aspectRatio = canvas.aspectRatio;
if (this.built && !this.disabled && $.isPlainObject(data)) {
if (isNumber(data.left)) {
canvas.left = data.left;
}
if (isNumber(data.top)) {
canvas.top = data.top;
}
if (isNumber(data.width)) {
canvas.width = data.width;
canvas.height = data.width / aspectRatio;
} else if (isNumber(data.height)) {
canvas.height = data.height;
canvas.width = data.height * aspectRatio;
}
this.renderCanvas(true);
}
},
getCropBoxData: function () {
var cropBox = this.cropBox,
data;
if (this.built && this.cropped) {
data = {
left: cropBox.left,
top: cropBox.top,
width: cropBox.width,
height: cropBox.height
};
}
return data || {};
},
setCropBoxData: function (data) {
var cropBox = this.cropBox,
aspectRatio = this.options.aspectRatio;
if (this.built && this.cropped && !this.disabled && $.isPlainObject(data)) {
if (isNumber(data.left)) {
cropBox.left = data.left;
}
if (isNumber(data.top)) {
cropBox.top = data.top;
}
if (isNumber(data.width)) {
cropBox.width = data.width;
}
if (isNumber(data.height)) {
cropBox.height = data.height;
}
if (aspectRatio) {
if (isNumber(data.width)) {
cropBox.height = cropBox.width / aspectRatio;
} else if (isNumber(data.height)) {
cropBox.width = cropBox.height * aspectRatio;
}
}
this.renderCropBox();
}
},
getCroppedCanvas: function (options) {
var originalWidth,
originalHeight,
canvasWidth,
canvasHeight,
scaledWidth,
scaledHeight,
scaledRatio,
aspectRatio,
canvas,
context,
data;
if (!this.built || !this.cropped || !SUPPORT_CANVAS) {
return;
}
if (!$.isPlainObject(options)) {
options = {};
}
data = this.getData();
originalWidth = data.width;
originalHeight = data.height;
aspectRatio = originalWidth / originalHeight;
if ($.isPlainObject(options)) {
scaledWidth = options.width;
scaledHeight = options.height;
if (scaledWidth) {
scaledHeight = scaledWidth / aspectRatio;
scaledRatio = scaledWidth / originalWidth;
} else if (scaledHeight) {
scaledWidth = scaledHeight * aspectRatio;
scaledRatio = scaledHeight / originalHeight;
}
}
canvasWidth = scaledWidth || originalWidth;
canvasHeight = scaledHeight || originalHeight;
canvas = $('<canvas>')[0];
canvas.width = canvasWidth;
canvas.height = canvasHeight;
context = canvas.getContext('2d');
if (options.fillColor) {
context.fillStyle = options.fillColor;
context.fillRect(0, 0, canvasWidth, canvasHeight);
}
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
context.drawImage.apply(context, (function () {
var source = getSourceCanvas(this.$clone[0], this.image),
sourceWidth = source.width,
sourceHeight = source.height,
args = [source],
srcX = data.x, // source canvas
srcY = data.y,
srcWidth,
srcHeight,
dstX, // destination canvas
dstY,
dstWidth,
dstHeight;
if (srcX <= -originalWidth || srcX > sourceWidth) {
srcX = srcWidth = dstX = dstWidth = 0;
} else if (srcX <= 0) {
dstX = -srcX;
srcX = 0;
srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX);
} else if (srcX <= sourceWidth) {
dstX = 0;
srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX);
}
if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) {
srcY = srcHeight = dstY = dstHeight = 0;
} else if (srcY <= 0) {
dstY = -srcY;
srcY = 0;
srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY);
} else if (srcY <= sourceHeight) {
dstY = 0;
srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
}
args.push(srcX, srcY, srcWidth, srcHeight);
// Scale destination sizes
if (scaledRatio) {
dstX *= scaledRatio;
dstY *= scaledRatio;
dstWidth *= scaledRatio;
dstHeight *= scaledRatio;
}
// Avoid "IndexSizeError" in IE and Firefox
if (dstWidth > 0 && dstHeight > 0) {
args.push(dstX, dstY, dstWidth, dstHeight);
}
return args;
}).call(this));
return canvas;
},
setAspectRatio: function (aspectRatio) {
var options = this.options;
if (!this.disabled && !isUndefined(aspectRatio)) {
options.aspectRatio = num(aspectRatio) || NaN; // 0 -> NaN
if (this.built) {
this.initCropBox();
if (this.cropped) {
this.renderCropBox();
}
}
}
},
setDragMode: function (mode) {
var $dragBox = this.$dragBox,
cropable = false,
movable = false;
if (!this.ready || this.disabled) {
return;
}
switch (mode) {
case 'crop':
if (this.options.dragCrop) {
cropable = true;
$dragBox.data('drag', mode);
} else {
movable = true;
}
break;
case 'move':
movable = true;
$dragBox.data('drag', mode);
break;
default:
$dragBox.removeData('drag');
}
$dragBox.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable);
}
});
prototype.change = function () {
var dragType = this.dragType,
options = this.options,
canvas = this.canvas,
container = this.container,
cropBox = this.cropBox,
width = cropBox.width,
height = cropBox.height,
left = cropBox.left,
top = cropBox.top,
right = left + width,
bottom = top + height,
minLeft = 0,
minTop = 0,
maxWidth = container.width,
maxHeight = container.height,
renderable = true,
aspectRatio = options.aspectRatio,
range = {
x: this.endX - this.startX,
y: this.endY - this.startY
},
offset;
if (options.strict) {
minLeft = cropBox.minLeft;
minTop = cropBox.minTop;
maxWidth = minLeft + min(container.width, canvas.width);
maxHeight = minTop + min(container.height, canvas.height);
}
if (aspectRatio) {
range.X = range.y * aspectRatio;
range.Y = range.x / aspectRatio;
}
switch (dragType) {
// Move cropBox
case 'all':
left += range.x;
top += range.y;
break;
// Resize cropBox
case 'e':
if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
renderable = false;
break;
}
width += range.x;
if (aspectRatio) {
height = width / aspectRatio;
top -= range.Y / 2;
}
if (width < 0) {
dragType = 'w';
width = 0;
}
break;
case 'n':
if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) {
renderable = false;
break;
}
height -= range.y;
top += range.y;
if (aspectRatio) {
width = height * aspectRatio;
left += range.X / 2;
}
if (height < 0) {
dragType = 's';
height = 0;
}
break;
case 'w':
if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
renderable = false;
break;
}
width -= range.x;
left += range.x;
if (aspectRatio) {
height = width / aspectRatio;
top += range.Y / 2;
}
if (width < 0) {
dragType = 'e';
width = 0;
}
break;
case 's':
if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) {
renderable = false;
break;
}
height += range.y;
if (aspectRatio) {
width = height * aspectRatio;
left -= range.X / 2;
}
if (height < 0) {
dragType = 'n';
height = 0;
}
break;
case 'ne':
if (aspectRatio) {
if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
renderable = false;
break;
}
height -= range.y;
top += range.y;
width = height * aspectRatio;
} else {
if (range.x >= 0) {
if (right < maxWidth) {
width += range.x;
} else if (range.y <= 0 && top <= minTop) {
renderable = false;
}
} else {
width += range.x;
}
if (range.y <= 0) {
if (top > minTop) {
height -= range.y;
top += range.y;
}
} else {
height -= range.y;
top += range.y;
}
}
if (width < 0 && height < 0) {
dragType = 'sw';
height = 0;
width = 0;
} else if (width < 0) {
dragType = 'nw';
width = 0;
} else if (height < 0) {
dragType = 'se';
height = 0;
}
break;
case 'nw':
if (aspectRatio) {
if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
renderable = false;
break;
}
height -= range.y;
top += range.y;
width = height * aspectRatio;
left += range.X;
} else {
if (range.x <= 0) {
if (left > minLeft) {
width -= range.x;
left += range.x;
} else if (range.y <= 0 && top <= minTop) {
renderable = false;
}
} else {
width -= range.x;
left += range.x;
}
if (range.y <= 0) {
if (top > minTop) {
height -= range.y;
top += range.y;
}
} else {
height -= range.y;
top += range.y;
}
}
if (width < 0 && height < 0) {
dragType = 'se';
height = 0;
width = 0;
} else if (width < 0) {
dragType = 'ne';
width = 0;
} else if (height < 0) {
dragType = 'sw';
height = 0;
}
break;
case 'sw':
if (aspectRatio) {
if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
renderable = false;
break;
}
width -= range.x;
left += range.x;
height = width / aspectRatio;
} else {
if (range.x <= 0) {
if (left > minLeft) {
width -= range.x;
left += range.x;
} else if (range.y >= 0 && bottom >= maxHeight) {
renderable = false;
}
} else {
width -= range.x;
left += range.x;
}
if (range.y >= 0) {
if (bottom < maxHeight) {
height += range.y;
}
} else {
height += range.y;
}
}
if (width < 0 && height < 0) {
dragType = 'ne';
height = 0;
width = 0;
} else if (width < 0) {
dragType = 'se';
width = 0;
} else if (height < 0) {
dragType = 'nw';
height = 0;
}
break;
case 'se':
if (aspectRatio) {
if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
renderable = false;
break;
}
width += range.x;
height = width / aspectRatio;
} else {
if (range.x >= 0) {
if (right < maxWidth) {
width += range.x;
} else if (range.y >= 0 && bottom >= maxHeight) {
renderable = false;
}
} else {
width += range.x;
}
if (range.y >= 0) {
if (bottom < maxHeight) {
height += range.y;
}
} else {
height += range.y;
}
}
if (width < 0 && height < 0) {
dragType = 'nw';
height = 0;
width = 0;
} else if (width < 0) {
dragType = 'sw';
width = 0;
} else if (height < 0) {
dragType = 'ne';
height = 0;
}
break;
// Move image
case 'move':
canvas.left += range.x;
canvas.top += range.y;
this.renderCanvas(true);
renderable = false;
break;
// Scale image
case 'zoom':
this.zoom(function (x1, y1, x2, y2) {
var z1 = sqrt(x1 * x1 + y1 * y1),
z2 = sqrt(x2 * x2 + y2 * y2);
return (z2 - z1) / z1;
}(
abs(this.startX - this.startX2),
abs(this.startY - this.startY2),
abs(this.endX - this.endX2),
abs(this.endY - this.endY2)
));
this.startX2 = this.endX2;
this.startY2 = this.endY2;
renderable = false;
break;
// Crop image
case 'crop':
if (range.x && range.y) {
offset = this.$cropper.offset();
left = this.startX - offset.left;
top = this.startY - offset.top;
width = cropBox.minWidth;
height = cropBox.minHeight;
if (range.x > 0) {
if (range.y > 0) {
dragType = 'se';
} else {
dragType = 'ne';
top -= height;
}
} else {
if (range.y > 0) {
dragType = 'sw';
left -= width;
} else {
dragType = 'nw';
left -= width;
top -= height;
}
}
// Show the cropBox if is hidden
if (!this.cropped) {
this.cropped = true;
this.$cropBox.removeClass(CLASS_HIDDEN);
}
}
break;
// No default
}
if (renderable) {
cropBox.width = width;
cropBox.height = height;
cropBox.left = left;
cropBox.top = top;
this.dragType = dragType;
this.renderCropBox();
}
// Override
this.startX = this.endX;
this.startY = this.endY;
};
$.extend(Cropper.prototype, prototype);
Cropper.DEFAULTS = {
// Defines the aspect ratio of the crop box
// Type: Number
aspectRatio: NaN,
// Defines the percentage of automatic cropping area when initializes
// Type: Number (Must large than 0 and less than 1)
autoCropArea: 0.8, // 80%
// Outputs the cropping results.
// Type: Function
crop: null,
// Previous/latest crop data
// Type: Object
data: null,
// Add extra containers for previewing
// Type: String (jQuery selector)
preview: '',
// Toggles
strict: true, // strict mode, the image cannot zoom out less than the container
responsive: true, // Rebuild when resize the window
checkImageOrigin: true, // Check if the target image is cross origin
modal: true, // Show the black modal
guides: true, // Show the dashed lines for guiding
highlight: true, // Show the white modal to highlight the crop box
background: true, // Show the grid background
autoCrop: true, // Enable to crop the image automatically when initialize
dragCrop: true, // Enable to create new crop box by dragging over the image
movable: true, // Enable to move the crop box
resizable: true, // Enable to resize the crop box
rotatable: true, // Enable to rotate the image
zoomable: true, // Enable to zoom the image
touchDragZoom: true, // Enable to zoom the image by wheeling mouse
mouseWheelZoom: true, // Enable to zoom the image by dragging touch
// Dimensions
minCanvasWidth: 0,
minCanvasHeight: 0,
minCropBoxWidth: 0,
minCropBoxHeight: 0,
minContainerWidth: 200,
minContainerHeight: 100,
// Events
build: null, // Function
built: null, // Function
dragstart: null, // Function
dragmove: null, // Function
dragend: null, // Function
zoomin: null, // Function
zoomout: null // Function
};
Cropper.setDefaults = function (options) {
$.extend(Cropper.DEFAULTS, options);
};
// Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin)
Cropper.TEMPLATE = (function (source, words) {
words = words.split(',');
return source.replace(/\d+/g, function (i) {
return words[i];
});
})('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-2-9" 3-2="move"></0><0 6="5-crop-9"><1 6="5-view-9"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face" 3-2="all"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>', 'div,span,drag,data,point,cropper,class,line,dashed,box');
/* Template source:
<div class="cropper-container">
<div class="cropper-canvas"></div>
<div class="cropper-drag-box" data-drag="move"></div>
<div class="cropper-crop-box">
<span class="cropper-view-box"></span>
<span class="cropper-dashed dashed-h"></span>
<span class="cropper-dashed dashed-v"></span>
<span class="cropper-face" data-drag="all"></span>
<span class="cropper-line line-e" data-drag="e"></span>
<span class="cropper-line line-n" data-drag="n"></span>
<span class="cropper-line line-w" data-drag="w"></span>
<span class="cropper-line line-s" data-drag="s"></span>
<span class="cropper-point point-e" data-drag="e"></span>
<span class="cropper-point point-n" data-drag="n"></span>
<span class="cropper-point point-w" data-drag="w"></span>
<span class="cropper-point point-s" data-drag="s"></span>
<span class="cropper-point point-ne" data-drag="ne"></span>
<span class="cropper-point point-nw" data-drag="nw"></span>
<span class="cropper-point point-sw" data-drag="sw"></span>
<span class="cropper-point point-se" data-drag="se"></span>
</div>
</div>
*/
// Save the other cropper
Cropper.other = $.fn.cropper;
// Register as jQuery plugin
$.fn.cropper = function (options) {
var args = toArray(arguments, 1),
result;
this.each(function () {
var $this = $(this),
data = $this.data('cropper'),
fn;
if (!data) {
$this.data('cropper', (data = new Cropper(this, options)));
}
if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
result = fn.apply(data, args);
}
});
return isUndefined(result) ? this : result;
};
$.fn.cropper.Constructor = Cropper;
$.fn.cropper.setDefaults = Cropper.setDefaults;
// No conflict
$.fn.cropper.noConflict = function () {
$.fn.cropper = Cropper.other;
return this;
};
});
$(function () {
'use strict';
var console = window.console || { log: function () {} },
$alert = $('.docs-alert'),
$message = $alert.find('.message'),
showMessage = function (message, type) {
$message.text(message);
if (type) {
$message.addClass(type);
}
$alert.fadeIn();
setTimeout(function () {
$alert.fadeOut();
}, 3000);
};
// Demo
// -------------------------------------------------------------------------
(function () {
var $image = $('.img-container > img'),
$dataX = $('#dataX'),
$dataY = $('#dataY'),
$dataHeight = $('#dataHeight'),
$dataWidth = $('#dataWidth'),
$dataRotate = $('#dataRotate'),
options = {
// data: {
// x: 420,
// y: 60,
// width: 640,
// height: 360
// },
// strict: false,
// responsive: false,
// checkImageOrigin: false
// modal: false,
// guides: false,
// highlight: false,
// background: false,
// autoCrop: false,
// autoCropArea: 0.5,
// dragCrop: false,
// movable: false,
// resizable: false,
// rotatable: false,
// zoomable: false,
// touchDragZoom: false,
// mouseWheelZoom: false,
// minCanvasWidth: 320,
// minCanvasHeight: 180,
// minCropBoxWidth: 160,
// minCropBoxHeight: 90,
// minContainerWidth: 320,
// minContainerHeight: 180,
// build: null,
// built: null,
// dragstart: null,
// dragmove: null,
// dragend: null,
// zoomin: null,
// zoomout: null,
aspectRatio: 16 / 9,
preview: '.img-preview',
crop: function (data) {
$dataX.val(Math.round(data.x));
$dataY.val(Math.round(data.y));
$dataHeight.val(Math.round(data.height));
$dataWidth.val(Math.round(data.width));
$dataRotate.val(Math.round(data.rotate));
}
};
$image.on({
'build.cropper': function (e) {
console.log(e.type);
},
'built.cropper': function (e) {
console.log(e.type);
},
'dragstart.cropper': function (e) {
console.log(e.type, e.dragType);
},
'dragmove.cropper': function (e) {
console.log(e.type, e.dragType);
},
'dragend.cropper': function (e) {
console.log(e.type, e.dragType);
},
'zoomin.cropper': function (e) {
console.log(e.type);
},
'zoomout.cropper': function (e) {
console.log(e.type);
}
}).cropper(options);
// Methods
$(document.body).on('click', '[data-method]', function () {
var data = $(this).data(),
$target,
result;
if (data.method) {
data = $.extend({}, data); // Clone a new one
if (typeof data.target !== 'undefined') {
$target = $(data.target);
if (typeof data.option === 'undefined') {
try {
data.option = JSON.parse($target.val());
} catch (e) {
console.log(e.message);
}
}
}
result = $image.cropper(data.method, data.option);
if (data.method === 'getCroppedCanvas') {
$('#getCroppedCanvasModal').modal().find('.modal-body').html(result);
}
if ($.isPlainObject(result) && $target) {
try {
$target.val(JSON.stringify(result));
} catch (e) {
console.log(e.message);
}
}
}
}).on('keydown', function (e) {
switch (e.which) {
case 37:
e.preventDefault();
$image.cropper('move', -1, 0);
break;
case 38:
e.preventDefault();
$image.cropper('move', 0, -1);
break;
case 39:
e.preventDefault();
$image.cropper('move', 1, 0);
break;
case 40:
e.preventDefault();
$image.cropper('move', 0, 1);
break;
}
});
// Import image
var $inputImage = $('#inputImage'),
URL = window.URL || window.webkitURL,
blobURL;
if (URL) {
$inputImage.change(function () {
var files = this.files,
file;
if (files && files.length) {
file = files[0];
if (/^image\/\w+$/.test(file.type)) {
blobURL = URL.createObjectURL(file);
$image.one('built.cropper', function () {
URL.revokeObjectURL(blobURL); // Revoke when load complete
}).cropper('reset').cropper('replace', blobURL);
$inputImage.val('');
} else {
showMessage('Please choose an image file.');
}
}
});
} else {
$inputImage.parent().remove();
}
// Options
$('.docs-options :checkbox').on('change', function () {
var $this = $(this);
options[$this.val()] = $this.prop('checked');
$image.cropper('destroy').cropper(options);
});
// Tooltips
$('[data-toggle="tooltip"]').tooltip();
}());
});