tui-picture-cropper.wxs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. var cropper = {
  2. CUT_START: null,
  3. cutX: 0, //画布x轴起点
  4. cutY: 0, //画布y轴起点0
  5. touchRelative: [{
  6. x: 0,
  7. y: 0
  8. }], //手指或鼠标和图片中心的相对位置
  9. flagCutTouch: false, //是否是拖动裁剪框
  10. hypotenuseLength: 0, //双指触摸时斜边长度
  11. flagEndTouch: false, //是否结束触摸
  12. canvasWidth: 0,
  13. canvasHeight: 0,
  14. imgWidth: 0, //图片宽度
  15. imgHeight: 0, //图片高度
  16. scale: 1, //图片缩放比
  17. angle: 0, //图片旋转角度
  18. imgTop: 0, //图片上边距
  19. imgLeft: 0, //图片左边距
  20. //是否限制移动范围(剪裁框只能在图片内,为true不可触摸转动图片)
  21. limitMove: true,
  22. minHeight: 0,
  23. maxHeight: 0,
  24. minWidth: 0,
  25. maxWidth: 0,
  26. windowHeight: 0,
  27. windowWidth: 0,
  28. init: true
  29. }
  30. function bool(str) {
  31. return str === 'true' || str == true ? true : false
  32. }
  33. function touchstart(e, ins) {
  34. //var instance = e.instance;
  35. // var state = instance.getState();
  36. var touch = e.touches || e.changedTouches;
  37. cropper.flagEndTouch = false;
  38. if (touch.length == 1) {
  39. cropper.touchRelative[0] = {
  40. x: touch[0].pageX - cropper.imgLeft,
  41. y: touch[0].pageY - cropper.imgTop
  42. };
  43. } else {
  44. var width = Math.abs(touch[0].pageX - touch[1].pageX);
  45. var height = Math.abs(touch[0].pageY - touch[1].pageY);
  46. cropper.touchRelative = [{
  47. x: touch[0].pageX - cropper.imgLeft,
  48. y: touch[0].pageY - cropper.imgTop
  49. },
  50. {
  51. x: touch[1].pageX - cropper.imgLeft,
  52. y: touch[1].pageY - cropper.imgTop
  53. }
  54. ];
  55. cropper.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
  56. }
  57. }
  58. function moveDuring(ins) {
  59. if (!ins) return;
  60. ins.callMethod('moveDuring')
  61. }
  62. function moveStop(ins) {
  63. if (!ins) return;
  64. ins.callMethod('moveStop')
  65. };
  66. function setCutCenter(ins) {
  67. var cutY = (cropper.windowHeight - cropper.canvasHeight) * 0.5;
  68. var cutX = (cropper.windowWidth - cropper.canvasWidth) * 0.5;
  69. //顺序不能变
  70. cropper.imgTop = cropper.imgTop - cropper.cutY + cutY;
  71. cropper.cutY = cutY; //截取的框上边距
  72. cropper.imgLeft = cropper.imgLeft - cropper.cutX + cutX;
  73. cropper.cutX = cutX; //截取的框左边距
  74. styleUpdate(ins)
  75. cutDetectionPosition(ins)
  76. imgTransform(ins)
  77. updateData(ins)
  78. }
  79. function touchmove(e, ins) {
  80. var touch = e.touches || e.changedTouches;
  81. if (cropper.flagEndTouch) return;
  82. moveDuring(ins);
  83. if (e.touches.length == 1) {
  84. var left = touch[0].pageX - cropper.touchRelative[0].x,
  85. top = touch[0].pageY - cropper.touchRelative[0].y;
  86. cropper.imgLeft = left;
  87. cropper.imgTop = top;
  88. imgTransform(ins);
  89. imgMarginDetectionPosition(ins);
  90. } else {
  91. var res = e.instance.getDataset();
  92. var minScale = +res.minscale;
  93. var maxScale = +res.maxscale;
  94. var disableRotate = bool(res.disablerotate)
  95. var width = Math.abs(touch[0].pageX - touch[1].pageX),
  96. height = Math.abs(touch[0].pageY - touch[1].pageY),
  97. hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
  98. scale = cropper.scale * (hypotenuse / cropper.hypotenuseLength),
  99. current_deg = 0;
  100. scale = scale <= minScale ? minScale : scale;
  101. scale = scale >= maxScale ? maxScale : scale;
  102. cropper.scale = scale;
  103. imgMarginDetectionScale(ins, true);
  104. var touchRelative = [{
  105. x: touch[0].pageX - cropper.imgLeft,
  106. y: touch[0].pageY - cropper.imgTop
  107. },
  108. {
  109. x: touch[1].pageX - cropper.imgLeft,
  110. y: touch[1].pageY - cropper.imgTop
  111. }
  112. ];
  113. if (!disableRotate) {
  114. var first_atan = (180 / Math.PI) * Math.atan2(touchRelative[0].y, touchRelative[0].x);
  115. var first_atan_old = (180 / Math.PI) * Math.atan2(cropper.touchRelative[0].y, cropper.touchRelative[0].x);
  116. var second_atan = (180 / Math.PI) * Math.atan2(touchRelative[1].y, touchRelative[1].x);
  117. var second_atan_old = (180 / Math.PI) * Math.atan2(cropper.touchRelative[1].y, cropper.touchRelative[1].x);
  118. var first_deg = first_atan - first_atan_old,
  119. second_deg = second_atan - second_atan_old;
  120. if (first_deg != 0) {
  121. current_deg = first_deg;
  122. } else if (second_deg != 0) {
  123. current_deg = second_deg;
  124. }
  125. }
  126. cropper.touchRelative = touchRelative;
  127. cropper.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
  128. //更新视图
  129. cropper.angle = cropper.angle + current_deg;
  130. imgTransform(ins);
  131. }
  132. }
  133. function touchend(e, ins) {
  134. cropper.flagEndTouch = true;
  135. moveStop(ins);
  136. updateData(ins)
  137. }
  138. function cutTouchStart(e, ins) {
  139. var touch = e.touches || e.changedTouches;
  140. var currentX = touch[0].pageX;
  141. var currentY = touch[0].pageY;
  142. /*
  143. * (右下-1 右上-2 左上-3 左下-4)
  144. * left_x [3,4]
  145. * top_y [2,3]
  146. * right_x [1,2]
  147. * bottom_y [1,4]
  148. */
  149. var left_x1 = cropper.cutX - 30;
  150. var left_x2 = cropper.cutX + 30;
  151. var top_y1 = cropper.cutY - 30;
  152. var top_y2 = cropper.cutY + 30;
  153. var right_x1 = cropper.cutX + cropper.canvasWidth - 30;
  154. var right_x2 = cropper.cutX + cropper.canvasWidth + 30;
  155. var bottom_y1 = cropper.cutY + cropper.canvasHeight - 30;
  156. var bottom_y2 = cropper.cutY + cropper.canvasHeight + 30;
  157. if (currentX > right_x1 && currentX < right_x2 && currentY > bottom_y1 && currentY < bottom_y2) {
  158. moveDuring();
  159. cropper.flagCutTouch = true;
  160. cropper.flagEndTouch = true;
  161. cropper.CUT_START = {
  162. width: cropper.canvasWidth,
  163. height: cropper.canvasHeight,
  164. x: currentX,
  165. y: currentY,
  166. corner: 1
  167. };
  168. } else if (currentX > right_x1 && currentX < right_x2 && currentY > top_y1 && currentY < top_y2) {
  169. moveDuring();
  170. cropper.flagCutTouch = true;
  171. cropper.flagEndTouch = true;
  172. cropper.CUT_START = {
  173. width: cropper.canvasWidth,
  174. height: cropper.canvasHeight,
  175. x: currentX,
  176. y: currentY,
  177. cutY: cropper.cutY,
  178. cutX: cropper.cutX,
  179. corner: 2
  180. };
  181. } else if (currentX > left_x1 && currentX < left_x2 && currentY > top_y1 && currentY < top_y2) {
  182. moveDuring();
  183. cropper.flagCutTouch = true;
  184. cropper.flagEndTouch = true;
  185. cropper.CUT_START = {
  186. width: cropper.canvasWidth,
  187. height: cropper.canvasHeight,
  188. cutY: cropper.cutY,
  189. cutX: cropper.cutX,
  190. x: currentX,
  191. y: currentY,
  192. corner: 3
  193. };
  194. } else if (currentX > left_x1 && currentX < left_x2 && currentY > bottom_y1 && currentY < bottom_y2) {
  195. moveDuring();
  196. cropper.flagCutTouch = true;
  197. cropper.flagEndTouch = true;
  198. cropper.CUT_START = {
  199. width: cropper.canvasWidth,
  200. height: cropper.canvasHeight,
  201. cutY: cropper.cutY,
  202. cutX: cropper.cutX,
  203. x: currentX,
  204. y: currentY,
  205. corner: 4
  206. };
  207. }
  208. }
  209. function cutTouchMove(e, ins) {
  210. if (!cropper.CUT_START || cropper.CUT_START === 'null') return;
  211. if (cropper.flagCutTouch) {
  212. var touch = e.touches || e.changedTouches;
  213. var res = e.instance.getDataset();
  214. var lockRatio = bool(res.lockratio);
  215. var lockWidth = bool(res.lockwidth);
  216. var lockHeight = bool(res.lockheight);
  217. if (lockRatio && (lockWidth || lockHeight)) return;
  218. var width = cropper.canvasWidth,
  219. height = cropper.canvasHeight,
  220. cutY = cropper.cutY,
  221. cutX = cropper.cutX;
  222. var size_correct = function() {
  223. width = width <= cropper.maxWidth ? (width >= cropper.minWidth ? width : cropper.minWidth) : cropper
  224. .maxWidth;
  225. height = height <= cropper.maxHeight ? (height >= cropper.minHeight ? height : cropper.minHeight) :
  226. cropper.maxHeight;
  227. }
  228. var size_inspect = function() {
  229. if ((width > cropper.maxWidth || width < cropper.minWidth || height > cropper.maxHeight || height <
  230. cropper.minHeight) &&
  231. lockRatio) {
  232. size_correct();
  233. return false;
  234. } else {
  235. size_correct();
  236. return true;
  237. }
  238. };
  239. height = cropper.CUT_START.height + (cropper.CUT_START.corner > 1 && cropper.CUT_START.corner < 4 ? 1 : -1) * (
  240. cropper.CUT_START.y - touch[0].pageY);
  241. switch (cropper.CUT_START.corner) {
  242. case 1:
  243. width = cropper.CUT_START.width - cropper.CUT_START.x + touch[0].pageX;
  244. if (lockRatio) {
  245. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  246. }
  247. if (!size_inspect()) return;
  248. break;
  249. case 2:
  250. width = cropper.CUT_START.width - cropper.CUT_START.x + touch[0].pageX;
  251. if (lockRatio) {
  252. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  253. }
  254. if (!size_inspect()) return;
  255. cutY = cropper.CUT_START.cutY - (height - cropper.CUT_START.height);
  256. break;
  257. case 3:
  258. width = cropper.CUT_START.width + cropper.CUT_START.x - touch[0].pageX;
  259. if (lockRatio) {
  260. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  261. }
  262. if (!size_inspect()) return;
  263. cutY = cropper.CUT_START.cutY - (height - cropper.CUT_START.height);
  264. cutX = cropper.CUT_START.cutX - (width - cropper.CUT_START.width);
  265. break;
  266. case 4:
  267. width = cropper.CUT_START.width + cropper.CUT_START.x - touch[0].pageX;
  268. if (lockRatio) {
  269. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  270. }
  271. if (!size_inspect()) return;
  272. cutX = cropper.CUT_START.cutX - (width - cropper.CUT_START.width);
  273. break;
  274. default:
  275. break;
  276. }
  277. if (!lockWidth && !lockHeight) {
  278. cropper.canvasWidth = width;
  279. cropper.cutX = cutX;
  280. cropper.canvasHeight = height;
  281. cropper.cutY = cutY;
  282. canvasHeight(ins);
  283. canvasWidth(ins);
  284. } else if (!lockWidth) {
  285. cropper.canvasWidth = width;
  286. cropper.cutX = cutX;
  287. canvasWidth(ins);
  288. } else if (!lockHeight) {
  289. cropper.canvasHeight = height;
  290. cropper.cutY = cutY;
  291. canvasHeight(ins);
  292. }
  293. styleUpdate(ins)
  294. imgMarginDetectionScale(ins);
  295. }
  296. }
  297. //检测剪裁框位置是否在允许的范围内(屏幕内)
  298. function cutDetectionPosition(ins) {
  299. var windowHeight = cropper.windowHeight,
  300. windowWidth = cropper.windowWidth;
  301. var cutDetectionPositionTop = function() {
  302. //检测上边距是否在范围内
  303. if (cropper.cutY < 0) {
  304. cropper.cutY = 0;
  305. }
  306. if (cropper.cutY > windowHeight - cropper.canvasHeight) {
  307. cropper.cutY = windowHeight - cropper.canvasHeight;
  308. }
  309. }
  310. var cutDetectionPositionLeft = function() {
  311. //检测左边距是否在范围内
  312. if (cropper.cutX < 0) {
  313. cropper.cutX = 0;
  314. }
  315. if (cropper.cutX > windowWidth - cropper.canvasWidth) {
  316. cropper.cutX = windowWidth - cropper.canvasWidth;
  317. }
  318. }
  319. //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
  320. if (cropper.cutY == null && cropper.cutX == null) {
  321. var cutY = (windowHeight - cropper.canvasHeight) * 0.5;
  322. var cutX = (windowWidth - cropper.canvasWidth) * 0.5;
  323. cropper.cutY = cutY; //截取的框上边距
  324. cropper.cutX = cutX; //截取的框左边距
  325. } else if (cropper.cutY != null && cropper.cutX != null) {
  326. cutDetectionPositionTop();
  327. cutDetectionPositionLeft();
  328. } else if (cropper.cutY != null && cropper.cutX == null) {
  329. cutDetectionPositionTop();
  330. cropper.cutX = (windowWidth - cropper.canvasWidth) / 2;
  331. } else if (cropper.cutY == null && cropper.cutX != null) {
  332. cutDetectionPositionLeft();
  333. cropper.cutY = (windowHeight - cropper.canvasHeight) / 2;
  334. }
  335. styleUpdate(ins)
  336. }
  337. /**
  338. * 图片边缘检测-缩放
  339. */
  340. function imgMarginDetectionScale(ins, delay) {
  341. if (!cropper.limitMove) return;
  342. var scale = cropper.scale;
  343. var imgWidth = cropper.imgWidth;
  344. var imgHeight = cropper.imgHeight;
  345. if ((cropper.angle / 90) % 2) {
  346. imgWidth = cropper.imgHeight;
  347. imgHeight = cropper.imgWidth;
  348. }
  349. if (imgWidth * scale < cropper.canvasWidth) {
  350. scale = cropper.canvasWidth / imgWidth;
  351. }
  352. if (imgHeight * scale < cropper.canvasHeight) {
  353. scale = Math.max(scale, cropper.canvasHeight / imgHeight);
  354. }
  355. imgMarginDetectionPosition(ins, scale, delay);
  356. }
  357. /**
  358. * 图片边缘检测-位置
  359. */
  360. function imgMarginDetectionPosition(ins, scale, delay) {
  361. if (!cropper.limitMove) return;
  362. var left = cropper.imgLeft;
  363. var top = cropper.imgTop;
  364. scale = scale || cropper.scale;
  365. var imgWidth = cropper.imgWidth;
  366. var imgHeight = cropper.imgHeight;
  367. if ((cropper.angle / 90) % 2) {
  368. imgWidth = cropper.imgHeight;
  369. imgHeight = cropper.imgWidth;
  370. }
  371. left = cropper.cutX + (imgWidth * scale) / 2 >= left ? left : cropper.cutX + (imgWidth * scale) / 2;
  372. left = cropper.cutX + cropper.canvasWidth - (imgWidth * scale) / 2 <= left ? left : cropper.cutX + cropper
  373. .canvasWidth -
  374. (imgWidth * scale) / 2;
  375. top = cropper.cutY + (imgHeight * scale) / 2 >= top ? top : cropper.cutY + (imgHeight * scale) / 2;
  376. top = cropper.cutY + cropper.canvasHeight - (imgHeight * scale) / 2 <= top ? top : cropper.cutY + cropper
  377. .canvasHeight -
  378. (imgHeight * scale) / 2;
  379. cropper.imgLeft = left;
  380. cropper.imgTop = top;
  381. cropper.scale = scale;
  382. styleUpdate(ins)
  383. if (!delay || delay === 'null') {
  384. imgTransform(ins);
  385. }
  386. }
  387. function cutTouchEnd(e, ins) {
  388. moveStop(ins);
  389. cropper.flagCutTouch = false;
  390. updateData(ins)
  391. }
  392. //改变截取框大小
  393. function computeCutSize(ins) {
  394. if (cropper.canvasWidth > cropper.windowWidth) {
  395. cropper.canvasWidth = cropper.windowWidth;
  396. // canvasWidth(ins)
  397. } else if (cropper.canvasWidth + cropper.cutX > cropper.windowWidth) {
  398. cropper.cutX = cropper.windowWidth - cropper.cutX;
  399. }
  400. if (cropper.canvasHeight > cropper.windowHeight) {
  401. cropper.canvasHeight = cropper.windowHeight;
  402. // canvasHeight(ins)
  403. } else if (cropper.canvasHeight + cropper.cutY > cropper.windowHeight) {
  404. cropper.cutY = cropper.windowHeight - cropper.cutY;
  405. }
  406. // styleUpdate(ins)
  407. }
  408. function styleUpdate(ins) {
  409. if (!ins) return;
  410. var tcb = ins.selectComponent('.tui-cropper-box');
  411. var tcm = ins.selectComponent('.tui-content-middle')
  412. var tct = ins.selectComponent('.tui-content-top')
  413. var twb = ins.selectComponent('.tui-wxs-bg')
  414. if (!tcb || !tcm || !tct || !twb) return;
  415. tcb.setStyle({
  416. 'width': cropper.canvasWidth + 'px',
  417. 'height': cropper.canvasHeight + 'px'
  418. })
  419. tcm.setStyle({
  420. 'height': cropper.canvasHeight + 'px'
  421. })
  422. tct.setStyle({
  423. 'height': cropper.cutY + 'px'
  424. })
  425. twb.setStyle({
  426. 'width': cropper.cutX + 'px'
  427. })
  428. }
  429. function imgTransform(ins) {
  430. var owner = ins.selectComponent('.tui-cropper-image')
  431. if (!owner) return
  432. var x = cropper.imgLeft - cropper.imgWidth / 2;
  433. var y = cropper.imgTop - cropper.imgHeight / 2;
  434. owner.setStyle({
  435. 'transform': 'translate3d(' + x + 'px,' + y + 'px,0) scale(' + cropper.scale + ') rotate(' + cropper
  436. .angle + 'deg)'
  437. })
  438. }
  439. function imageReset(ins) {
  440. cropper.scale = 1;
  441. cropper.angle = 0;
  442. imgTransform(ins);
  443. }
  444. //监听截取框宽高变化
  445. function canvasWidth(ins) {
  446. if (cropper.canvasWidth < cropper.minWidth) {
  447. cropper.canvasWidth = cropper.minWidth;
  448. }
  449. if (!ins) return;
  450. computeCutSize(ins);
  451. }
  452. function canvasHeight(ins) {
  453. if (cropper.canvasHeight < cropper.minHeight) {
  454. cropper.canvasHeight = cropper.minHeight;
  455. }
  456. if (!ins) return;
  457. computeCutSize(ins);
  458. }
  459. function updateData(ins) {
  460. if (!ins) return;
  461. ins.callMethod('change', {
  462. cutX: cropper.cutX,
  463. cutY: cropper.cutY,
  464. canvasWidth: cropper.canvasWidth,
  465. canvasHeight: cropper.canvasHeight,
  466. imgWidth: cropper.imgWidth,
  467. imgHeight: cropper.imgHeight,
  468. scale: cropper.scale,
  469. angle: cropper.angle,
  470. imgTop: cropper.imgTop,
  471. imgLeft: cropper.imgLeft
  472. })
  473. }
  474. function propsChange(prop, oldProp, ownerInstance, ins) {
  475. if (prop && prop !== 'null') {
  476. var params = prop.split(',')
  477. var type = +params[0]
  478. var dataset = ins.getDataset();
  479. if (cropper.init || type == 4) {
  480. cropper.maxHeight = +dataset.maxheight;
  481. cropper.minHeight = +dataset.minheight;
  482. cropper.maxWidth = +dataset.maxwidth;
  483. cropper.minWidth = +dataset.minwidth;
  484. cropper.canvasWidth = +dataset.width;
  485. cropper.canvasHeight = +dataset.height;
  486. cropper.imgTop = dataset.windowheight / 2;
  487. cropper.imgLeft = dataset.windowwidth / 2;
  488. cropper.imgWidth = +dataset.imgwidth;
  489. cropper.imgHeight = +dataset.imgheight;
  490. cropper.windowHeight = +dataset.windowheight;
  491. cropper.windowWidth = +dataset.windowwidth;
  492. cropper.init = false
  493. } else if (type == 2 || type == 3) {
  494. cropper.imgWidth = +dataset.imgwidth;
  495. cropper.imgHeight = +dataset.imgheight;
  496. }
  497. cropper.limitMove = bool(dataset.limitmove);
  498. cropper.angle = +dataset.angle;
  499. if (type == 3) {
  500. imgTransform(ownerInstance);
  501. }
  502. switch (type) {
  503. case 1:
  504. setCutCenter(ownerInstance);
  505. //设置裁剪框大小>设置图片尺寸>绘制canvas
  506. computeCutSize(ownerInstance);
  507. //检查裁剪框是否在范围内
  508. cutDetectionPosition(ownerInstance);
  509. break;
  510. case 2:
  511. setCutCenter(ownerInstance);
  512. break;
  513. case 3:
  514. imgMarginDetectionScale(ownerInstance)
  515. break;
  516. case 4:
  517. imageReset(ownerInstance);
  518. break;
  519. case 5:
  520. setCutCenter(ownerInstance);
  521. break;
  522. default:
  523. break;
  524. }
  525. }
  526. }
  527. module.exports = {
  528. touchstart: touchstart,
  529. touchmove: touchmove,
  530. touchend: touchend,
  531. cutTouchStart: cutTouchStart,
  532. cutTouchMove: cutTouchMove,
  533. cutTouchEnd: cutTouchEnd,
  534. propsChange: propsChange
  535. }