康巴易测肤/伤疤uniapp小程序类
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

465 lines
15KB

  1. <template>
  2. <view class="container">
  3. <view class="image-box" :style="{
  4. backgroundImage: 'url(' + src + ')',
  5. backgroundSize: imageBoxWidth + 'rpx' + ' ' + imageBoxHeight + 'rpx',
  6. width: imageBoxWidth + 'rpx',
  7. height: imageBoxHeight + 'rpx',
  8. borderRadius: cropShape == 'rect' ? '' : '',
  9. }">
  10. <view class="mask"></view>
  11. <view class="cropping-box" @touchstart.stop="touchstart" @touchmove.stop="touchmove"
  12. @touchend.stop="touchend" :style="{
  13. top: cropBoxY + 'rpx',
  14. left: cropBoxX + 'rpx',
  15. width: cropBoxWidth + 'rpx',
  16. height: cropBoxHeight + 'rpx',
  17. backgroundImage: 'url(' + src + ')',
  18. backgroundSize: imageBoxWidth + 'rpx' + ' ' + imageBoxHeight + 'rpx',
  19. backgroundPositionX: (-cropBoxX - 4) + 'rpx',
  20. backgroundPositionY: (-cropBoxY - 4) + 'rpx',
  21. borderRadius: cropShape == 'rect' ? '' : '50%'
  22. }">
  23. <!-- 裁剪小组件 -->
  24. <!-- <view v-if="cropShape == 'rect' && !isFixedSize" class="zoom-handle-rect" data-body="handle"></view> -->
  25. <!-- <view v-if="cropShape == 'circular'" class="zoom-chandle-circular" data-body="handle"></view> -->
  26. </view>
  27. </view>
  28. <!-- <canvas class="canvas" canvas-id="canvas" id="canvas" :style="{width: canvasWidth + 'px', height: canvasHeight + 'px'}"></canvas> -->
  29. <view class="operation-area">
  30. <view class="crop-area">
  31. <u--image :src="cropImgPath" mode="widthFix" :customStyle="{ border: '2px solid #F3D4A3' }"
  32. shape="circle" width="100px" height="100px" @click="onPre"></u--image>
  33. </view>
  34. <view class="action">
  35. <!-- <view shape="circle" hover-class="none" class="btn" @click="cancel">取消</view> -->
  36. <view shape="circle" hover-class="none" class="btn full" @click="cropping(true)">继续</view>
  37. </view>
  38. </view>
  39. </view>
  40. </template>
  41. <script>
  42. let startX, startY;
  43. let boxX, boxY, boxWidth, boxHeight;
  44. let imageOriginalWidth, imageOriginalHeight;
  45. let imageZoomRatio;
  46. let windowInfo;
  47. export default {
  48. name: 'imageCropping',
  49. props: {
  50. src: {
  51. type: String,
  52. },
  53. ratioGroup: {
  54. type: Array,
  55. default() {
  56. return []
  57. }
  58. },
  59. isFixedSize: {
  60. type: Boolean,
  61. default: false
  62. },
  63. cropShape: {
  64. type: String,
  65. default: 'circular' // 'rect' , 'circular'
  66. }
  67. },
  68. data() {
  69. return {
  70. imageBoxWidth: 0,
  71. imageBoxHeight: 0,
  72. cropBoxX: 0,
  73. cropBoxY: 0,
  74. cropBoxWidth: 0,
  75. cropBoxHeight: 0,
  76. // move: 移动 , zoom: 缩放
  77. mode: '',
  78. cropSize: 100,
  79. cropImgPath: ''
  80. }
  81. },
  82. mounted() {
  83. this.getImageInfo();
  84. },
  85. methods: {
  86. // 获取图片尺寸
  87. getImageInfo() {
  88. windowInfo = uni.getWindowInfo();
  89. if (this.src) {
  90. uni.getImageInfo({
  91. src: this.src,
  92. success: (res) => {
  93. console.log("图片尺寸信息", res);
  94. console.log("当前屏幕尺寸", windowInfo);
  95. imageOriginalWidth = (res.width)/* 300 */;
  96. imageOriginalHeight = (res.height)/* 300 */;
  97. let widthZoomRatio = imageOriginalWidth / windowInfo.windowWidth;
  98. let heightZoomRatio = imageOriginalHeight / windowInfo.windowHeight;
  99. imageZoomRatio = widthZoomRatio > heightZoomRatio ? widthZoomRatio : heightZoomRatio;
  100. this.imageBoxWidth = (imageOriginalWidth / imageZoomRatio);
  101. this.imageBoxHeight = (imageOriginalHeight / imageZoomRatio);
  102. console.log("this.imageBoxWidth", this.imageBoxWidth);
  103. console.log("this.imageBoxHeight", this.imageBoxHeight);
  104. this.setRatio('1:1');
  105. },
  106. fail: (error) => {
  107. console.log("error", error);
  108. }
  109. })
  110. }
  111. },
  112. touchstart(event) {
  113. startX = event.touches[0].clientX;
  114. startY = event.touches[0].clientY;
  115. if (event.target.dataset.body == "handle") {
  116. this.mode = 'zoom';
  117. boxWidth = this.cropBoxWidth;
  118. boxHeight = this.cropBoxHeight;
  119. } else {
  120. this.mode = 'move';
  121. boxX = this.cropBoxX;
  122. boxY = this.cropBoxY;
  123. }
  124. },
  125. touchmove(event) {
  126. let distanceX = event.touches[0].clientX - startX;
  127. let distanceY = event.touches[0].clientY - startY;
  128. let x = boxX + distanceX;
  129. let y = boxY + distanceY;
  130. let width = boxWidth + distanceX;
  131. let height = boxHeight + distanceY;
  132. let maxX = this.imageBoxWidth - this.cropBoxWidth;
  133. let maxY = this.imageBoxHeight - this.cropBoxHeight;
  134. let maxWidth = this.imageBoxWidth - this.cropBoxX;
  135. let maxHeight = this.imageBoxHeight - this.cropBoxY;
  136. switch (this.mode) {
  137. case 'move':
  138. this.cropBoxX = x < 0 ? 0 : (x > maxX ? maxX : x);
  139. this.cropBoxY = y < 0 ? 0 : (y > maxY ? maxY : y);
  140. break;
  141. case 'zoom':
  142. if (this.cropShape == 'rect') {
  143. this.cropBoxWidth = width > maxWidth ? maxWidth : width;
  144. this.cropBoxHeight = height > maxHeight ? maxHeight : height;
  145. } else {
  146. this.cropBoxHeight = height > maxHeight ? maxHeight : height;
  147. this.cropBoxWidth = height > maxHeight ? maxHeight : height;
  148. }
  149. break;
  150. }
  151. },
  152. touchend() {
  153. setTimeout(() => {
  154. this.cropping(false);
  155. }, 500)
  156. },
  157. setRatio(ratio) {
  158. if (ratio === 'full') {
  159. this.cropBoxWidth = this.imageBoxWidth;
  160. this.cropBoxHeight = this.imageBoxHeight;
  161. this.cropBoxX = 0;
  162. this.cropBoxY = 0;
  163. } else {
  164. let x = ratio.split(':')[0];
  165. let y = ratio.split(':')[1];
  166. let r1 = (x / y);
  167. let r2 = (y / x);
  168. if (this.imageBoxWidth < this.imageBoxHeight) {
  169. console.log("1");
  170. let size = this.imageBoxWidth;
  171. if (size / r1 > this.imageBoxHeight) {
  172. size = this.imageBoxHeight;
  173. this.cropBoxWidth = ((size / r2) - this.cropSize) / 2;
  174. this.cropBoxHeight = (size - this.cropSize) / 2;
  175. this.cropBoxX = this.cropSize / 2;
  176. this.cropBoxY = (this.imageBoxWidth - this.imageBoxWidth) / 2;
  177. } else {
  178. this.cropBoxWidth = (size - this.cropSize) / 2;
  179. this.cropBoxHeight = ((size / r1) - this.cropSize) / 2;
  180. this.cropBoxX = this.cropSize / 2;
  181. this.cropBoxY = (this.imageBoxHeight - this.cropBoxHeight) / 2;
  182. }
  183. } else {
  184. console.log("2");
  185. let size = this.imageBoxHeight;
  186. if (size / r1 > this.imageBoxWidth) {
  187. size = this.imageBoxWidth;
  188. this.cropBoxWidth = (size - this.cropSize) / 2;
  189. this.cropBoxHeight = ((size / r2) - this.cropSize);
  190. this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
  191. this.cropBoxY = ((this.imageBoxHeight - this.cropBoxHeight)) / 2;
  192. } else {
  193. this.cropBoxWidth = ((size / r1) - this.cropSize) / 2;
  194. this.cropBoxHeight = (size - this.cropSize) / 2;
  195. this.cropBoxX = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
  196. this.cropBoxY = ((this.imageBoxWidth - this.cropBoxWidth)) / 2;
  197. }
  198. }
  199. }
  200. },
  201. async cropping(state) {
  202. let that = this;
  203. let x = this.cropBoxX * imageZoomRatio;
  204. let y = this.cropBoxY * imageZoomRatio;
  205. let w = this.cropBoxWidth * imageZoomRatio;
  206. let h = this.cropBoxHeight * imageZoomRatio;
  207. // 方式2:
  208. const canvas = uni.createOffscreenCanvas({ type: '2d', width: w, height: h });
  209. const context = canvas.getContext('2d');
  210. context.fillStyle = '#fff'; // 设置绘制后的填充颜色
  211. context.globalCompositeOperation = 'source-over';
  212. const image = canvas.createImage();
  213. await new Promise((resolve, reject) => {
  214. image.onload = resolve
  215. image.onerror = reject
  216. image.src = this.src;
  217. })
  218. context.clearRect(0, 0, w, h);
  219. if (this.cropShape == 'circular') {
  220. context.beginPath();
  221. context.arc(w / 2, h / 2, w / 2, 0, Math.PI * 2);
  222. context.fill();
  223. context.clip();
  224. context.clip();
  225. }
  226. context.drawImage(image, x, y, w, h, 0, 0, w, h);
  227. const DataURL = canvas.toDataURL();
  228. const fs = wx.getFileSystemManager();
  229. let tempFilePath = `${wx.env.USER_DATA_PATH}/` + new Date().getTime() + '.jpg'
  230. fs.writeFile({
  231. filePath: tempFilePath,
  232. data: DataURL.replace('data:image/png;base64,', ''),
  233. encoding: 'base64',
  234. success: res => {
  235. that.$emit('completed', {
  236. tempFilePath
  237. });
  238. that.cropImgPath = tempFilePath;
  239. },
  240. fail(res) {
  241. console.error(res)
  242. }
  243. })
  244. setTimeout(() => {
  245. if (state) {
  246. // TODO 对接接口
  247. /* let image = await this.$api.upload(
  248. that.$util.tempUrlToUpload(that.cropImgPath, `${that.$util.formateDate('yyyy-mm-dd-HH:MM:SS')}_result.jpg`,)
  249. );
  250. let imgUrl = image.data.fileUrl;
  251. console.log("imgUrl", imgUrl); */
  252. that.$store.commit('setResultPath', that.cropImgPath);
  253. uni.navigateTo({
  254. url: '/pages/details/index',
  255. })
  256. }
  257. }, 800)
  258. // 方式一:
  259. // const context = uni.createCanvasContext('canvas', this)
  260. // context.drawImage(this.src,x,y,w,h,0, 0, w, h)
  261. // context.draw(false, ()=>{
  262. // console.log(123);
  263. // uni.canvasToTempFilePath({
  264. // canvas: context,
  265. // success: function(res) {
  266. // console.log(res)
  267. // },
  268. // complete: function(res){
  269. // console.log(res)
  270. // }
  271. // },this)
  272. // })
  273. },
  274. yuantu() {
  275. this.$emit('completed', {
  276. tempFilePath: this.src
  277. })
  278. },
  279. cancel() {
  280. this.$emit('cancel')
  281. },
  282. onPre() {
  283. if (!this.cropImgPath) return;
  284. uni.previewImage({
  285. urls: [this.cropImgPath]
  286. })
  287. }
  288. }
  289. }
  290. </script>
  291. <style lang="scss" scoped>
  292. .container {
  293. width: 100vw;
  294. height: 100vh;
  295. overflow: scroll;
  296. /* position: fixed;
  297. left: 0;
  298. bottom: 400rpx; */
  299. z-index: 99;
  300. display: flex;
  301. align-items: center;
  302. justify-content: center;
  303. background-color: #fff;
  304. flex-direction: column;
  305. .image-box {
  306. position: fixed;
  307. left: 25%;
  308. bottom: 400rpx;
  309. background-size: contain;
  310. background-repeat: no-repeat;
  311. // filter: invert(1);
  312. z-index: 999;
  313. background-color: #fff;
  314. .mask {
  315. width: 100%;
  316. height: 100%;
  317. position: absolute;
  318. left: 0;
  319. top: 0;
  320. background-color: rgba(0, 0, 0, 0.3);
  321. z-index: 99;
  322. }
  323. .cropping-box {
  324. position: absolute;
  325. border: 6rpx solid #F3D4A3;
  326. box-sizing: border-box;
  327. background-repeat: no-repeat;
  328. z-index: 9999;
  329. // .zoom-handle-rect,
  330. // .zoom-chandle-circular{
  331. // width: 10px;
  332. // height: 10px;
  333. // background-color: springgreen;
  334. // border-radius: 50%;
  335. // position: absolute;
  336. // right: -6px;
  337. // bottom: -6px;
  338. // }
  339. /* .zoom-chandle-circular{
  340. right: 50%;
  341. transform: translateX(5px);
  342. } */
  343. }
  344. }
  345. }
  346. .operation-area {
  347. position: absolute;
  348. left: 0;
  349. bottom: 20rpx;
  350. z-index: 99999;
  351. width: 100%;
  352. padding: 10rpx 0;
  353. display: flex;
  354. flex-direction: column;
  355. align-items: flex-start;
  356. justify-content: center;
  357. overflow: scroll;
  358. padding-bottom: env(safe-area-inset-bottom);
  359. .crop-area {
  360. width: 100%;
  361. display: flex;
  362. justify-content: center;
  363. align-items: center;
  364. }
  365. .ratio-area {
  366. display: flex;
  367. align-items: center;
  368. justify-content: center;
  369. margin-bottom: 16rpx;
  370. .ratio-btn {
  371. display: inline-block;
  372. padding: 8rpx 20rpx;
  373. border: 2rpx solid white;
  374. color: white;
  375. margin: 0 10rpx;
  376. font-size: 12px;
  377. }
  378. }
  379. .bottom {
  380. height: 120rpx;
  381. width: 100%;
  382. display: flex;
  383. align-items: center;
  384. justify-content: center;
  385. button {
  386. display: inline-block;
  387. margin: 0 20rpx;
  388. }
  389. }
  390. .action {
  391. height: 120rpx;
  392. width: 100vw;
  393. position: relative;
  394. /* bottom: 60rpx;
  395. left: 0; */
  396. display: flex;
  397. justify-content: center;
  398. align-items: center;
  399. background: none;
  400. z-index: 99999;
  401. .btn {
  402. height: 70rpx;
  403. line-height: 70rpx;
  404. width: 80vw;
  405. border: 4rpx solid #333;
  406. text-align: center;
  407. border-radius: 60rpx;
  408. font-family: OPPOSans;
  409. font-weight: bold;
  410. font-size: 32rpx;
  411. color: #333;
  412. &.full {
  413. background-color: #333;
  414. color: #F3D4A3;
  415. margin-left: 30rpx;
  416. font-weight: bold;
  417. }
  418. }
  419. }
  420. }
  421. .canvas {
  422. position: absolute;
  423. bottom: 0;
  424. left: 0;
  425. z-index: 1;
  426. border: 1px solid;
  427. // display: none;
  428. }
  429. </style>