the latest code
This commit is contained in:
1 parent
d28bc1ed43
commit
9bbb24a52b
12226 files changed
+1455579
-21
No files matched your search
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": false
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
+462
@@ -0,0 +1,462 @@
|
||||
<a href="https://www.npmjs.com/package/cropme" target="_blank"><img src="https://img.shields.io/npm/v/cropme.svg" alt="Latest version" /></a>
|
||||
<a href="https://www.npmjs.com/package/cropme" target="_blank"><img src="https://img.shields.io/npm/dt/cropme.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://www.npmjs.com/package/cropme" target="_blank"><img src="https://img.shields.io/npm/l/cropme.svg" alt="Package License" /></a>
|
||||
[](https://www.jsdelivr.com/package/npm/cropme)
|
||||
|
||||
# Cropme
|
||||
|
||||
Cropme is a customizable and easy to use javascript image cropper plugin.
|
||||
|
||||
[See the demo](https://shpontex.github.io/cropme)
|
||||
|
||||
## Features
|
||||
|
||||
Support:
|
||||
|
||||
- Two-dimensional translation
|
||||
- Scaling
|
||||
- Free rotation
|
||||
- Rotation and scale around the image center or the viewport center
|
||||
- Multi-touch support (pinch-zoom, two finger rotation, ...)
|
||||
- Base64 and blob exportation
|
||||
- Multiple croppers
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
dist/
|
||||
├── cropme.css
|
||||
├── cropme.min.css (compressed)
|
||||
├── cropme.js (UMD)
|
||||
└── cropme.min.js (UMD, compressed)
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
**npm**
|
||||
|
||||
```
|
||||
npm install cropme
|
||||
```
|
||||
|
||||
**Download**
|
||||
|
||||
[Download the project](https://github.com/shpontex/cropme/archive/master.zip) and extract it.\
|
||||
then put the dist/cropme.min.css and the dist/cropme.min.js in you project.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="path-to/cropme.min.css">
|
||||
<script src="path-to/cropme.min.js"></script>
|
||||
```
|
||||
|
||||
**CDN**
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cropme@latest/dist/cropme.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/cropme@latest/dist/cropme.min.js"></script>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Syntax
|
||||
|
||||
```js
|
||||
new Cropme(element, options);
|
||||
```
|
||||
|
||||
- **element** (`HTMLElement`, required): *the cropper wrapping HTML element, can be a `<div>` or `<img>` tag.
|
||||
|
||||
|
||||
- **options** (`Object`, optional): *The configuration options, see [**Options**](#options).*
|
||||
|
||||
### Example
|
||||
|
||||
**Vanilla javascript**
|
||||
|
||||
```html
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
var element = document.getElementById('container');
|
||||
var cropme = new Cropme(element);
|
||||
cropme.bind({
|
||||
url: 'images/naruto.jpg'
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- or use image tag -->
|
||||
<img src="images/naruto.jpg" id="myImage" />
|
||||
<script>
|
||||
var element = document.getElementById('myImage');
|
||||
new Cropme(element);
|
||||
</script>
|
||||
```
|
||||
|
||||
**JQuery**
|
||||
|
||||
```html
|
||||
<div id="container"></div>
|
||||
|
||||
<script>
|
||||
var example = $('#container').cropme();
|
||||
example.cropme('bind', {
|
||||
url: 'images/naruto.jpg'
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- or use image tag -->
|
||||
<img src="images/naruto.jpg" id="myImage" />
|
||||
<script>
|
||||
$('#myImage').cropme();
|
||||
</script>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
### Container
|
||||
|
||||
- Target: the container of the cropper.
|
||||
- Key: `container`
|
||||
- Parameters:
|
||||
- **width** (`int|string`, default: `300`): *the outer container width*
|
||||
- **height** (`int`, default: `300`): *the outer container height*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
// Fixed container
|
||||
container: {
|
||||
width: 500,
|
||||
height: 400
|
||||
}
|
||||
// responsive container
|
||||
container: {
|
||||
width: '100%',
|
||||
height: 400
|
||||
}
|
||||
```
|
||||
### Viewport
|
||||
|
||||
- Target: the part that will be cropped.
|
||||
- Key: `viewport`
|
||||
- Parameters:
|
||||
- **width** (`int`, default: `100`): *the viewport width*
|
||||
- **height** (`int`, default: `100`): *the viewport height*
|
||||
- **type** (`string`, default: `square`, available: `circle`): *the viewport frame form*
|
||||
- **border** (`object`): *the viewport frame border*
|
||||
- **enable** (`bool`, default: `true`): *toggle the border*
|
||||
- **width** (`int`, default: `2`): *the border width*
|
||||
- **color** (`string`, unit: `hex, rgba, hsl`, default: `#fff`): *the border color*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
viewport: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
type: 'circle',
|
||||
border: {
|
||||
enable: true,
|
||||
width: 2,
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Zoom
|
||||
|
||||
- Target: the image zoom options
|
||||
- Key: `zoom`,
|
||||
- Parameters:
|
||||
- **min** (`number`, default: `0.01`): *minimum zoom*
|
||||
- **max** (`number`, default: `3`): *maximum zoom*
|
||||
- **enable** (`bool`, default: `true`): *enable or disable the zoom feature*
|
||||
- **mouseWheel** (`bool`, default: `true`): *enable or disable mouse wheel zoom*
|
||||
- **slider** (`bool`, default: `false`): *toggle the slider input*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
zoom: {
|
||||
min: 0.01,
|
||||
max: 3,
|
||||
enable: true,
|
||||
mouseWheel: true,
|
||||
slider: false
|
||||
}
|
||||
```
|
||||
|
||||
### Rotation
|
||||
|
||||
- Target: the image rotation
|
||||
- Key: `rotation`
|
||||
- Parameters:
|
||||
- **enable** (`bool`, default: `true`): *enable or disable the rotation*
|
||||
- **slider** (`bool`, default: `false`): *toggle the slider input*
|
||||
- **position** (`string`, default: `right`, available: `right, left`): *the slider input position*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
rotation: {
|
||||
enable: true,
|
||||
slider: false,
|
||||
position: 'right'
|
||||
}
|
||||
```
|
||||
|
||||
### Transform origin
|
||||
|
||||
- Target: the image transform origin
|
||||
- Parameter:
|
||||
- **transformOrigin** (`string`, default: `viewport`,available: `image`, `viewport`)\
|
||||
*image: the transform origin is the image center*\
|
||||
*viewport: the transform origin is the viewport center*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
{
|
||||
transformOrigin: 'viewport'
|
||||
}
|
||||
```
|
||||
|
||||
### Custom class
|
||||
|
||||
- Target: the container class
|
||||
- Parameter:
|
||||
- **customClass** (`string`, default: `null`): *the class of the container*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
{
|
||||
customClass: 'my-custom-class'
|
||||
}
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### bind()
|
||||
|
||||
*Binds an image and return a promise after the image is loaded.*
|
||||
|
||||
#### Arguments
|
||||
|
||||
The `bind()` method expects an `Object` containing:
|
||||
|
||||
- **url** (required)
|
||||
- **type**: `String`
|
||||
- **description**: The url of the image to bind.
|
||||
- **position**
|
||||
- **x**: (`int`,the x translation coordinate).
|
||||
- **y**: (`int`,the y translation coordinate).\
|
||||
The image is translated from its origin.\
|
||||
If not specified, the image is centered horizontaly and verticaly.
|
||||
- **scale**: (`float`,The scale of the image, 1 is the original image size),\
|
||||
If not specified, the image will takes the container's height and scale automatically.
|
||||
- **angle**: (`int`,The rotation of the image by an angle in degree around its origin).
|
||||
- **origin**: (`object`,The x and y coordonate of the image transform origin),\
|
||||
if origin is set, the `transformOrigin` option will be override and set to `viewport`,\
|
||||
since `image` option means that the transform origin is the center of the image,\
|
||||
in that case `origin` is not required.
|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var container = $('#container').cropme();
|
||||
|
||||
container.cropme('bind', {
|
||||
url: 'images/naruto.jpg',
|
||||
position: {
|
||||
x: 230,
|
||||
y: -30,
|
||||
scale: 1.3,
|
||||
angle: 35,
|
||||
origin: {
|
||||
x: 623.26,
|
||||
y: 1150
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// If you want to do some changes directly after binding the image
|
||||
|
||||
container.cropme('bind', {
|
||||
url: 'images/naruto.jpg',
|
||||
})
|
||||
.then(function(){
|
||||
//example
|
||||
container.cropme('rotate')
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### rotate()
|
||||
|
||||
*Rotate the image to the given angle.*
|
||||
|
||||
#### Arguments
|
||||
|
||||
- **angle**
|
||||
- **description**: The angle the image will be rotated to.\
|
||||
The rotation is not relative to the current image rotation.
|
||||
- **type**: `number`
|
||||
- **unit**: `degree`
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var myImage = $('#myImage').cropme();
|
||||
|
||||
myImage.cropme('rotate', 90);
|
||||
```
|
||||
|
||||
### crop()
|
||||
|
||||
*Returns a promise with the cropped image.*
|
||||
|
||||
#### Arguments
|
||||
|
||||
As a parameter, the `crop()` function can receive:
|
||||
|
||||
1. An `Object` containing:
|
||||
- **type**
|
||||
- **type**: `String`
|
||||
- **default**: `base64`
|
||||
- **possible value**: `base64`, `blob`
|
||||
- **description**: The image exportation format
|
||||
- **width**
|
||||
- **type**: `int`
|
||||
- **description**: The width of the output images, the height will be \
|
||||
proportional.
|
||||
- **scale**
|
||||
- **type**: `number`
|
||||
- **description**: The size of the ouput, relative to the original image size.\
|
||||
If `scale` has a value, the `width` get ignored.
|
||||
- **mimetype**
|
||||
- **type**: `String`
|
||||
- **default**: `image/png`
|
||||
- **description**: The output image format.
|
||||
- **quality**
|
||||
- **type**: `number`
|
||||
- **default**: `0.92` (`0.80` for `image/webp` mimetype when output is blob).
|
||||
- **description**: A Number between `0` and `1` indicating image quality.\
|
||||
Works only with `image/jpeg` or `image/webp` (formats that use lossy
|
||||
compression).
|
||||
2. A `String` specifying the exportation format (`base64` or `blob`)
|
||||
|
||||
*For more information about `mimetype` and `quality` arguments: \
|
||||
→ [`toBlob()` and `toDataURL()` HTMLCanvasElement documentation](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement).*
|
||||
|
||||
Calling `crop()` without parameters returns a **base64** image with the viewport size.
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var myImage = $('#myImage').cropme();
|
||||
|
||||
// string
|
||||
myImage.cropme('crop', 'blob')
|
||||
.then(function(output) {
|
||||
// here you can use the blob output
|
||||
});
|
||||
|
||||
// object
|
||||
myImage.cropme('crop', {
|
||||
type: 'base64',
|
||||
width: 800
|
||||
}).then(function(output) {
|
||||
// here you can use the base64 output
|
||||
});
|
||||
|
||||
|
||||
// no parameter
|
||||
myImage.cropme('crop')
|
||||
.then(function(output) {
|
||||
// here you can use the base64 output
|
||||
});
|
||||
```
|
||||
### position()
|
||||
|
||||
*Returns an object specifying the image position*\
|
||||
When you create a new cropme you can bind the image with this position object.
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var myImage = $('#myImage').cropme();
|
||||
|
||||
var position = myImage.cropme('position');
|
||||
```
|
||||
|
||||
**Output**: `Object`
|
||||
|
||||
```js
|
||||
{
|
||||
x: 230,
|
||||
y: -30,
|
||||
scale: 1.3,
|
||||
angle: 35,
|
||||
origin: {
|
||||
x: 623.26,
|
||||
y: 1150
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### reload()
|
||||
|
||||
*Reload the cropme instance with a new parameters*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var myImage = $('#myImage').cropme({
|
||||
container: {
|
||||
width: 300,
|
||||
height: 200
|
||||
}
|
||||
});
|
||||
|
||||
myImage.cropme('reload', {
|
||||
container: {
|
||||
width: 455,
|
||||
height: 600
|
||||
},
|
||||
viewport: {
|
||||
width: 150,
|
||||
height: 240,
|
||||
border: {
|
||||
enable: true,
|
||||
width: 5,
|
||||
color: '#f00'
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### destroy()
|
||||
|
||||
*Destroy the cropme instance*
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
var myImage = $('#myImage').cropme();
|
||||
|
||||
myImage.cropme('destroy');
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for your contribution to this project.
|
||||
|
||||
### Installation
|
||||
|
||||
Fork the project then
|
||||
|
||||
```
|
||||
npm install && npm run watch
|
||||
```
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
.navbar {
|
||||
box-shadow: 0 .125rem .25rem rgba(0,0,0,.075)!important;
|
||||
/* background-color:#5bc0de; */
|
||||
}
|
||||
#cropme-result {
|
||||
width: 200px;
|
||||
}
|
||||
h2.display-4 {
|
||||
font-size: 25px;
|
||||
}
|
||||
.title {
|
||||
|
||||
}
|
||||
.options {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.output {
|
||||
background-color: #eee;
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*!
|
||||
* cropme v1.4.3
|
||||
* https://shpontex.github.io/cropme
|
||||
*
|
||||
* Copyright 2020 shpontex
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2020-03-02T12:55:13.295Z
|
||||
*/
|
||||
.cropme-wrapper {
|
||||
width: 100%;
|
||||
height: 100%; }
|
||||
|
||||
.cropme-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 0 auto; }
|
||||
.cropme-container img {
|
||||
width: initial !important;
|
||||
cursor: move;
|
||||
opacity: 0;
|
||||
touch-action: none; }
|
||||
|
||||
#img {
|
||||
border: 5px solid #f00; }
|
||||
|
||||
.viewport {
|
||||
box-sizing: content-box !important;
|
||||
position: absolute;
|
||||
border-style: solid;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
box-shadow: 0 0 2000px 2000px rgba(0, 0, 0, 0.5);
|
||||
z-index: 0;
|
||||
pointer-events: none; }
|
||||
.viewport.circle {
|
||||
border-radius: 50%; }
|
||||
|
||||
.cropme-slider, .cropme-rotation-slider {
|
||||
text-align: center; }
|
||||
.cropme-slider input, .cropme-rotation-slider input {
|
||||
-webkit-appearance: none; }
|
||||
.cropme-slider input:disabled, .cropme-rotation-slider input:disabled {
|
||||
opacity: 0.5; }
|
||||
.cropme-slider input::-webkit-slider-runnable-track, .cropme-rotation-slider input::-webkit-slider-runnable-track {
|
||||
height: 3px;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 3px; }
|
||||
.cropme-slider input::-webkit-slider-thumb, .cropme-rotation-slider input::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
border-radius: 50%;
|
||||
background: #ddd;
|
||||
margin-top: -6px; }
|
||||
.cropme-slider input:focus, .cropme-rotation-slider input:focus {
|
||||
outline: none; }
|
||||
+1211
File diff suppressed because it is too large.
Load diff
+9
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* cropme v1.4.3
|
||||
* https://shpontex.github.io/cropme
|
||||
*
|
||||
* Copyright 2020 shpontex
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2020-03-02T12:55:13.295Z
|
||||
*/.cropme-wrapper{width:100%;height:100%}.cropme-container{position:relative;overflow:hidden;margin:0 auto}.cropme-container img{width:auto!important;cursor:move;opacity:0;touch-action:none}#img{border:5px solid red}.viewport{box-sizing:content-box!important;position:absolute;border-style:solid;margin:auto;top:0;bottom:0;right:0;left:0;box-shadow:0 0 2000px 2000px rgba(0,0,0,.5);z-index:0;pointer-events:none}.viewport.circle{border-radius:50%}.cropme-rotation-slider,.cropme-slider{text-align:center}.cropme-rotation-slider input,.cropme-slider input{-webkit-appearance:none}.cropme-rotation-slider input:disabled,.cropme-slider input:disabled{opacity:.5}.cropme-rotation-slider input::-webkit-slider-runnable-track,.cropme-slider input::-webkit-slider-runnable-track{height:3px;background:rgba(0,0,0,.5);border-radius:3px}.cropme-rotation-slider input::-webkit-slider-thumb,.cropme-slider input::-webkit-slider-thumb{-webkit-appearance:none;height:16px;width:16px;border-radius:50%;background:#ddd;margin-top:-6px}.cropme-rotation-slider input:focus,.cropme-slider input:focus{outline:none}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* cropme v1.4.3
|
||||
* https://shpontex.github.io/cropme
|
||||
*
|
||||
* Copyright 2020 shpontex
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2020-03-02T12:55:13.295Z
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).Cropme=e()}(this,function(){"use strict";function Z(t){return(Z="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function r(t,e){for(var i=0;i<e.length;i++){var r=e[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function p(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}function a(t){return t&&"object"===Z(t)&&!Array.isArray(t)}function h(t){for(var e=arguments.length,i=new Array(1<e?e-1:0),r=1;r<e;r++)i[r-1]=arguments[r];if(!i.length)return t;var o,n=i.shift();if(Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(t){if(null==t)throw new TypeError("Cannot convert first argument to object");for(var e=Object(t),i=1;i<arguments.length;i++){var r=arguments[i];if(null!=r){r=Object(r);for(var o=Object.keys(Object(r)),n=0,s=o.length;n<s;n++){var p=o[n],a=Object.getOwnPropertyDescriptor(r,p);void 0!==a&&a.enumerable&&(e[p]=r[p])}}}return e}}),a(t)&&a(n))for(var s in n)a(n[s])?(t[s]||Object.assign(t,p({},s,{})),h(t[s],n[s])):(o=n[s])&&Array.isArray(o)?(t[s]||Object.assign(t,p({},s,[])),t[s]=t[s].concat(n[s])):Object.assign(t,p({},s,n[s]));return h.apply(void 0,[t].concat(i))}function w(){return"translate3d("+this.properties.x+"px,"+this.properties.y+"px, 0) scale("+this.properties.scale+") rotate("+this.properties.deg+"deg)"}function d(t,e){return t+"px "+e+"px"}function l(){if(this.properties.rotation_slider)this.options.rotation.slider?this.properties.rotation_slider.disabled=!this.options.rotation.enable:(this.properties.wrapper.removeChild(this.properties.rotation_slider.parentNode),delete this.properties.rotation_slider),this.properties.rotation_slider&&(this.properties.rotation_slider.style.width=this.properties.container.offsetWidth+"px");else if(this.options.rotation.slider){var t=document.createElement("div");t.classList.add("cropme-rotation-slider");var e=this.properties.rotation_slider=document.createElement("input");e.type="range",e.setAttribute("min",-180),e.setAttribute("max",180),e.setAttribute("step",1),e.value=0,e.style.width=this.properties.container.offsetWidth+"px",t.appendChild(e),this.properties.wrapper.appendChild(t);var i=this;this.properties.rotation_slider.addEventListener(o()?"change":"input",function(t){i.rotate(t.target.value)}),this.properties.rotation_slider.disabled=!this.options.rotation.enable}}function o(){var t=window.navigator.userAgent,e=t.indexOf("MSIE ");if(0<e)return parseInt(t.substring(e+5,t.indexOf(".",e)),10);if(0<t.indexOf("Trident/")){var i=t.indexOf("rv:");return parseInt(t.substring(i+3,t.indexOf(".",i)),10)}var r=t.indexOf("Edge/");return 0<r&&parseInt(t.substring(r+5,t.indexOf(".",r)),10)}function u(){function t(){var t=(this.properties.wrapper.offsetWidth-this.properties.container.offsetWidth)/2,e=this.properties.container.offsetWidth/2+12+t;"left"===this.options.rotation.position&&(e=-this.properties.container.offsetWidth/2-20+t);var i=(this.properties.container.offsetWidth-this.properties.container.offsetHeight)/2,r=this.properties.container.offsetHeight/2+12-i;this.properties.sliderContainer.style.transform="translate3d("+e+"px, "+r+"px, 0) rotate(-90deg)";var o=this.properties.container.offsetWidth/2;this.properties.sliderContainer.style.transformOrigin=o+"px 12px",this.properties.sliderContainer.style.marginTop="-24px",this.properties.slider.disabled=!this.options.zoom.enable}if(this.properties.slider)this.options.zoom.slider?t.call(this):(this.properties.wrapper.removeChild(this.properties.slider.parentNode),delete this.properties.slider);else if(this.options.zoom.slider){var e=this,i=this.properties.sliderContainer=document.createElement("div");i.classList.add("cropme-slider");var r=this.properties.slider=document.createElement("input");r.type="range",r.setAttribute("min",this.options.zoom.min),r.setAttribute("max",this.options.zoom.max),r.setAttribute("step",1e-6),r.style.width=this.properties.container.offsetHeight+"px",i.style.width=this.properties.container.offsetHeight+"px",i.appendChild(r),this.properties.wrapper.insertBefore(i,this.properties.wrapper.firstChild),this.properties.slider.value=this.properties.scale,this.properties.slider.addEventListener(o()?"change":"input",function(t){e.properties.scale=parseFloat(t.target.value),e.properties.image.style.transform=w.call(e)}),t.call(this)}}function e(){var t=this.properties.container;t||(t=this.properties.container=document.createElement("div"),this.properties.wrapper.appendChild(t)),t.classList.add("cropme-container"),t.style.width=this.options.container.width+("string"==typeof this.options.container.width?"":"px"),t.Line truncated
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 384 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 457 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
+192
@@ -0,0 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1 user-scalable=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||
|
||||
<link rel="stylesheet" href="dist/cropme.css">
|
||||
<title>Cropme | a javascript image cropper</title>
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light">
|
||||
<a class="navbar-brand" href="https://github.com/shpontex/cropme">
|
||||
<svg height="32" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/shpontex/cropme">Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section class="p-4">
|
||||
<div class="container">
|
||||
<div class="description text-center">
|
||||
<h1 class="display-4">Cropme</h1>
|
||||
<p>Cropme is a customizable and easy to use javascript image cropping plugin </p>
|
||||
</div>
|
||||
<div class="row mt-5" id="app">
|
||||
<div class="col-md-6">
|
||||
<div id="cropme"></div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="cropmeModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Cropme result</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<img id="cropme-result" src="" alt="cropme">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="cropmePosition" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Cropme Position output</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<pre><code>{{ position}}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="options">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="title">Viewport Type</div>
|
||||
<select class="form-control" v-model="options.viewport.type">
|
||||
<option value="square">square (default)</option>
|
||||
<option value="circle">circle</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="title">transform origin center</div>
|
||||
<select class="form-control" v-model="options.transformOrigin">
|
||||
<option value="image">image</option>
|
||||
<option value="viewport">viewport (default)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<div class="title">Border</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
enable: <select class="form-control" v-model="options.viewport.border.enable">
|
||||
<option :value="true">true (default)</option>
|
||||
<option :value="false">false</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
width: <select class="form-control" v-model="options.viewport.border.width">
|
||||
<option value="2">2 (default)</option>
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
color: <select class="form-control" v-model="options.viewport.border.color">
|
||||
<option value="#fff">white (default)</option>
|
||||
<option value="#f00">red</option>
|
||||
<option value="#00f">bleu</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<div class="title">Zoom</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
enable: <select class="form-control" v-model="options.zoom.enable">
|
||||
<option :value="true">true (default)</option>
|
||||
<option :value="false">false</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
mouseWheel: <select class="form-control" v-model="options.zoom.mouseWheel">
|
||||
<option :value="true">true (default)</option>
|
||||
<option :value="false">false</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
slider: <select class="form-control" v-model="options.zoom.slider">
|
||||
<option :value="true">true</option>
|
||||
<option :value="false">false (default)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<div class="title">Rotation</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
enable: <select class="form-control" v-model="options.rotation.enable">
|
||||
<option :value="true">true (default)</option>
|
||||
<option :value="false">false</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
slider: <select class="form-control" v-model="options.rotation.slider">
|
||||
<option :value="true">true</option>
|
||||
<option :value="false">false (default)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
Position: <select class="form-control" v-model="options.rotation.position">
|
||||
<option value="left">left</option>
|
||||
<option value="right">right (default)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-outline-danger" @click="reset">Reset </button>
|
||||
<button class="btn btn-outline-success float-right" @click="crop">Crop me</button>
|
||||
<button class="btn btn-outline-info float-right mr-3" @click="getPosition">Get position</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 w-100 p-3 output">
|
||||
<pre><code>{{ options}}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
|
||||
<script src="dist/cropme.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
options: {},
|
||||
position: {},
|
||||
defaultOptions: {
|
||||
container: {
|
||||
width: '100%',
|
||||
height: 400
|
||||
},
|
||||
viewport: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
type: 'circle',
|
||||
border: {
|
||||
width: 2,
|
||||
enable: true,
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
zoom: {
|
||||
enable: true,
|
||||
mouseWheel: true,
|
||||
slider: true
|
||||
},
|
||||
rotation: {
|
||||
slider: true,
|
||||
enable: true,
|
||||
position: 'left'
|
||||
},
|
||||
transformOrigin: 'viewport',
|
||||
},
|
||||
cropme: {},
|
||||
el: {}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler: function(val) {
|
||||
this.cropme.reload(val)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created:function() {
|
||||
this.options = JSON.parse(JSON.stringify(this.defaultOptions))
|
||||
},
|
||||
mounted:function() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init:function() {
|
||||
this.el = document.getElementById('cropme')
|
||||
this.cropme = new Cropme(this.el, this.options)
|
||||
this.cropme.bind({
|
||||
url: 'images/pic.jpeg',
|
||||
})
|
||||
},
|
||||
getPosition:function() {
|
||||
this.position = this.cropme.position()
|
||||
$('#cropmePosition').modal()
|
||||
},
|
||||
crop:function() {
|
||||
let img = document.getElementById('cropme-result')
|
||||
this.cropme.crop({
|
||||
width: 600
|
||||
}).then(function(res) {
|
||||
img.src = res
|
||||
$('#cropmeModal').modal()
|
||||
})
|
||||
},
|
||||
reset:function() {
|
||||
this.options = JSON.parse(JSON.stringify(this.defaultOptions))
|
||||
this.cropme.destroy()
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
})
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { isObject } from './isObject';
|
||||
import { isArray } from './isArray';
|
||||
|
||||
export default function nestedObjectAssign(target, ...sources){
|
||||
if (!sources.length)
|
||||
return target;
|
||||
|
||||
const source = sources.shift();
|
||||
|
||||
if (!Object.assign) {
|
||||
Object.defineProperty(Object, 'assign', {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: function(target) {
|
||||
'use strict';
|
||||
if (target === undefined || target === null) {
|
||||
throw new TypeError('Cannot convert first argument to object');
|
||||
}
|
||||
|
||||
var to = Object(target);
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var nextSource = arguments[i];
|
||||
if (nextSource === undefined || nextSource === null) {
|
||||
continue;
|
||||
}
|
||||
nextSource = Object(nextSource);
|
||||
|
||||
var keysArray = Object.keys(Object(nextSource));
|
||||
for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
|
||||
var nextKey = keysArray[nextIndex];
|
||||
var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
|
||||
if (desc !== undefined && desc.enumerable) {
|
||||
to[nextKey] = nextSource[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
return to;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isObject(target) && isObject(source)){
|
||||
for (const key in source){
|
||||
if (isObject(source[key])){
|
||||
if (!target[key]) {
|
||||
Object.assign(target, {[key]: {}});
|
||||
}
|
||||
|
||||
nestedObjectAssign(target[key], source[key]);
|
||||
} else if (isArray(source[key])) {
|
||||
if (!target[key]) {
|
||||
Object.assign(target, {[key]: []});
|
||||
}
|
||||
|
||||
target[key] = target[key].concat(source[key]);
|
||||
} else {
|
||||
Object.assign(target, {[key]: source[key]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nestedObjectAssign(target, ...sources);
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export function isArray(item){
|
||||
return (item && Array.isArray(item));
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export function isObject(item){
|
||||
return (item && typeof item === 'object' && !Array.isArray(item));
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "cropme",
|
||||
"version": "1.4.3",
|
||||
"description": "Javascript image cropper",
|
||||
"main": "dist/cropme.js",
|
||||
"scripts": {
|
||||
"build": "npm run build:js && npm run minify:js && npm run minify:css",
|
||||
"build:js": "rollup -c",
|
||||
"minify:js": "uglifyjs dist/cropme.js -o dist/cropme.min.js -c -m --comments '/^/*!/'",
|
||||
"minify:css": "postcss dist/cropme.css -u cssnano -o dist/cropme.min.css --no-map",
|
||||
"watch": "rollup -c -w"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/shpontex/cropme.git"
|
||||
},
|
||||
"keywords": [
|
||||
"javascript",
|
||||
"image",
|
||||
"crop",
|
||||
"move",
|
||||
"zoom",
|
||||
"rotate",
|
||||
"scale",
|
||||
"cropme",
|
||||
"cropping",
|
||||
"html",
|
||||
"css",
|
||||
"javascript"
|
||||
],
|
||||
"author": "shpontex",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Pierre Ellul",
|
||||
"email": "[email protected]",
|
||||
"url": "https://pellul.github.io"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "https://shpontex.github.io/cropme",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"create-banner": "^1.0.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"node-sass": "^4.12.0",
|
||||
"postcss-cli": "^6.1.3",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-url": "^8.0.0",
|
||||
"rollup": "^1.17.0",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"uglify-js": "^3.6.0"
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
const pkg = require('./package')
|
||||
import createBanner from 'create-banner'
|
||||
const babel = require('rollup-plugin-babel')
|
||||
var sass = require('node-sass');
|
||||
const fs = require('fs')
|
||||
const banner = createBanner()
|
||||
|
||||
sass.render({
|
||||
file: 'src/cropme.sass',
|
||||
}, function (err, result) {
|
||||
if (!err) {
|
||||
fs.writeFile('dist/cropme.css', banner + result.css, function (err) {});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
banner,
|
||||
name: "Cropme",
|
||||
file: `dist/${pkg.name}.js`,
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
babel(),
|
||||
],
|
||||
};
|
||||
+632
@@ -0,0 +1,632 @@
|
||||
import nestedObjectAssign from '../js/nestedObjectAssign/index'
|
||||
|
||||
(function(undefined) {!function(n){function t(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return n[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var e={};t.m=n,t.c=e,t.i=function(n){return n},t.d=function(n,e,r){t.o(n,e)||Object.defineProperty(n,e,{configurable:!1,enumerable:!0,get:r})},t.n=function(n){var e=n&&n.__esModule?function(){return n["default"]}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=100)}({100:function(n,t,e){(function(n){var t=e(5);try{n.Promise=t,window.Promise=t}catch(r){}}).call(t,e(2))},2:function(n,t){var e;e=function(){return this}();try{e=e||Function("return this")()||(0,eval)("this")}catch(r){"object"==typeof window&&(e=window)}n.exports=e},5:function(n,t,e){(function(t){!function(){"use strict";function e(){return rn[q][B]||D}function r(n){return n&&"object"==typeof n}function o(n){return"function"==typeof n}function i(n,t){return n instanceof t}function u(n){return i(n,M)}function c(n,t,e){if(!t(n))throw h(e)}function f(){try{return R.apply(S,arguments)}catch(n){return nn.e=n,nn}}function s(n,t){return R=n,S=t,f}function a(n,t){function e(){for(var e=0;e<o;)t(r[e],r[e+1]),r[e++]=P,r[e++]=P;o=0,r.length>n&&(r.length=n)}var r=A(n),o=0;return function(n,t){r[o++]=n,r[o++]=t,2===o&&rn.nextTick(e)}}function l(n,t){var e,r,u,c,f=0;if(!n)throw h(Q);var a=n[rn[q][z]];if(o(a))r=a.call(n);else{if(!o(n.next)){if(i(n,A)){for(e=n.length;f<e;)t(n[f],f++);return f}throw h(Q)}r=n}for(;!(u=r.next()).done;)if((c=s(t)(u.value,f++))===nn)throw o(r[G])&&r[G](),c.e;return f}function h(n){return new TypeError(n)}function v(n){return(n?"":V)+(new M).stack}function _(n,t){var e="on"+n.toLowerCase(),r=O[e];H&&H.listeners(n).length?n===Z?H.emit(n,t._v,t):H.emit(n,t):r?r({reason:t._v,promise:t}):rn[n](t._v,t)}function p(n){return n&&n._s}function d(n){if(p(n))return new n(tn);var t,e,r;return t=new n(function(n,o){if(t)throw h();e=n,r=o}),c(e,o),c(r,o),t}function w(n,t){var e=!1;return function(r){e||(e=!0,L&&(n[N]=v(!0)),t===Y?k(n,r):x(n,t,r))}}function y(n,t,e,r){return o(e)&&(t._onFulfilled=e),o(r)&&(n[J]&&_(X,n),t._onRejected=r),L&&(t._p=n),n[n._c++]=t,n._s!==$&&on(n,t),t}function m(n){if(n._umark)return!0;n._umark=!0;for(var t,e=0,r=n._c;e<r;)if(t=n[e++],t._onRejected||m(t))return!0}function j(n,t){function e(n){return r.push(n.replace(/^\s+|\s+$/g,""))}var r=[];return L&&(t[N]&&e(t[N]),function o(n){n&&K in n&&(o(n._next),e(n[K]+""),o(n._p))}(t)),(n&&n.stack?n.stack:n)+("\n"+r.join("\n")).replace(en,"")}function g(n,t){return n(t)}function x(n,t,e){var r=0,o=n._c;if(n._s===$)for(n._s=t,n._v=e,t===U&&(L&&u(e)&&(e.longStack=j(e,n)),un(n));r<o;)on(n,n[r++]);return n}function k(n,t){if(t===n&&t)return x(n,U,h(W)),n;if(t!==C&&(o(t)||r(t))){var e=s(b)(t);if(e===nn)return x(n,U,e.e),n;o(e)?(L&&p(t)&&(n._next=t),p(t)?T(n,t,e):rn.nextTick(function(){T(n,t,e)})):x(n,Y,t)}else x(n,Y,t);return n}function b(n){return n.then}function T(n,t,e){var r=s(e,t)(function(e){t&&(t=C,k(n,e))},function(e){t&&(t=C,x(n,U,e))});r===nn&&t&&(x(n,U,r.e),t=C)}var P,R,S,C=null,F="object"==typeof self,O=F?self:t,E=O.Promise,H=O.process,I=O.console,L=!1,A=Array,M=Error,U=1,Y=2,$=3,q="Symbol",z="iterator",B="species",D=q+"("+B+")",G="return",J="_uh",K="_pt",N="_st",Q="Invalid argument",V="\nFrom previous ",W="Chaining cycle detected for promise",X="rejectionHandled",Z="unhandledRejection",nn={e:C},tn=function(){},en=/^.+\/node_modules\/yaku\/.+\n?/gm,rn=function(n){var t,e=this;if(!r(e)||e._s!==P)throw h("Invalid this");if(e._s=$,L&&(e[K]=v()),n!==tn){if(!o(n))throw h(Q);(t=s(n)(w(e,Y),w(e,U)))===nn&&x(e,U,t.e)}};rn["default"]=rn,function(n,t){for(var e in t)n[e]=t[e]}(rn.prototype,{then:function(n,t){if(this._s===undefined)throw h();return y(this,d(rn.speciesConstructor(this,rn)),n,t)},"catch":function(n){return this.then(P,n)},"finally":function(n){return this.then(function(t){return rn.resolve(n()).then(function(){return t})},function(t){return rn.resolve(n()).then(function(){throw t})})},_c:0,_p:C}),rn.resolve=function(n){return p(n)?n:k(d(this),n)},rn.reject=function(n){return x(d(this),U,n)},rn.race=function(n){var t=this,e=d(t),r=function(n){x(e,Y,n)},o=function(n){x(e,U,n)},i=s(l)(n,function(n){t.resolve(n).then(r,o)});return i===nn?t.reject(i.e):e},rn.all=function(n){function t(n){x(o,U,n)}var e,r=this,o=d(r),i=[];return(e=s(l)(n,function(n,u){r.resolve(n).then(function(n){i[u]=n,--e||x(o,Y,i)},t)}))===nn?r.reject(e.e):(e||x(o,Y,[]),o)},rn.Symbol=O[q]||{},s(function(){Object.defineProperty(rn,e(),{get:function(){return this}})})(),rn.speciesConstructor=function(n,t){var r=n.constructor;return r?r[e()]||t:t},rn.unhandledRejection=function(n,t){I&&I.error("Uncaught (in promise)",L?t.longStack:j(n,t))},rn.rejectionHandled=tn,rn.enableLongStackTrace=function(){L=!0},rn.nextTick=F?function(n){E?new E(function(n){n()}).then(n):setTimeout(n)}:H.nextTick,rn._s=1;var on=a(999,function(n,t){var e,r;return(r=n._s!==U?t._onFulfilled:Line truncated
|
||||
|
||||
if (window.jQuery) {
|
||||
jQuery.fn.cropme = function (options = {}, obj) {
|
||||
if (typeof options === 'object') {
|
||||
return this.each(function () {
|
||||
var cropme = new Cropme(this, options)
|
||||
$(this).data('cropme', cropme)
|
||||
})
|
||||
} else if (typeof options === 'string') {
|
||||
var cropme = $(this).data('cropme');
|
||||
switch (options) {
|
||||
case 'position':
|
||||
return cropme.position();
|
||||
case 'bind':
|
||||
return cropme.bind(obj);
|
||||
case 'crop':
|
||||
return cropme.crop(obj);
|
||||
case 'rotate':
|
||||
return cropme.rotate(obj);
|
||||
case 'reload':
|
||||
return cropme.reload(obj);
|
||||
case 'destroy':
|
||||
return cropme.destroy();
|
||||
default:
|
||||
throw 'Error: ' + options + ' method not found';
|
||||
}
|
||||
} else {
|
||||
throw 'Error: the argument must be an object or a string'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function transform() {
|
||||
return 'translate3d(' + this.properties.x + 'px,' + this.properties.y + 'px, 0) scale(' + this.properties.scale + ') rotate(' + this.properties.deg + 'deg)'
|
||||
}
|
||||
|
||||
function transformOrigin(x, y) {
|
||||
return x + 'px ' + y + 'px'
|
||||
}
|
||||
|
||||
function createRotationSlider() {
|
||||
if (this.properties.rotation_slider) {
|
||||
if (!this.options.rotation.slider) {
|
||||
this.properties.wrapper.removeChild(this.properties.rotation_slider.parentNode)
|
||||
delete this.properties.rotation_slider
|
||||
} else {
|
||||
this.properties.rotation_slider.disabled = !this.options.rotation.enable
|
||||
}
|
||||
if(this.properties.rotation_slider){
|
||||
this.properties.rotation_slider.style.width = this.properties.container.offsetWidth + 'px'
|
||||
}
|
||||
} else {
|
||||
if (this.options.rotation.slider) {
|
||||
const sliderContainer = document.createElement('div')
|
||||
sliderContainer.classList.add('cropme-rotation-slider')
|
||||
const slider = this.properties.rotation_slider = document.createElement('input')
|
||||
slider.type = 'range'
|
||||
slider.setAttribute('min', -180)
|
||||
slider.setAttribute('max', 180)
|
||||
slider.setAttribute('step', 1)
|
||||
slider.value = 0
|
||||
|
||||
slider.style.width = this.properties.container.offsetWidth + 'px'
|
||||
sliderContainer.appendChild(slider)
|
||||
this.properties.wrapper.appendChild(sliderContainer)
|
||||
let self = this
|
||||
this.properties.rotation_slider.addEventListener(detectIE() ? 'change' : 'input', function (e) {
|
||||
self.rotate(e.target.value)
|
||||
})
|
||||
this.properties.rotation_slider.disabled = !this.options.rotation.enable
|
||||
}
|
||||
}
|
||||
}
|
||||
function detectIE() {
|
||||
var ua = window.navigator.userAgent;
|
||||
|
||||
var msie = ua.indexOf('MSIE ');
|
||||
if (msie > 0) {
|
||||
// IE 10 or older => return version number
|
||||
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
||||
}
|
||||
|
||||
var trident = ua.indexOf('Trident/');
|
||||
if (trident > 0) {
|
||||
// IE 11 => return version number
|
||||
var rv = ua.indexOf('rv:');
|
||||
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
||||
}
|
||||
|
||||
var edge = ua.indexOf('Edge/');
|
||||
if (edge > 0) {
|
||||
// Edge (IE 12+) => return version number
|
||||
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
||||
}
|
||||
|
||||
// other browser
|
||||
return false;
|
||||
}
|
||||
|
||||
function createSlider() {
|
||||
function changeSliderParameter() {
|
||||
let diff = (this.properties.wrapper.offsetWidth - this.properties.container.offsetWidth) / 2
|
||||
let positionX = this.properties.container.offsetWidth / 2 + 12 + diff
|
||||
if (this.options.rotation.position === 'left') {
|
||||
positionX = -this.properties.container.offsetWidth / 2 - 20 + diff
|
||||
}
|
||||
let diffH = (this.properties.container.offsetWidth - this.properties.container.offsetHeight) / 2
|
||||
const positionY = this.properties.container.offsetHeight / 2 + 12 - diffH
|
||||
this.properties.sliderContainer.style.transform = 'translate3d(' + positionX + 'px, ' + positionY + 'px, 0) rotate(-90deg)'
|
||||
let sliderOrigin = this.properties.container.offsetWidth / 2
|
||||
this.properties.sliderContainer.style.transformOrigin = sliderOrigin + 'px 12px'
|
||||
|
||||
this.properties.sliderContainer.style.marginTop = '-24px'
|
||||
this.properties.slider.disabled = !this.options.zoom.enable
|
||||
}
|
||||
if (this.properties.slider) {
|
||||
if (!this.options.zoom.slider) {
|
||||
this.properties.wrapper.removeChild(this.properties.slider.parentNode)
|
||||
delete this.properties.slider
|
||||
} else {
|
||||
changeSliderParameter.call(this)
|
||||
}
|
||||
} else {
|
||||
if (this.options.zoom.slider) {
|
||||
let self = this
|
||||
const sliderContainer = this.properties.sliderContainer = document.createElement('div')
|
||||
sliderContainer.classList.add('cropme-slider')
|
||||
const slider = this.properties.slider = document.createElement('input')
|
||||
slider.type = 'range'
|
||||
|
||||
slider.setAttribute('min', this.options.zoom.min)
|
||||
slider.setAttribute('max', this.options.zoom.max)
|
||||
slider.setAttribute('step', 0.000001)
|
||||
slider.style.width = this.properties.container.offsetHeight + 'px'
|
||||
sliderContainer.style.width = this.properties.container.offsetHeight + 'px'
|
||||
|
||||
sliderContainer.appendChild(slider)
|
||||
this.properties.wrapper.insertBefore(sliderContainer, this.properties.wrapper.firstChild)
|
||||
this.properties.slider.value = this.properties.scale
|
||||
this.properties.slider.addEventListener(detectIE() ? 'change' : 'input', function (e) {
|
||||
self.properties.scale = parseFloat(e.target.value)
|
||||
self.properties.image.style.transform = transform.call(self)
|
||||
})
|
||||
changeSliderParameter.call(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createContainer() {
|
||||
let container = this.properties.container
|
||||
|
||||
if (!container) {
|
||||
container = this.properties.container = document.createElement('div')
|
||||
this.properties.wrapper.appendChild(container)
|
||||
}
|
||||
container.classList.add('cropme-container')
|
||||
container.style.width = this.options.container.width + (typeof this.options.container.width === 'string' ? '' : 'px')
|
||||
container.style.height = this.options.container.height + 'px'
|
||||
}
|
||||
|
||||
function createImage() {
|
||||
if (!this.properties.image) {
|
||||
this.properties.image = new Image()
|
||||
}
|
||||
this.properties.image.ondragstart = () => false
|
||||
this.properties.container.appendChild(this.properties.image)
|
||||
}
|
||||
|
||||
function createViewport() {
|
||||
|
||||
const viewport = this.properties.viewport = this.properties.viewport || document.createElement('div')
|
||||
const container = this.properties.container
|
||||
const options = this.options
|
||||
|
||||
|
||||
const border_width = options.viewport.border.width
|
||||
container.style.width = options.viewport.width > container.offsetWidth ? (options.viewport.width + border_width * 2) + "px" : container.offsetWidth
|
||||
container.style.height = options.viewport.height > container.offsetHeight ? (options.viewport.height + border_width * 2) + "px" : container.offsetHeight
|
||||
viewport.style.width = options.viewport.width + 'px'
|
||||
viewport.style.height = options.viewport.height + 'px'
|
||||
|
||||
viewport.className = 'viewport'
|
||||
if (options.viewport.type === 'circle') {
|
||||
viewport.className = 'viewport circle'
|
||||
}
|
||||
|
||||
if (options.viewport.border.enable) {
|
||||
let viewport_border = (container.offsetWidth - options.viewport.width) / 2
|
||||
options.viewport.border.width = viewport_border < options.viewport.border.width ? viewport_border : options.viewport.border.width
|
||||
} else {
|
||||
options.viewport.border.width = 0
|
||||
}
|
||||
|
||||
this.properties.viewport.style.borderWidth = options.viewport.border.width + 'px'
|
||||
this.properties.viewport.style.borderColor = options.viewport.border.color
|
||||
this.properties.container.appendChild(viewport)
|
||||
}
|
||||
|
||||
function getOrigin() {
|
||||
const origin = this.properties.image.style.transformOrigin.split('px ')
|
||||
return {
|
||||
x: parseFloat(origin[0]),
|
||||
y: parseFloat(origin[1])
|
||||
}
|
||||
}
|
||||
|
||||
function setRotationOrigin() {
|
||||
let origin = getOrigin.call(this)
|
||||
let ox = origin.x
|
||||
let oy = origin.y
|
||||
let angle = -parseInt(this.properties.deg) * Math.PI / 180
|
||||
if (this.options.transformOrigin === 'viewport') {
|
||||
let deg = this.properties.deg
|
||||
this.properties.deg = 0
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
let scale = this.properties.scale,
|
||||
container = this.properties.container,
|
||||
imageData = this.properties.image.getBoundingClientRect(),
|
||||
viewportData = this.properties.viewport.getBoundingClientRect(),
|
||||
top = (viewportData.top - imageData.top) + (viewportData.height / 2),
|
||||
left = (viewportData.left - imageData.left) + (viewportData.width / 2),
|
||||
cx,
|
||||
cy
|
||||
|
||||
let bx = left / scale
|
||||
let by = top / scale
|
||||
|
||||
let npx = (bx - ox)
|
||||
let npy = (by - oy)
|
||||
|
||||
let x = npx * Math.cos(angle) - npy * Math.sin(angle)
|
||||
let y = npx * Math.sin(angle) + npy * Math.cos(angle)
|
||||
cx = ox + x
|
||||
cy = oy + y
|
||||
|
||||
this.properties.x = container.offsetWidth / 2 - cx
|
||||
this.properties.y = container.offsetHeight / 2 - cy
|
||||
this.properties.image.style.transformOrigin = transformOrigin.call(this, cx, cy)
|
||||
this.properties.deg = deg
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
} else {
|
||||
this.properties.x -= this.properties.origin_x - ox
|
||||
this.properties.y -= this.properties.origin_y - oy
|
||||
this.properties.image.style.transformOrigin = transformOrigin.call(this, this.properties.origin_x, this.properties.origin_y)
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
function createContext() {
|
||||
createContainer.call(this)
|
||||
createRotationSlider.call(this)
|
||||
createSlider.call(this)
|
||||
createImage.call(this)
|
||||
createViewport.call(this)
|
||||
|
||||
let x, y, moveX = 0,
|
||||
moveY = 0,
|
||||
self = this
|
||||
|
||||
let down = function (e) {
|
||||
e.preventDefault()
|
||||
let pageX = e.pageX
|
||||
let pageY = e.pageY
|
||||
if (e.touches) {
|
||||
pageX = e.touches[0].pageX
|
||||
pageY = e.touches[0].pageY
|
||||
}
|
||||
moveX = self.properties.x || moveX
|
||||
moveY = self.properties.y || moveY
|
||||
x = pageX - moveX
|
||||
y = pageY - moveY
|
||||
|
||||
document.addEventListener('mousemove', move)
|
||||
document.addEventListener('touchmove', move)
|
||||
document.addEventListener('mouseup', up)
|
||||
document.addEventListener('touchend', up)
|
||||
}
|
||||
self.properties.image.addEventListener('mousedown', down)
|
||||
self.properties.image.addEventListener('touchstart', down)
|
||||
|
||||
let move = function (e) {
|
||||
e.preventDefault()
|
||||
let pageX = e.pageX
|
||||
let pageY = e.pageY
|
||||
if (e.touches) {
|
||||
pageX = e.touches[0].pageX
|
||||
pageY = e.touches[0].pageY
|
||||
}
|
||||
if (e.touches && e.touches.length > 1) {
|
||||
let second_touches = e.touches[1]
|
||||
let x = pageX - second_touches.pageX
|
||||
let y = pageY - second_touches.pageY
|
||||
|
||||
if (self.options.rotation.enable) {
|
||||
let deg = 90 - Math.atan2(x, y) * 180 / Math.PI
|
||||
if (!self.properties.odeg) {
|
||||
self.properties.odeg = deg - self.properties.deg
|
||||
}
|
||||
self.properties.deg = deg - self.properties.odeg
|
||||
}
|
||||
|
||||
if (self.options.zoom.enable) {
|
||||
let touches_dist = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
|
||||
if (!self.properties.od) {
|
||||
self.properties.od = touches_dist / self.properties.scale
|
||||
}
|
||||
self.properties.scale = touches_dist / self.properties.od
|
||||
if(self.properties.slider) {
|
||||
self.properties.slider.value = self.properties.scale
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.properties.x = pageX - x
|
||||
self.properties.y = pageY - y
|
||||
}
|
||||
self.properties.image.style.transform = transform.call(self)
|
||||
}
|
||||
|
||||
let up = function () {
|
||||
document.removeEventListener('touchmove', move)
|
||||
document.removeEventListener('mousemove', move)
|
||||
document.removeEventListener('mouseup', up)
|
||||
document.removeEventListener('touchend', up)
|
||||
self.properties.od = 0
|
||||
self.properties.odeg = 0
|
||||
setRotationOrigin.call(self)
|
||||
}
|
||||
|
||||
let mousewheel = function (e) {
|
||||
e.preventDefault()
|
||||
let scale = self.properties.scale + (e.wheelDelta / 1200 * self.properties.scale)
|
||||
if (scale > self.options.zoom.min && scale < self.options.zoom.max && self.options.zoom.mouseWheel && self.options.zoom.enable) {
|
||||
if (self.options.zoom.slider) {
|
||||
self.properties.slider.value = scale
|
||||
}
|
||||
self.properties.scale = scale
|
||||
self.properties.image.style.transform = transform.call(self)
|
||||
}
|
||||
}
|
||||
self.properties.container.addEventListener('mousewheel', mousewheel)
|
||||
}
|
||||
|
||||
function createCanvas(options) {
|
||||
let canvas = document.createElement('canvas'),
|
||||
ctx = canvas.getContext('2d')
|
||||
|
||||
let width = this.options.viewport.width
|
||||
let height = this.options.viewport.height
|
||||
|
||||
if (typeof options === 'object') {
|
||||
if (options.scale) {
|
||||
width = width * options.scale
|
||||
height = height * options.scale
|
||||
} else if (options.width) {
|
||||
height = options.width * height / width
|
||||
width = options.width
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
|
||||
const xs = width / this.options.viewport.width
|
||||
const ys = height / this.options.viewport.height
|
||||
|
||||
const deg = this.properties.deg
|
||||
const nx = this.properties.x
|
||||
const ny = this.properties.y
|
||||
|
||||
function transformImage(deg, ox, oy) {
|
||||
this.properties.deg = deg
|
||||
this.properties.x = ox
|
||||
this.properties.y = oy
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
}
|
||||
|
||||
transformImage.call(this, 0, this.properties.ox, this.properties.oy)
|
||||
|
||||
const imageData = this.properties.image.getBoundingClientRect()
|
||||
const viewportData = this.properties.viewport.getBoundingClientRect()
|
||||
const x = xs * (imageData.left - viewportData.left - this.options.viewport.border.width)
|
||||
const y = ys * (imageData.top - viewportData.top - this.options.viewport.border.width)
|
||||
const image_origin_rotation = this.options.transformOrigin
|
||||
|
||||
const tx = (nx - this.properties.x) * xs
|
||||
const ty = (ny - this.properties.y) * ys
|
||||
|
||||
if (image_origin_rotation === 'image') {
|
||||
ctx.translate(tx, ty)
|
||||
}
|
||||
ctx.translate(width / 2, height / 2)
|
||||
ctx.rotate(deg * Math.PI / 180)
|
||||
|
||||
if (image_origin_rotation === 'image') {
|
||||
ctx.translate(-width / 2, -height / 2)
|
||||
} else {
|
||||
ctx.translate(-width / 2 + tx, -height / 2 + ty)
|
||||
}
|
||||
|
||||
ctx.drawImage(this.properties.image, x, y, imageData.width * xs, imageData.height * ys)
|
||||
|
||||
if (this.options.viewport.type === 'circle') {
|
||||
if (image_origin_rotation === 'image') {
|
||||
ctx.translate(width / 2, height / 2)
|
||||
} else {
|
||||
ctx.translate(width / 2 - tx, height / 2 - ty)
|
||||
}
|
||||
ctx.rotate(-deg * Math.PI / 180)
|
||||
ctx.translate(-width / 2, -height / 2)
|
||||
ctx.scale(1, this.options.viewport.height / this.options.viewport.width)
|
||||
if (image_origin_rotation === 'image') {
|
||||
ctx.translate(-tx * 2, -ty * 2)
|
||||
} else {
|
||||
ctx.translate(-tx, -ty)
|
||||
}
|
||||
ctx.globalCompositeOperation = 'destination-in'
|
||||
ctx.arc(width / 2 + tx, height / 2 + ty, width / 2, 0, 2 * Math.PI)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
transformImage.call(this, deg, nx, ny)
|
||||
return canvas
|
||||
}
|
||||
|
||||
|
||||
class Cropme {
|
||||
constructor(el, options) {
|
||||
if (el.className.indexOf('cropme-wrapper') > -1) {
|
||||
throw 'Error: Cropme is already initialized'
|
||||
}
|
||||
this.properties = {}
|
||||
this.options = nestedObjectAssign(defaultOptions, options)
|
||||
if (this.options.viewport.width > this.options.container.width) {
|
||||
throw 'Error: Viewport width cannot be greater that container width'
|
||||
}
|
||||
if (this.options.viewport.height > this.options.container.height) {
|
||||
throw 'Error: Viewport height cannot be greater that container height'
|
||||
}
|
||||
this.properties.wrapper = el
|
||||
if (el.tagName.toLowerCase() === 'img') {
|
||||
this.properties.image = el
|
||||
this.properties.wrapper = document.createElement('div')
|
||||
el.parentNode.insertBefore(this.properties.wrapper, el.previousSibling)
|
||||
el.parentNode.removeChild(el)
|
||||
}
|
||||
this.properties.wrapper.className += ' cropme-wrapper ' + this.options.customClass
|
||||
createContext.call(this)
|
||||
|
||||
if (this.properties.image.src) {
|
||||
this.bind({
|
||||
url: this.properties.image.src
|
||||
})
|
||||
}
|
||||
}
|
||||
resize() {
|
||||
const container = this.properties.container
|
||||
let newW = this.properties.container_w - container.offsetWidth
|
||||
let newH = this.properties.container_h - container.offsetHeight
|
||||
container.style.width = this.options.container.width + (typeof this.options.container.width === 'string' ? '' : 'px')
|
||||
|
||||
if (container.offsetWidth > this.options.viewport.width) {
|
||||
this.properties.x -= newW / 2
|
||||
this.properties.y -= newH / 2
|
||||
|
||||
this.properties.container_w = container.offsetWidth
|
||||
this.properties.container_h = container.offsetHeight
|
||||
|
||||
this.properties.ox -= newW / 2
|
||||
this.properties.oy -= newH / 2
|
||||
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
createSlider.call(this)
|
||||
createRotationSlider.call(this)
|
||||
} else {
|
||||
container.style.width = (this.options.viewport.width + this.options.viewport.border.width * 2) + 'px'
|
||||
}
|
||||
|
||||
}
|
||||
bind(obj) {
|
||||
window.onresize = this.resize.bind(this)
|
||||
this.properties.image.src = obj.url
|
||||
let properties = this.properties
|
||||
let options = this.options
|
||||
let self = this
|
||||
return new Promise(resolve => {
|
||||
this.properties.image.onload = function () {
|
||||
|
||||
let imageData = properties.image.getBoundingClientRect()
|
||||
let containerData = properties.container.getBoundingClientRect()
|
||||
|
||||
let cx = (containerData.width - imageData.width) / 2
|
||||
let cy = (containerData.height - imageData.height) / 2
|
||||
let scale = containerData.height / imageData.height
|
||||
let deg = 0
|
||||
properties.ox = cx
|
||||
properties.oy = cy
|
||||
let origin = {}
|
||||
|
||||
if (typeof obj.position === 'object') {
|
||||
cx = obj.position.x ? obj.position.x + cx : cx
|
||||
cy = obj.position.y ? obj.position.y + cy : cy
|
||||
scale = obj.position.scale || scale
|
||||
deg = obj.position.angle || deg
|
||||
origin = obj.position.origin || origin
|
||||
options.transformOrigin = obj.position.origin === 'object' ? 'viewport' : 'image'
|
||||
}
|
||||
|
||||
if (options.zoom.max <= options.zoom.min) {
|
||||
throw 'Error: max zoom cannot be less or equal to min zoom'
|
||||
}
|
||||
|
||||
if (scale < options.zoom.min) {
|
||||
scale = options.zoom.min
|
||||
}
|
||||
if (scale > options.zoom.max) {
|
||||
scale = options.zoom.max
|
||||
}
|
||||
|
||||
properties.x = cx
|
||||
properties.y = cy
|
||||
|
||||
properties.container_w = containerData.width
|
||||
properties.container_h = containerData.height
|
||||
properties.origin_x = imageData.width / 2
|
||||
properties.origin_y = imageData.height / 2
|
||||
|
||||
properties.scale = scale
|
||||
if (self.options.zoom.slider) {
|
||||
properties.slider.value = scale
|
||||
}
|
||||
if (self.options.rotation.slider) {
|
||||
properties.rotation_slider.value = deg
|
||||
}
|
||||
properties.deg = deg
|
||||
properties.image.style.transform = transform.call(self)
|
||||
|
||||
properties.image.style.transformOrigin = transformOrigin.call(self, origin.x || properties.origin_x, origin.y || properties.origin_y)
|
||||
properties.image.style.opacity = 1
|
||||
setRotationOrigin.call(self)
|
||||
resolve(self.properties.image)
|
||||
}
|
||||
})
|
||||
}
|
||||
rotate(deg) {
|
||||
this.properties.deg = deg
|
||||
let origin = this.properties.image.style.transformOrigin.split('px ')
|
||||
let ox = parseInt(origin[0])
|
||||
let oy = parseInt(origin[1])
|
||||
this.properties.rotate_originx = ox
|
||||
this.properties.rotate_originy = oy
|
||||
this.properties.image.style.transform = transform.call(this)
|
||||
}
|
||||
crop(options) {
|
||||
const canvas = createCanvas.call(this, options)
|
||||
const output = (typeof options === 'object') ? options.type : options
|
||||
return new Promise(resolve => {
|
||||
if (output === 'blob') {
|
||||
canvas.toBlob(
|
||||
blob => resolve(URL.createObjectURL(blob)),
|
||||
options.mimetype,
|
||||
options.quality
|
||||
)
|
||||
} else {
|
||||
if (typeof options === 'object') {
|
||||
resolve(canvas.toDataURL(options.mimetype, options.quality))
|
||||
} else {
|
||||
resolve(canvas.toDataURL())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
position() {
|
||||
let position = {
|
||||
x: parseFloat((this.properties.x - this.properties.ox).toFixed(3)),
|
||||
y: parseFloat((this.properties.y - this.properties.oy).toFixed(3)),
|
||||
scale: parseFloat(this.properties.scale.toFixed(4)),
|
||||
angle: parseInt(this.properties.deg),
|
||||
}
|
||||
if (this.options.transformOrigin === 'viewport') {
|
||||
position.origin = getOrigin.call(this)
|
||||
}
|
||||
return position
|
||||
}
|
||||
reload(options) {
|
||||
this.options = nestedObjectAssign(defaultOptions, options)
|
||||
createSlider.call(this)
|
||||
createContainer.call(this)
|
||||
createRotationSlider.call(this)
|
||||
createViewport.call(this)
|
||||
setRotationOrigin.call(this)
|
||||
}
|
||||
destroy() {
|
||||
this.properties.wrapper.innerHTML = ''
|
||||
this.properties.wrapper.className = this.properties.wrapper.className.replace('cropme-wrapper', '')
|
||||
delete this.options
|
||||
delete this.properties
|
||||
}
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
container: {
|
||||
width: 300,
|
||||
height: 300,
|
||||
},
|
||||
viewport: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
border: {
|
||||
enable: true,
|
||||
width: 2,
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
transformOrigin: 'viewport',
|
||||
zoom: {
|
||||
min: 0.01,
|
||||
max: 3,
|
||||
enable: true,
|
||||
mouseWheel: true,
|
||||
slider: false
|
||||
},
|
||||
customClass: '',
|
||||
rotation: {
|
||||
slider: false,
|
||||
enable: true,
|
||||
position: 'right'
|
||||
}
|
||||
}
|
||||
export default Cropme
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
.cropme-wrapper
|
||||
width: 100%
|
||||
height: 100%
|
||||
.cropme-container
|
||||
position: relative
|
||||
overflow: hidden
|
||||
margin: 0 auto
|
||||
img
|
||||
width: initial !important
|
||||
cursor: move
|
||||
opacity: 0
|
||||
touch-action: none
|
||||
#img
|
||||
border: 5px solid #f00
|
||||
|
||||
.viewport
|
||||
box-sizing: content-box !important
|
||||
position: absolute
|
||||
border-style: solid
|
||||
margin: auto
|
||||
top: 0
|
||||
bottom: 0
|
||||
right: 0
|
||||
left: 0
|
||||
box-shadow: 0 0 2000px 2000px rgba(0, 0, 0, 0.5)
|
||||
z-index: 0
|
||||
pointer-events: none
|
||||
&.circle
|
||||
border-radius: 50%
|
||||
|
||||
.cropme-slider,.cropme-rotation-slider
|
||||
text-align: center
|
||||
input
|
||||
-webkit-appearance: none
|
||||
&:disabled
|
||||
opacity: 0.5
|
||||
&::-webkit-slider-runnable-track
|
||||
height: 3px
|
||||
background: rgba(0, 0, 0, 0.5)
|
||||
border-radius: 3px
|
||||
&::-webkit-slider-thumb
|
||||
-webkit-appearance: none
|
||||
height: 16px
|
||||
width: 16px
|
||||
border-radius: 50%
|
||||
background: #ddd
|
||||
margin-top: -6px
|
||||
&:focus
|
||||
outline: none
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import Cropme from './cropme'
|
||||
|
||||
export default Cropme
|
||||
Reference in new issue
Block a user