qf-image-cropper.wxs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /**
  2. * 图片编辑器-手势监听
  3. * 1. wxs 暂不支持 es6 语法
  4. * 2. 支持编译到微信小程序、QQ小程序、app-vue、H5上(uni-app 2.2.5及以上版本)
  5. */
  6. /** 图片偏移量 */
  7. var offset = { x: 0, y: 0 };
  8. /** 图片缩放比例 */
  9. var scale = 1;
  10. /** 图片最小缩放比例 */
  11. var minScale = 1;
  12. /** 图片旋转角度 */
  13. var rotate = 0;
  14. /** 触摸点 */
  15. var touches = [];
  16. /** 图片布局信息 */
  17. var img = {};
  18. /** 系统信息 */
  19. var sys = {};
  20. /** 裁剪区域布局信息 */
  21. var area = {};
  22. /** 触摸行为类型 */
  23. var touchType = '';
  24. /** 操作角的位置 */
  25. var activeAngle = 0;
  26. /** 裁剪区域布局信息偏移量 */
  27. var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
  28. /**
  29. * 计算两点间距
  30. * @param {Object} touches 触摸点信息
  31. */
  32. function getDistanceByTouches(touches) {
  33. // 根据勾股定理求两点间距离
  34. var a = touches[1].pageX - touches[0].pageX;
  35. var b = touches[1].pageY - touches[0].pageY;
  36. var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
  37. // 求两点间的中点坐标
  38. // 1. a、b可能为负值
  39. // 2. 在求a、b时,如用touches[1]减touches[0],则求中点坐标也得用touches[1]减a/2、b/2
  40. // 3. 同理,在求a、b时,也可用touches[0]减touches[1],则求中点坐标也得用touches[0]减a/2、b/2
  41. var x = touches[1].pageX - a / 2;
  42. var y = touches[1].pageY - b / 2;
  43. return { c, x, y };
  44. };
  45. /**
  46. * 修正取值
  47. * @param {Object} a
  48. * @param {Object} b
  49. * @param {Object} c
  50. * @param {Object} reverse 是否反向
  51. */
  52. function correctValue(a, b, c, reverse) {
  53. return reverse ? Math.max(Math.min(a, b), c) : Math.min(Math.max(a, b), c);
  54. }
  55. /**
  56. * 检查边界:限制 x、y 拖动范围,禁止滑出边界
  57. * @param {Object} e 点坐标
  58. */
  59. function checkRange(e) {
  60. var r = rotate / 90 % 2;
  61. if(r === 1) { // 因图片宽高可能不等,翻转 90° 或 270° 后图片宽高需反着计算,且左右和上下边界要根据差值做偏移
  62. var o = (img.height - img.width) / 2; // 宽高差值一半
  63. return {
  64. x: correctValue(e.x, -img.height + o + area.width + area.left, area.left + o, img.height < area.height),
  65. y: correctValue(e.y, -img.width - o + area.height + area.top, area.top - o, img.width < area.width)
  66. }
  67. }
  68. return {
  69. x: correctValue(e.x, -img.width + area.width + area.left, area.left, img.width < area.width),
  70. y: correctValue(e.y, -img.height + area.height + area.top, area.top, img.height < area.height)
  71. }
  72. };
  73. /**
  74. * 变更图片布局信息
  75. * @param {Object} e 布局信息
  76. */
  77. function changeImageRect(e) {
  78. offset.x += e.x || 0;
  79. offset.y += e.y || 0;
  80. var image = e.instance.selectComponent('.crop-image');
  81. if(e.check && area.checkRange) { // 检查边界
  82. var point = checkRange(offset);
  83. if(offset.x !== point.x || offset.y !== point.y) {
  84. offset = point;
  85. }
  86. }
  87. // image.setStyle({
  88. // width: img.width + 'px',
  89. // height: img.height + 'px',
  90. // transform: 'translate(' + offset.x + 'px, ' + offset.y + 'px) rotate(' + rotate +'deg)'
  91. // });
  92. var ox = (img.width - img.oldWidth) / 2;
  93. var oy = (img.height - img.oldHeight) / 2;
  94. image.setStyle({
  95. width: img.oldWidth + 'px',
  96. height: img.oldHeight + 'px',
  97. transform: (img.gpu ? 'translateZ(0) ' : '') + 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
  98. });
  99. e.instance.callMethod('dataChange', {
  100. width: img.width,
  101. height: img.height,
  102. x: offset.x,
  103. y: offset.y,
  104. rotate: rotate
  105. });
  106. };
  107. /**
  108. * 变更裁剪区域布局信息
  109. * @param {Object} e 布局信息
  110. */
  111. function changeAreaRect(e) {
  112. // 变更蒙版样式
  113. var masks = e.instance.selectAllComponents('.crop-mask-block');
  114. var maskStyles = [
  115. {
  116. left: 0,
  117. width: (area.left + areaOffset.left) + 'px',
  118. top: 0,
  119. bottom: 0,
  120. 'z-index': area.zIndex + 2
  121. },
  122. {
  123. left: (area.right + areaOffset.right) + 'px',
  124. right: 0,
  125. top: 0,
  126. bottom: 0,
  127. 'z-index': area.zIndex + 2
  128. },
  129. {
  130. left: (area.left + areaOffset.left) + 'px',
  131. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  132. top: 0,
  133. height: (area.top + areaOffset.top) + 'px',
  134. 'z-index': area.zIndex + 2
  135. },
  136. {
  137. left: (area.left + areaOffset.left) + 'px',
  138. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  139. top: (area.bottom + areaOffset.bottom) + 'px',
  140. // height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px',
  141. bottom: 0,
  142. 'z-index': area.zIndex + 2
  143. }
  144. ];
  145. var len = masks.length;
  146. for (var i = 0; i < len; i++) {
  147. masks[i].setStyle(maskStyles[i]);
  148. }
  149. // 变更边框样式
  150. if(area.showBorder) {
  151. var border = e.instance.selectComponent('.crop-border');
  152. border.setStyle({
  153. left: (area.left + areaOffset.left) + 'px',
  154. top: (area.top + areaOffset.top) + 'px',
  155. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  156. height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
  157. 'z-index': area.zIndex + 3
  158. });
  159. }
  160. // 变更参考线样式
  161. if(area.showGrid) {
  162. var grids = e.instance.selectAllComponents('.crop-grid');
  163. var gridStyles = [
  164. {
  165. 'border-width': '1px 0 0 0',
  166. left: (area.left + areaOffset.left) + 'px',
  167. right: (area.right + areaOffset.right) + 'px',
  168. top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px',
  169. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  170. 'z-index': area.zIndex + 3
  171. },
  172. {
  173. 'border-width': '1px 0 0 0',
  174. left: (area.left + areaOffset.left) + 'px',
  175. right: (area.right + areaOffset.right) + 'px',
  176. top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px',
  177. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  178. 'z-index': area.zIndex + 3
  179. },
  180. {
  181. 'border-width': '0 1px 0 0',
  182. top: (area.top + areaOffset.top) + 'px',
  183. bottom: (area.bottom + areaOffset.bottom) + 'px',
  184. left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px',
  185. height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
  186. 'z-index': area.zIndex + 3
  187. },
  188. {
  189. 'border-width': '0 1px 0 0',
  190. top: (area.top + areaOffset.top) + 'px',
  191. bottom: (area.bottom + areaOffset.bottom) + 'px',
  192. left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px',
  193. height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
  194. 'z-index': area.zIndex + 3
  195. }
  196. ];
  197. var len = grids.length;
  198. for (var i = 0; i < len; i++) {
  199. grids[i].setStyle(gridStyles[i]);
  200. }
  201. }
  202. // 变更四个伸缩角样式
  203. if(area.showAngle) {
  204. var angles = e.instance.selectAllComponents('.crop-angle');
  205. var angleStyles = [
  206. {
  207. 'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px',
  208. left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
  209. top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
  210. 'z-index': area.zIndex + 3
  211. },
  212. {
  213. 'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0',
  214. left: (area.right + areaOffset.right - area.angleSize) + 'px',
  215. top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
  216. 'z-index': area.zIndex + 3
  217. },
  218. {
  219. 'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px',
  220. left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
  221. top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
  222. 'z-index': area.zIndex + 3
  223. },
  224. {
  225. 'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0',
  226. left: (area.right + areaOffset.right - area.angleSize) + 'px',
  227. top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
  228. 'z-index': area.zIndex + 3
  229. }
  230. ];
  231. var len = angles.length;
  232. for (var i = 0; i < len; i++) {
  233. angles[i].setStyle(angleStyles[i]);
  234. }
  235. }
  236. // 变更圆角样式
  237. if(area.radius > 0) {
  238. var circleBox = e.instance.selectComponent('.crop-circle-box');
  239. var circle = e.instance.selectComponent('.crop-circle');
  240. var radius = area.radius;
  241. if(area.width === area.height && area.radius >= area.width / 2) { // 圆形
  242. radius = (area.width / 2);
  243. } else { // 圆角矩形
  244. if(area.width !== area.height) { // 限制圆角半径不能超过短边的一半
  245. radius = Math.min(area.width / 2, area.height / 2, radius);
  246. }
  247. }
  248. circleBox.setStyle({
  249. left: (area.left + areaOffset.left) + 'px',
  250. top: (area.top + areaOffset.top) + 'px',
  251. width: (area.width + areaOffset.right - areaOffset.left) + 'px',
  252. height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
  253. 'z-index': area.zIndex + 2
  254. });
  255. circle.setStyle({
  256. 'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)',
  257. 'border-radius': radius + 'px'
  258. });
  259. }
  260. };
  261. /**
  262. * 缩放图片
  263. * @param {Object} e 布局信息
  264. */
  265. function scaleImage(e) {
  266. var last = scale;
  267. scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale);
  268. if(last !== scale) {
  269. img.width = img.oldWidth * scale;
  270. img.height = img.oldHeight * scale;
  271. // 参考问题:有一个长4000px、宽4000px的四方形ABCD,A点的坐标固定在(-2000,-2000),
  272. // 该四边形上有一个点E,坐标为(-100,-300),将该四方形复制一份并缩小到90%后,
  273. // 新四边形的A点坐标为多少时可使新四边形的E点与原四边形的E点重合?
  274. // 预期效果:从图中选取某点(参照物)为中心点进行缩放,缩放时无论图像怎么变化,该点位置始终固定不变
  275. // 计算方法:以相同起点先计算缩放前后两点间的距离,再加上原图像偏移量即可
  276. e.x = (e.x - offset.x) * (1 - scale / last);
  277. e.y = (e.y - offset.y) * (1 - scale / last);
  278. changeImageRect(e);
  279. return true;
  280. }
  281. return false;
  282. };
  283. /**
  284. * 获取触摸点在哪个角
  285. * @param {number} x 触摸点x轴坐标
  286. * @param {number} y 触摸点y轴坐标
  287. * @return {number} 角的位置:0=无;1=左上;2=右上;3=左下;4=右下;
  288. */
  289. function getToucheAngle(x, y) {
  290. // console.log('getToucheAngle', x, y, JSON.stringify(area))
  291. var o = area.angleBorderWidth; // 需扩大触发范围则把 o 值加大即可
  292. if(y >= area.top - o && y <= area.top + area.angleSize + o) {
  293. if(x >= area.left - o && x <= area.left + area.angleSize + o) {
  294. return 1; // 左上角
  295. } else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
  296. return 2; // 右上角
  297. }
  298. } else if(y >= area.bottom - area.angleSize - o && y <= area.bottom + o) {
  299. if(x >= area.left - o && x <= area.left + area.angleSize + o) {
  300. return 3; // 左下角
  301. } else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
  302. return 4; // 右下角
  303. }
  304. }
  305. return 0; // 无触摸到角
  306. };
  307. /**
  308. * 重置数据
  309. */
  310. function resetData() {
  311. offset = { x: 0, y: 0 };
  312. scale = 1;
  313. minScale = img.minScale;
  314. rotate = 0;
  315. };
  316. /**
  317. * 顺时针翻转图片90°
  318. * @param {Object} e 事件对象
  319. * @param {Object} o 组件实例对象
  320. */
  321. function rotateImage(e, o, r) {
  322. rotate = (rotate + r) % 360;
  323. if(img.minScale >= 1) {
  324. // 因图片宽高可能不等,翻转后图片宽高需足够填满裁剪区域
  325. minScale = 1;
  326. if(img.width < area.height) {
  327. minScale = area.height / img.oldWidth;
  328. } else if(img.height < area.width) {
  329. minScale = (area.width / img.oldHeight)
  330. }
  331. if(minScale !== 1) {
  332. scaleImage({
  333. instance: o,
  334. scale: minScale - scale,
  335. x: sys.windowWidth / 2,
  336. y: (sys.windowHeight - sys.offsetBottom) / 2
  337. });
  338. }
  339. }
  340. // 由于拖动画布后会导致图片位置偏移,翻转时的旋转中心点需是图片区域+偏移区域的中心点
  341. // 翻转x轴中心点 = (超出裁剪区域右侧的图片宽度 - 超出裁剪区域左侧的图片宽度) / 2
  342. // 翻转y轴中心点 = (超出裁剪区域下方的图片宽度 - 超出裁剪区域上方的图片宽度) / 2
  343. var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2;
  344. var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2;
  345. changeImageRect({
  346. instance: o,
  347. check: true,
  348. x: -ox - oy,
  349. y: -oy + ox
  350. });
  351. };
  352. module.exports = {
  353. /**
  354. * 初始化:观察数据变更
  355. * @param {Object} newVal 新数据
  356. * @param {Object} oldVal 旧数据
  357. * @param {Object} o 组件实例对象
  358. */
  359. initObserver: function(newVal, oldVal, o, i) {
  360. if(newVal) {
  361. img = newVal.img;
  362. sys = newVal.sys;
  363. area = newVal.area;
  364. minScale = img.minScale;
  365. resetData();
  366. img.src && changeImageRect({
  367. instance: o,
  368. x: (sys.windowWidth - img.width) / 2,
  369. y: (sys.windowHeight - sys.offsetBottom - img.height) / 2
  370. });
  371. changeAreaRect({
  372. instance: o
  373. });
  374. // console.log('initRect', JSON.stringify(newVal))
  375. }
  376. },
  377. /**
  378. * 鼠标滚轮滚动
  379. * @param {Object} e 事件对象
  380. * @param {Object} o 组件实例对象
  381. */
  382. mousewheel: function(e, o) {
  383. if(!img.src) return;
  384. scaleImage({
  385. instance: o,
  386. check: true,
  387. // 鼠标向上滚动时,deltaY 固定 -100,鼠标向下滚动时,deltaY 固定 100
  388. scale: e.detail.deltaY > 0 ? -0.05 : 0.05,
  389. x: e.touches[0].pageX,
  390. y: e.touches[0].pageY
  391. });
  392. },
  393. /**
  394. * 触摸开始
  395. * @param {Object} e 事件对象
  396. * @param {Object} o 组件实例对象
  397. */
  398. touchstart: function(e, o) {
  399. if(!img.src) return;
  400. touches = e.touches;
  401. activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0;
  402. if(touches.length === 1 && activeAngle !== 0) {
  403. touchType = 'stretch'; // 伸缩裁剪区域
  404. } else {
  405. touchType = '';
  406. }
  407. // console.log('touchstart', JSON.stringify(e), activeAngle)
  408. },
  409. /**
  410. * 触摸移动
  411. * @param {Object} e 事件对象
  412. * @param {Object} o 组件实例对象
  413. */
  414. touchmove: function(e, o) {
  415. if(!img.src) return;
  416. // console.log('touchmove', JSON.stringify(e), JSON.stringify(o))
  417. if(touchType === 'stretch') { // 触摸四个角进行拉伸
  418. var point = e.touches[0];
  419. var start = touches[0];
  420. var x = point.pageX - start.pageX;
  421. var y = point.pageY - start.pageY;
  422. if(x !== 0 || y !== 0) {
  423. var maxX = area.width * (1 - area.minScale);
  424. var maxY = area.height * (1 - area.minScale);
  425. // console.log(x, y, maxX, maxY, offset, area)
  426. touches[0] = point;
  427. switch(activeAngle) {
  428. case 1: // 左上角
  429. x += areaOffset.left;
  430. y += areaOffset.top;
  431. if(x >= 0 && y >= 0) { // 有效滑动
  432. var max = minScale < 1 && area.checkRange && ((offset.x > 0 && offset.x >= area.left) || (offset.y > 0 && offset.y >= area.top))
  433. ? Math.min(offset.y - area.top, offset.x - area.left)
  434. : false;
  435. if(x > y) { // 以x轴滑动距离为缩放基准
  436. if(typeof max === 'number') maxX = max;
  437. if(x > maxX) x = maxX;
  438. y = x * area.height / area.width;
  439. } else { // 以y轴滑动距离为缩放基准
  440. if(typeof max === 'number') maxY = max;
  441. if(y > maxY) y = maxY;
  442. x = y * area.width / area.height;
  443. }
  444. areaOffset.left = x;
  445. areaOffset.top = y;
  446. }
  447. break;
  448. case 2: // 右上角
  449. x += areaOffset.right;
  450. y += areaOffset.top;
  451. if(x <= 0 && y >= 0) { // 有效滑动
  452. var max = minScale < 1 && area.checkRange && ((offset.x > 0 && offset.x + img.width <= area.right) || (offset.y > 0 && offset.y >= area.top))
  453. ? Math.min(offset.y - area.top, area.right - offset.x - img.width)
  454. : false;
  455. if(-x > y) { // 以x轴滑动距离为缩放基准
  456. if(typeof max === 'number') maxX = max;
  457. if(-x > maxX) x = -maxX;
  458. y = -x * area.height / area.width;
  459. } else { // 以y轴滑动距离为缩放基准
  460. if(typeof max === 'number') maxY = max;
  461. if(y > maxY) y = maxY;
  462. x = -y * area.width / area.height;
  463. }
  464. areaOffset.right = x;
  465. areaOffset.top = y;
  466. }
  467. break;
  468. case 3: // 左下角
  469. x += areaOffset.left;
  470. y += areaOffset.bottom;
  471. if(x >= 0 && y <= 0) { // 有效滑动
  472. var max = minScale < 1 && area.checkRange && ((offset.x > 0 && offset.x >= area.left) || (offset.y > 0 && offset.y + img.height <= area.bottom))
  473. ? Math.min(area.bottom - offset.y - img.height, offset.x - area.left)
  474. : false;
  475. if(x > -y) { // 以x轴滑动距离为缩放基准
  476. if(typeof max === 'number') maxX = max;
  477. if(x > maxX) x = maxX;
  478. y = -x * area.height / area.width;
  479. } else { // 以y轴滑动距离为缩放基准
  480. if(typeof max === 'number') maxY = max;
  481. if(-y > maxY) y = -maxY;
  482. x = -y * area.width / area.height;
  483. }
  484. areaOffset.left = x;
  485. areaOffset.bottom = y;
  486. }
  487. break;
  488. case 4: // 右下角
  489. x += areaOffset.right;
  490. y += areaOffset.bottom;
  491. if(x <= 0 && y <= 0) { // 有效滑动
  492. var max = minScale < 1 && area.checkRange && ((offset.x > 0 && offset.x + img.width <= area.right) || (offset.y > 0 && offset.y + img.height <= area.bottom))
  493. ? Math.min(area.bottom - offset.y - img.height, area.right - offset.x - img.width)
  494. : false;
  495. if(-x > -y) { // 以x轴滑动距离为缩放基准
  496. if(typeof max === 'number') maxX = max;
  497. if(-x > maxX) x = -maxX;
  498. y = x * area.height / area.width;
  499. } else { // 以y轴滑动距离为缩放基准
  500. if(typeof max === 'number') maxY = max;
  501. if(-y > maxY) y = -maxY;
  502. x = y * area.width / area.height;
  503. }
  504. areaOffset.right = x;
  505. areaOffset.bottom = y;
  506. }
  507. break;
  508. }
  509. // console.log(x, y, JSON.stringify(areaOffset))
  510. changeAreaRect({
  511. instance: o,
  512. });
  513. // this.draw();
  514. }
  515. } else if (e.touches.length == 2) { // 双点触摸缩放
  516. var start = getDistanceByTouches(touches);
  517. var end = getDistanceByTouches(e.touches);
  518. scaleImage({
  519. instance: o,
  520. check: !area.bounce,
  521. scale: (end.c - start.c) / 100,
  522. x: end.x,
  523. y: end.y
  524. });
  525. touchType = 'scale';
  526. } else if(touchType === 'scale') {// 从双点触摸变成单点触摸 / 从缩放变成拖动
  527. touchType = 'move';
  528. } else {
  529. changeImageRect({
  530. instance: o,
  531. check: !area.bounce,
  532. x: e.touches[0].pageX - touches[0].pageX,
  533. y: e.touches[0].pageY - touches[0].pageY
  534. });
  535. touchType = 'move';
  536. }
  537. touches = e.touches;
  538. },
  539. /**
  540. * 触摸结束
  541. * @param {Object} e 事件对象
  542. * @param {Object} o 组件实例对象
  543. */
  544. touchend: function(e, o) {
  545. if(!img.src) return;
  546. if(touchType === 'stretch') { // 拉伸裁剪区域的四个角缩放
  547. // 裁剪区域宽度被缩放到多少
  548. var left = areaOffset.left;
  549. var right = areaOffset.right;
  550. var top = areaOffset.top;
  551. var bottom = areaOffset.bottom;
  552. var w = area.width + right - left;
  553. var h = area.height + bottom - top;
  554. // 图像放大倍数
  555. var p = scale * (area.width / w) - scale;
  556. // 复原裁剪区域
  557. areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
  558. changeAreaRect({
  559. instance: o,
  560. });
  561. scaleImage({
  562. instance: o,
  563. scale: p,
  564. x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0),
  565. y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0)
  566. });
  567. } else if (area.bounce) { // 检查边界并矫正,实现拖动到边界时有回弹效果
  568. changeImageRect({
  569. instance: o,
  570. check: true
  571. });
  572. }
  573. },
  574. /**
  575. * 顺时针翻转图片90°
  576. * @param {Object} e 事件对象
  577. * @param {Object} o 组件实例对象
  578. */
  579. rotateImage: function(e, o) {
  580. rotateImage(e, o, 90);
  581. },
  582. rotateImage90: function(e, o) {
  583. rotateImage(e, o, 90)
  584. },
  585. rotateImage270: function(e, o) {
  586. rotateImage(e, o, 270)
  587. },
  588. // 此处只用于对齐其他平台端的样式参数,防止异常,无作用
  589. imageStyles: '',
  590. maskStylesList: ['', '', '', ''],
  591. borderStyles: '',
  592. gridStylesList: ['', '', '', ''],
  593. angleStylesList: ['', '', '', ''],
  594. circleBoxStyles: '',
  595. circleStyles: '',
  596. }