康巴易测肤/伤疤uniapp小程序类
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

index.vue 15KB

1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
1ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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>