tui-picture-cropper.wxs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  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.maxWidth;
  224. height = height <= cropper.maxHeight ? (height >= cropper.minHeight ? height : cropper.minHeight) : cropper.maxHeight;
  225. }
  226. var size_inspect = function() {
  227. if ((width > cropper.maxWidth || width < cropper.minWidth || height > cropper.maxHeight || height < cropper.minHeight) &&
  228. lockRatio) {
  229. size_correct();
  230. return false;
  231. } else {
  232. size_correct();
  233. return true;
  234. }
  235. };
  236. height = cropper.CUT_START.height + (cropper.CUT_START.corner > 1 && cropper.CUT_START.corner < 4 ? 1 : -1) * (
  237. cropper.CUT_START.y - touch[0].pageY);
  238. switch (cropper.CUT_START.corner) {
  239. case 1:
  240. width = cropper.CUT_START.width - cropper.CUT_START.x + touch[0].pageX;
  241. if (lockRatio) {
  242. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  243. }
  244. if (!size_inspect()) return;
  245. break;
  246. case 2:
  247. width = cropper.CUT_START.width - cropper.CUT_START.x + touch[0].pageX;
  248. if (lockRatio) {
  249. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  250. }
  251. if (!size_inspect()) return;
  252. cutY = cropper.CUT_START.cutY - (height - cropper.CUT_START.height);
  253. break;
  254. case 3:
  255. width = cropper.CUT_START.width + cropper.CUT_START.x - touch[0].pageX;
  256. if (lockRatio) {
  257. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  258. }
  259. if (!size_inspect()) return;
  260. cutY = cropper.CUT_START.cutY - (height - cropper.CUT_START.height);
  261. cutX = cropper.CUT_START.cutX - (width - cropper.CUT_START.width);
  262. break;
  263. case 4:
  264. width = cropper.CUT_START.width + cropper.CUT_START.x - touch[0].pageX;
  265. if (lockRatio) {
  266. height = width / (cropper.canvasWidth / cropper.canvasHeight);
  267. }
  268. if (!size_inspect()) return;
  269. cutX = cropper.CUT_START.cutX - (width - cropper.CUT_START.width);
  270. break;
  271. default:
  272. break;
  273. }
  274. if (!lockWidth && !lockHeight) {
  275. cropper.canvasWidth = width;
  276. cropper.cutX = cutX;
  277. cropper.canvasHeight = height;
  278. cropper.cutY = cutY;
  279. canvasHeight(ins);
  280. canvasWidth(ins);
  281. } else if (!lockWidth) {
  282. cropper.canvasWidth = width;
  283. cropper.cutX = cutX;
  284. canvasWidth(ins);
  285. } else if (!lockHeight) {
  286. cropper.canvasHeight = height;
  287. cropper.cutY = cutY;
  288. canvasHeight(ins);
  289. }
  290. styleUpdate(ins)
  291. imgMarginDetectionScale(ins);
  292. }
  293. }
  294. //检测剪裁框位置是否在允许的范围内(屏幕内)
  295. function cutDetectionPosition(ins) {
  296. var windowHeight = cropper.windowHeight,
  297. windowWidth = cropper.windowWidth;
  298. var cutDetectionPositionTop = function() {
  299. //检测上边距是否在范围内
  300. if (cropper.cutY < 0) {
  301. cropper.cutY = 0;
  302. }
  303. if (cropper.cutY > windowHeight - cropper.canvasHeight) {
  304. cropper.cutY = windowHeight - cropper.canvasHeight;
  305. }
  306. }
  307. var cutDetectionPositionLeft = function() {
  308. //检测左边距是否在范围内
  309. if (cropper.cutX < 0) {
  310. cropper.cutX = 0;
  311. }
  312. if (cropper.cutX > windowWidth - cropper.canvasWidth) {
  313. cropper.cutX = windowWidth - cropper.canvasWidth;
  314. }
  315. }
  316. //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
  317. if (cropper.cutY == null && cropper.cutX == null) {
  318. var cutY = (windowHeight - cropper.canvasHeight) * 0.5;
  319. var cutX = (windowWidth - cropper.canvasWidth) * 0.5;
  320. cropper.cutY = cutY; //截取的框上边距
  321. cropper.cutX = cutX; //截取的框左边距
  322. } else if (cropper.cutY != null && cropper.cutX != null) {
  323. cutDetectionPositionTop();
  324. cutDetectionPositionLeft();
  325. } else if (cropper.cutY != null && cropper.cutX == null) {
  326. cutDetectionPositionTop();
  327. cropper.cutX = (windowWidth - cropper.canvasWidth) / 2;
  328. } else if (cropper.cutY == null && cropper.cutX != null) {
  329. cutDetectionPositionLeft();
  330. cropper.cutY = (windowHeight - cropper.canvasHeight) / 2;
  331. }
  332. styleUpdate(ins)
  333. }
  334. /**
  335. * 图片边缘检测-缩放
  336. */
  337. function imgMarginDetectionScale(ins, delay) {
  338. if (!cropper.limitMove) return;
  339. var scale = cropper.scale;
  340. var imgWidth = cropper.imgWidth;
  341. var imgHeight = cropper.imgHeight;
  342. if ((cropper.angle / 90) % 2) {
  343. imgWidth = cropper.imgHeight;
  344. imgHeight = cropper.imgWidth;
  345. }
  346. if (imgWidth * scale < cropper.canvasWidth) {
  347. scale = cropper.canvasWidth / imgWidth;
  348. }
  349. if (imgHeight * scale < cropper.canvasHeight) {
  350. scale = Math.max(scale, cropper.canvasHeight / imgHeight);
  351. }
  352. imgMarginDetectionPosition(ins, scale, delay);
  353. }
  354. /**
  355. * 图片边缘检测-位置
  356. */
  357. function imgMarginDetectionPosition(ins, scale, delay) {
  358. if (!cropper.limitMove) return;
  359. var left = cropper.imgLeft;
  360. var top = cropper.imgTop;
  361. scale = scale || cropper.scale;
  362. var imgWidth = cropper.imgWidth;
  363. var imgHeight = cropper.imgHeight;
  364. if ((cropper.angle / 90) % 2) {
  365. imgWidth = cropper.imgHeight;
  366. imgHeight = cropper.imgWidth;
  367. }
  368. left = cropper.cutX + (imgWidth * scale) / 2 >= left ? left : cropper.cutX + (imgWidth * scale) / 2;
  369. left = cropper.cutX + cropper.canvasWidth - (imgWidth * scale) / 2 <= left ? left : cropper.cutX + cropper.canvasWidth -
  370. (imgWidth * scale) / 2;
  371. top = cropper.cutY + (imgHeight * scale) / 2 >= top ? top : cropper.cutY + (imgHeight * scale) / 2;
  372. top = cropper.cutY + cropper.canvasHeight - (imgHeight * scale) / 2 <= top ? top : cropper.cutY + cropper.canvasHeight -
  373. (imgHeight * scale) / 2;
  374. cropper.imgLeft = left;
  375. cropper.imgTop = top;
  376. cropper.scale = scale;
  377. styleUpdate(ins)
  378. if (!delay || delay === 'null') {
  379. imgTransform(ins);
  380. }
  381. }
  382. function cutTouchEnd(e, ins) {
  383. moveStop(ins);
  384. cropper.flagCutTouch = false;
  385. updateData(ins)
  386. }
  387. //改变截取框大小
  388. function computeCutSize(ins) {
  389. if (cropper.canvasWidth > cropper.windowWidth) {
  390. cropper.canvasWidth = cropper.windowWidth;
  391. // canvasWidth(ins)
  392. } else if (cropper.canvasWidth + cropper.cutX > cropper.windowWidth) {
  393. cropper.cutX = cropper.windowWidth - cropper.cutX;
  394. }
  395. if (cropper.canvasHeight > cropper.windowHeight) {
  396. cropper.canvasHeight = cropper.windowHeight;
  397. // canvasHeight(ins)
  398. } else if (cropper.canvasHeight + cropper.cutY > cropper.windowHeight) {
  399. cropper.cutY = cropper.windowHeight - cropper.cutY;
  400. }
  401. // styleUpdate(ins)
  402. }
  403. function styleUpdate(ins) {
  404. if (!ins) return;
  405. ins.selectComponent('.tui-cropper-box').setStyle({
  406. 'width': cropper.canvasWidth + 'px',
  407. 'height': cropper.canvasHeight + 'px'
  408. })
  409. ins.selectComponent('.tui-content-middle').setStyle({
  410. 'height': cropper.canvasHeight + 'px'
  411. })
  412. ins.selectComponent('.tui-content-top').setStyle({
  413. 'height': cropper.cutY + 'px'
  414. })
  415. ins.selectComponent('.tui-wxs-bg').setStyle({
  416. 'width': cropper.cutX + 'px'
  417. })
  418. }
  419. function imgTransform(ins) {
  420. var owner = ins.selectComponent('.tui-cropper-image')
  421. if (!owner) return
  422. var x = cropper.imgLeft - cropper.imgWidth / 2;
  423. var y = cropper.imgTop - cropper.imgHeight / 2;
  424. owner.setStyle({
  425. 'transform': 'translate3d(' + x + 'px,' + y + 'px,0) scale(' + cropper.scale + ') rotate(' + cropper.angle + 'deg)'
  426. })
  427. }
  428. function imageReset(ins) {
  429. cropper.scale = 1;
  430. cropper.angle = 0;
  431. imgTransform(ins);
  432. }
  433. //监听截取框宽高变化
  434. function canvasWidth(ins) {
  435. if (cropper.canvasWidth < cropper.minWidth) {
  436. cropper.canvasWidth = cropper.minWidth;
  437. }
  438. if (!ins) return;
  439. computeCutSize(ins);
  440. }
  441. function canvasHeight(ins) {
  442. if (cropper.canvasHeight < cropper.minHeight) {
  443. cropper.canvasHeight = cropper.minHeight;
  444. }
  445. if (!ins) return;
  446. computeCutSize(ins);
  447. }
  448. function updateData(ins) {
  449. if (!ins) return;
  450. ins.callMethod('change', {
  451. cutX: cropper.cutX,
  452. cutY: cropper.cutY,
  453. canvasWidth: cropper.canvasWidth,
  454. canvasHeight: cropper.canvasHeight,
  455. imgWidth: cropper.imgWidth,
  456. imgHeight: cropper.imgHeight,
  457. scale: cropper.scale,
  458. angle: cropper.angle,
  459. imgTop: cropper.imgTop,
  460. imgLeft: cropper.imgLeft
  461. })
  462. }
  463. function propsChange(prop, oldProp, ownerInstance, ins) {
  464. if (prop && prop !== 'null') {
  465. var params = prop.split(',')
  466. var type = +params[0]
  467. var dataset = ins.getDataset();
  468. if (cropper.init || type == 4) {
  469. cropper.maxHeight = +dataset.maxheight;
  470. cropper.minHeight = +dataset.minheight;
  471. cropper.maxWidth = +dataset.maxwidth;
  472. cropper.minWidth = +dataset.minwidth;
  473. cropper.canvasWidth = +dataset.width;
  474. cropper.canvasHeight = +dataset.height;
  475. cropper.imgTop = dataset.windowheight / 2;
  476. cropper.imgLeft = dataset.windowwidth / 2;
  477. cropper.imgWidth = +dataset.imgwidth;
  478. cropper.imgHeight = +dataset.imgheight;
  479. cropper.windowHeight = +dataset.windowheight;
  480. cropper.windowWidth = +dataset.windowwidth;
  481. cropper.init = false
  482. } else if (type == 2 || type == 3) {
  483. cropper.imgWidth = +dataset.imgwidth;
  484. cropper.imgHeight = +dataset.imgheight;
  485. }
  486. cropper.limitMove = bool(dataset.limitmove);
  487. cropper.angle = +dataset.angle;
  488. if (type == 3) {
  489. imgTransform(ownerInstance);
  490. }
  491. switch (type) {
  492. case 1:
  493. setCutCenter(ownerInstance);
  494. //设置裁剪框大小>设置图片尺寸>绘制canvas
  495. computeCutSize(ownerInstance);
  496. //检查裁剪框是否在范围内
  497. cutDetectionPosition(ownerInstance);
  498. break;
  499. case 2:
  500. setCutCenter(ownerInstance);
  501. break;
  502. case 3:
  503. imgMarginDetectionScale(ownerInstance)
  504. break;
  505. case 4:
  506. imageReset(ownerInstance);
  507. break;
  508. case 5:
  509. setCutCenter(ownerInstance);
  510. break;
  511. default:
  512. break;
  513. }
  514. }
  515. }
  516. module.exports = {
  517. touchstart: touchstart,
  518. touchmove: touchmove,
  519. touchend: touchend,
  520. cutTouchStart: cutTouchStart,
  521. cutTouchMove: cutTouchMove,
  522. cutTouchEnd: cutTouchEnd,
  523. propsChange: propsChange
  524. }