vue-croppa
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -1,1 +0,479 @@ | ||
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):t.Croppa=i()}(this,function(){"use strict";var t={getPointerCoords:function(t,i){var e=i.canvas,a=i.quality,n=e.getBoundingClientRect(),h=t.touches?t.touches[0].clientX:t.clientX,o=t.touches?t.touches[0].clientY:t.clientY;return{x:(h-n.left)*a,y:(o-n.top)*a}}};Number.isInteger=Number.isInteger||function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t};var i={render:function(){var t=this,i=t.$createElement,e=t._self._c||i;return e("div",{class:"croppa-container "+(t.img?"croppa--has-target":"")+" "+(t.disabled?"croppa--disabled":"")},[e("input",{ref:"fileInput",attrs:{type:"file",accept:t.inputAccept,disabled:t.disabled,hidden:""},on:{change:t.handleInputChange}}),e("canvas",{ref:"canvas",on:{click:function(i){!t.disabled&&t.chooseFile()},touchstart:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerStart(i)},mousedown:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerStart(i)},pointerstart:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerStart(i)},touchend:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerEnd(i)},touchcancel:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerEnd(i)},mouseup:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerEnd(i)},pointerend:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerEnd(i)},pointercancel:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerEnd(i)},touchmove:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerMove(i)},mousemove:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerMove(i)},pointermove:function(i){i.stopPropagation(),i.preventDefault(),t.handlePointerMove(i)},DOMMouseScroll:function(i){i.stopPropagation(),i.preventDefault(),t.handleWheel(i)},mousewheel:function(i){i.stopPropagation(),i.preventDefault(),t.handleWheel(i)}}}),t.showRemoveButton&&t.img?e("svg",{staticClass:"icon icon-remove",style:"top: -"+t.height/40+"px; right: -"+t.width/40+"px",attrs:{viewBox:"0 0 1024 1024",version:"1.1",xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink",width:t.removeButtonSize||t.width/10,height:t.removeButtonSize||t.width/10},on:{click:t.unset}},[e("path",{attrs:{d:"M511.921231 0C229.179077 0 0 229.257846 0 512 0 794.702769 229.179077 1024 511.921231 1024 794.781538 1024 1024 794.702769 1024 512 1024 229.257846 794.781538 0 511.921231 0ZM732.041846 650.633846 650.515692 732.081231C650.515692 732.081231 521.491692 593.683692 511.881846 593.683692 502.429538 593.683692 373.366154 732.081231 373.366154 732.081231L291.761231 650.633846C291.761231 650.633846 430.316308 523.500308 430.316308 512.196923 430.316308 500.696615 291.761231 373.523692 291.761231 373.523692L373.366154 291.918769C373.366154 291.918769 503.453538 430.395077 511.881846 430.395077 520.349538 430.395077 650.515692 291.918769 650.515692 291.918769L732.041846 373.523692C732.041846 373.523692 593.447385 502.547692 593.447385 512.196923 593.447385 521.412923 732.041846 650.633846 732.041846 650.633846Z",fill:t.removeButtonColor}})]):t._e()])},staticRenderFns:[],model:{prop:"value",event:"init"},props:{value:Object,width:{type:Number,default:200,validator:function(t){return t>0}},height:{type:Number,default:200,validator:function(t){return t>0}},placeholder:{type:String,default:"Choose File"},placeholderColor:{default:"#606060"},placeholderFontSize:{type:Number,default:0,validator:function(t){return t>=0}},canvasColor:{default:"#e6e6e6"},quality:{type:Number,default:2,validator:function(t){return Number.isInteger(t)&&t>0&&t<=5}},zoomSpeed:{default:3,type:Number,validator:function(t){return t>0}},inputAccept:{type:String,default:"image/*"},fileSizeLimit:{type:Number,default:0,validator:function(t){return t>=0}},disabled:Boolean,reverseZoomingGesture:Boolean,preventWhiteSpace:Boolean,showRemoveButton:{type:Boolean,default:!0},removeButtonColor:{type:String,default:"red"},removeButtonSize:{type:Number}},data:function(){return{instance:null,canvas:null,ctx:null,img:null,dragging:!1,lastMovingCoord:null,imgData:{},dataUrl:""}},computed:{realWidth:function(){return this.width*this.quality},realHeight:function(){return this.height*this.quality}},mounted:function(){this.init()},watch:{value:function(t){this.instance=t},realWidth:"init",realHeight:"init",canvasColor:"init",placeholder:"init",placeholderColor:"init",placeholderFontSize:"init",preventWhiteSpace:"imgContentInit"},methods:{init:function(){var t=this;this.canvas=this.$refs.canvas,this.canvas.width=this.realWidth,this.canvas.height=this.realHeight,this.canvas.style.width=this.width+"px",this.canvas.style.height=this.height+"px",this.ctx=this.canvas.getContext("2d"),this.unset(),this.$emit("init",{getCanvas:function(){return t.canvas},getContext:function(){return t.ctx},getChosenFile:function(){return t.$refs.fileInput.files[0]},getImage:function(){return t.img},getActuallImageSize:function(){return{width:t.realWidth,height:t.realHeight}},moveUpwards:function(i){t.move({x:0,y:-i})},moveDownwards:function(i){t.move({x:0,y:i})},moveLeftwards:function(i){t.move({x:-i,y:0})},moveRightwards:function(i){t.move({x:i,y:0})},zoomIn:function(){t.zoom(!0,{x:t.imgData.startX+t.imgData.width/2,y:t.imgData.startY+t.imgData.height/2})},zoomOut:function(){t.zoom(!1,{x:t.imgData.startX+t.imgData.width/2,y:t.imgData.startY+t.imgData.height/2})},reset:this.unset,chooseFile:this.chooseFile,generateDataUrl:this.generateDataUrl})},unset:function(){var t=this.ctx;t.clearRect(0,0,this.realWidth,this.realHeight),this.paintBackground(),t.textBaseline="middle",t.textAlign="center";var i=this.realWidth/1.5/this.placeholder.length,e=this.placeholderFontSize&&0!=this.placeholderFontSize?this.placeholderFontSize:i;t.font=e+"px sans-serif",t.fillStyle=this.placeholderColor&&"default"!=this.placeholderColor?this.placeholderColor:"#606060",t.fillText(this.placeholder,this.realWidth/2,this.realHeight/2),this.img=null,this.$refs.fileInput.value="",this.imgData={}},chooseFile:function(){this.img||this.$refs.fileInput.click()},handleInputChange:function(){var t=this,i=this.$refs.fileInput;if(i.files.length){var e=i.files[0];if(this.$emit("file-choose",e),!this.fileSizeIsValid(e))throw this.$emit("file-size-exceed",e),new Error("File size exceeds limit which is "+this.fileSizeLimit+" bytes.");var a=new FileReader;a.onload=function(i){var e=i.target.result,a=new Image;a.src=e,a.onload=function(){t.img=a,t.imgContentInit()}},a.readAsDataURL(e)}},fileSizeIsValid:function(t){return!!t&&(!this.fileSizeLimit||t.size<this.fileSizeLimit)},imgContentInit:function(){this.imgData.startX=0,this.imgData.startY=0;var t=this.img.naturalWidth,i=this.img.naturalHeight;if(i/t<this.realHeight/this.realWidth){var e=i/this.realHeight;this.imgData.width=t/e,this.imgData.startX=-(this.imgData.width-this.realWidth)/2,this.imgData.height=this.realHeight}else{var a=t/this.realWidth;this.imgData.height=i/a,this.imgData.startY=-(this.imgData.height-this.realHeight)/2,this.imgData.width=this.realWidth}this.draw()},handlePointerStart:function(t){if(!this.disabled&&!(t.which&&t.which>1)&&(this.dragging=!0,document)){var i=["mouseup","touchend","touchcancel","pointerend","pointercancel"],e=!0,a=!1,n=void 0;try{for(var h,o=i[Symbol.iterator]();!(e=(h=o.next()).done);e=!0){var r=h.value;document.addEventListener(r,this.handlePointerEnd)}}catch(t){a=!0,n=t}finally{try{!e&&o.return&&o.return()}finally{if(a)throw n}}}},handlePointerEnd:function(t){this.disabled||(this.dragging=!1,this.lastMovingCoord=null)},handlePointerMove:function(i){if(!this.disabled&&this.dragging){var e=t.getPointerCoords(i,this);this.lastMovingCoord&&this.move({x:e.x-this.lastMovingCoord.x,y:e.y-this.lastMovingCoord.y}),this.lastMovingCoord=e}},handleWheel:function(i){if(!this.disabled){var e=t.getPointerCoords(i,this);i.wheelDelta<0||i.detail<0?this.zoom(this.reverseZoomingGesture,e):(i.wheelDelta>0||i.detail>0)&&this.zoom(!this.reverseZoomingGesture,e)}},move:function(t){t&&(this.imgData.startX+=t.x,this.imgData.startY+=t.y,this.preventWhiteSpace&&this.preventMovingToWhiteSpace(),this.$emit("move"),this.draw())},preventMovingToWhiteSpace:function(){this.imgData.startX>0&&(this.imgData.startX=0),this.imgData.startY>0&&(this.imgData.startY=0),this.realWidth-this.imgData.startX>this.imgData.width&&(this.imgData.startX=-(this.imgData.width-this.realWidth)),this.realHeight-this.imgData.startY>this.imgData.height&&(this.imgData.startY=-(this.imgData.height-this.realHeight))},zoom:function(t,i){var e=this.realWidth/1e5*this.zoomSpeed,a=1;t?a=1+e:this.imgData.width>20&&(a=1-e),this.imgData.width=this.imgData.width*a,this.imgData.height=this.imgData.height*a;var n=(a-1)*(i.x-this.imgData.startX),h=(a-1)*(i.y-this.imgData.startY);if(this.imgData.startX=this.imgData.startX-n,this.imgData.startY=this.imgData.startY-h,this.preventWhiteSpace){if(this.imgData.width<this.realWidth){var o=this.realWidth/this.imgData.width;this.imgData.width=this.realWidth,this.imgData.height=this.imgData.height*o}if(this.imgData.height<this.realHeight){var r=this.realHeight/this.imgData.height;this.imgData.height=this.realHeight,this.imgData.width=this.imgData.width*r}this.preventMovingToWhiteSpace()}this.$emit("zoom"),this.draw()},paintBackground:function(){var t=this.canvasColor&&"default"!=this.canvasColor?this.canvasColor:"#e6e6e6";this.ctx.fillStyle=t,this.ctx.fillRect(0,0,this.realWidth,this.realHeight)},draw:function(){var t=this.ctx;if(this.img){var i=this.imgData,e=i.startX,a=i.startY,n=i.width,h=i.height;t.clearRect(0,0,this.realWidth,this.realHeight),this.paintBackground(),t.drawImage(this.img,e,a,n,h)}},generateDataUrl:function(){return this.img?this.canvas.toDataURL():""}}};return{install:function(t,e){t.component("croppa",i)}}}); | ||
/* | ||
* vue-croppa v0.0.3 | ||
* https://github.com/zhanziyang/vue-croppa | ||
* | ||
* Copyright (c) 2017 zhanziyang | ||
* Released under the ISC license | ||
*/ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global.Croppa = factory()); | ||
}(this, (function () { 'use strict'; | ||
var u = { | ||
getPointerCoords: function getPointerCoords(evt, cropperVM) { | ||
var canvas = cropperVM.canvas, | ||
quality = cropperVM.quality; | ||
var rect = canvas.getBoundingClientRect(); | ||
var clientX = evt.touches ? evt.touches[0].clientX : evt.clientX; | ||
var clientY = evt.touches ? evt.touches[0].clientY : evt.clientY; | ||
return { | ||
x: (clientX - rect.left) * quality, | ||
y: (clientY - rect.top) * quality | ||
}; | ||
} | ||
}; | ||
Number.isInteger = Number.isInteger || function (value) { | ||
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value; | ||
}; | ||
var props = { | ||
value: Object, | ||
width: { | ||
type: Number, | ||
default: 200, | ||
validator: function validator(val) { | ||
return val > 0; | ||
} | ||
}, | ||
height: { | ||
type: Number, | ||
default: 200, | ||
validator: function validator(val) { | ||
return val > 0; | ||
} | ||
}, | ||
placeholder: { | ||
type: String, | ||
default: 'Choose File' | ||
}, | ||
placeholderColor: { | ||
default: '#606060' | ||
}, | ||
placeholderFontSize: { | ||
type: Number, | ||
default: 0, | ||
validator: function validator(val) { | ||
return val >= 0; | ||
} | ||
}, | ||
canvasColor: { | ||
default: '#e6e6e6' | ||
}, | ||
quality: { | ||
type: Number, | ||
default: 2, | ||
validator: function validator(val) { | ||
return Number.isInteger(val) && val > 0; | ||
} | ||
}, | ||
zoomSpeed: { | ||
default: 3, | ||
type: Number, | ||
validator: function validator(val) { | ||
return val > 0; | ||
} | ||
}, | ||
accept: { | ||
type: String, | ||
default: 'image/*' | ||
}, | ||
fileSizeLimit: { | ||
type: Number, | ||
default: 0, | ||
validator: function validator(val) { | ||
return val >= 0; | ||
} | ||
}, | ||
disabled: Boolean, | ||
disableClickToChoose: Boolean, | ||
disableDragToMove: Boolean, | ||
disableScrollToZoom: Boolean, | ||
reverseZoomingGesture: Boolean, | ||
preventWhiteSpace: Boolean, | ||
showRemoveButton: { | ||
type: Boolean, | ||
default: true | ||
}, | ||
removeButtonColor: { | ||
type: String, | ||
default: 'red' | ||
}, | ||
removeButtonSize: { | ||
type: Number | ||
} | ||
}; | ||
var INIT_EVENT = 'init'; | ||
var FILE_CHOOSE_EVENT = 'file-choose'; | ||
var FILE_SIZE_EXCEED_EVENT = 'file-size-exceed'; | ||
var MOVE_EVENT = 'move'; | ||
var ZOOM_EVENT = 'zoom'; | ||
var cropper = { render: function render() { | ||
var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('div', { class: 'croppa-container ' + (_vm.img ? 'croppa--has-target' : '') + ' ' + (_vm.disabled ? 'croppa--disabled' : '') + ' ' + (_vm.disableClickToChoose ? 'croppa--disabled-cc' : '') + ' ' + (_vm.disableDragToMove && _vm.disableScrollToZoom ? 'croppa--disabled-mz' : '') }, [_c('input', { ref: "fileInput", attrs: { "type": "file", "accept": _vm.accept, "disabled": _vm.disabled, "hidden": "" }, on: { "change": _vm.handleInputChange } }), _c('canvas', { ref: "canvas", on: { "click": function click($event) { | ||
!_vm.disabled && _vm.chooseFile(); | ||
}, "touchstart": function touchstart($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerStart($event); | ||
}, "mousedown": function mousedown($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerStart($event); | ||
}, "pointerstart": function pointerstart($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerStart($event); | ||
}, "touchend": function touchend($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerEnd($event); | ||
}, "touchcancel": function touchcancel($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerEnd($event); | ||
}, "mouseup": function mouseup($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerEnd($event); | ||
}, "pointerend": function pointerend($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerEnd($event); | ||
}, "pointercancel": function pointercancel($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerEnd($event); | ||
}, "touchmove": function touchmove($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerMove($event); | ||
}, "mousemove": function mousemove($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerMove($event); | ||
}, "pointermove": function pointermove($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handlePointerMove($event); | ||
}, "DOMMouseScroll": function DOMMouseScroll($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handleWheel($event); | ||
}, "mousewheel": function mousewheel($event) { | ||
$event.stopPropagation();$event.preventDefault();_vm.handleWheel($event); | ||
} } }), _vm.showRemoveButton && _vm.img ? _c('svg', { staticClass: "icon icon-remove", style: 'top: -' + _vm.height / 40 + 'px; right: -' + _vm.width / 40 + 'px', attrs: { "viewBox": "0 0 1024 1024", "version": "1.1", "xmlns": "http://www.w3.org/2000/svg", "xmlns:xlink": "http://www.w3.org/1999/xlink", "width": _vm.removeButtonSize || _vm.width / 10, "height": _vm.removeButtonSize || _vm.width / 10 }, on: { "click": _vm.unset } }, [_c('path', { attrs: { "d": "M511.921231 0C229.179077 0 0 229.257846 0 512 0 794.702769 229.179077 1024 511.921231 1024 794.781538 1024 1024 794.702769 1024 512 1024 229.257846 794.781538 0 511.921231 0ZM732.041846 650.633846 650.515692 732.081231C650.515692 732.081231 521.491692 593.683692 511.881846 593.683692 502.429538 593.683692 373.366154 732.081231 373.366154 732.081231L291.761231 650.633846C291.761231 650.633846 430.316308 523.500308 430.316308 512.196923 430.316308 500.696615 291.761231 373.523692 291.761231 373.523692L373.366154 291.918769C373.366154 291.918769 503.453538 430.395077 511.881846 430.395077 520.349538 430.395077 650.515692 291.918769 650.515692 291.918769L732.041846 373.523692C732.041846 373.523692 593.447385 502.547692 593.447385 512.196923 593.447385 521.412923 732.041846 650.633846 732.041846 650.633846Z", "fill": _vm.removeButtonColor } })]) : _vm._e()]); | ||
}, staticRenderFns: [], | ||
model: { | ||
prop: 'value', | ||
event: 'init' | ||
}, | ||
props: props, | ||
data: function data() { | ||
return { | ||
instance: null, | ||
canvas: null, | ||
ctx: null, | ||
img: null, | ||
dragging: false, | ||
lastMovingCoord: null, | ||
imgData: {}, | ||
dataUrl: '' | ||
}; | ||
}, | ||
computed: { | ||
realWidth: function realWidth() { | ||
return this.width * this.quality; | ||
}, | ||
realHeight: function realHeight() { | ||
return this.height * this.quality; | ||
} | ||
}, | ||
mounted: function mounted() { | ||
this.init(); | ||
}, | ||
watch: { | ||
value: function value(val) { | ||
this.instance = val; | ||
}, | ||
realWidth: 'init', | ||
realHeight: 'init', | ||
canvasColor: 'init', | ||
placeholder: 'init', | ||
placeholderColor: 'init', | ||
placeholderFontSize: 'init', | ||
preventWhiteSpace: 'imgContentInit' | ||
}, | ||
methods: { | ||
init: function init() { | ||
var _this = this; | ||
this.canvas = this.$refs.canvas; | ||
this.canvas.width = this.realWidth; | ||
this.canvas.height = this.realHeight; | ||
this.canvas.style.width = this.width + 'px'; | ||
this.canvas.style.height = this.height + 'px'; | ||
this.ctx = this.canvas.getContext('2d'); | ||
this.unset(); | ||
this.$emit(INIT_EVENT, { | ||
getCanvas: function getCanvas() { | ||
return _this.canvas; | ||
}, | ||
getContext: function getContext() { | ||
return _this.ctx; | ||
}, | ||
getChosenFile: function getChosenFile() { | ||
return _this.$refs.fileInput.files[0]; | ||
}, | ||
getActualImageSize: function getActualImageSize() { | ||
return { | ||
width: _this.realWidth, | ||
height: _this.realHeight | ||
}; | ||
}, | ||
moveUpwards: function moveUpwards(amount) { | ||
_this.move({ x: 0, y: -amount }); | ||
}, | ||
moveDownwards: function moveDownwards(amount) { | ||
_this.move({ x: 0, y: amount }); | ||
}, | ||
moveLeftwards: function moveLeftwards(amount) { | ||
_this.move({ x: -amount, y: 0 }); | ||
}, | ||
moveRightwards: function moveRightwards(amount) { | ||
_this.move({ x: amount, y: 0 }); | ||
}, | ||
zoomIn: function zoomIn() { | ||
_this.zoom(true, { | ||
x: _this.imgData.startX + _this.imgData.width / 2, | ||
y: _this.imgData.startY + _this.imgData.height / 2 | ||
}); | ||
}, | ||
zoomOut: function zoomOut() { | ||
_this.zoom(false, { | ||
x: _this.imgData.startX + _this.imgData.width / 2, | ||
y: _this.imgData.startY + _this.imgData.height / 2 | ||
}); | ||
}, | ||
reset: this.unset, | ||
chooseFile: this.chooseFile, | ||
generateDataUrl: this.generateDataUrl, | ||
generateBlob: this.generateBlob | ||
}); | ||
}, | ||
unset: function unset() { | ||
var ctx = this.ctx; | ||
ctx.clearRect(0, 0, this.realWidth, this.realHeight); | ||
this.paintBackground(); | ||
ctx.textBaseline = 'middle'; | ||
ctx.textAlign = 'center'; | ||
var defaultFontSize = this.realWidth / 1.5 / this.placeholder.length; | ||
var fontSize = !this.placeholderFontSize || this.placeholderFontSize == 0 ? defaultFontSize : this.placeholderFontSize; | ||
ctx.font = fontSize + 'px sans-serif'; | ||
ctx.fillStyle = !this.placeholderColor || this.placeholderColor == 'default' ? '#606060' : this.placeholderColor; | ||
ctx.fillText(this.placeholder, this.realWidth / 2, this.realHeight / 2); | ||
this.img = null; | ||
this.$refs.fileInput.value = ''; | ||
this.imgData = {}; | ||
}, | ||
chooseFile: function chooseFile() { | ||
if (this.img || this.disableClickToChoose) return; | ||
this.$refs.fileInput.click(); | ||
}, | ||
handleInputChange: function handleInputChange() { | ||
var _this2 = this; | ||
var input = this.$refs.fileInput; | ||
if (!input.files.length) return; | ||
var file = input.files[0]; | ||
this.$emit(FILE_CHOOSE_EVENT, file); | ||
if (!this.fileSizeIsValid(file)) { | ||
this.$emit(FILE_SIZE_EXCEED_EVENT, file); | ||
throw new Error('File size exceeds limit which is ' + this.fileSizeLimit + ' bytes.'); | ||
} | ||
var fr = new FileReader(); | ||
fr.onload = function (e) { | ||
var fileData = e.target.result; | ||
var img = new Image(); | ||
img.src = fileData; | ||
img.onload = function () { | ||
_this2.img = img; | ||
_this2.imgContentInit(); | ||
}; | ||
}; | ||
fr.readAsDataURL(file); | ||
}, | ||
fileSizeIsValid: function fileSizeIsValid(file) { | ||
if (!file) return false; | ||
if (!this.fileSizeLimit) return true; | ||
return file.size < this.fileSizeLimit; | ||
}, | ||
imgContentInit: function imgContentInit() { | ||
this.imgData.startX = 0; | ||
this.imgData.startY = 0; | ||
var imgWidth = this.img.naturalWidth; | ||
var imgHeight = this.img.naturalHeight; | ||
var imgRatio = imgHeight / imgWidth; | ||
var canvasRatio = this.realHeight / this.realWidth; | ||
// display as fit | ||
if (imgRatio < canvasRatio) { | ||
var ratio = imgHeight / this.realHeight; | ||
this.imgData.width = imgWidth / ratio; | ||
this.imgData.startX = -(this.imgData.width - this.realWidth) / 2; | ||
this.imgData.height = this.realHeight; | ||
} else { | ||
var _ratio = imgWidth / this.realWidth; | ||
this.imgData.height = imgHeight / _ratio; | ||
this.imgData.startY = -(this.imgData.height - this.realHeight) / 2; | ||
this.imgData.width = this.realWidth; | ||
} | ||
this.draw(); | ||
}, | ||
handlePointerStart: function handlePointerStart(evt) { | ||
if (this.disabled) return; | ||
if (evt.which && evt.which > 1) return; | ||
this.dragging = true; | ||
if (document) { | ||
var cancelEvents = ['mouseup', 'touchend', 'touchcancel', 'pointerend', 'pointercancel']; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = cancelEvents[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var e = _step.value; | ||
document.addEventListener(e, this.handlePointerEnd); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
handlePointerEnd: function handlePointerEnd(evt) { | ||
if (this.disabled) return; | ||
this.dragging = false; | ||
this.lastMovingCoord = null; | ||
}, | ||
handlePointerMove: function handlePointerMove(evt) { | ||
if (this.disabled || this.disableDragToMove) return; | ||
if (!this.dragging) return; | ||
var coord = u.getPointerCoords(evt, this); | ||
if (this.lastMovingCoord) { | ||
this.move({ | ||
x: coord.x - this.lastMovingCoord.x, | ||
y: coord.y - this.lastMovingCoord.y | ||
}); | ||
} | ||
this.lastMovingCoord = coord; | ||
}, | ||
handleWheel: function handleWheel(evt) { | ||
if (this.disabled || this.disableScrollToZoom) return; | ||
var coord = u.getPointerCoords(evt, this); | ||
if (evt.wheelDelta < 0 || evt.detail < 0) { | ||
// 手指向上 | ||
this.zoom(this.reverseZoomingGesture, coord); | ||
} else if (evt.wheelDelta > 0 || evt.detail > 0) { | ||
// 手指向下 | ||
this.zoom(!this.reverseZoomingGesture, coord); | ||
} | ||
}, | ||
move: function move(offset) { | ||
if (!offset) return; | ||
this.imgData.startX += offset.x; | ||
this.imgData.startY += offset.y; | ||
if (this.preventWhiteSpace) { | ||
this.preventMovingToWhiteSpace(); | ||
} | ||
this.$emit(MOVE_EVENT); | ||
this.draw(); | ||
}, | ||
preventMovingToWhiteSpace: function preventMovingToWhiteSpace() { | ||
if (this.imgData.startX > 0) { | ||
this.imgData.startX = 0; | ||
} | ||
if (this.imgData.startY > 0) { | ||
this.imgData.startY = 0; | ||
} | ||
if (this.realWidth - this.imgData.startX > this.imgData.width) { | ||
this.imgData.startX = -(this.imgData.width - this.realWidth); | ||
} | ||
if (this.realHeight - this.imgData.startY > this.imgData.height) { | ||
this.imgData.startY = -(this.imgData.height - this.realHeight); | ||
} | ||
}, | ||
zoom: function zoom(zoomIn, pos) { | ||
var speed = this.realWidth / 100000 * this.zoomSpeed; | ||
var x = 1; | ||
if (zoomIn) { | ||
x = 1 + speed; | ||
} else if (this.imgData.width > 20) { | ||
x = 1 - speed; | ||
} | ||
this.imgData.width = this.imgData.width * x; | ||
this.imgData.height = this.imgData.height * x; | ||
var offsetX = (x - 1) * (pos.x - this.imgData.startX); | ||
var offsetY = (x - 1) * (pos.y - this.imgData.startY); | ||
this.imgData.startX = this.imgData.startX - offsetX; | ||
this.imgData.startY = this.imgData.startY - offsetY; | ||
if (this.preventWhiteSpace) { | ||
if (this.imgData.width < this.realWidth) { | ||
var _x = this.realWidth / this.imgData.width; | ||
this.imgData.width = this.realWidth; | ||
this.imgData.height = this.imgData.height * _x; | ||
} | ||
if (this.imgData.height < this.realHeight) { | ||
var _x2 = this.realHeight / this.imgData.height; | ||
this.imgData.height = this.realHeight; | ||
this.imgData.width = this.imgData.width * _x2; | ||
} | ||
this.preventMovingToWhiteSpace(); | ||
} | ||
this.$emit(ZOOM_EVENT); | ||
this.draw(); | ||
}, | ||
paintBackground: function paintBackground() { | ||
var backgroundColor = !this.canvasColor || this.canvasColor == 'default' ? '#e6e6e6' : this.canvasColor; | ||
this.ctx.fillStyle = backgroundColor; | ||
this.ctx.fillRect(0, 0, this.realWidth, this.realHeight); | ||
}, | ||
draw: function draw() { | ||
var ctx = this.ctx; | ||
if (!this.img) return; | ||
var _imgData = this.imgData, | ||
startX = _imgData.startX, | ||
startY = _imgData.startY, | ||
width = _imgData.width, | ||
height = _imgData.height; | ||
ctx.clearRect(0, 0, this.realWidth, this.realHeight); | ||
this.paintBackground(); | ||
ctx.drawImage(this.img, startX, startY, width, height); | ||
}, | ||
generateDataUrl: function generateDataUrl(type) { | ||
if (!this.img) return ''; | ||
return this.canvas.toDataURL(type); | ||
}, | ||
generateBlob: function generateBlob(callback, mimeType, qualityArgument) { | ||
if (!this.img) return null; | ||
this.canvas.toBlob(callback, mimeType, qualityArgument); | ||
} | ||
} | ||
}; | ||
var VueCroppa = { | ||
install: function install(Vue, options) { | ||
Vue.component('croppa', cropper); | ||
} | ||
}; | ||
return VueCroppa; | ||
}))); |
{ | ||
"name": "vue-croppa", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "A simple straightforward customizable image cropper for vue.js.", | ||
@@ -9,2 +9,3 @@ "main": "dist/vue-croppa.js", | ||
"build": "rollup -c --environment BUILD:production", | ||
"build:min": "rollup -c --environment BUILD:production-min", | ||
"dev": "rollup -c -w" | ||
@@ -25,3 +26,8 @@ }, | ||
"image cropper", | ||
"vue plugin" | ||
"vue plugin", | ||
"move", | ||
"zoom", | ||
"javascript", | ||
"web", | ||
"front-end" | ||
], | ||
@@ -47,2 +53,3 @@ "author": "zhanziyang", | ||
"postcss": "^6.0.2", | ||
"postcss-clean": "^1.0.2", | ||
"rollup": "^0.43.0", | ||
@@ -49,0 +56,0 @@ "rollup-plugin-babel": "^2.7.1", |
244
README.md
# vue-croppa | ||
A simple straightforward customizable image cropper for vue.js. | ||
> A simple straightforward customizable image cropper for vue.js. | ||
## Template Example | ||
```html | ||
<croppa v-model="myCroppa" | ||
:width="400" | ||
:height="400" | ||
:canvas-color="default" | ||
:placeholder="Choose File" | ||
:placeholder-font-size="0" | ||
:placeholder-color="default" | ||
:input-accept="image/*" | ||
:file-size-limit="0" | ||
:quality="2" | ||
:zoom-speed="3" | ||
:disabled="false" | ||
:disable-click-to-choose="false" | ||
:disable-drag-to-move="false" | ||
:disable-scroll-to-zoom="false" | ||
:prevent-white-space="false" | ||
:reverse-zooming-gesture="false" | ||
:show-remove-button="true" | ||
:remove-button-color="red" | ||
:remove-button-size="0" | ||
@init="handleCroppaInit" | ||
@file-choose="handleCroppaFileChoose" | ||
@file-size-exceed="handleCroppaFileSizeExceed" | ||
@move="handleCroppaMove" | ||
@zoom="handleCroppaZoom"></croppa> | ||
``` | ||
## Method Examples | ||
```js | ||
this.myCroppa.reset() | ||
this.myCroppa.zoomIn() | ||
alert(this.myCroppa.generateDataUrl()) | ||
``` | ||
## Quick Start | ||
### 1. Import vue-croppa into your vue.js project. | ||
Using build tools: | ||
``` | ||
npm install --save vue-croppa | ||
``` | ||
```js | ||
import Vue from 'vue' | ||
import Croppa from 'vue-croppa' | ||
Vue.use(Croppa) | ||
``` | ||
```js | ||
// If your build tool supports css module | ||
import 'vue-croppa/dist/vue-croppa.css' | ||
``` | ||
Not using build tools: | ||
```html | ||
<link href="https://unpkg.com/vue-croppa/dist/vue-croppa.min.css" rel="stylesheet" type="text/css"> | ||
<script src="https://unpkg.com/vue-croppa/dist/vue-croppa.min.js"></script> | ||
``` | ||
```js | ||
Vue.use(Croppa) | ||
``` | ||
### 2. Now you have it. The simplest usage: | ||
```html | ||
<croppa v-model="myCroppa"></croppa> | ||
``` | ||
## Documentation | ||
### 🌱 Props | ||
#### v-model | ||
A two-way binding prop. It syncs an object from within the croppa component with a data in parent. We can use this object to invoke useful methods (Check out "Methods" section). | ||
- type: `object` | ||
- default: `null` | ||
#### width | ||
Display width of the preview container. | ||
- type: `number` | ||
- default: `200` | ||
- valid: `val > 0` | ||
#### height | ||
Display height of the preview container. | ||
- type: `number` | ||
- default: `200` | ||
- valid: `val > 0` | ||
#### placeholder | ||
Placeholder text of the preview container. It shows up when there is no image. | ||
- type: `string` | ||
- default: `'Choose File'` | ||
#### placeholder-color | ||
Placeholder text color. | ||
- type: same as what `CanvasRenderingContext2D.fillStyle` accepts. | ||
- default: `'#606060'` | ||
#### placeholder-font-size | ||
Placeholder text font size in pixel. When set to `0`, the font size will be ajust automatically so that the whole placehoder only takes up 2/3 of the container's width. | ||
- type: `number` | ||
- default: `0` | ||
#### canvas-color | ||
Initial background color and white space color if there is an image. | ||
- type: same as what `CanvasRenderingContext2D.fillStyle` accepts. | ||
- default: `'#e6e6e6'` | ||
#### quality | ||
Specifies how many times larger the actual image is than the container's display size. | ||
- type: `number` | ||
- default: `2` | ||
- valid: `isInteger(val) && val > 0 | ||
#### zoom speed | ||
Specifies how fast the zoom is reacting to scroll gestures. Default to level 3. | ||
- type: `number` | ||
- default: `3` | ||
- valid: `val > 0` | ||
#### accept | ||
Limits the types of files that users can choose. | ||
- type: same as what `accept` attribute of HTML `input` element takes. | ||
- default: `'image/*'` | ||
#### file-size-limit | ||
Limits the byte size of file that users can choose. If set to `0`, then no limit. | ||
- type: `number` | ||
- default: `0` | ||
#### disabled | ||
Disables user interaction. | ||
- type: `boolean` | ||
- default: `false` | ||
#### disable-click-to-choose | ||
Disables the default "click to choose file" user interaction. You can instead open the file chooser window programmatically by invoking `chooseFile()` method. | ||
- type: `boolean` | ||
- default: `false` | ||
#### disable-drag-to-move | ||
Disables the default "drag to move" user interaction. You can instead move the image programmatically by invoking `moveUpwards()` / `moveDownwards()` / `moveLeftwards()` / `moveRightwards()` methods. | ||
- type: `boolean` | ||
- default: `false` | ||
#### disable-scroll-to-zoom | ||
Disables the default "scroll to zoom" user interaction. You can instead zoom the image programmatically by invoking `zoomIn()` / `zoomOut()` methods. | ||
- type: `boolean` | ||
- default: `false` | ||
#### reverse-zooming-gesture | ||
Reverses the zoom-in/zoom-out direction when scrolling.- type: `boolean` | ||
- type: `boolean` | ||
- default: `false` | ||
#### prevent-white-space | ||
Prevents revealing background white space when moving and zooming the image. | ||
- type: `boolean` | ||
- default: `false` | ||
#### show-remove-button | ||
Specifies whether to show the built-in remove-button. You can change the button's color and size using the following two props. If you still find it ugly, hide it and use the `reset()` method to implement your own trigger. | ||
- type: `boolean` | ||
- default: `false` | ||
#### remove-button-color | ||
Changes the default color of the remove-button. Accepts any css color format. | ||
- type: `string` | ||
- default: `'red'` | ||
#### remove-button-size | ||
Specifies the remove-button's width and height (they are equal). If set to `0`, then it use the default size. | ||
- type: `number` | ||
- default: default size is ajust accordingly to container's size | ||
--- | ||
### 🌱 Methods | ||
#### myCroppa.getCanvas() | ||
- returns the canvas object | ||
#### myCroppa.getContext() | ||
- returns the canvas context object | ||
#### myCroppa.getChosenFile() | ||
#### myCroppa.getActualImageSize() | ||
- Return an object `{ width, height }` describing the real image size (preview size ` * quality`) | ||
#### myCroppa.moveUpwards( amountInPx: number ) | ||
#### myCroppa.moveDownwards( amountInPx: number ) | ||
#### myCroppa.moveLeftwards( amountInPx: number ) | ||
#### myCroppa.moveRightwards( amountInPx: number ) | ||
#### myCroppa.zoomIn() | ||
#### myCroppa.zoomOut() | ||
#### myCroppa.chooseFile() | ||
- Opens the file chooser window to choose file. Useful when default click-to-choose interaction is disabled. | ||
#### myCroppa.reset() | ||
- Removes the current image, can be used to implement your own remove-button. | ||
#### myCroppa.generateDataUrl( type: string ) | ||
- Returns a data-URL containing a representation of the image in the format specified by the type parameter (defaults to png). | ||
#### myCroppa.generateBlob( callback: function, mimeType: string, qualityArgument: number ) | ||
- Creates a Blob object representing the image contained in the canvas. Look up argument definition [here](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob). | ||
--- | ||
### 🌱 Events | ||
#### init | ||
- handler(croppa) | ||
- `croppa` is a croppa object to invoke methods - same as what `v-model` binds. | ||
#### file-choose | ||
- emitted when user choose a file from the poppup window. | ||
- handler(file) | ||
- `file` is a file object - same as what `getChosenFile()` returns. | ||
#### file-size-exceed: | ||
- emitted after file choosing if the chosen file's size exceeds the limit specified by prop fileSizeLimit. | ||
- handler(file) | ||
- `file` is a file object - same as what `getChosenFile()` returns. | ||
#### move | ||
#### zoom |
@@ -9,11 +9,24 @@ const json = require('rollup-plugin-json') | ||
const autoprefixer = require('autoprefixer') | ||
const clean = require('postcss-clean') | ||
const postcss = require('postcss') | ||
const fs = require('fs') | ||
let production = /^production/.test(process.env.BUILD) | ||
let min = process.env.BUILD === 'production-min' | ||
module.exports = { | ||
entry: 'src/main.js', | ||
dest: `${process.env.BUILD === 'production' ? 'dist' : 'docs/croppa'}/vue-croppa.js`, | ||
dest: `${production ? 'dist' : 'docs/croppa'}/vue-croppa${min ? '.min' : ''}.js`, | ||
format: 'umd', | ||
moduleName: 'Croppa', | ||
sourceMap: process.env.BUILD === 'production' ? false : 'inline', | ||
sourceMap: production ? false : 'inline', | ||
banner: `\ | ||
/* | ||
* vue-croppa v0.0.3 | ||
* https://github.com/zhanziyang/vue-croppa | ||
* | ||
* Copyright (c) 2017 zhanziyang | ||
* Released under the ISC license | ||
*/ | ||
`, | ||
plugins: [ | ||
@@ -25,7 +38,7 @@ commentjs(), | ||
css: function (css, allStyles, compile) { | ||
postcss([autoprefixer]).process(css).then(function (result) { | ||
postcss(min ? [autoprefixer, clean] : [autoprefixer]).process(css).then(function (result) { | ||
result.warnings().forEach(function (warn) { | ||
console.warn(warn.toString()) | ||
}) | ||
fs.writeFile(`${process.env.BUILD === 'production' ? 'dist' : 'docs/croppa'}/vue-croppa.css`, result.css, (err) => { | ||
fs.writeFile(`${production ? 'dist' : 'docs/croppa'}/vue-croppa${min ? '.min' : ''}.css`, result.css, (err) => { | ||
if (err) throw err | ||
@@ -36,8 +49,12 @@ }) | ||
}), | ||
(process.env.BUILD === 'production' && eslint()), | ||
(production && eslint()), | ||
babel({ | ||
exclude: 'node_modules/**' // only transpile our source code | ||
exclude: 'node_modules/**' | ||
}), | ||
(process.env.BUILD === 'production' && uglify()) | ||
(min && uglify({ | ||
output: { | ||
comments: /zhanziyang/ | ||
} | ||
})) | ||
] | ||
} |
@@ -42,3 +42,3 @@ Number.isInteger = Number.isInteger || function (value) { | ||
validator: function (val) { | ||
return Number.isInteger(val) && val > 0 && val <= 5 | ||
return Number.isInteger(val) && val > 0 | ||
} | ||
@@ -53,3 +53,3 @@ }, | ||
}, | ||
inputAccept: { | ||
accept: { | ||
type: String, | ||
@@ -66,2 +66,5 @@ default: 'image/*' | ||
disabled: Boolean, | ||
disableClickToChoose: Boolean, | ||
disableDragToMove: Boolean, | ||
disableScrollToZoom: Boolean, | ||
reverseZoomingGesture: Boolean, | ||
@@ -68,0 +71,0 @@ preventWhiteSpace: Boolean, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
197728
16
4673
244
3
26