uni-img-cropper.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. <template>
  2. <view class="container" v-show="isShow">
  3. <view>
  4. <view class="cropper-content">
  5. <view v-if="isShowImg" class="uni-corpper"
  6. :style="'width:' + cropperInitW + 'px;height:' + cropperInitH + 'px;background:#000'">
  7. <view class="uni-corpper-content" :style="
  8. 'width:' +
  9. cropperW +
  10. 'px;height:' +
  11. cropperH +
  12. 'px;left:' +
  13. cropperL +
  14. 'px;top:' +
  15. cropperT +
  16. 'px'
  17. ">
  18. <image :src="imageSrc" :style="'width:' + cropperW + 'px;height:' + cropperH + 'px'"></image>
  19. <view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove"
  20. @touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd" :style="
  21. 'left:' + cutL + 'px;top:' + cutT + 'px;right:' + cutR + 'px;bottom:' + cutB + 'px'
  22. ">
  23. <view class="uni-cropper-view-box">
  24. <view class="uni-cropper-dashed-h"></view>
  25. <view class="uni-cropper-dashed-v"></view>
  26. <!-- 截图区域顶部 -->
  27. <view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart"
  28. @touchmove.stop="dragMove"></view>
  29. <!-- 截图区域右侧 -->
  30. <view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart"
  31. @touchmove.stop="dragMove"></view>
  32. <!-- 截图区域底部 -->
  33. <view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart"
  34. @touchmove.stop="dragMove"></view>
  35. <!-- 截图区域左侧 -->
  36. <view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart"
  37. @touchmove.stop="dragMove"></view>
  38. <!-- 右下角截图滑块 -->
  39. <view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart"
  40. @touchmove.stop="dragMove"></view>
  41. <view class="uni-cropper-point point-tr" data-drag="topTight"></view>
  42. <view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart"
  43. @touchmove.stop="dragMove"></view>
  44. <view class="uni-cropper-point point-rb" data-drag="rightBottom"
  45. @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
  46. <view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart"
  47. @touchmove.stop="dragMove" @touchend.stop="dragEnd"></view>
  48. <view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view>
  49. <view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart"
  50. @touchmove.stop="dragMove"></view>
  51. <view class="uni-cropper-point point-lt" data-drag="leftTop"></view>
  52. </view>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <view class="cropper-config">
  58. <view class="button-box">
  59. <button type="warn" @click="chooseImage(1)">重选</button>
  60. <button type="warn" @click="previewImg">预览</button>
  61. <button type="warn" @click="finish">完成</button>
  62. </view>
  63. </view>
  64. <canvas canvas-id="myCanvas" :style="
  65. 'position:absolute;border: 2px solid red; width:' +
  66. imageW +
  67. 'px;height:' +
  68. imageH +
  69. 'px;top:-9999px;left:-9999px;'
  70. "></canvas>
  71. </view>
  72. </view>
  73. </template>
  74. <script>
  75. let sysInfo = uni.getSystemInfoSync();
  76. let SCREEN_WIDTH = sysInfo.screenWidth;
  77. let SCREEN_HEIGHT = sysInfo.windowHeight + 40;
  78. let PAGE_X, // 手按下的x位置
  79. PAGE_Y, // 手按下y的位置
  80. PR = sysInfo.pixelRatio, // dpi
  81. T_PAGE_X, // 手移动的时候x的位置
  82. T_PAGE_Y, // 手移动的时候Y的位置
  83. CUT_L, // 初始化拖拽元素的left值
  84. CUT_T, // 初始化拖拽元素的top值
  85. CUT_R, // 初始化拖拽元素的
  86. CUT_B, // 初始化拖拽元素的
  87. CUT_W, // 初始化拖拽元素的宽度
  88. CUT_H, // 初始化拖拽元素的高度
  89. IMG_RATIO, // 图片比例
  90. IMG_REAL_W, // 图片实际的宽度
  91. IMG_REAL_H, // 图片实际的高度
  92. DRAFG_MOVE_RATIO = 1, //移动时候的比例,
  93. INIT_DRAG_POSITION = 100, // 初始化屏幕宽度和裁剪区域的宽度之差,用于设置初始化裁剪的宽度
  94. DRAW_IMAGE_W = sysInfo.screenWidth; // 设置生成的图片宽度
  95. export default {
  96. /**
  97. * 页面的初始数据
  98. */
  99. data() {
  100. return {
  101. imageSrc: "",
  102. isShow: false,
  103. isShowImg: false,
  104. // 初始化的宽高
  105. cropperInitW: SCREEN_WIDTH,
  106. cropperInitH: SCREEN_HEIGHT,
  107. // 动态的宽高
  108. cropperW: SCREEN_WIDTH,
  109. cropperH: SCREEN_HEIGHT - 100,
  110. // 动态的left top值
  111. cropperL: 0,
  112. cropperT: 0,
  113. transL: 0,
  114. transT: 0,
  115. // 图片缩放值
  116. scaleP: 0,
  117. imageW: 0,
  118. imageH: 0,
  119. // 裁剪框 宽高
  120. cutL: 0,
  121. cutT: 0,
  122. cutB: SCREEN_WIDTH,
  123. cutR: "100%",
  124. qualityWidth: DRAW_IMAGE_W,
  125. innerAspectRadio: DRAFG_MOVE_RATIO,
  126. };
  127. },
  128. props: {
  129. /* 截图质量,压缩比 */
  130. quality: {
  131. type: Number | String,
  132. default: 1,
  133. },
  134. /*
  135. * 传入图片路径,将跳过选择图片步骤直接进入截图界面。
  136. * 需要特别注意:H5端 Canvas 内绘制的图像需要支持跨域访问才能成功。
  137. */
  138. imgSrc: String,
  139. /* 输出图片类型:仅支持png格式或jpg格式 */
  140. fileType: {
  141. type: String,
  142. default: "png",
  143. validator: function(t) {
  144. // 这个值必须匹配下列字符串中的一个
  145. return t === "png" || t === "jpg";
  146. },
  147. },
  148. /* 截取类型,自由截取free;固定比例截取(正方形)fixed */
  149. cropperType: {
  150. type: String,
  151. default: "free",
  152. validator: function(t) {
  153. // 这个值必须匹配下列字符串中的一个
  154. return t === "free" || t === "fixed" || t === "ratio";
  155. },
  156. },
  157. ratio: {
  158. type: Number,
  159. default: 1,
  160. },
  161. },
  162. created() {
  163. if (this.imgSrc) {
  164. this.imageSrc = this.imgSrc;
  165. this.loadImage();
  166. this.isShow = true;
  167. this.isShowImg = true;
  168. }
  169. },
  170. methods: {
  171. setData: function(obj) {
  172. let that = this;
  173. Object.keys(obj).forEach(function(key) {
  174. that.$set(that.$data, key, obj[key]);
  175. });
  176. },
  177. /* 选择图片 */
  178. chooseImage: function(e) {
  179. var _this = this;
  180. uni.chooseImage({
  181. count: e,
  182. success: function(res) {
  183. if(res.tempFiles[0].size / 1024 < 1024) {
  184. _this.setData({
  185. imageSrc: res.tempFilePaths[0],
  186. });
  187. _this.loadImage();
  188. _this.isShow = true;
  189. } else {
  190. uni.showToast({
  191. title: '图片大小不能超过1024KB,当前大小' + (res.tempFiles[0].size / 1024).toFixed(2) + 'KB',
  192. icon: 'none'
  193. })
  194. }
  195. },
  196. });
  197. },
  198. /* 将图片加载到画布 */
  199. loadImage: function() {
  200. var _this = this;
  201. uni.showLoading({
  202. title: "图片加载中...",
  203. });
  204. /* 获取图片信息 */
  205. uni.getImageInfo({
  206. src: _this.imageSrc,
  207. success: function success(res) {
  208. let imgH = res.height;
  209. let imgW = res.width;
  210. // let IMG_SCR_H_R = SCREEN_HEIGHT / imgH;
  211. // let IMG_SCR_W_R = SCREEN_WIDTH / imgW;
  212. /* 图片的宽高比 */
  213. IMG_RATIO = imgW / imgH;
  214. /**
  215. * 如果图片更高一些,为确保图片能够完整在视窗内显示需如下处理
  216. * 1. 缩放图片的高为 视窗高度减去底部菜单按钮高度(120)
  217. * 2. 根据图片缩放后的高度,根据图片宽高比计算图片的宽度
  218. * 3. 如果步骤2计算的图片宽度大于屏幕宽度,则需要再次调整图片宽度为视窗宽度-margin(10)
  219. * 4. 根据步骤3的宽度,结合图片宽高比重新计算图片的高度
  220. */
  221. if (IMG_RATIO < 1 && (SCREEN_HEIGHT - 120) * IMG_RATIO < SCREEN_WIDTH - 10) {
  222. IMG_REAL_W = (SCREEN_HEIGHT - 120) * IMG_RATIO;
  223. IMG_REAL_H = SCREEN_HEIGHT - 120;
  224. } else {
  225. IMG_REAL_W = SCREEN_WIDTH - 10;
  226. IMG_REAL_H = IMG_REAL_W / IMG_RATIO;
  227. }
  228. /* 初始化裁剪区域的位置和形状 */
  229. let [cutT, cutB, cutL, cutR] = _this.initCutArea(IMG_RATIO, IMG_REAL_H,
  230. IMG_REAL_W);
  231. _this.setData({
  232. /* 裁剪区域的宽高同图片尺寸 */
  233. cropperW: IMG_REAL_W,
  234. cropperH: IMG_REAL_H,
  235. /* 上下左右各留一定的margin已便更好的拖动裁剪区域 */
  236. cropperL: Math.ceil((SCREEN_WIDTH - IMG_REAL_W) / 2),
  237. /* 留出底部操作按钮位置 70 */
  238. cropperT: Math.ceil((SCREEN_HEIGHT - IMG_REAL_H - 90) / 2),
  239. cutL: cutL,
  240. cutT: cutT,
  241. cutR: cutR,
  242. cutB: cutB,
  243. // 图片缩放值
  244. imageW: IMG_REAL_W,
  245. imageH: IMG_REAL_H,
  246. scaleP: IMG_REAL_W / SCREEN_WIDTH,
  247. qualityWidth: DRAW_IMAGE_W,
  248. innerAspectRadio: IMG_RATIO,
  249. });
  250. _this.setData({
  251. isShowImg: true,
  252. });
  253. uni.hideLoading();
  254. },
  255. });
  256. },
  257. initCutArea(IMG_RATIO, IMG_REAL_H, IMG_REAL_W) {
  258. let _this = this;
  259. /* 自由裁剪裁剪区域默认覆盖整个图片 */
  260. let cutT = 0;
  261. let cutB = 0;
  262. let cutL = 0;
  263. let cutR = 0;
  264. /* 正方形裁剪,初始化裁剪区域为正方形并居中 */
  265. if (_this.cropperType == "fixed") {
  266. if (IMG_RATIO < 1) {
  267. /* 图片比较高 */
  268. cutT = (IMG_REAL_H - IMG_REAL_W) / 2;
  269. cutB = (IMG_REAL_H - IMG_REAL_W) / 2;
  270. } else {
  271. /* 图片比较宽 */
  272. cutL = (IMG_REAL_W - IMG_REAL_H) / 2;
  273. cutR = (IMG_REAL_W - IMG_REAL_H) / 2;
  274. }
  275. }
  276. /* 固定比例裁剪,初始化裁剪区域比例和设定值相同 */
  277. if (_this.cropperType == "ratio") {
  278. let ratio = +_this.ratio;
  279. if (IMG_RATIO < 1) {
  280. /* 图片比较高 */
  281. if (IMG_REAL_W / ratio > IMG_REAL_H) {
  282. cutT = cutB = 0;
  283. cutL = cutR = (IMG_REAL_W - IMG_REAL_H * ratio) / 2;
  284. } else {
  285. cutR = cutL = 0;
  286. cutT = cutB = (IMG_REAL_H - IMG_REAL_W / ratio) / 2;
  287. }
  288. } else {
  289. /* 图片比较宽 */
  290. if (IMG_REAL_H * ratio > IMG_REAL_W) {
  291. cutL = cutR = 0;
  292. cutB = cutT = (IMG_REAL_H - IMG_REAL_W / ratio) / 2;
  293. } else {
  294. cutT = cutB = 0;
  295. cutL = cutR = (IMG_REAL_W - IMG_REAL_H * ratio) / 2;
  296. }
  297. }
  298. }
  299. return [cutT, cutB, cutL, cutR];
  300. },
  301. // 拖动时候触发的touchStart事件
  302. contentStartMove(e) {
  303. PAGE_X = e.touches[0].pageX;
  304. PAGE_Y = e.touches[0].pageY;
  305. },
  306. // 拖动时候触发的touchMove事件
  307. contentMoveing(e) {
  308. var _this = this;
  309. var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  310. var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  311. // 左移
  312. if (dragLengthX > 0) {
  313. if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL;
  314. } else {
  315. if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR;
  316. }
  317. if (dragLengthY > 0) {
  318. if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT;
  319. } else {
  320. if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB;
  321. }
  322. this.setData({
  323. cutL: this.cutL - dragLengthX,
  324. cutT: this.cutT - dragLengthY,
  325. cutR: this.cutR + dragLengthX,
  326. cutB: this.cutB + dragLengthY,
  327. });
  328. PAGE_X = e.touches[0].pageX;
  329. PAGE_Y = e.touches[0].pageY;
  330. },
  331. contentTouchEnd() {},
  332. // 获取图片尺寸信息
  333. previewImg() {
  334. try {
  335. var _this = this;
  336. uni.showLoading({
  337. title: "图片生成中...",
  338. });
  339. // 将图片写入画布
  340. const ctx = uni.createCanvasContext("myCanvas", _this);
  341. ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H);
  342. ctx.draw(true, () => {
  343. // 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
  344. var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W;
  345. var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H;
  346. var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W;
  347. var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H;
  348. uni.canvasToTempFilePath({
  349. x: canvasL,
  350. y: canvasT,
  351. width: canvasW,
  352. height: canvasH,
  353. // destWidth: canvasW,
  354. // destHeight: canvasH,
  355. quality: +this.quality,
  356. fileType: this.fileType,
  357. canvasId: "myCanvas",
  358. success: function(res) {
  359. uni.hideLoading();
  360. // 成功获得地址的地方
  361. uni.previewImage({
  362. current: "", // 当前显示图片的http链接
  363. urls: [res.tempFilePath], // 需要预览的图片http链接列表
  364. });
  365. },
  366. fail: function(err) {
  367. uni.hideLoading();
  368. uni.showToast({
  369. title: "图片截取失败!",
  370. icon: "none",
  371. });
  372. },
  373. },
  374. // _this
  375. );
  376. });
  377. } catch (e) {
  378. console.log(e)
  379. }
  380. },
  381. /* 完成裁剪,输出裁剪后的图片路径 */
  382. finish() {
  383. var _this = this;
  384. uni.showLoading({
  385. title: "图片生成中...",
  386. });
  387. // 将图片写入画布
  388. const ctx = uni.createCanvasContext("myCanvas", _this);
  389. ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H);
  390. ctx.draw(true, () => {
  391. // 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
  392. var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W;
  393. var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H;
  394. var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W;
  395. var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H;
  396. uni.canvasToTempFilePath({
  397. x: canvasL,
  398. y: canvasT,
  399. width: canvasW,
  400. height: canvasH,
  401. // destWidth: canvasW,
  402. // destHeight: canvasH,
  403. quality: +this.quality,
  404. fileType: this.fileType,
  405. canvasId: "myCanvas",
  406. success: function(res) {
  407. uni.hideLoading();
  408. // 成功获得地址的地方
  409. _this.$emit("getImg", res.tempFilePath);
  410. _this.isShow = false;
  411. },
  412. fail: function(err) {
  413. uni.hideLoading();
  414. uni.showToast({
  415. title: "图片截取失败!",
  416. icon: "none",
  417. });
  418. },
  419. },
  420. // _this
  421. );
  422. });
  423. },
  424. // 设置大小的时候触发的touchStart事件
  425. dragStart(e) {
  426. T_PAGE_X = e.touches[0].pageX;
  427. T_PAGE_Y = e.touches[0].pageY;
  428. CUT_L = this.cutL;
  429. CUT_R = this.cutR;
  430. CUT_B = this.cutB;
  431. CUT_T = this.cutT;
  432. },
  433. // 设置大小的时候触发的touchMove事件
  434. dragMove(e) {
  435. // this.cropperType == "fixed" ? this.fixedScaleDrag(e) : this.freeDrag(e);
  436. this[this.cropperType + "Drag"](e);
  437. },
  438. /* 固定比例(正方形)截取 ,只有右下角裁剪滑动拖动有效*/
  439. fixedDrag(e) {
  440. var _this = this;
  441. var dragType = e.target.dataset.drag;
  442. switch (dragType) {
  443. case "rightBottom":
  444. var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  445. // var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  446. // if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B;
  447. if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R;
  448. /* 右侧和底部同比变化 */
  449. let cutB = CUT_B + dragLengthX;
  450. let cutR = CUT_R + dragLengthX;
  451. /* 越界判断 */
  452. if (_this.cutB == 0 && cutB < 0) return;
  453. if (_this.cutR == 0 && cutR < 0) return;
  454. (_this.cutB > 0 || CUT_B == 0) &&
  455. this.setData({
  456. cutB: cutB < 0 ? 0 : cutB,
  457. cutR: cutR,
  458. });
  459. break;
  460. default:
  461. break;
  462. }
  463. },
  464. /* 等比例截图,只能通过右下角的滑块改变截图区域 */
  465. ratioDrag(e) {
  466. var _this = this;
  467. var dragType = e.target.dataset.drag;
  468. switch (dragType) {
  469. case "rightBottom":
  470. var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  471. // var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  472. // if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B;
  473. if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R;
  474. /* 右侧和底部同比变化 */
  475. let cutB = CUT_B + dragLengthX / _this.ratio;
  476. let cutR = CUT_R + dragLengthX;
  477. /* 越界判断 */
  478. if (_this.cutB == 0 && cutB < 0) return;
  479. if (_this.cutR == 0 && cutR < 0) return;
  480. (_this.cutB > 0 || CUT_B == 0) &&
  481. this.setData({
  482. cutB: cutB < 0 ? 0 : cutB,
  483. cutR: cutR,
  484. });
  485. break;
  486. default:
  487. break;
  488. }
  489. },
  490. /* 自由截取,整个裁剪边框均能拖动 */
  491. freeDrag(e) {
  492. var _this = this;
  493. var dragType = e.target.dataset.drag;
  494. switch (dragType) {
  495. case "right":
  496. var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  497. if (CUT_R + dragLength < 0) dragLength = -CUT_R;
  498. this.setData({
  499. cutR: CUT_R + dragLength,
  500. });
  501. break;
  502. case "left":
  503. var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  504. if (CUT_L - dragLength < 0) dragLength = CUT_L;
  505. if (CUT_L - dragLength > this.cropperW - this.cutR)
  506. dragLength = CUT_L - (this.cropperW - this.cutR);
  507. this.setData({
  508. cutL: CUT_L - dragLength,
  509. });
  510. break;
  511. case "top":
  512. var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  513. if (CUT_T - dragLength < 0) dragLength = CUT_T;
  514. if (CUT_T - dragLength > this.cropperH - this.cutB)
  515. dragLength = CUT_T - (this.cropperH - this.cutB);
  516. this.setData({
  517. cutT: CUT_T - dragLength,
  518. });
  519. break;
  520. case "bottom":
  521. var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  522. if (CUT_B + dragLength < 0) dragLength = -CUT_B;
  523. this.setData({
  524. cutB: CUT_B + dragLength,
  525. });
  526. break;
  527. case "rightBottom":
  528. var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO;
  529. var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO;
  530. if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B;
  531. if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R;
  532. let cutB = CUT_B + dragLengthY;
  533. let cutR = CUT_R + dragLengthX;
  534. this.setData({
  535. cutB: cutB,
  536. cutR: cutR,
  537. });
  538. break;
  539. default:
  540. break;
  541. }
  542. },
  543. },
  544. };
  545. </script>
  546. <style>
  547. /* pages/uni-cropper/index.wxss */
  548. .container {
  549. background-color: #fff;
  550. position: fixed;
  551. top: 0;
  552. left: 0;
  553. right: 0;
  554. bottom: 50px;
  555. display: block;
  556. align-items: center;
  557. flex-direction: column;
  558. z-index: 998;
  559. height: 100vh;
  560. }
  561. .cropper-config {
  562. position: fixed;
  563. z-index: 999;
  564. bottom: 60px;
  565. left: 0;
  566. right: 0;
  567. width: 90%;
  568. margin: 0 auto;
  569. /* padding: 20upx 40upx; */
  570. }
  571. .button-box {
  572. display: flex;
  573. flex-direction: row;
  574. justify-content: space-between;
  575. width: 100%;
  576. }
  577. .button-box button {
  578. width: 25%;
  579. line-height: 35px;
  580. height: 35px;
  581. }
  582. .cropper-content {
  583. width: 100%;
  584. min-height: 750upx;
  585. }
  586. .uni-corpper {
  587. position: relative;
  588. overflow: hidden;
  589. box-sizing: border-box;
  590. margin: 0 auto;
  591. -webkit-user-select: none;
  592. -moz-user-select: none;
  593. -ms-user-select: none;
  594. user-select: none;
  595. -webkit-tap-highlight-color: transparent;
  596. -webkit-touch-callout: none;
  597. }
  598. .uni-corpper-content {
  599. position: relative;
  600. }
  601. .uni-corpper-content image {
  602. display: block;
  603. width: 100%;
  604. min-width: 0 !important;
  605. max-width: none !important;
  606. /* height: 100%; */
  607. min-height: 0 !important;
  608. /* max-height: none !important; */
  609. max-height: calc(100vh - 100upx);
  610. margin: 0 auto;
  611. image-orientation: 0deg !important;
  612. }
  613. /* 移动图片效果 */
  614. .uni-cropper-drag-box {
  615. position: absolute;
  616. z-index: 1;
  617. top: 0;
  618. right: 0;
  619. bottom: 0;
  620. left: 0;
  621. cursor: move;
  622. background: rgba(0, 0, 0, 0.479);
  623. }
  624. /* 内部的信息 */
  625. .uni-corpper-crop-box {
  626. position: absolute;
  627. z-index: 2;
  628. max-height: calc(100vh - 100upx);
  629. background: rgba(56, 50, 50, 0.479);
  630. }
  631. .uni-corpper-crop-box .uni-cropper-view-box {
  632. position: relative;
  633. display: block;
  634. overflow: visible;
  635. width: 100%;
  636. height: 100%;
  637. max-height: calc(100vh - 100upx);
  638. outline: 5upx solid rgb(100, 97, 97);
  639. outline-color: rgba(255, 255 255, 1);
  640. }
  641. /* 横向虚线 */
  642. .uni-cropper-dashed-h {
  643. position: absolute;
  644. top: 33.33333333%;
  645. left: 0;
  646. width: 100%;
  647. height: 33.33333333%;
  648. border-top: 1upx dashed rgba(255, 255, 255, 0.5);
  649. border-bottom: 1upx dashed rgba(255, 255, 255, 0.5);
  650. }
  651. /* 纵向虚线 */
  652. .uni-cropper-dashed-v {
  653. position: absolute;
  654. top: 0;
  655. left: 33.33333333%;
  656. width: 33.33333333%;
  657. height: 100%;
  658. border-right: 1upx dashed rgba(255, 255, 255, 0.5);
  659. border-left: 1upx dashed rgba(255, 255, 255, 0.5);
  660. }
  661. /* 四个方向的线 为了之后的拖动事件*/
  662. .uni-cropper-line-t {
  663. position: absolute;
  664. top: 0;
  665. left: 0;
  666. display: block;
  667. width: 100%;
  668. height: 3upx;
  669. cursor: n-resize;
  670. opacity: 0.1;
  671. background-color: white;
  672. }
  673. .uni-cropper-line-t::before {
  674. position: absolute;
  675. z-index: 11;
  676. top: 50%;
  677. right: 0upx;
  678. bottom: 0;
  679. width: 100%;
  680. height: 41upx;
  681. content: "";
  682. -webkit-transform: translate3d(0, -50%, 0);
  683. transform: translate3d(0, -50%, 0);
  684. background: transparent;
  685. }
  686. .uni-cropper-line-r {
  687. position: absolute;
  688. top: 0;
  689. right: 0upx;
  690. display: block;
  691. width: 3upx;
  692. height: 100%;
  693. cursor: e-resize;
  694. opacity: 0.1;
  695. background-color: white;
  696. }
  697. .uni-cropper-line-r::before {
  698. position: absolute;
  699. z-index: 11;
  700. top: 0;
  701. bottom: 0;
  702. left: 50%;
  703. width: 41upx;
  704. height: 100%;
  705. content: "";
  706. -webkit-transform: translate3d(-50%, 0, 0);
  707. transform: translate3d(-50%, 0, 0);
  708. background: transparent;
  709. }
  710. .uni-cropper-line-b {
  711. position: absolute;
  712. bottom: 0;
  713. left: 0;
  714. display: block;
  715. width: 100%;
  716. height: 3upx;
  717. cursor: s-resize;
  718. opacity: 0.1;
  719. background-color: white;
  720. }
  721. .uni-cropper-line-b::before {
  722. position: absolute;
  723. z-index: 11;
  724. top: 50%;
  725. right: 0upx;
  726. bottom: 0;
  727. width: 100%;
  728. height: 41upx;
  729. content: "";
  730. -webkit-transform: translate3d(0, -50%, 0);
  731. transform: translate3d(0, -50%, 0);
  732. background: transparent;
  733. }
  734. .uni-cropper-line-l {
  735. position: absolute;
  736. top: 0;
  737. left: 0;
  738. display: block;
  739. width: 3upx;
  740. height: 100%;
  741. cursor: w-resize;
  742. opacity: 0.1;
  743. background-color: white;
  744. }
  745. .uni-cropper-line-l::before {
  746. position: absolute;
  747. z-index: 11;
  748. top: 0;
  749. bottom: 0;
  750. left: 50%;
  751. width: 41upx;
  752. height: 100%;
  753. content: "";
  754. -webkit-transform: translate3d(-50%, 0, 0);
  755. transform: translate3d(-50%, 0, 0);
  756. background: transparent;
  757. }
  758. .uni-cropper-point {
  759. position: absolute;
  760. z-index: 3;
  761. width: 5upx;
  762. height: 5upx;
  763. opacity: 0.75;
  764. background-color: rgb(145, 132, 132);
  765. }
  766. .point-t {
  767. top: -3upx;
  768. left: 50%;
  769. margin-left: -3upx;
  770. cursor: n-resize;
  771. }
  772. .point-tr {
  773. top: -3upx;
  774. left: 100%;
  775. margin-left: -3upx;
  776. cursor: n-resize;
  777. }
  778. .point-r {
  779. top: 50%;
  780. left: 100%;
  781. margin-top: -3upx;
  782. margin-left: -3upx;
  783. cursor: n-resize;
  784. }
  785. .point-rb {
  786. position: absolute;
  787. z-index: 1112;
  788. top: 100%;
  789. left: 100%;
  790. width: 36upx;
  791. height: 36upx;
  792. cursor: n-resize;
  793. -webkit-transform: translate3d(-50%, -50%, 0);
  794. transform: translate3d(-50%, -50%, 0);
  795. opacity: 1;
  796. background-color: rgb(231, 222, 222);
  797. }
  798. .point-b {
  799. top: 100%;
  800. left: 50%;
  801. margin-top: -3upx;
  802. margin-left: -3upx;
  803. cursor: n-resize;
  804. }
  805. .point-bl {
  806. top: 100%;
  807. left: 0;
  808. margin-top: -3upx;
  809. margin-left: -3upx;
  810. cursor: n-resize;
  811. }
  812. .point-l {
  813. top: 50%;
  814. left: 0;
  815. margin-top: -3upx;
  816. margin-left: -3upx;
  817. cursor: n-resize;
  818. }
  819. .point-lt {
  820. top: 0;
  821. left: 0;
  822. margin-top: -3upx;
  823. margin-left: -3upx;
  824. cursor: n-resize;
  825. }
  826. /* 裁剪框预览内容 */
  827. .uni-cropper-viewer {
  828. position: relative;
  829. overflow: hidden;
  830. width: 100%;
  831. height: 100%;
  832. }
  833. .uni-cropper-viewer image {
  834. position: absolute;
  835. z-index: 2;
  836. }
  837. </style>