graceImageCrop.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. <template>
  2. <view class="vue-cropper" ref="cropper" :style="{top:`${containerTop}px`}" v-show="show">
  3. <view class="cropper-box">
  4. <view class="cropper-box-canvas" @touchstart.stop.prevent="imgTouchStart"
  5. @touchmove.stop.prevent="imgMoveing" @touchend.stop.prevent="imgMoveEnd" :style="{
  6. 'width': '750rpx',
  7. 'transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ x / scale + 'px,' + y / scale + 'px,' + '0)'
  8. + 'rotateZ('+ rotate * 90 +'deg)'}">
  9. <image :src="src" mode="widthFix" :style="{width:'100%', height : imageHeight +'px'}"></image>
  10. </view>
  11. </view>
  12. <view class="cropper-drag-box cropper-modal cropper-move pointer-events"></view>
  13. <view class="cropper-crop-box" :class="{'pointer-events': cropFixed}"
  14. :style="{
  15. 'width': cropW + 'px','height': cropH + 'px',
  16. 'transform': 'translate3d('+ cropOffsertX + 'px,' + cropOffsertY + 'px,' + '0)'}">
  17. <view class="cropper-view-box">
  18. <image :style="{
  19. 'width': imageWidth + 'px',
  20. height : imageHeight +'px',
  21. 'transform': 'scale(' + scale + ',' + scale + ') ' + 'translate3d('+ (x - cropOffsertX) / scale + 'px,' + (y - cropOffsertY) / scale + 'px,' + '0)' + 'rotateZ('+ rotate * 90 +'deg)'}"
  22. :src="src"></image>
  23. </view>
  24. <view v-if="!cropFixed" class="cropper-face cropper-move" @touchstart.stop.prevent="touchStart" @touchmove.stop.prevent="cropMoveing"></view>
  25. <view class="crop-line line-w"></view>
  26. <view class="crop-line line-a"></view>
  27. <view class="crop-line line-s"></view>
  28. <view class="crop-line line-d"></view>
  29. </view>
  30. <canvas id="myCanvas" canvas-id="myCanvas" class="cropper-canvas" :style="{ 'width': cropW + 'px','height': cropH + 'px' }"></canvas>
  31. <view class="uni-info__ft" :style="{paddingBottom:iPhoneXBottomHeightRpx+'rpx', background:'#FFFFFF'}">
  32. <view class="uni-modal__btn uni-modal__btn_default" style="color: rgb(0, 0, 0);" @tap="cancel">取消</view>
  33. <view class="uni-modal__btn uni-modal__btn_primary" style="color: rgb(0, 122, 255);" @tap="confirm">确定</view>
  34. </view>
  35. </view>
  36. </template>
  37. <script>
  38. export default {
  39. name: 'image-cropper',
  40. props: {
  41. cropWidth: {
  42. type: Number,
  43. default: 200,
  44. },
  45. cropHeight: {
  46. type: Number,
  47. default: 200
  48. },
  49. cropFixed: {
  50. type: Boolean,
  51. default: false,
  52. },
  53. src: {
  54. type: String,
  55. },
  56. showResetBtn: {
  57. type: Boolean,
  58. default: true,
  59. },
  60. showRotateBtn: {
  61. type: Boolean,
  62. default: true,
  63. }
  64. },
  65. data() {
  66. const sysInfo = uni.getSystemInfoSync();
  67. const pixelRatio = sysInfo.pixelRatio;
  68. return {
  69. show: false,
  70. scale: 1,
  71. rotate: 0,
  72. cropW: 0,
  73. cropH: 0,
  74. cropOldW: 0,
  75. cropOldH: 0,
  76. sysInfo: sysInfo,
  77. pixelRatio: pixelRatio,
  78. imageRealWidth: 0,
  79. imageRealHeight: 0,
  80. cropOffsertX: 0,
  81. cropOffsertY: 0,
  82. startX: 0,
  83. startY: 0,
  84. // 裁剪框与边界间距
  85. border: 5,
  86. x: 0,
  87. y: 0,
  88. startL: 0,
  89. oldScale: 1,
  90. iPhoneXBottomHeightRpx:0,
  91. imageWidth : 100,
  92. imageHeight : 100,
  93. imageRatio : 1
  94. }
  95. },
  96. created:function(){
  97. const sysInfo = uni.getSystemInfoSync();
  98. const pixelRatio = sysInfo.pixelRatio;
  99. var iPhoneXBottom = 0;
  100. sysInfo.model = sysInfo.model.replace(' ', '');
  101. sysInfo.model = sysInfo.model.toLowerCase();
  102. if(sysInfo.model.indexOf('iphonex') != -1 || sysInfo.model.indexOf('iphone11') != -1){
  103. this.iPhoneXBottomHeightRpx = 50;
  104. }else{
  105. this.iPhoneXBottomHeightRpx = 0;
  106. }
  107. },
  108. watch: {
  109. src(val) {if(val.length > 0) { this.init();}},
  110. show(val) {if(!val){}}
  111. },
  112. computed: {
  113. containerTop() {
  114. let top = 0
  115. // #ifdef H5
  116. top = 44
  117. // #endif
  118. return top;
  119. },
  120. // 容器高度
  121. containerHeight() {
  122. return this.windowHeight - 48;
  123. },
  124. // 屏幕宽度
  125. windowWidth() {
  126. return this.sysInfo.windowWidth;
  127. },
  128. windowHeight() {
  129. return this.sysInfo.windowHeight;
  130. }
  131. },
  132. methods: {
  133. rotateHandler() {
  134. if(this.rotate == 3) {
  135. this.rotate = 0;
  136. }else {
  137. ++this.rotate
  138. }
  139. },
  140. init() {
  141. this.rotate = 0;
  142. this.scale = 1;
  143. this.cropW = this.cropWidth
  144. this.cropH = this.cropHeight
  145. uni.showLoading({title: '图片加载中...',})
  146. this.loadImage(this.src).then((e) => {
  147. uni.hideLoading()
  148. }).catch((e) => {
  149. uni.hideLoading()
  150. uni.showModal({ title: '标题', content: '图片加载失败'});
  151. })
  152. },
  153. loadImage(src) {
  154. const _this = this
  155. return new Promise((resolve, reject) => {
  156. uni.getImageInfo({
  157. src: src,
  158. success: (res) => {
  159. _this.imageRealWidth = res.width
  160. _this.imageRealHeight = res.height
  161. _this.imageRatio = _this.imageRealWidth / _this.imageRealHeight;
  162. // 等比缩放后的宽度
  163. _this.imageWidth = _this.windowWidth;
  164. // 等比缩放后的高度
  165. _this.imageHeight = _this.windowWidth / _this.imageRatio;
  166. _this.cropOffsertX = _this.windowWidth / 2 - _this.cropW / 2
  167. _this.cropOffsertY = _this.windowHeight / 2 - _this.cropH / 2
  168. _this.show = true;
  169. _this.$nextTick(() => {
  170. _this.x = 0;
  171. _this.y = 0
  172. });
  173. resolve(res)
  174. },
  175. fail: (e) => {
  176. _this.show = false
  177. reject(e)
  178. }
  179. })
  180. }).catch((e) => {});
  181. },
  182. cancel() {
  183. this.show = false
  184. this.$emit('cancel')
  185. },
  186. confirm(event) {
  187. uni.showLoading({
  188. title: '裁剪中...',
  189. })
  190. const _this = this
  191. const ctx = uni.createCanvasContext('myCanvas', _this);
  192. const pixelRatio = _this.pixelRatio;
  193. const imgage = _this.src;
  194. const imgW = _this.imageWidth * _this.scale;
  195. const imgH = _this.imageHeight * _this.scale
  196. const rotate = _this.rotate;
  197. let dx = _this.cropOffsertX - _this.x - (_this.imageWidth - imgW) / 2;
  198. let dy = _this.cropOffsertY - _this.y - (_this.imageHeight - imgH) / 2;
  199. ctx.setFillStyle('white');
  200. ctx.fillRect(0, 0, imgW, imgH);
  201. ctx.save();
  202. ctx.rotate((rotate * 90 * Math.PI) / 180);
  203. switch (rotate) {
  204. case 1:
  205. dx += (imgH-imgW) / 2
  206. dy -= (imgH-imgW) / 2
  207. ctx.drawImage(imgage, -dy, dx, imgW, -imgH);
  208. break;
  209. case 2:
  210. ctx.drawImage(imgage, dx, dy, -imgW, -imgH);
  211. break;
  212. case 3:
  213. dx += (imgH-imgW) / 2
  214. dy -= (imgH-imgW) / 2
  215. ctx.drawImage(imgage, dy, -dx, -imgW, imgH);
  216. break;
  217. default:
  218. ctx.drawImage(imgage, -dx, -dy, imgW, imgH);
  219. //ctx.drawImage(imgage, 2, 2, 375,375);
  220. break;
  221. }
  222. ctx.restore()
  223. // #ifdef MP-ALIPAY
  224. ctx.draw(true, () => {
  225. ctx.toTempFilePath({
  226. destWidth: _this.cropW * pixelRatio,
  227. destHeight: _this.cropH * pixelRatio,
  228. success: (res) => {
  229. uni.hideLoading()
  230. event.detail.tempFilePath =res.apFilePath
  231. _this.show = false
  232. _this.$emit('confirm', event)
  233. },
  234. fail: (e) => {
  235. uni.hideLoading()
  236. uni.showModal({
  237. title: '提示',
  238. content: '裁剪失败'
  239. })
  240. }
  241. }, _this);
  242. });
  243. // #endif
  244. // #ifndef MP-ALIPAY
  245. ctx.draw(false, () => {
  246. uni.canvasToTempFilePath({
  247. canvasId: 'myCanvas',
  248. destWidth: _this.cropW * pixelRatio,
  249. destHeight: _this.cropH * pixelRatio,
  250. success: (res) => {
  251. uni.hideLoading()
  252. event.detail.tempFilePath = res.tempFilePath;
  253. _this.show = false
  254. _this.$emit('confirm', event)
  255. },
  256. fail: (e) => {
  257. uni.hideLoading()
  258. uni.showModal({
  259. title: '提示',
  260. content: '裁剪失败'
  261. })
  262. }
  263. }, _this);
  264. })
  265. // #endif
  266. },
  267. imgTouchStart(e) {
  268. if(e.touches.length == 2) {
  269. this.oldScale = this.scale
  270. this.scaling = true
  271. const x = e.touches[0].pageX - e.touches[1].pageX
  272. const y = e.touches[0].pageY - e.touches[1].pageY
  273. const hypotenuse = Math.sqrt(
  274. Math.pow(x, 2) +
  275. Math.pow(y, 2)
  276. )
  277. this.startL = Math.max(x, y, hypotenuse)
  278. uni.showModal({content: this.startL});
  279. } else {
  280. this.startX = e.touches[0].pageX - this.x
  281. this.startY = e.touches[0].pageY - this.y
  282. }
  283. },
  284. imgMoveing(e) {
  285. if(this.scaling) {
  286. let scale = this.oldScale;
  287. const x = e.touches[0].pageX - e.touches[1].pageX
  288. const y = e.touches[0].pageY - e.touches[1].pageY
  289. const hypotenuse = Math.sqrt(
  290. Math.pow(x, 2) +
  291. Math.pow(y, 2)
  292. )
  293. const newL = Math.max(x, y, hypotenuse)
  294. const cha = newL - this.startL;
  295. // 根据图片本身大小 决定每次改变大小的系数, 图片越大系数越小
  296. // 1px - 0.2
  297. let coe = 1;
  298. coe =
  299. coe / this.imageWidth > coe / this.imageHeight
  300. ? coe / this.imageHeight
  301. : coe / this.imageWidth;
  302. coe = coe > 0.1 ? 0.1 : coe;
  303. const num = coe * cha;
  304. if (cha > 0) {
  305. scale += Math.abs(num);
  306. } else if (cha < 0) {
  307. scale > Math.abs(num) ? (scale -= Math.abs(num)) : scale;
  308. }
  309. this.scale = scale;
  310. } else {
  311. const moveX = e.touches[0].pageX - this.startX
  312. const moveY = e.touches[0].pageY - this.startY
  313. this.x = moveX
  314. this.y = moveY
  315. }
  316. },
  317. imgMoveEnd() {
  318. setTimeout(() => {
  319. this.scaling = false
  320. }, 100)
  321. },
  322. touchStart(e) {
  323. this.startX = e.touches[0].pageX - this.cropOffsertX;
  324. this.startY = e.touches[0].pageY - this.cropOffsertY;
  325. this.cropOldW = this.cropW
  326. this.cropOldH = this.cropH
  327. },
  328. cropMoveing(e) {
  329. const moveX = this._cropX(e.touches[0].pageX - this.startX)
  330. const moveY = this._cropY(e.touches[0].pageY - this.startY)
  331. this.cropOffsertX = moveX
  332. this.cropOffsertY = moveY
  333. },
  334. dragMove(e, type) {
  335. if(this.cropFixed) {
  336. return false
  337. }
  338. const moveX = e.touches[0].pageX - this.startX
  339. const moveY = e.touches[0].pageY - this.startY
  340. switch (type) {
  341. case 'left-top':
  342. this._cropMoveLeft(moveX)
  343. this._cropMoveTop(moveY)
  344. break;
  345. case 'middle-top':
  346. this._cropMoveTop(moveY)
  347. break;
  348. case 'right-top':
  349. this._cropMoveTop(moveY)
  350. this._cropMoveRight(moveX)
  351. break;
  352. case 'middle-right':
  353. this._cropMoveRight(moveX)
  354. break;
  355. case 'right-bottom':
  356. this._cropMoveRight(moveX)
  357. this._cropMoveBottom(moveY)
  358. break;
  359. case 'middle-bottom':
  360. this._cropMoveBottom(moveY)
  361. break;
  362. case 'left-bottom':
  363. this._cropMoveBottom(moveY)
  364. this._cropMoveLeft(moveX)
  365. break;
  366. case 'middle-left':
  367. this._cropMoveLeft(moveX)
  368. break;
  369. default:
  370. break;
  371. }
  372. },
  373. _cropMoveTop(y) {
  374. const topY = this._cropY(y)
  375. this.cropH += this.cropOffsertY - topY
  376. this.cropOffsertY = topY
  377. },
  378. _cropMoveRight(x) {
  379. if(this.cropOldW + x >= this.windowWidth - this.border) {
  380. return false;
  381. }
  382. this.cropW = this.cropOldW + (x - this.cropOffsertX)
  383. },
  384. _cropMoveBottom(y) {
  385. if(this.cropOldH + y >= this.windowHeight - this.containerTop - this.border) {
  386. return false;
  387. }
  388. this.cropH = this.cropOldH + (y - this.cropOffsertY)
  389. },
  390. _cropMoveLeft(x) {
  391. const leftX = this._cropY(x)
  392. this.cropW += this.cropOffsertX - leftX
  393. this.cropOffsertX = leftX
  394. },
  395. _cropX(x) {
  396. if(x <= this.border) {
  397. return this.border
  398. }
  399. if(x + this.cropW >= this.windowWidth - this.border) {
  400. return this.windowWidth - this.cropW - this.border
  401. }
  402. return x
  403. },
  404. _cropY(y) {
  405. if(y <= this.border) {
  406. return this.border
  407. }
  408. if(y + this.cropH >= this.windowHeight - this.containerTop - this.border) {
  409. return this.windowHeight - this.cropH - this.containerTop - this.border
  410. }
  411. return y
  412. }
  413. }
  414. }
  415. </script>
  416. <style scoped lang="css">
  417. @font-face {
  418. font-family: "iconfont";
  419. src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAR4AAsAAAAACKgAAAQsAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqEfIRGATYCJAMMCwgABCAFhG0HShugB8gOJUHBwAAAAAFEBNmwzd4dtatSmmpFoVAEhUThEAYkCozFKDCqCVO6RfH/89v869awDnTR1qrSANFt4GG4SNxreBn91fmV9f3+53J613ieHba+N1zmGM8PA7oXTaCAxpjei8IoLWFsGLu4jPME6vWJJdovqmgAO4U2LRBnep0K7GJmpYQWanXVOWuLuAFrtenK4haAa/f38QnKsCOpyrRFh6eFWsh5KXnfYcn958BGQNKfE8wmMmaAQpzkuo9Z+ukZluoltVV5abUipL5i/ysArlhWVut/eCRBVNPUjYg6oUo7JTHFoaYDSvdacnKTq9GAB4AY5y2dtL3qpFh1DENdnJC6Hq+xYb7pyRMDMzc/fYoJjY8flwO3m98rMucF+IZHj6Cagw5UeKpxyFbt2rHGY/8jpa7CYMvLfcIesLjY3bdqhaf+nqgQs2qT/+rjCH/VfA0VFGuAC3iE8NEr/Vau8vZsXiUy7+V3c3tQQXMAuNjDCC89KDIHH0OFhnUi81GEPwyc7wZUaN7DnUf4g+ZLQsMKYV/94NjK7R7TEM4niTY1oJ5zEU62aNVaasUub08YLUEam5EnT6a61/I17dNk+vTu9jpJjXhsTFwjqTtpCBxBIIgS6iQnc/Zod1YGKp0rAwsD8kkyP6AwcK0hcAwkiQmBhWvxPZWKDu86aUH2nLEdi9rGX1eXq5P6A1SrnAucMVMdZH/GKi/jyfCqJyucfK3mXpVujXOPfFf5LC4Dvx0X/943JyOq4HuCTZ8KiIPPAb6ro8akpT6ufiq39BQrNlk5mp8pO0JlJLk8f5QalRjoP60IMx0N8n7wGhSD3n6/F1zlcTVz/cR+Ev0lkLSTd7UiPbD/wCxGRMA2Krwro2O0bTQtImbwhjAJc0S3N4ROx15/PH60IzaIOjCbEelqkDOfETNxb/FMixnWNzeJp2KPQw9A5d76jGUOQOUvH7RE/o2RfkNatd3OGf9q0QKbnq8WB7qy+hVqJRjJn1BQgP/iErks0yy5iGJTrOayW7C/z0IoZH0qNH+7N+31XXc7G2p1hZDU6IWs1ghaqDNQpcEKVKu1BfWmFW9u0IFhKUodpswCEFodgqTZHWStbqOF+hqqdPsG1VrDEuodhfueDcZCj+QzuIrFtZh6BNNraIowbCzi1dbhOlOfionKXHoTzgzoY5hCKk/minEKZ/pYMDCoU7IsgREM3Y8Vgcvwvj4aMzK0AdewUpJljWkyGZH3IKmG7gfEHgZOhYXTwqiNwOhp0CiE3ZiFpL5fB6dj0keFKcGV+JvgGAP0vWMUpOQ10GI1VQt3LoMHDNJRYrEIPInAoPXDFEEnrk9P0zDG/FEGOA2WFNkiaZRGhuoRddXS8bX917cL6mn9c6TIUXSekybKHKQfJXFq2KSiRklLYU8dNKWDIX0cAA==') format('woff2');
  420. }
  421. .vue-cropper {
  422. position: fixed;
  423. left: 0;
  424. right: 0;
  425. bottom: 0;
  426. z-index: 998;
  427. box-sizing: border-box;
  428. user-select: none;
  429. -webkit-user-select: none;
  430. -moz-user-select: none;
  431. -ms-user-select: none;
  432. direction: ltr;
  433. touch-action: none;
  434. text-align: left;
  435. background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC");
  436. }
  437. .cropper-canvas {
  438. position: absolute;
  439. top: -9999px;
  440. left:-9999px;
  441. z-index: -998;
  442. }
  443. .vue-cropper .uni-info__ft {
  444. position: absolute;
  445. line-height: 48px;
  446. font-size: 18px;
  447. display: -webkit-box;
  448. display: -webkit-flex;
  449. display: flex;
  450. bottom: 0;
  451. left: 0;
  452. right: 0;
  453. z-index: 998;
  454. }
  455. .btn-group {
  456. position: absolute;
  457. right: 30px;
  458. bottom: 98px;
  459. z-index: 998;
  460. }
  461. .btn-item {
  462. position: relative;
  463. width:40px;
  464. height:40px;
  465. background:#fff;
  466. border-radius: 20px;
  467. display: inline-block;
  468. margin-left: 10px;
  469. text-align:center; line-height:40px;
  470. }
  471. .btn-item:active {background: #ccc;}
  472. .rotate-btn {
  473. font-family: "iconfont" !important;
  474. font-size:30px;
  475. font-style: normal;
  476. -webkit-font-smoothing: antialiased;
  477. -moz-osx-font-smoothing: grayscale;
  478. }
  479. .rotate-btn:before {
  480. content: "\e65c";
  481. margin-left: -2px;
  482. }
  483. .reset-btn {
  484. font-family: "iconfont" !important;
  485. font-size:30px;
  486. font-style: normal;
  487. -webkit-font-smoothing: antialiased;
  488. -moz-osx-font-smoothing: grayscale;
  489. }
  490. .reset-btn:before {
  491. content: "\e648";
  492. margin-left: -2px;
  493. }
  494. .vue-cropper .uni-info__ft:after {
  495. content: " ";
  496. position: absolute;
  497. left: 0;
  498. top: 0;
  499. right: 0;
  500. height: 1px;
  501. border-top: 1px solid #d5d5d6;
  502. color: #d5d5d6;
  503. -webkit-transform-origin: 0 0;
  504. transform-origin: 0 0;
  505. -webkit-transform: scaleY(.5);
  506. transform: scaleY(.5);
  507. z-index: 998;
  508. }
  509. .vue-cropper .uni-modal__btn {
  510. display: block;
  511. -webkit-box-flex: 1;
  512. -webkit-flex: 1;
  513. flex: 1;
  514. color: #3cc51f;
  515. text-decoration: none;
  516. -webkit-tap-highlight-color: rgba(0,0,0,0);
  517. position: relative;
  518. text-align: center;
  519. background-color: #fff;
  520. z-index: 998;
  521. }
  522. .vue-cropper .uni-modal__btn:first-child:after { display: none }
  523. .vue-cropper .uni-modal__btn:after {
  524. content: " ";
  525. position: absolute;
  526. left: 0;
  527. top: 0;
  528. width: 1px;
  529. bottom: 0;
  530. border-left: 1px solid #d5d5d6;
  531. color: #d5d5d6;
  532. -webkit-transform-origin: 0 0;
  533. transform-origin: 0 0;
  534. -webkit-transform: scaleX(.5);
  535. transform: scaleX(.5);
  536. z-index: 998;
  537. }
  538. .vue-cropper .uni-modal__btn:active {
  539. background-color: #eee;
  540. }
  541. .cropper-box,
  542. .cropper-box-canvas,
  543. .cropper-drag-box,
  544. .cropper-crop-box,
  545. .cropper-face {
  546. position: absolute;
  547. top: 0;
  548. right: 0;
  549. bottom: 0;
  550. left: 0;
  551. user-select: none;
  552. z-index: 998;
  553. }
  554. .uni-image {
  555. width: 100%;
  556. height: 100%;
  557. }
  558. .cropper-box-canvas image {
  559. position: relative;
  560. text-align: left;
  561. user-select: none;
  562. transform: none;
  563. max-width: none;
  564. max-height: none;
  565. z-index: 998;
  566. }
  567. .cropper-box {
  568. overflow: hidden;
  569. }
  570. .cropper-move {
  571. cursor: move;
  572. }
  573. .cropper-crop {
  574. cursor: crosshair;
  575. }
  576. .cropper-modal {
  577. background: rgba(0, 0, 0, 0.5);
  578. }
  579. .pointer-events {
  580. pointer-events:none;
  581. }
  582. .cropper-crop-box {
  583. /*border: 2px solid #39f;*/
  584. }
  585. .cropper-view-box {
  586. display: block;
  587. overflow: hidden;
  588. width: 100%;
  589. height: 100%;
  590. outline: 1px solid #39f;
  591. outline-color: rgba(51, 153, 255, 0.75);
  592. user-select: none;
  593. }
  594. .cropper-view-box image {
  595. user-select: none;
  596. text-align: left;
  597. max-width: none;
  598. max-height: none;
  599. }
  600. .cropper-face {
  601. top: 0;
  602. left: 0;
  603. background-color: #fff;
  604. opacity: 0.1;
  605. }
  606. .crop-line {
  607. position: absolute;
  608. display: block;
  609. width: 100%;
  610. height: 100%;
  611. opacity: 0.1;
  612. z-index: 998;
  613. }
  614. .line-w {
  615. top: -3px;
  616. left: 0;
  617. height: 5px;
  618. cursor: n-resize;
  619. }
  620. .line-a {
  621. top: 0;
  622. left: -3px;
  623. width: 5px;
  624. cursor: w-resize;
  625. }
  626. .line-s {
  627. bottom: -3px;
  628. left: 0;
  629. height: 5px;
  630. cursor: s-resize;
  631. }
  632. .line-d {
  633. top: 0;
  634. right: -3px;
  635. width: 5px;
  636. cursor: e-resize;
  637. }
  638. .crop-point {
  639. position: absolute;
  640. width: 8px;
  641. height: 8px;
  642. opacity: 0.75;
  643. background-color: #39f;
  644. border-radius: 100%;
  645. z-index: 998;
  646. }
  647. .point-lt {
  648. top: -4px;
  649. left: -4px;
  650. cursor: nw-resize;
  651. }
  652. .point-mt {
  653. top: -5px;
  654. left: 50%;
  655. margin-left: -3px;
  656. cursor: n-resize;
  657. }
  658. .point-rt {
  659. top: -4px;
  660. right: -4px;
  661. cursor: ne-resize;
  662. }
  663. .point-ml {
  664. top: 50%;
  665. left: -4px;
  666. margin-top: -3px;
  667. cursor: w-resize;
  668. }
  669. .point-mr {
  670. top: 50%;
  671. right: -4px;
  672. margin-top: -3px;
  673. cursor: e-resize;
  674. }
  675. .point-lb {
  676. bottom: -5px;
  677. left: -4px;
  678. cursor: sw-resize;
  679. }
  680. .point-mb {
  681. bottom: -5px;
  682. left: 50%;
  683. margin-left: -3px;
  684. cursor: s-resize;
  685. }
  686. .point-rb {
  687. bottom: -5px;
  688. right: -4px;
  689. cursor: se-resize;
  690. }
  691. </style>