weCropper.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. (function(global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.weCropper = factory());
  5. }(this, (function() {
  6. 'use strict';
  7. /**
  8. * Created by sail on 2017/6/11.
  9. */
  10. var device = void 0;
  11. var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended'];
  12. function firstLetterUpper(str) {
  13. return str.charAt(0).toUpperCase() + str.slice(1);
  14. }
  15. function setTouchState(instance) {
  16. for (var _len = arguments.length, arg = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  17. arg[_key - 1] = arguments[_key];
  18. }
  19. TOUCH_STATE.forEach(function(key, i) {
  20. if (arg[i] !== undefined) {
  21. instance[key] = arg[i];
  22. }
  23. });
  24. }
  25. function validator(instance, o) {
  26. Object.defineProperties(instance, o);
  27. }
  28. function getDevice() {
  29. if (!device) {
  30. device = wx.getSystemInfoSync();
  31. }
  32. return device;
  33. }
  34. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {
  35. return typeof obj;
  36. } : function(obj) {
  37. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  38. };
  39. var classCallCheck = function(instance, Constructor) {
  40. if (!(instance instanceof Constructor)) {
  41. throw new TypeError("Cannot call a class as a function");
  42. }
  43. };
  44. var createClass = function() {
  45. function defineProperties(target, props) {
  46. for (var i = 0; i < props.length; i++) {
  47. var descriptor = props[i];
  48. descriptor.enumerable = descriptor.enumerable || false;
  49. descriptor.configurable = true;
  50. if ("value" in descriptor) descriptor.writable = true;
  51. Object.defineProperty(target, descriptor.key, descriptor);
  52. }
  53. }
  54. return function(Constructor, protoProps, staticProps) {
  55. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  56. if (staticProps) defineProperties(Constructor, staticProps);
  57. return Constructor;
  58. };
  59. }();
  60. var slicedToArray = function() {
  61. function sliceIterator(arr, i) {
  62. var _arr = [];
  63. var _n = true;
  64. var _d = false;
  65. var _e = undefined;
  66. try {
  67. for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
  68. _arr.push(_s.value);
  69. if (i && _arr.length === i) break;
  70. }
  71. } catch (err) {
  72. _d = true;
  73. _e = err;
  74. } finally {
  75. try {
  76. if (!_n && _i["return"]) _i["return"]();
  77. } finally {
  78. if (_d) throw _e;
  79. }
  80. }
  81. return _arr;
  82. }
  83. return function(arr, i) {
  84. if (Array.isArray(arr)) {
  85. return arr;
  86. } else if (Symbol.iterator in Object(arr)) {
  87. return sliceIterator(arr, i);
  88. } else {
  89. throw new TypeError("Invalid attempt to destructure non-iterable instance");
  90. }
  91. };
  92. }();
  93. var tmp = {};
  94. var DEFAULT = {
  95. id: {
  96. default: 'cropper',
  97. get: function get$$1() {
  98. return tmp.id;
  99. },
  100. set: function set$$1(value) {
  101. if (typeof value !== 'string') {}
  102. tmp.id = value;
  103. }
  104. },
  105. width: {
  106. default: 750,
  107. get: function get$$1() {
  108. return tmp.width;
  109. },
  110. set: function set$$1(value) {
  111. tmp.width = value;
  112. }
  113. },
  114. height: {
  115. default: 750,
  116. get: function get$$1() {
  117. return tmp.height;
  118. },
  119. set: function set$$1(value) {
  120. tmp.height = value;
  121. }
  122. },
  123. scale: {
  124. default: 2.5,
  125. get: function get$$1() {
  126. return tmp.scale;
  127. },
  128. set: function set$$1(value) {
  129. tmp.scale = value;
  130. }
  131. },
  132. zoom: {
  133. default: 5,
  134. get: function get$$1() {
  135. return tmp.zoom;
  136. },
  137. set: function set$$1(value) {
  138. tmp.zoom = value;
  139. }
  140. },
  141. src: {
  142. default: 'cropper',
  143. get: function get$$1() {
  144. return tmp.src;
  145. },
  146. set: function set$$1(value) {
  147. tmp.src = value;
  148. }
  149. },
  150. cut: {
  151. default: {},
  152. get: function get$$1() {
  153. return tmp.cut;
  154. },
  155. set: function set$$1(value) {
  156. tmp.cut = value;
  157. }
  158. },
  159. onReady: {
  160. default: null,
  161. get: function get$$1() {
  162. return tmp.ready;
  163. },
  164. set: function set$$1(value) {
  165. tmp.ready = value;
  166. }
  167. },
  168. onBeforeImageLoad: {
  169. default: null,
  170. get: function get$$1() {
  171. return tmp.beforeImageLoad;
  172. },
  173. set: function set$$1(value) {
  174. tmp.beforeImageLoad = value;
  175. }
  176. },
  177. onImageLoad: {
  178. default: null,
  179. get: function get$$1() {
  180. return tmp.imageLoad;
  181. },
  182. set: function set$$1(value) {
  183. tmp.imageLoad = value;
  184. }
  185. },
  186. onBeforeDraw: {
  187. default: null,
  188. get: function get$$1() {
  189. return tmp.beforeDraw;
  190. },
  191. set: function set$$1(value) {
  192. tmp.beforeDraw = value;
  193. }
  194. }
  195. };
  196. /**
  197. * Created by sail on 2017/6/11.
  198. */
  199. function prepare() {
  200. var self = this;
  201. var _getDevice = getDevice(),
  202. windowWidth = _getDevice.windowWidth;
  203. self.attachPage = function() {
  204. var pages = getCurrentPages
  205. // 获取到当前page上下文
  206. ();
  207. var pageContext = pages[pages.length - 1];
  208. // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问
  209. pageContext.wecropper = self;
  210. };
  211. self.createCtx = function() {
  212. var id = self.id;
  213. if (id) {
  214. self.ctx = wx.createCanvasContext(id);
  215. }
  216. };
  217. self.deviceRadio = windowWidth / 750;
  218. self.deviceRadio=self.deviceRadio.toFixed(2)
  219. }
  220. /**
  221. *
  222. */
  223. function observer() {
  224. var self = this;
  225. var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad'];
  226. self.on = function(event, fn) {
  227. if (EVENT_TYPE.indexOf(event) > -1) {
  228. if (typeof fn === 'function') {
  229. event === 'ready' ? fn(self) : self['on' + firstLetterUpper(event)] = fn;
  230. }
  231. }
  232. return self;
  233. };
  234. }
  235. /**
  236. * Created by sail on 2017/6/11.
  237. */
  238. function methods() {
  239. var self = this;
  240. var deviceRadio = self.deviceRadio;
  241. console.log(JSON.stringify(self));
  242. var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
  243. var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度
  244. var _self$cut = self.cut,
  245. _self$cut$x = _self$cut.x,
  246. x = _self$cut$x === undefined ? 0 : _self$cut$x,
  247. _self$cut$y = _self$cut.y,
  248. y = _self$cut$y === undefined ? 0 : _self$cut$y,
  249. _self$cut$width = _self$cut.width,
  250. width = _self$cut$width === undefined ? boundWidth : _self$cut$width,
  251. _self$cut$height = _self$cut.height,
  252. height = _self$cut$height === undefined ? boundHeight : _self$cut$height;
  253. self.updateCanvas = function() {
  254. if (self.croperTarget) {
  255. // 画布绘制图片
  256. self.ctx.drawImage(self.croperTarget, self.imgLeft, self.imgTop, self.scaleWidth, self.scaleHeight);
  257. }
  258. typeof self.onBeforeDraw === 'function' && self.onBeforeDraw(self.ctx, self);
  259. self.setBoundStyle // 设置边界样式
  260. ();
  261. self.ctx.draw();
  262. return self;
  263. };
  264. self.pushOrign = function(src) {
  265. self.src = src;
  266. typeof self.onBeforeImageLoad === 'function' && self.onBeforeImageLoad(self.ctx, self);
  267. uni.getImageInfo({
  268. src: src,
  269. success: function success(res) {
  270. var innerAspectRadio = res.width / res.height;
  271. self.croperTarget = res.path||src;
  272. if (innerAspectRadio < width / height) {
  273. self.rectX = x;
  274. self.baseWidth = width;
  275. self.baseHeight = width / innerAspectRadio;
  276. self.rectY = y - Math.abs((height - self.baseHeight) / 2);
  277. } else {
  278. self.rectY = y;
  279. self.baseWidth = height * innerAspectRadio;
  280. self.baseHeight = height;
  281. self.rectX = x - Math.abs((width - self.baseWidth) / 2);
  282. }
  283. self.imgLeft = self.rectX;
  284. self.imgTop = self.rectY;
  285. self.scaleWidth = self.baseWidth;
  286. self.scaleHeight = self.baseHeight;
  287. self.updateCanvas();
  288. typeof self.onImageLoad === 'function' && self.onImageLoad(self.ctx, self);
  289. }
  290. });
  291. self.update();
  292. return self;
  293. };
  294. self.getCropperImage = function() {
  295. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  296. args[_key] = arguments[_key];
  297. }
  298. var id = self.id;
  299. var ARG_TYPE = toString.call(args[0]);
  300. switch (ARG_TYPE) {
  301. case '[object Object]':
  302. var _args$0$quality = args[0].quality,
  303. quality = _args$0$quality === undefined ? 10 : _args$0$quality;
  304. console.log("quality--"+quality);
  305. uni.canvasToTempFilePath({
  306. canvasId: id,
  307. x: x,
  308. y: y,
  309. width: width,
  310. height: height,
  311. destWidth: width * quality / (deviceRadio * 10),
  312. destHeight: height * quality / (deviceRadio * 10),
  313. success: function success(res) {
  314. console.log(res);
  315. typeof args[args.length - 1] === 'function' && args[args.length - 1](res.tempFilePath);
  316. }
  317. });
  318. break;
  319. case '[object Function]':
  320. uni.canvasToTempFilePath({
  321. canvasId: id,
  322. x: x,
  323. y: y,
  324. fileType:"jpg",
  325. width: width,
  326. height: height,
  327. destWidth: width ,
  328. destHeight: height,
  329. success: function success(res) {
  330. typeof args[args.length - 1] === 'function' && args[args.length - 1](res.tempFilePath);
  331. }
  332. });
  333. break;
  334. }
  335. return self;
  336. };
  337. }
  338. /**
  339. * Created by sail on 2017/6/11.
  340. */
  341. function update() {
  342. var self = this;
  343. if (!self.src) return;
  344. self.__oneTouchStart = function(touch) {
  345. self.touchX0 = touch.x;
  346. self.touchY0 = touch.y;
  347. };
  348. self.__oneTouchMove = function(touch) {
  349. var xMove = void 0,
  350. yMove = void 0;
  351. //计算单指移动的距离
  352. if (self.touchended) {
  353. return self.updateCanvas();
  354. }
  355. xMove = touch.x - self.touchX0;
  356. yMove = touch.y - self.touchY0;
  357. var imgLeft = self.rectX + xMove;
  358. var imgTop = self.rectY + yMove;
  359. self.outsideBound(imgLeft, imgTop);
  360. self.updateCanvas();
  361. };
  362. self.__twoTouchStart = function(touch0, touch1) {
  363. var xMove = void 0,
  364. yMove = void 0,
  365. oldDistance = void 0;
  366. self.touchX1 = self.rectX + self.scaleWidth / 2;
  367. self.touchY1 = self.rectY + self.scaleHeight / 2;
  368. //计算两指距离
  369. xMove = touch1.x - touch0.x;
  370. yMove = touch1.y - touch0.y;
  371. oldDistance = Math.sqrt(xMove * xMove + yMove * yMove);
  372. self.oldDistance = oldDistance;
  373. };
  374. self.__twoTouchMove = function(touch0, touch1) {
  375. var xMove = void 0,
  376. yMove = void 0,
  377. newDistance = void 0;
  378. var scale = self.scale,
  379. zoom = self.zoom;
  380. // 计算二指最新距离
  381. xMove = touch1.x - touch0.x;
  382. yMove = touch1.y - touch0.y;
  383. newDistance = Math.sqrt(xMove * xMove + yMove * yMove
  384. // 使用0.005的缩放倍数具有良好的缩放体验
  385. );
  386. self.newScale = self.oldScale + 0.001 * zoom * (newDistance - self.oldDistance);
  387. // 设定缩放范围
  388. self.newScale <= 1 && (self.newScale = 1);
  389. self.newScale >= scale && (self.newScale = scale);
  390. self.scaleWidth = self.newScale * self.baseWidth;
  391. self.scaleHeight = self.newScale * self.baseHeight;
  392. var imgLeft = self.touchX1 - self.scaleWidth / 2;
  393. var imgTop = self.touchY1 - self.scaleHeight / 2;
  394. self.outsideBound(imgLeft, imgTop);
  395. self.updateCanvas();
  396. };
  397. self.__xtouchEnd = function() {
  398. self.oldScale = self.newScale;
  399. self.rectX = self.imgLeft;
  400. self.rectY = self.imgTop;
  401. };
  402. }
  403. /**
  404. * Created by sail on 2017/6/11.
  405. */
  406. var handle = {
  407. // 图片手势初始监测
  408. touchStart: function touchStart(e) {
  409. var self = this;
  410. var _e$touches = slicedToArray(e.touches, 2),
  411. touch0 = _e$touches[0],
  412. touch1 = _e$touches[1];
  413. console.log(JSON.stringify(touch1));
  414. if(!touch0.x){
  415. touch0.x=touch0.clientX;
  416. touch0.y=touch0.clientY;
  417. if(touch1){
  418. touch1.x=touch1.clientX;
  419. touch1.y=touch1.clientY;
  420. }
  421. }
  422. setTouchState(self, true, null, null
  423. //计算第一个触摸点的位置,并参照改点进行缩放
  424. );
  425. self.__oneTouchStart(touch0
  426. // 两指手势触发
  427. );
  428. if (e.touches.length >= 2) {
  429. self.__twoTouchStart(touch0, touch1);
  430. }
  431. },
  432. // 图片手势动态缩放
  433. touchMove: function touchMove(e) {
  434. var self = this;
  435. var _e$touches2 = slicedToArray(e.touches, 2),
  436. touch0 = _e$touches2[0],
  437. touch1 = _e$touches2[1];
  438. if(!touch0.x){
  439. touch0.x=touch0.clientX;
  440. touch0.y=touch0.clientY;
  441. if(touch1){
  442. touch1.x=touch1.clientX;
  443. touch1.y=touch1.clientY;
  444. }
  445. }
  446. setTouchState(self, null, true
  447. // 单指手势时触发
  448. );
  449. if (e.touches.length === 1) {
  450. self.__oneTouchMove(touch0);
  451. }
  452. // 两指手势触发
  453. if (e.touches.length >= 2) {
  454. self.__twoTouchMove(touch0, touch1);
  455. }
  456. },
  457. touchEnd: function touchEnd(e) {
  458. var self = this;
  459. setTouchState(self, false, false, true);
  460. self.__xtouchEnd();
  461. }
  462. };
  463. /**
  464. * Created by sail on 1017/6/12.
  465. */
  466. function cut() {
  467. var self = this;
  468. var deviceRadio = self.deviceRadio;
  469. var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
  470. var boundHeight = self.height;
  471. // 裁剪框默认高度,即整个画布高度
  472. var _self$cut = self.cut,
  473. _self$cut$x = _self$cut.x,
  474. x = _self$cut$x === undefined ? 0 : _self$cut$x,
  475. _self$cut$y = _self$cut.y,
  476. y = _self$cut$y === undefined ? 0 : _self$cut$y,
  477. _self$cut$width = _self$cut.width,
  478. width = _self$cut$width === undefined ? boundWidth : _self$cut$width,
  479. _self$cut$height = _self$cut.height,
  480. height = _self$cut$height === undefined ? boundHeight : _self$cut$height;
  481. /**
  482. * 设置边界
  483. * @param imgLeft 图片左上角横坐标值
  484. * @param imgTop 图片左上角纵坐标值
  485. */
  486. self.outsideBound = function(imgLeft, imgTop) {
  487. self.imgLeft = imgLeft >= x ? x : self.scaleWidth + imgLeft - x <= width ? x + width - self.scaleWidth : imgLeft;
  488. self.imgTop = imgTop >= y ? y : self.scaleHeight + imgTop - y <= height ? y + height - self.scaleHeight : imgTop;
  489. };
  490. /**
  491. * 设置边界样式
  492. * @param color 边界颜色
  493. */
  494. self.setBoundStyle = function() {
  495. var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
  496. _ref$color = _ref.color,
  497. color = _ref$color === undefined ? '#04b00f' : _ref$color,
  498. _ref$mask = _ref.mask,
  499. mask = _ref$mask === undefined ? 'rgba(0, 0, 0, 0.3)' : _ref$mask,
  500. _ref$lineWidth = _ref.lineWidth,
  501. lineWidth = _ref$lineWidth === undefined ? 1 : _ref$lineWidth;
  502. // 绘制半透明层
  503. self.ctx.beginPath();
  504. self.ctx.setFillStyle(mask);
  505. self.ctx.fillRect(0, 0, x, boundHeight);
  506. self.ctx.fillRect(x, 0, width, y);
  507. self.ctx.fillRect(x, y + height, width, boundHeight - y - height);
  508. self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight);
  509. self.ctx.fill
  510. // 设置边界左上角样式
  511. // 为使边界样式处于边界外边缘,此时x、y均要减少lineWidth
  512. ();
  513. self.ctx.beginPath();
  514. self.ctx.setStrokeStyle(color);
  515. self.ctx.setLineWidth(lineWidth);
  516. self.ctx.moveTo(x - lineWidth, y + 10 - lineWidth);
  517. self.ctx.lineTo(x - lineWidth, y - lineWidth);
  518. self.ctx.lineTo(x + 10 - lineWidth, y - lineWidth);
  519. self.ctx.stroke
  520. // 设置边界左下角样式
  521. // 为使边界样式处于边界外边缘,此时x要减少lineWidth、y要增加lineWidth
  522. ();
  523. self.ctx.beginPath();
  524. self.ctx.setStrokeStyle(color);
  525. self.ctx.setLineWidth(lineWidth);
  526. self.ctx.moveTo(x - lineWidth, y + height - 10 + lineWidth);
  527. self.ctx.lineTo(x - lineWidth, y + height + lineWidth);
  528. self.ctx.lineTo(x + 10 - lineWidth, y + height + lineWidth);
  529. self.ctx.stroke
  530. // 设置边界右上角样式
  531. // 为使边界样式处于边界外边缘,此时x要增加lineWidth、y要减少lineWidth
  532. ();
  533. self.ctx.beginPath();
  534. self.ctx.setStrokeStyle(color);
  535. self.ctx.setLineWidth(lineWidth);
  536. self.ctx.moveTo(x + width - 10 + lineWidth, y - lineWidth);
  537. self.ctx.lineTo(x + width + lineWidth, y - lineWidth);
  538. self.ctx.lineTo(x + width + lineWidth, y + 10 - lineWidth);
  539. self.ctx.stroke
  540. // 设置边界右下角样式
  541. // 为使边界样式处于边界外边缘,此时x、y均要增加lineWidth
  542. ();
  543. self.ctx.beginPath();
  544. self.ctx.setStrokeStyle(color);
  545. self.ctx.setLineWidth(lineWidth);
  546. self.ctx.moveTo(x + width + lineWidth, y + height - 10 + lineWidth);
  547. self.ctx.lineTo(x + width + lineWidth, y + height + lineWidth);
  548. self.ctx.lineTo(x + width - 10 + lineWidth, y + height + lineWidth);
  549. self.ctx.stroke();
  550. };
  551. }
  552. var __version__ = '1.1.4';
  553. var weCropper = function() {
  554. function weCropper(params) {
  555. classCallCheck(this, weCropper);
  556. var self = this;
  557. var _default = {};
  558. validator(self, DEFAULT);
  559. Object.keys(DEFAULT).forEach(function(key) {
  560. _default[key] = DEFAULT[key].default;
  561. });
  562. Object.assign(self, _default, params);
  563. self.prepare();
  564. self.attachPage();
  565. self.createCtx();
  566. self.observer();
  567. self.cutt();
  568. self.methods();
  569. self.init();
  570. self.update();
  571. return self;
  572. }
  573. createClass(weCropper, [{
  574. key: 'init',
  575. value: function init() {
  576. var self = this;
  577. var src = self.src;
  578. self.version = __version__;
  579. typeof self.onReady === 'function' && self.onReady(self.ctx, self);
  580. if (src) {
  581. self.pushOrign(src);
  582. }
  583. setTouchState(self, false, false, false);
  584. self.oldScale = 1;
  585. self.newScale = 1;
  586. return self;
  587. }
  588. }]);
  589. return weCropper;
  590. }();
  591. Object.assign(weCropper.prototype, handle);
  592. weCropper.prototype.prepare = prepare;
  593. weCropper.prototype.observer = observer;
  594. weCropper.prototype.methods = methods;
  595. weCropper.prototype.cutt = cut;
  596. weCropper.prototype.update = update;
  597. return weCropper;
  598. })));