vue-xcrop
Version:
A simple mobile image cropper for Vue 1/2
1,915 lines • 54.3 kB
JavaScript
/*!
* @name vue-xcrop v1.0.0
* @github https://github.com/ffx0s/vue-crop
* @license MIT.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Crop = factory());
}(this, (function () { 'use strict';
function extend(to, _from) {
for (var key in _from) {
to[key] = _from[key];
}
return to;
}
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var crop = createCommonjsModule(function (module, exports) {
/*!
* @name xcrop v1.0.2
* @github https://github.com/ffx0s/xcrop
* @license MIT.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof undefined === 'function' && undefined.amd ? undefined(factory) :
(global.Crop = factory());
}(commonjsGlobal, (function () { 'use strict';
/**
* 空函数
*/
function noop() {}
/**
* 获取随机uid
* @returns {String} uid
*/
/**
* 对象合并
* @param {Object} target 目标对象
* @param {Object} object 属性将会合并到目标对象上
* @returns {Object} 返回目标对象
*/
function extend(target, object) {
for (var key in object) {
target[key] = object[key];
}
return target;
}
var URL = window.URL && window.URL.createObjectURL ? window.URL : window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : null;
function dataURItoBlob(dataURI) {
var byteString = void 0;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = window.atob(dataURI.split(',')[1]);
} else {
byteString = unescape(dataURI.split(',')[1]);
}
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob = void 0;
try {
blob = new window.Blob([ab], {
type: mimeString
});
} catch (e) {
// TypeError old chrome and FF
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
if (e.name === 'TypeError' && window.BlobBuilder) {
var bb = new window.BlobBuilder();
bb.append(ia.buffer);
blob = bb.getBlob(mimeString);
} else if (e.name === 'InvalidStateError') {
// InvalidStateError (tested on FF13 WinXP)
blob = new window.Blob([ab], {
type: mimeString
});
} else {
// We're screwed, blob constructor unsupported entirely
}
}
return blob;
}
var isObjectURL = function isObjectURL(url) {
return (/^blob:/i.test(url)
);
};
function objectURLToBlob(url, callback) {
var http = new window.XMLHttpRequest();
http.open('GET', url, true);
http.responseType = 'blob';
http.onload = function (e) {
if (this.status === 200 || this.status === 0) {
callback(this.response);
}
};
http.send();
}
function httpURLToArrayBuffer(url, callback) {
var http = new window.XMLHttpRequest();
http.onload = function () {
if (this.status === 200 || this.status === 0) {
callback(http.response);
} else {
throw new Error('Could not load image');
}
http = null;
};
http.open('GET', url, true);
http.responseType = 'arraybuffer';
http.send(null);
}
function scaleCanvas(canvas, scale) {
var newCanvas = document.createElement('canvas');
var ctx = newCanvas.getContext('2d');
var width = canvas.width;
var height = canvas.height;
newCanvas.width = width * scale;
newCanvas.height = height * scale;
ctx.drawImage(canvas, 0, 0, width, height, 0, 0, newCanvas.width, newCanvas.height);
return newCanvas;
}
function antialisScale(canvas, scale) {
var newCanvas = document.createElement('canvas');
var newCtx = newCanvas.getContext('2d');
var ctx = canvas.getContext('2d');
var sourceWidth = canvas.width;
var sourceHeight = canvas.height;
var width = sourceWidth * scale;
var height = sourceHeight * scale;
newCanvas.width = width;
newCanvas.height = height;
// 缩小操作的次数
var steps = Math.ceil(Math.log(sourceWidth / width) / Math.log(2));
// 缩小操作
// 进行steps次的减半缩小
for (var i = 0; i < steps; i++) {
ctx.drawImage(canvas, 0, 0, sourceWidth * 0.5, sourceHeight * 0.5);
}
// 放大操作
// 进行steps次的两倍放大
newCtx.drawImage(canvas, 0, 0, canvas.width * Math.pow(0.5, steps), canvas.height * Math.pow(0.5, steps), 0, 0, width, height);
return newCanvas;
}
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var isBase64Image = function isBase64Image(src) {
return src.indexOf(';base64,') > 0;
};
/**
* 获取图片方向
* @param {Object} binFile ArrayBuffer
*/
function getOrientation(binFile) {
var view = new DataView(binFile);
if (view.getUint16(0, false) !== 0xFFD8) return -2;
var length = view.byteLength;
var offset = 2;
while (offset < length) {
var marker = view.getUint16(offset, false);
offset += 2;
if (marker === 0xFFE1) {
if (view.getUint32(offset += 2, false) !== 0x45786966) {
return -1;
}
var little = view.getUint16(offset += 6, false) === 0x4949;
offset += view.getUint32(offset + 4, little);
var tags = view.getUint16(offset, little);
offset += 2;
for (var i = 0; i < tags; i++) {
if (view.getUint16(offset + i * 12, little) === 0x0112) {
return view.getUint16(offset + i * 12 + 8, little);
}
}
} else if ((marker & 0xFF00) !== 0xFF00) break;else offset += view.getUint16(offset, false);
}
return -1;
}
/**
* https://github.com/stomita/ios-imagefile-megapixel
* Rendering image element (with resizing) into the canvas element
*/
function renderImageToCanvas(img, canvas, options, doSquash) {
var iw = img.naturalWidth;
var ih = img.naturalHeight;
if (!(iw + ih)) return;
var width = options.width;
var height = options.height;
var ctx = canvas.getContext('2d');
ctx.save();
transformCoordinate(canvas, ctx, width, height, options.orientation);
var subsampled = detectSubsampling(img);
if (subsampled) {
iw /= 2;
ih /= 2;
}
var d = 1024; // size of tiling canvas
var tmpCanvas = document.createElement('canvas');
tmpCanvas.width = tmpCanvas.height = d;
var tmpCtx = tmpCanvas.getContext('2d');
var vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1;
var dw = Math.ceil(d * width / iw);
var dh = Math.ceil(d * height / ih / vertSquashRatio);
var sy = 0;
var dy = 0;
while (sy < ih) {
var sx = 0;
var dx = 0;
while (sx < iw) {
tmpCtx.clearRect(0, 0, d, d);
tmpCtx.drawImage(img, -sx, -sy);
ctx.drawImage(tmpCanvas, 0, 0, d, d, dx, dy, dw, dh);
sx += d;
dx += dw;
}
sy += d;
dy += dh;
}
ctx.restore();
tmpCanvas = tmpCtx = null;
}
/**
* https://github.com/stomita/ios-imagefile-megapixel
* Detect subsampling in loaded image.
* In iOS, larger images than 2M pixels may be subsampled in rendering.
*/
function detectSubsampling(img) {
var iw = img.naturalWidth;
var ih = img.naturalHeight;
if (iw * ih > 1024 * 1024) {
// subsampling may happen over megapixel image
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 1;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, -iw + 1, 0);
// subsampled image becomes half smaller in rendering size.
// check alpha channel value to confirm image is covering edge pixel or not.
// if alpha value is 0 image is not covering, hence subsampled.
return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
} else {
return false;
}
}
/**
* https://github.com/stomita/ios-imagefile-megapixel
* Detecting vertical squash in loaded image.
* Fixes a bug which squash image vertically while drawing into canvas for some images.
*/
function detectVerticalSquash(img, iw, ih) {
var canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = ih;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
var data = ctx.getImageData(0, 0, 1, ih).data;
// search image edge pixel position in case it is squashed vertically.
var sy = 0;
var ey = ih;
var py = ih;
while (py > sy) {
var alpha = data[(py - 1) * 4 + 3];
if (alpha === 0) {
ey = py;
} else {
sy = py;
}
py = ey + sy >> 1;
}
var ratio = py / ih;
return ratio === 0 ? 1 : ratio;
}
/**
* 改变canvas的方向
* @param {Element} canvas 画布
* @param {Object} ctx 画布上下文
* @param {Number} width 画布宽度
* @param {Number} height 画布高度
* @param {Number} srcOrientation 方向
*/
function transformCoordinate(canvas, ctx, width, height, srcOrientation) {
// set proper canvas dimensions before transform & export
if ([5, 6, 7, 8].indexOf(srcOrientation) > -1) {
canvas.width = height;
canvas.height = width;
} else {
canvas.width = width;
canvas.height = height;
}
// transform context before drawing image
switch (srcOrientation) {
case 2:
ctx.transform(-1, 0, 0, 1, width, 0);break;
case 3:
ctx.transform(-1, 0, 0, -1, width, height);break;
case 4:
ctx.transform(1, 0, 0, -1, 0, height);break;
case 5:
ctx.transform(0, 1, 1, 0, 0, 0);break;
case 6:
ctx.transform(0, 1, -1, 0, height, 0);break;
case 7:
ctx.transform(0, -1, -1, 0, height, width);break;
case 8:
ctx.transform(0, -1, 1, 0, 0, width);break;
default:
ctx.transform(1, 0, 0, 1, 0, 0);
}
}
/**
* 图片铺满容器
* @param {Number} imgW 图片宽度
* @param {Number} imgH 图片高度
* @param {Number} divW 容器宽度
* @param {Number} divH 容器高度
*/
function imgCover(imgW, imgH, divW, divH) {
var scale = imgW / imgH;
var width = divW;
var height = width / scale;
var x = 0;
var y = -(height - divH) / 2;
if (height < divH) {
height = divH;
width = scale * height;
x = -(width - divW) / 2;
y = 0;
}
return {
width: width,
height: height,
x: x,
y: y
};
}
/**
* 将图片转成canvas
* @param {(string|file|element)} target 目标
* @param {Function} callback 转换成功回调函数
* @param {Object} opt 可选项
*/
function imageToCanvas(target, callback, opt) {
var options = extend({ maxWidth: 2000, maxHeight: 2000 }, opt);
function imageOrientation(arrayBuffer, file) {
var orientation = getOrientation(arrayBuffer);
var isBlob = typeof file !== 'string';
var src = isBlob ? URL.createObjectURL(file) : file;
var doSquash = isBlob && file.type === 'image/jpeg';
var img = new window.Image();
if (!isBase64Image(src)) {
img.crossOrigin = '*';
}
img.onload = function () {
createCanvas(img, orientation, callback, doSquash, options);
isBlob && URL.revokeObjectURL(src);
};
img.src = src;
}
function handleBinaryFile(file) {
var fileReader = new window.FileReader();
fileReader.onload = function (e) {
imageOrientation(e.target.result, file);
};
fileReader.readAsArrayBuffer(file);
}
// 文件对象
if (window.FileReader && (target instanceof window.Blob || target instanceof window.File)) {
handleBinaryFile(target);
return;
}
// imageElement 或者 canvasElement
if ((typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType) {
if (target.tagName === 'IMG') {
imageToCanvas(target.src, callback);
}
if (target.tagName === 'CANVAS') {
callback(target);
}
return;
}
// base64图片
if (isBase64Image(target)) {
handleBinaryFile(dataURItoBlob(target));
return;
}
// objectURL
if (isObjectURL(target)) {
objectURLToBlob(target, handleBinaryFile);
} else {
// http/https图片地址
httpURLToArrayBuffer(target, function (arrayBuffer) {
imageOrientation(arrayBuffer, target);
});
}
}
function createCanvas(img, orientation, callback, doSquash, options) {
var canvas = document.createElement('canvas');
var maxWidth = options.maxWidth,
maxHeight = options.maxHeight,
width = options.width,
height = options.height;
var imgWidth = img.naturalWidth;
var imgHeight = img.naturalHeight;
if (width && !height) {
height = imgHeight * width / imgWidth << 0;
} else if (height && !width) {
width = imgWidth * height / imgHeight << 0;
} else {
width = imgWidth;
height = imgHeight;
}
if (maxWidth && imgWidth > maxWidth) {
width = maxWidth;
height = imgHeight * width / imgWidth << 0;
}
if (maxHeight && height > maxHeight) {
height = maxHeight;
width = imgWidth * height / imgHeight << 0;
}
renderImageToCanvas(img, canvas, { orientation: orientation, width: width, height: height }, doSquash);
callback(canvas);
}
/**
* 简单封装创建节点和绑定移除事件的操作
*/
/**
* 节点对象
* @param {String} tagName 节点标签
* @param {Object} attr 属性
* @param {Array} children 子节点
*/
function Element(tagName, attr) {
var children = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
for (var name in attr) {
this[name] = attr[name];
}
this.tagName = tagName;
this.children = children;
}
Element.prototype = {
// 创建节点
create: function create() {
this.el = document.createElement(this.tagName);
this.el.className = this.className;
this.addEvent();
return this.el;
}
/**
* 绑定/移除事件方法
*/
};['addEvent', 'removeEvent'].forEach(function (value) {
Element.prototype[value] = function () {
for (var eventName in this.events) {
this.el[value + 'Listener'](eventName, this.events[eventName], false);
}
};
});
/**
* 创建dom节点
* @param {Object} element Element实例化的对象
* @param {Function} callback 创建完成回调
*/
function createElement(element) {
var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : noop;
if (typeof element === 'string') {
var _node = document.createTextNode(element);
callback(element);
return _node;
}
var node = element.create();
// 如果有子节点,则递归调用创建
element.children.forEach(function (child) {
var childNode = createElement(child, callback);
node.appendChild(childNode);
});
callback(element);
return node;
}
/**
* 从html中移除dom节点及绑定事件
* @param {Object} element Element实例化的对象
* @param {Boolean} flag 是否从html中移除节点
*/
function removeElement(element, flag) {
if (typeof element === 'string') return;
element.children.forEach(function (child) {
removeElement(child, false);
});
element.removeEvent();
if (flag) {
document.body.removeChild(element.el);
}
}
/**
* 渲染样式
* @param {String} cssText css样式
* @param {Element} elem css插入节点
*/
function renderStyle(cssText) {
var elem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.getElementsByTagName('head')[0];
var styleElem = document.createElement('style');
try {
styleElem.appendChild(document.createTextNode(cssText));
} catch (err) {
styleElem.stylesheet.cssText = cssText;
}
elem.appendChild(styleElem);
return styleElem;
}
function initRender(pinch) {
pinch.canvas = createCanvas$1(pinch.options.width, pinch.options.height);
pinch.context = pinch.canvas.getContext('2d');
}
function addRender(Pinch) {
var proto = Pinch.prototype;
proto.render = function () {
var pinch = this;
var options = pinch.options;
options.el = typeof options.el === 'string' ? document.querySelector(options.el) : options.el;
options.el.appendChild(pinch.canvas);
// 获取canvas位于html里实际的大小
pinch.rect = pinch.canvas.getBoundingClientRect();
// 利用canvas的宽度和实际的宽度作为它的大小比例
pinch.canvasScale = options.width / pinch.rect.width;
};
}
/**
* 创建一个宽高为100%的画布
* @param {Number} width 画布宽度
* @param {Number} height 画布高度
*/
function createCanvas$1(width, height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.style.cssText = 'width:100%;height:100%;';
return canvas;
}
var slice = Array.prototype.slice;
function Observer() {
this.events = {};
}
Observer.prototype = {
on: function on(signals, fn) {
var ob = this;
signals.split(' ').forEach(function (signal) {
if (!ob.events[signal]) {
ob.events[signal] = [];
}
fn && ob.events[signal].push(fn);
});
},
emit: function emit(signals) {
var ob = this;
var args = slice.call(arguments, 1);
signals = signals.split(' ').forEach(function (signal) {
var events = ob.events[signal];
if (events) {
events.forEach(function (fn) {
return fn.apply(ob, args);
});
}
});
},
off: function off(signal, fn) {
var ob = this;
var events = ob.events[signal];
if (events) {
events.forEach(function (fn) {
return events.splice(events.indexOf(fn), 1);
});
}
}
};
// t:当前时间、b:初始值、c:变化值、d:总时间,返回结果为当前的位置
var Easing = {
// linear (t, b, c, d) {
// return c * t / d + b
// },
// easeInQuad (t, b, c, d) {
// return c * (t /= d) * t + b
// },
// easeOutQuad (t, b, c, d) {
// return -c * (t /= d) * (t - 2) + b
// },
easeOutStrong: function easeOutStrong(t, b, c, d) {
return -c * ((t = t / d - 1) * t * t * t - 1) + b;
},
// easeInOutQuad (t, b, c, d) {
// if ((t /= d / 2) < 1) {
// return c / 2 * t * t + b
// } else {
// return -c / 2 * ((--t) * (t - 2) - 1) + b
// }
// },
// easeInCubic (t, b, c, d) {
// return c * (t /= d) * t * t + b
// },
easeOutCubic: function easeOutCubic(t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
}
// easeInOutCubic (t, b, c, d) {
// if ((t /= d / 2) < 1) {
// return c / 2 * t * t * t + b
// } else {
// return c / 2 * ((t -= 2) * t * t + 2) + b
// }
// },
// easeInQuart (t, b, c, d) {
// return c * (t /= d) * t * t * t + b
// },
// easeOutQuart (t, b, c, d) {
// return -c * ((t = t / d - 1) * t * t * t - 1) + b
// },
// easeInOutQuart (t, b, c, d) {
// if ((t /= d / 2) < 1) {
// return c / 2 * t * t * t * t + b
// } else {
// return -c / 2 * ((t -= 2) * t * t * t - 2) + b
// }
// },
// easeInQuint (t, b, c, d) {
// return c * (t /= d) * t * t * t * t + b
// },
// easeOutQuint (t, b, c, d) {
// return c * ((t = t / d - 1) * t * t * t * t + 1) + b
// },
// easeInOutQuint (t, b, c, d) {
// if ((t /= d / 2) < 1) {
// return c / 2 * t * t * t * t * t + b
// } else {
// return c / 2 * ((t -= 2) * t * t * t * t + 2) + b
// }
// },
// easeInSine (t, b, c, d) {
// return -c * Math.cos(t / d * (Math.PI / 2)) + c + b
// },
// easeOutSine (t, b, c, d) {
// return c * Math.sin(t / d * (Math.PI / 2)) + b
// },
// easeInOutSine (t, b, c, d) {
// return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b
// },
// easeInExpo (t, b, c, d) {
// var _ref
// return (_ref = t === 0) !== null ? _ref : {
// b: c * Math.pow(2, 10 * (t / d - 1)) + b
// }
// },
// easeOutExpo (t, b, c, d) {
// var _ref
// return (_ref = t === d) !== null ? _ref : b + {
// c: c * (-Math.pow(2, -10 * t / d) + 1) + b
// }
// },
// easeInOutExpo (t, b, c, d) {
// if (t === 0) {
// }
// if (t === d) {
// // b + c
// }
// if ((t /= d / 2) < 1) {
// return c / 2 * Math.pow(2, 10 * (t - 1)) + b
// } else {
// return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b
// }
// },
// easeInCirc (t, b, c, d) {
// return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b
// },
// easeOutCirc (t, b, c, d) {
// return c * Math.sqrt(1 - (t = t / d - 1) * t) + b
// },
// easeInOutCirc (t, b, c, d) {
// if ((t /= d / 2) < 1) {
// return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b
// } else {
// return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b
// }
// },
// easeInElastic (t, b, c, d) {
// var a, p, s
// s = 1.70158
// p = 0
// a = c
// if (t === 0) {
// // b
// } else if ((t /= d) === 1) {
// // b + c
// }
// if (!p) {
// p = d * 0.3
// }
// if (a < Math.abs(c)) {
// a = c
// s = p / 4
// } else {
// s = p / (2 * Math.PI) * Math.asin(c / a)
// }
// return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b
// },
// easeOutElastic (t, b, c, d) {
// var a, p, s
// s = 1.70158
// p = 0
// a = c
// if (t === 0) {
// // b
// } else if ((t /= d) === 1) {
// // b + c
// }
// if (!p) {
// p = d * 0.3
// }
// if (a < Math.abs(c)) {
// a = c
// s = p / 4
// } else {
// s = p / (2 * Math.PI) * Math.asin(c / a)
// }
// return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b
// },
// easeInOutElastic (t, b, c, d) {
// var a, p, s
// s = 1.70158
// p = 0
// a = c
// if (t === 0) {
// // b
// } else if ((t /= d / 2) === 2) {
// // b + c
// }
// if (!p) {
// p = d * (0.3 * 1.5)
// }
// if (a < Math.abs(c)) {
// a = c
// s = p / 4
// } else {
// s = p / (2 * Math.PI) * Math.asin(c / a)
// }
// if (t < 1) {
// return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b
// } else {
// return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b
// }
// },
// easeInBack (t, b, c, d, s) {
// if (s === void 0) {
// s = 1.70158
// }
// return c * (t /= d) * t * ((s + 1) * t - s) + b
// },
// easeOutBack (t, b, c, d, s) {
// if (s === void 0) {
// s = 1.70158
// }
// return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b
// },
// easeInOutBack (t, b, c, d, s) {
// if (s === void 0) {
// s = 1.70158
// }
// if ((t /= d / 2) < 1) {
// return c / 2 * (t * t * (((s *= 1.525) + 1) * t - s)) + b
// } else {
// return c / 2 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2) + b
// }
// },
// easeInBounce (t, b, c, d) {
// var v
// v = Easing.easeOutBounce(d - t, 0, c, d)
// return c - v + b
// },
// easeOutBounce (t, b, c, d) {
// if ((t /= d) < 1 / 2.75) {
// return c * (7.5625 * t * t) + b
// } else if (t < 2 / 2.75) {
// return c * (7.5625 * (t -= 1.5 / 2.75) * t + 0.75) + b
// } else if (t < 2.5 / 2.75) {
// return c * (7.5625 * (t -= 2.25 / 2.75) * t + 0.9375) + b
// } else {
// return c * (7.5625 * (t -= 2.625 / 2.75) * t + 0.984375) + b
// }
// },
// easeInOutBounce (t, b, c, d) {
// var v
// if (t < d / 2) {
// v = Easing.easeInBounce(t * 2, 0, c, d)
// return v * 0.5 + b
// } else {
// v = Easing.easeOutBounce(t * 2 - d, 0, c, d)
// return v * 0.5 + c * 0.5 + b
// }
// }
};
// requestAnimationFrame 兼容处理
var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
return window.setTimeout(callback, 1000 / 60);
};
// cancelAnimationFrame 兼容处理
var cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || function (id) {
clearTimeout(id);
};
/**
* 获取当前时间戳
* @returns {Number} 时间戳
*/
var now = function now() {
return new Date().getTime();
};
/**
* 动画执行函数,仅在opiotns.running函数返回数值,不做具体元素的动画操作
* @param {Object} options 选项
* @property {Number} [options.time = 500] 在指定时间(ms)内完成动画,默认500ms
* @property {String} [options.type = 'easeOutQuad'] 动画类型,默认linear
* @property {Array} options.targets 二维数组,存放起始值与目标值,例:[[0, 100], [100, 0]],表示起始值0到目标值100的过程中的变化,变化的数值会作为options.running函数的参数返回
* @property {Function} options.running - options.targets数值变化过程会执行这个函数
* @property {Function} options.end 结束后的回调函数
*/
var animate = function (options) {
var timer = null;
var _options$time = options.time,
time = _options$time === undefined ? 500 : _options$time,
_options$type = options.type,
type = _options$type === undefined ? 'easeOutQuad' : _options$type,
targets = options.targets,
running = options.running,
end = options.end;
var startTime = now();
function step() {
var changeTime = now();
var scale = 1 - (Math.max(0, startTime - changeTime + time) / time || 0);
var value = [];
targets.forEach(function (target) {
var currentValue = target[0] === target[1] ? target[0] : Easing[type](scale * time, target[0], target[1] - target[0], time) || 0;
value.push(currentValue);
});
running(value);
if (scale === 1) {
cancelAnimationFrame(timer);
end && end();
} else {
timer = requestAnimationFrame(step);
}
}
timer = requestAnimationFrame(step);
return {
stop: function stop() {
cancelAnimationFrame(timer);
}
};
};
function initEvent(pinch) {
pinch.eventList = ['mousewheel', 'touchstart', 'touchmove', 'touchend'];
pinch.observer = new Observer();
// 最后一次触摸操作的参数
pinch.last = {
scale: 1,
point: { x: 0, y: 0 },
move: { x: 0, y: 0 },
time: 0,
dis: { time: 0, x: 0, y: 0 }
};
pinch.touchDelay = 3;
pinch.animation = { stop: noop };
}
function addEvent(Pinch) {
var proto = Pinch.prototype;
proto.bindEvent = function () {
var pinch = this;
var target = pinch.options.touchTarget || pinch.canvas;
pinch.eventList.forEach(function (value) {
target.addEventListener(value, pinch, false);
});
};
proto.handleEvent = function (e) {
var pinch = this;
switch (e.type) {
case 'touchstart':
pinch.touchstart(e);
break;
case 'touchmove':
pinch.touchmove(e);
break;
case 'touchend':
pinch.touchend(e);
break;
// debug
case 'mousewheel':
pinch.mousewheel(e);
break;
}
};
// debug
proto.mousewheel = function (e) {
e.preventDefault();
var pinch = this;
pinch.rect = pinch.canvas.getBoundingClientRect();
var point = {
x: (e.clientX - pinch.rect.left) * pinch.canvasScale,
y: (e.clientY - pinch.rect.top) * pinch.canvasScale
};
var STEP = 0.99;
var factor = e.deltaY;
var scaleChanged = Math.pow(STEP, factor);
pinch.last.point = point;
pinch.scaleTo(point, pinch.scale * scaleChanged);
pinch.emit('mousewheel', e);
};
proto.touchstart = function (e) {
e.preventDefault();
var pinch = this;
var touches = e.touches;
pinch.rect = pinch.canvas.getBoundingClientRect();
pinch.animation.stop();
if (touches.length === 2) {
pinch.pinchstart(e);
} else if (touches.length === 1) {
pinch.dragstart(e);
}
};
proto.touchmove = function (e) {
var pinch = this;
var touches = e.touches;
if (touches.length === 2) {
pinch.pinchmove(e);
} else if (touches.length === 1) {
pinch.dragmove(e);
}
};
proto.touchend = function (e) {
var pinch = this;
var touches = e.touches;
if (touches.length) {
// pinch end
pinch.emit('pinchend', e);
pinch.dragstart(e);
} else {
// drag end
pinch.dragend(e);
}
};
proto.dragstart = function (e) {
var pinch = this;
var touches = e.touches;
pinch.last.move = {
x: touches[0].clientX - pinch.rect.left,
y: touches[0].clientY - pinch.rect.top
};
pinch.last.dis = { time: 0, x: 0, y: 0 };
pinch.last.time = new Date().getTime();
pinch.touchDelay = 3;
pinch.emit('dragstart', e);
};
proto.dragmove = function (e) {
var pinch = this;
var touches = e.touches;
var move = {
x: touches[0].clientX - pinch.rect.left,
y: touches[0].clientY - pinch.rect.top
};
var x = (move.x - pinch.last.move.x) * pinch.canvasScale;
var y = (move.y - pinch.last.move.y) * pinch.canvasScale;
var nowTime = new Date().getTime();
pinch.last.dis = { x: x, y: y, time: nowTime - pinch.last.time };
pinch.last.time = nowTime;
pinch.last.move = move;
// 延迟防止手误操作
if (pinch.touchDelay) {
pinch.touchDelay--;
return;
}
pinch.moveTo(pinch.position.x + x, pinch.position.y + y);
pinch.emit('dragmove', e);
};
proto.dragend = function (e) {
var pinch = this;
if (!pinch.validation()) {
// 缓冲动画
var vx = pinch.last.dis.x / pinch.last.dis.time;
var vy = pinch.last.dis.y / pinch.last.dis.time;
var speed = 0.5;
if (Math.abs(vx) > speed || Math.abs(vy) > speed) {
var time = 200;
var x = pinch.position.x + vx * time;
var y = pinch.position.y + vy * time;
var result = pinch.checkBorder({ x: x, y: y }, pinch.scale, { x: x, y: y });
if (result.isDraw) {
x = result.xpos;
y = result.ypos;
}
pinch.animation = animate({
time: time * 2,
targets: [[pinch.position.x, x], [pinch.position.y, y]],
type: 'easeOutStrong',
running: function running(target) {
pinch.position.x = target[0];
pinch.position.y = target[1];
pinch.draw();
},
end: function end() {
pinch.validation();
}
});
}
}
pinch.emit('dragend', e);
};
proto.pinchstart = function (e) {
var pinch = this;
var zoom = touchEach(e.touches, function (touch) {
return { x: touch.clientX, y: touch.clientY };
});
var touchCenter = Pinch.getTouchCenter(zoom);
pinch.last.zoom = zoom;
pinch.last.point = {
x: (touchCenter.x - pinch.rect.left) * pinch.canvasScale,
y: (touchCenter.y - pinch.rect.top) * pinch.canvasScale
};
pinch.touchDelay = 5;
pinch.emit('pinchstart', e);
};
proto.pinchmove = function (e) {
var pinch = this;
var zoom = touchEach(e.touches, function (touch) {
return { x: touch.clientX, y: touch.clientY };
});
// 双指的中心点
var touchCenter = Pinch.getTouchCenter(zoom);
// 相对于canvas画布的中心点
var point = {
x: (touchCenter.x - pinch.rect.left) * pinch.canvasScale,
y: (touchCenter.y - pinch.rect.top) * pinch.canvasScale
// 双指两次移动间隔的差值
};var disX = point.x - pinch.last.point.x;
var disY = point.y - pinch.last.point.y;
// 双指两次移动间隔的比例
var scaleChanged = Pinch.getScale(pinch.last.zoom, zoom);
pinch.last.zoom = zoom;
pinch.last.point = point;
// 延迟防止手误操作
if (pinch.touchDelay) {
pinch.touchDelay--;
return;
}
pinch.position.x += disX;
pinch.position.y += disY;
pinch.scaleTo(point, pinch.scale * scaleChanged);
pinch.emit('pinchmove', e);
};
proto.emit = function (name) {
this.observer.emit.apply(this.observer, arguments);
};['on', 'off'].forEach(function (value) {
proto[value] = function (name, fn) {
this.observer[value](name, fn && fn.bind(this));
};
});
}
function touchEach(touches, callback) {
var arr = [];
for (var attr in touches) {
if (typeof +attr === 'number' && !isNaN(+attr)) {
arr.push(callback(touches[attr], attr));
}
}
return arr;
}
function initActions(pinch) {
// 缩放比例
pinch.scale = 1;
// 图片缩放原点坐标
pinch.firstOrigin = { x: 0, y: 0
// 图片相对于canvas的坐标
};pinch.position = { x: 0, y: 0, width: 0, height: 0
// 图片数据
};pinch.image = { width: 0, height: 0, el: null };
}
function addActions(Pinch) {
var proto = Pinch.prototype;
// 加载目标图片
proto.load = function (target, callback) {
var pinch = this;
var _pinch$options = pinch.options,
width = _pinch$options.width,
height = _pinch$options.height,
offset = _pinch$options.offset,
loaded = _pinch$options.loaded,
maxTargetWidth = _pinch$options.maxTargetWidth,
maxTargetHeight = _pinch$options.maxTargetHeight,
maxScale = _pinch$options.maxScale;
imageToCanvas(target, success, { maxWidth: maxTargetWidth, maxHeight: maxTargetHeight });
function success(canvas) {
// image.el为原目标图片的canvas版本,后续画布drawImage会用到
var image = { el: canvas, width: canvas.width, height: canvas.height
// 减去偏移量获得实际容器的大小
};var pinchWidth = width - (offset.left + offset.right);
var pinchHeight = height - (offset.top + offset.bottom);
// 通过imgCover实现图片铺满容器,返回图片的坐标位置
pinch.position = imgCover(image.width, image.height, pinchWidth, pinchHeight);
// 需要加上偏移量
pinch.position.x += offset.left;
pinch.position.y += offset.top;
// 图片缩放比例
pinch.scale = pinch.position.width / image.width;
// 图片尺寸比画布小时,修正最大比例和最小比例
var _maxScale = Math.max(pinch.scale, maxScale);
var _minScale = pinch.scale;
pinch.options.maxScale = _maxScale === _minScale ? pinch.scale * Math.max(maxScale, 1) : maxScale;
pinch.options.minScale = _minScale;
pinch.image = image;
// 图片原点
pinch.firstOrigin = {
x: pinch.position.x,
y: pinch.position.y
};
pinch.draw();
setTimeout(function () {
callback && callback();
loaded.call(pinch);
});
}
};
proto.remove = function () {
var pinch = this;
var target = pinch.options.touchTarget || pinch.canvas;
pinch.eventList.forEach(function (value) {
target.removeEventListener(value, pinch, false);
});
pinch.options.el.removeChild(pinch.canvas);
};
proto.draw = function () {
var pinch = this;
var options = pinch.options;
var context = pinch.context;
var _pinch$position = pinch.position,
x = _pinch$position.x,
y = _pinch$position.y;
context.clearRect(0, 0, options.width, options.height);
context.save();
pinch.context.translate(x, y);
context.scale(pinch.scale, pinch.scale);
context.drawImage(pinch.image.el, 0, 0, pinch.image.width, pinch.image.height);
context.restore();
};
proto.moveTo = function (xpos, ypos, transition) {
var pinch = this;
if (transition) {
pinch.animate(pinch.scale, xpos, ypos);
} else {
pinch.position.x = xpos;
pinch.position.y = ypos;
pinch.draw();
}
};
/**
* 图片缩放函数,以point点为中心点进行缩放
* @param {object} point 坐标点
* @property {number} point.x x坐标
* @property {number} point.y y坐标
* @param {number} zoom 缩放比例
*/
proto.scaleTo = function (point, scale) {
var pinch = this;
if (scale === pinch.scale) return;
var scaleChanged = scale / pinch.scale;
var _Pinch$calculate = Pinch.calculate(pinch.position, pinch.firstOrigin, point, scale / scaleChanged, scaleChanged),
x = _Pinch$calculate.x,
y = _Pinch$calculate.y;
pinch.scale = scale;
pinch.moveTo(x, y);
};
proto.animate = function (scale, xpos, ypos) {
var pinch = this;
pinch.animation = animate({
targets: [[pinch.scale, scale], [pinch.position.x, xpos], [pinch.position.y, ypos]],
time: 450,
type: 'easeOutCubic',
running: function running(target) {
pinch.scale = target[0];
pinch.position.x = target[1];
pinch.position.y = target[2];
pinch.draw();
}
});
};
}
function addValidation(Pinch) {
var proto = Pinch.prototype;
proto.validation = function () {
var pinch = this;
var _pinch$options = pinch.options,
maxScale = _pinch$options.maxScale,
minScale = _pinch$options.minScale;
var scale = pinch.scale;
var result = { xpos: pinch.position.x, ypos: pinch.position.y, isDraw: false
// 缩放比例判断
};if (scale > maxScale) {
setScale(maxScale);
} else if (scale < minScale) {
setScale(minScale);
} else {
result = pinch.checkBorder(pinch.position, scale, pinch.position);
}
function setScale(newScale) {
var scaleChanged = newScale / pinch.scale;
var _Pinch$calculate = Pinch.calculate(pinch.position, pinch.firstOrigin, pinch.last.point, scale, scaleChanged),
x = _Pinch$calculate.x,
y = _Pinch$calculate.y;
scale = newScale;
result = pinch.checkBorder({ x: x, y: y }, newScale, { x: x, y: y });
result.isDraw = true;
}
if (result.isDraw) {
pinch.animate(scale, result.xpos, result.ypos);
}
return result.isDraw;
};
/**
* 边界值判断
* @param {Object} curPos 当前位置
* @param {Number} scale 目标比例
* @param {Object} position 目标位置
*/
proto.checkBorder = function (curPos, scale, position) {
var pinch = this;
var _pinch$options2 = pinch.options,
width = _pinch$options2.width,
height = _pinch$options2.height,
offset = _pinch$options2.offset;
var imageWidth = scale * pinch.image.width;
var imageHeight = scale * pinch.image.height;
var w = width - (offset.left + offset.right) - (imageWidth - (offset.left - position.x));
var h = height - (offset.top + offset.bottom) - (imageHeight - (offset.top - position.y));
var xpos = curPos.x;
var ypos = curPos.y;
var isDraw = false;
if (ypos > offset.top) {
// top
ypos = offset.top;
isDraw = true;
} else if (h > 0) {
// bottom
ypos = ypos + h;
isDraw = true;
}
if (xpos > offset.left) {
// left
xpos = offset.left;
isDraw = true;
} else if (w > 0) {
// right
xpos = xpos + w;
isDraw = true;
}
return {
xpos: xpos,
ypos: ypos,
isDraw: isDraw
};
};
}
function sum(a, b) {
return a + b;
}
/**
* 获取两个点的中心
* @param {Array} vectors 点
*/
function getTouchCenter(vectors) {
return {
x: vectors.map(function (v) {
return v.x;
}).reduce(sum) / vectors.length,
y: vectors.map(function (v) {
return v.y;
}).reduce(sum) / vectors.length
};
}
// 获取点距离
function getDistance(p1, p2, props) {
props = props || ['x', 'y'];
var x = p2[props[0]] - p1[props[0]];
var y = p2[props[1]] - p1[props[1]];
return Math.sqrt(x * x + y * y);
}
/**
* 通过两点距离计算比例
* @param {Array} start 起始点
* @param {Array} end 结束点
*/
function getScale(start, end) {
return getDistance(end[0], end[1]) / getDistance(start[0], start[1]);
}
/**
* 以点坐标为原点计进行缩放,计算缩放后位置的函数,返回缩放后的x,y,scale值
* https://stackoverflow.com/questions/48097552/how-to-zoom-on-a-point-with-javascript
* @param {Object} currentOrigin 当前原点坐标
* @param {Object} firstOrigin 第一次缩放时的原点坐标
* @param {Object} point 缩放点
* @param {Number} scale 当前比例
* @param {Number} scaleChanged 每次缩放的比例系数
*/
function calculate(currentOrigin, firstOrigin, point, scale, scaleChanged) {
// 鼠标坐标与当前原点的距离
var distanceX = point.x - currentOrigin.x;
var distanceY = point.y - currentOrigin.y;
// 新原点坐标
var newOriginX = currentOrigin.x + distanceX * (1 - scaleChanged);
var newOriginY = currentOrigin.y + distanceY * (1 - scaleChanged);
var offsetX = newOriginX - firstOrigin.x;
var offsetY = newOriginY - firstOrigin.y;
return {
scale: scale * scaleChanged,
x: firstOrigin.x + offsetX,
y: firstOrigin.y + offsetY
};
}
var addGlobal = function (Pinch) {
Pinch.getTouchCenter = getTouchCenter;
Pinch.getDistance = getDistance;
Pinch.getScale = getScale;
Pinch.calculate = calculate;
Pinch.Observer = Observer;
};
function getDefaultOptions$1() {
return {
target: null,
maxTargetWidth: 2000,
maxTargetHeight: 2000,
el: null,
// canvas宽度
width: 800,
// canvas高度
height: 800,
// 最大缩放比例,最小缩放比例默认为 canvas 与图片大小计算的比例
maxScale: 2,
touchTarget: null,
// canvas位于容器的偏移量
offset: {
left: 0,
right: 0,
top: 0,
bottom: 0
},
loaded: noop
};
}
function Pinch(el, options) {
options.el = el;
this.init(options);
this.render();
this.bindEvent();
this.load(options.target);
}
Pinch.prototype.init = function (options) {
var pinch = this;
pinch.options = extend(getDefaultOptions$1(), options);
initRender(pinch);
initEvent(pinch);
initActions(pinch);
};
// 添加静态方法
addGlobal(Pinch);
// 添加渲染相关的原型方法
addRender(Pinch);
// 添加事件相关的原型方法
addEvent(Pinch);
// 添加操作相关的原型方法
addActions(Pinch);
// 添加验证相关的原型方法
addValidation(Pinch);
/**
* 获取裁剪默认选项
*/
function getDefaultOptions() {
return {
// 允许图片的最大宽度
maxTargetWidth: 2000,
// 允许图片的最大高度
maxTargetHeight: 2000,
// 插入到el节点
el: document.body,
// 裁剪框width
width: 300,
// 裁剪框height
height: 300,
// 图片初始x坐标
x: undefined,
// 图片初始y坐标
y: undefined,
// 允许缩放的最大比例
maxScale: 2,
// canavs画布比例
canvasScale: 2,
// 代理触摸事件的节点
touchTarget: null,
// 生命周期函数
created: noop, // 创建完成
mounted: noop, // 已插入到页面节点
loaded: noop, // 裁剪的图片加载完成
// 取消事件回调
cancle: noop,
// 确认事件回调
confirm: noop
};
}
/**
* 裁剪对象
* @param {Object} options 裁剪选项
*/
function Crop(options) {
this.init(options);
}
Crop.prototype = {
/**
* 初始化
* @param {Object} options 裁剪选项
*/
init: function init(options) {
this.options = extend(getDefaultOptions(), options);
this.create();
},
/**
* 创建dom节点
*/
create: function create() {
var crop = this;
var options = crop.options;
var el = options.el;
crop.options.el = el = typeof el === 'string' ? document.querySelector(el) : el;
var styles = [];
var width = options.width;
var height = options.height;
var docEl = document.documentElement;
// 裁剪最外层div
var wrapProps = {
className: 'crop-wrap',
width: docEl.clientWidth,
height: docEl.clientHeight,
style: function style() {
return '\n .' + this.className + ' {\n position: fixed;\n left: 0;\n top: 0;\n overflow: hidden;\n width: ' + this.width + 'px;\n height: ' + this.height + 'px;\n background: #000;\n z-index: 99;\n }\n ';
}
// 遮罩层
};var maskProps = {
className: 'crop-mask',
left: typeof options.x === 'number' ? options.x - wrapProps.width : -(width + wrapProps.width) / 2,
top: typeof options.y === 'number' ? options.y - wrapProps.height : -(height + wrapProps.height) / 2,
style: function style() {
return '\n .' + this.className + ' {\n position: absolute; \n left: ' + this.left + 'px;\n top: ' + this.top + 'px;\n width: ' + width + 'px; \n height: ' + height + 'px; \n overflow: hidden;\n border: 1px solid rgba(0, 0, 0, .6);\n border-width: ' + wrapProps.height + 'px ' + wrapProps.width + 'px;\n transform: translateZ(0);\n -webkit-transform: translateZ(0);\n box-sizing: content-box;\n }\n .' + this.className + ':after {\n position: absolute;\n left: 0;\n top: 0;\n float: left;\n content: \'\';\n width: 200%;\n height: 200%;\n border: 1px solid #fff;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n -webkit-transform: scale(0.5);\n transform: scale(0.5);\n -webkit-transform-origin: 0 0;\n transform-origin: 0 0;\n }\n ';
}
// 底部按钮外层div
};var handleProps = {
className: 'crop-handle',
style: function style() {
return '\n .' + this.className + ' {\n position: absolute;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 50px;\n line-height: 50px;\n transform: translateZ(0);\n -webkit-transform: translateZ(0);\n }\n .' + this.className + ' > div {\n height: 100px;\n width: 80px;\n color: #fff;\n font-size: 16px;\n text-align: center;\n }\n ';
}
// 取消按钮
};var cancleProps = {
className: 'crop-cancle',
style: function style() {
return '\n .' + this.className + ' {\n float: left;\n }\n ';
},
events: {
touchstart: options.cancle.bind(crop)
}
// 确认按钮
};var confirmProps = {
className: 'crop-confirm',
style: function style() {
return '\n .' + this.className + ' {\n float: right;\n }\n ';
},
events: {
touchstart: options.confirm.bind(crop)
}
// 实例化节点对象
};crop.root = new Element('div', wrapProps, [new Element('div', maskProps), new Element('div', handleProps, [new Element('div', cancleProps, ['取消']), new Element('div', confirmProps, ['确认'])])]);
// 创建dom节点
createElement(crop.root, function (element) {
element.style && styles.push(element.style());
});
crop.styles = styles.join('');
crop.area = { width: width, height: height };
options.x = wrapProps.width + maskProps.left;
options.y = wrapProps.height + maskProps.top;
options.created.call(crop);
},
render: function render() {
var crop = this;
var options = crop.options;
if (!Crop.isRenderStyle) {
renderStyle(crop.styles);
Crop.isRenderStyle = true;
}
options.el.appendChild(crop.root.el);
initPinch(crop);
setTimeout(function () {
options.mounted.call(crop);
}, 0);
},
get: function get() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { width: undefined, height: undefined, type: 'image/jpeg', quality: 0.85, format: 'canvas' };
var crop = this;
var pinch = crop.pinch;
var width = config.width,
height = config.height,
type = config.type,
quality = config.quality,
format = config.format;
var scale = pinch.options.width / pinch.rect.width;
var clipWidth = crop.area.width * scale;
var clipHeight = crop.area.height * scale;
var defaultCanvas = getDefaultCanvas();
function getDefaultCanvas() {
var canvas = document.createElement('canvas');
var x = pinch.options.offset.left;
var y = pinch.options.offset.top;
var ctx = canvas.getContext('2d');
canvas.width = clipWidth;
canvas.height = clipHeight;
ctx.drawImage(pinch.canvas, x, y, clipWidth, clipHeight, 0, 0, clipWidth, clipHeight);
return canvas;
}
var result = {};
var value = width || height;
if (value) {
var clipScale = width ? width / clipWidth : height / clipHeight;
var newCanvas = value >= 150 ? scaleCanvas(defaultCanvas, clipScale) : antialisScale(defaultCanvas, clipScale);
result.canvas = newCanvas;
} else {
result.canvas = defaultCanvas;
}
switch (format) {
case 'src':
result.src = result.canvas.toDataURL(type, quality);
break;
case 'blob':
result.blob = dataURItoBlob(result.canvas.toDataURL(type, quality));
break;
case 'url':
result.url = URL.createObjectURL(dataURItoBlob(result.canvas.toDataURL(type, quality)));
}
return result;
},
load: function load(target) {
var crop = this;
crop.options.target = target;
if (crop.pinch) {
crop.pinch.load(target);
} else {
this.render();
}
},
show: function show() {
var _this = this;
// 加定时器保证在其他任务完成之后执行
setTimeout(function () {
_this.root.el.style.display = 'block';
});
},
hide: function hide() {
var _this2 = this;
// 加定时器保证在其他任务完成之后执行
setTimeout(function () {
_this2.root.el.style.display = 'none';
});
},
destroy: function destroy() {
var crop = this;
if (crop.pinch) {
crop.pinch.remove();
removeElement(crop.root, crop.options.el);
}
},
moveTo: function moveTo(x, y) {
var transition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
var result = this.pinch.checkBorder({ x: x, y: y }, this.pinch.scale, { x: x, y: y });
if (result.isDraw) {
x = result.xpos;
y = result.ypos;
}
this.pinch.moveTo(x, y, transition);
},
scaleTo: function scaleTo(point, zoom) {
this.pinch.scaleTo(point, zoom);
}
};
Crop.isRenderStyle = false;
Crop.loadImage = imageToCanvas;
Crop.Pinch = Pinch;
function initPinch(crop) {
var _crop$options = crop.options,
target = _crop$options.target,
maxTargetWidth = _crop$options.maxTargetWidth,
maxTargetHeight = _crop$options.maxTargetHeight,
canvasScale = _crop$options.canvasScale,
x = _crop$options.x,
y = _crop$options.y,
el = _crop$options.el,
maxScale = _crop$options.maxScale,
minScale = _crop$options.minScale,
loaded = _crop$options.loaded;
var _crop$root = crop.root,
touchTarget = _crop$root.el,
width = _crop$root.width,
height = _crop$root.height;
var pinchOptions = {
target: target,
maxTargetWidth: maxTargetWidth,
maxTargetHeight: maxTargetHeight,
el: el,
maxScale: maxScale,
minScale: minScale,
loaded: loaded,
touchTarget: touchTarget,
width: width * canvasScale,
height: height * canvasScale,
offset: {
left: x * canvasScale,
right: (width - crop.area.width - x) * canvasScale,
top: y * canvasScale,
bottom: (height - crop.area.height - y) * canvasScale
}
};
crop.pinch = new Pinch(touchTarget, pinchOptions);
}
return Crop;
})));
});
var props = {
target: {
type: null,
required: true
},
options: {
type: Object,
default: function _default() {
return {
maxTargetWidth: 2000,
maxTargetHeight: 2000,
width: 300,
height: 300,
x: undefined,
y: undefined,
maxScale: 2,
canvasScale: 2,
touchTarget: null
};
}
},
autoClose: {
type: Boolean,
default: true
}
};
var CropComponent = {
name: 'crop',
props: props,
template: '<div class="vue-crop-component" style="width: 0; height: 0;"></div>',
watch: {
target: function target(_target) {
this.load();
}
},
ready: function ready() {
this.init();
},
mounted: function mounted() {
this.init();
},
methods: {
init: function init() {
var vm = this;
var options = extend(vm.options, {
el: vm.$el,
cancle: function cancle() {
vm.$emit('on-cancle');
vm.autoClose && vm._crop.hide();
},
confirm: function confirm() {
vm.$emit('on-confirm', vm._crop);
vm.autoClose && vm._crop.hide();
},
loaded: function loaded() {
vm.$emit('on-loaded', vm._crop);
vm._crop.show();
},
mounted: function mounted() {
vm.$emit('on-mounted', vm._crop);
vm.addTouchEvents();
}
});
vm._crop = new crop(options);
},
load: function load() {
if (this.target && this._crop) {
this._crop.load(this.target);
}
},
addTouchEvents: function addTouchEvents() {
var vm = this;
var events = ['dragstart', 'dragmove', 'dragend', 'pinchstart', 'pinchmove', 'pinchend'];
events.forEach(function (eventName) {
vm._crop.pinch.on(eventName, function (e) {
vm.$emit('on-' + eventName, e);
});
});
}
},
beforeDestroy: function beforeDestroy() {
this._crop && this._crop.destroy();
this._crop = null;
}
};
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.component('crop', CropComponent);
}
return CropComponent;
})));