oa-avatar.vue 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. <template name="yq-avatar">
  2. <view>
  3. <image
  4. :src="imgSrc.imgSrc"
  5. @tap="fSelect"
  6. :style="[imgStyle]"
  7. class="my-avatar"
  8. ></image>
  9. <canvas
  10. canvas-id="avatar-canvas"
  11. id="avatar-canvas"
  12. class="my-canvas"
  13. :style="{ top: styleTop, height: cvsStyleHeight }"
  14. disable-scroll="false"
  15. ></canvas>
  16. <canvas
  17. canvas-id="oper-canvas"
  18. id="oper-canvas"
  19. class="oper-canvas"
  20. :style="{ top: styleTop, height: cvsStyleHeight }"
  21. disable-scroll="false"
  22. @touchstart="fStart"
  23. @touchmove="fMove"
  24. @touchend="fEnd"
  25. ></canvas>
  26. <canvas
  27. canvas-id="prv-canvas"
  28. id="prv-canvas"
  29. class="prv-canvas"
  30. disable-scroll="false"
  31. @touchstart="fHideImg"
  32. :style="{ height: cvsStyleHeight, top: prvTop }"
  33. ></canvas>
  34. <view class="oper-wrapper" :style="{ display: styleDisplay }">
  35. <view class="oper">
  36. <view class="btn-wrapper" v-if="showOper">
  37. <view @tap="fSelect" hover-class="hover" :style="{ width: btnWidth }"
  38. ><text>重选</text></view
  39. >
  40. <view @tap="fClose" hover-class="hover" :style="{ width: btnWidth }"
  41. ><text>关闭</text></view
  42. >
  43. <view
  44. @tap="fRotate"
  45. hover-class="hover"
  46. :style="{ width: btnWidth, display: btnDsp }"
  47. ><text>旋转</text></view
  48. >
  49. <view @tap="fPreview" hover-class="hover" :style="{ width: btnWidth }"
  50. ><text>预览</text></view
  51. >
  52. <view @tap="fUpload" hover-class="hover" :style="{ width: btnWidth }"
  53. ><text>上传</text></view
  54. >
  55. </view>
  56. <view class="clr-wrapper" v-else>
  57. <slider
  58. class="my-slider"
  59. @change="fColorChange"
  60. block-size="25"
  61. value="0"
  62. min="-100"
  63. max="100"
  64. activeColor="red"
  65. backgroundColor="green"
  66. block-color="grey"
  67. show-value
  68. ></slider>
  69. <view
  70. @tap="fPrvUpload"
  71. hover-class="hover"
  72. :style="{ width: btnWidth }"
  73. ><text>上传</text></view
  74. >
  75. </view>
  76. </view>
  77. </view>
  78. </view>
  79. </template>
  80. <script>
  81. /* eslint-disable */
  82. const tabHeight = 50;
  83. export default {
  84. name: 'yq-avatar',
  85. data() {
  86. return {
  87. cvsStyleHeight: '0px',
  88. styleDisplay: 'none',
  89. styleTop: '-10000px',
  90. prvTop: '-10000px',
  91. imgStyle: {},
  92. selStyle: {},
  93. showOper: true,
  94. imgSrc: {
  95. imgSrc: ''
  96. },
  97. btnWidth: '19%',
  98. btnDsp: 'flex'
  99. };
  100. },
  101. watch: {
  102. avatarSrc() {
  103. this.imgSrc.imgSrc = this.avatarSrc;
  104. }
  105. },
  106. props: {
  107. avatarSrc: '',
  108. avatarStyle: '',
  109. selWidth: '',
  110. selHeight: '',
  111. expWidth: '',
  112. expHeight: '',
  113. minScale: '',
  114. maxScale: '',
  115. canScale: '',
  116. canRotate: '',
  117. lockWidth: '',
  118. lockHeight: '',
  119. stretch: '',
  120. lock: '',
  121. noTab: '',
  122. inner: '',
  123. quality: '',
  124. index: ''
  125. },
  126. created() {
  127. this.ctxCanvas = uni.createCanvasContext('avatar-canvas', this);
  128. this.ctxCanvasOper = uni.createCanvasContext('oper-canvas', this);
  129. this.ctxCanvasPrv = uni.createCanvasContext('prv-canvas', this);
  130. this.qlty = parseInt(this.quality) || 0.9;
  131. this.imgSrc.imgSrc = this.avatarSrc;
  132. this.letRotate =
  133. this.canRotate === 'false' || this.inner === 'true' ? 0 : 1;
  134. this.letScale = this.canScale === 'false' ? 0 : 1;
  135. this.isin = this.inner === 'true' ? 1 : 0;
  136. this.indx = this.index || undefined;
  137. this.mnScale = this.minScale || 0.3;
  138. this.mxScale = this.maxScale || 4;
  139. this.noBar = this.noTab === 'true' ? 1 : 0;
  140. this.stc = this.stretch;
  141. this.lck = this.lock;
  142. if (this.isin) {
  143. this.btnWidth = '24%';
  144. this.btnDsp = 'none';
  145. } else {
  146. this.btnWidth = '19%';
  147. this.btnDsp = 'flex';
  148. }
  149. if (this.noBar) {
  150. this.moreHeight = 0;
  151. this.fWindowResize();
  152. } else {
  153. uni.showTabBar({
  154. complete: res => {
  155. this.moreHeight = res.errMsg === 'showTabBar:ok' ? 50 : 0;
  156. this.fWindowResize();
  157. }
  158. });
  159. }
  160. },
  161. methods: {
  162. fWindowResize() {
  163. let sysInfo = uni.getSystemInfoSync();
  164. this.platform = sysInfo.platform;
  165. this.pixelRatio = sysInfo.pixelRatio;
  166. this.windowWidth = sysInfo.windowWidth;
  167. // #ifdef H5
  168. this.drawTop = sysInfo.windowTop;
  169. this.windowHeight = sysInfo.windowHeight + sysInfo.windowBottom;
  170. this.cvsStyleHeight = this.windowHeight - tabHeight + 'px';
  171. // #endif
  172. // #ifdef APP-PLUS
  173. if (this.platform === 'android') {
  174. this.windowHeight = sysInfo.screenHeight + sysInfo.statusBarHeight;
  175. this.cvsStyleHeight = this.windowHeight - tabHeight + 'px';
  176. } else {
  177. this.windowHeight = sysInfo.windowHeight + this.moreHeight;
  178. this.cvsStyleHeight = this.windowHeight - tabHeight + 6 + 'px';
  179. }
  180. // #endif
  181. // #ifdef MP
  182. this.windowHeight = sysInfo.windowHeight + this.moreHeight;
  183. this.cvsStyleHeight = this.windowHeight - tabHeight - 2 + 'px';
  184. // #endif
  185. this.pxRatio = this.windowWidth / 750;
  186. let style = this.avatarStyle;
  187. if (style && style !== true && (style = style.trim())) {
  188. style = style.split(';');
  189. let obj = {};
  190. for (let v of style) {
  191. if (!v) continue;
  192. v = v.trim().split(':');
  193. if (v[1].indexOf('upx') >= 0) {
  194. let arr = v[1].trim().split(' ');
  195. for (let k in arr) {
  196. if (!arr[k]) continue;
  197. if (arr[k].indexOf('upx') >= 0) {
  198. arr[k] = parseFloat(arr[k]) * this.pxRatio + 'px';
  199. }
  200. }
  201. v[1] = arr.join(' ');
  202. }
  203. obj[v[0].trim()] = v[1].trim();
  204. }
  205. this.imgStyle = obj;
  206. }
  207. this.expWidth &&
  208. (this.exportWidth =
  209. this.expWidth.indexOf('upx') >= 0
  210. ? parseInt(this.expWidth) * this.pxRatio
  211. : parseInt(this.expWidth));
  212. this.expHeight &&
  213. (this.exportHeight =
  214. this.expHeight.indexOf('upx') >= 0
  215. ? parseInt(this.expHeight) * this.pxRatio
  216. : parseInt(this.expHeight));
  217. if (this.styleDisplay === 'flex') {
  218. this.fDrawInit(true);
  219. }
  220. this.fHideImg();
  221. },
  222. fSelect() {
  223. if (this.fSelecting) return;
  224. this.fSelecting = true;
  225. setTimeout(() => {
  226. this.fSelecting = false;
  227. }, 500);
  228. uni.chooseImage({
  229. count: 1,
  230. sizeType: ['original', 'compressed'],
  231. sourceType: ['album', 'camera'],
  232. success: r => {
  233. uni.showLoading({ mask: true });
  234. let path = (this.imgPath = r.tempFilePaths[0]);
  235. uni.getImageInfo({
  236. src: path,
  237. success: r => {
  238. this.imgWidth = r.width;
  239. this.imgHeight = r.height;
  240. this.path = path;
  241. if (!this.hasSel) {
  242. let style = this.selStyle || {};
  243. if (this.selWidth && this.selHeight) {
  244. let selWidth =
  245. this.selWidth.indexOf('upx') >= 0
  246. ? parseInt(this.selWidth) * this.pxRatio
  247. : parseInt(this.selWidth),
  248. selHeight =
  249. this.selHeight.indexOf('upx') >= 0
  250. ? parseInt(this.selHeight) * this.pxRatio
  251. : parseInt(this.selHeight);
  252. style.width = selWidth + 'px';
  253. style.height = selHeight + 'px';
  254. style.top =
  255. (this.windowHeight - selHeight - tabHeight) / 2 + 'px';
  256. style.left = (this.windowWidth - selWidth) / 2 + 'px';
  257. } else {
  258. uni.showModal({
  259. title: '裁剪框的宽或高没有设置',
  260. showCancel: false
  261. });
  262. return;
  263. }
  264. this.selStyle = style;
  265. }
  266. if (this.noBar) {
  267. this.fDrawInit(true);
  268. } else {
  269. uni.hideTabBar({
  270. complete: () => {
  271. this.fDrawInit(true);
  272. }
  273. });
  274. }
  275. },
  276. fail: () => {
  277. this.$mHelper.toast('error3');
  278. },
  279. complete() {
  280. uni.hideLoading();
  281. }
  282. });
  283. }
  284. });
  285. },
  286. fUpload() {
  287. if (this.fUploading) return;
  288. this.fUploading = true;
  289. setTimeout(() => {
  290. this.fUploading = false;
  291. }, 1000);
  292. let style = this.selStyle,
  293. x = parseInt(style.left),
  294. y = parseInt(style.top),
  295. width = parseInt(style.width),
  296. height = parseInt(style.height),
  297. expWidth = this.exportWidth || width,
  298. expHeight = this.exportHeight || height;
  299. // #ifdef H5
  300. x *= this.pixelRatio;
  301. y *= this.pixelRatio;
  302. expWidth = width;
  303. expHeight = height;
  304. // #endif
  305. uni.showLoading({ mask: true });
  306. this.styleDisplay = 'none';
  307. this.styleTop = '-10000px';
  308. this.hasSel = false;
  309. this.fHideImg();
  310. uni.canvasToTempFilePath(
  311. {
  312. x: x,
  313. y: y,
  314. width: width,
  315. height: height,
  316. destWidth: expWidth,
  317. destHeight: expHeight,
  318. canvasId: 'avatar-canvas',
  319. fileType: 'png',
  320. quality: this.qlty,
  321. success: r => {
  322. r = r.tempFilePath;
  323. // #ifdef H5
  324. this.btop(r).then(r => {
  325. if (this.exportWidth && this.exportHeight) {
  326. let ctxCanvas = this.ctxCanvas;
  327. (expWidth = this.exportWidth), (expHeight = this.exportHeight);
  328. ctxCanvas.drawImage(r, 0, 0, expWidth, expHeight);
  329. ctxCanvas.draw(false, () => {
  330. uni.canvasToTempFilePath({
  331. x: 0,
  332. y: 0,
  333. width: expWidth,
  334. height: expHeight,
  335. destWidth: expWidth,
  336. destHeight: expHeight,
  337. canvasId: 'avatar-canvas',
  338. fileType: 'png',
  339. quality: this.qlty,
  340. success: r => {
  341. r = r.tempFilePath;
  342. this.btop(r).then(r => {
  343. this.$emit('upload', {
  344. avatar: this.imgSrc,
  345. path: r,
  346. index: this.indx,
  347. data: this.rtn
  348. });
  349. });
  350. },
  351. fail: () => {
  352. this.$mHelper.toast('error0');
  353. }
  354. });
  355. });
  356. } else {
  357. this.$emit('upload', {
  358. avatar: this.imgSrc,
  359. path: r,
  360. index: this.indx,
  361. data: this.rtn
  362. });
  363. }
  364. });
  365. // #endif
  366. // #ifndef H5
  367. this.$emit('upload', {
  368. avatar: this.imgSrc,
  369. path: r,
  370. index: this.indx,
  371. data: this.rtn
  372. });
  373. // #endif
  374. },
  375. fail: res => {
  376. this.$mHelper.toast('error1');
  377. },
  378. complete: () => {
  379. uni.hideLoading();
  380. this.noBar || uni.showTabBar();
  381. }
  382. },
  383. this
  384. );
  385. },
  386. fPrvUpload() {
  387. if (this.fPrvUploading) return;
  388. this.fPrvUploading = true;
  389. setTimeout(() => {
  390. this.fPrvUploading = false;
  391. }, 1000);
  392. let style = this.selStyle,
  393. destWidth = parseInt(style.width),
  394. destHeight = parseInt(style.height),
  395. prvX = this.prvX,
  396. prvY = this.prvY,
  397. prvWidth = this.prvWidth,
  398. prvHeight = this.prvHeight,
  399. expWidth = this.exportWidth || prvWidth,
  400. expHeight = this.exportHeight || prvHeight;
  401. // #ifdef H5
  402. prvX *= this.pixelRatio;
  403. prvY *= this.pixelRatio;
  404. expWidth = prvWidth;
  405. expHeight = prvHeight;
  406. // #endif
  407. uni.showLoading({ mask: true });
  408. this.styleDisplay = 'none';
  409. this.styleTop = '-10000px';
  410. this.hasSel = false;
  411. this.fHideImg();
  412. uni.canvasToTempFilePath(
  413. {
  414. x: prvX,
  415. y: prvY,
  416. width: prvWidth,
  417. height: prvHeight,
  418. destWidth: expWidth,
  419. destHeight: expHeight,
  420. canvasId: 'prv-canvas',
  421. fileType: 'png',
  422. quality: this.qlty,
  423. success: r => {
  424. r = r.tempFilePath;
  425. // #ifdef H5
  426. this.btop(r).then(r => {
  427. if (this.exportWidth && this.exportHeight) {
  428. let ctxCanvas = this.ctxCanvas;
  429. (expWidth = this.exportWidth), (expHeight = this.exportHeight);
  430. ctxCanvas.drawImage(r, 0, 0, expWidth, expHeight);
  431. ctxCanvas.draw(false, () => {
  432. uni.canvasToTempFilePath({
  433. x: 0,
  434. y: 0,
  435. width: expWidth,
  436. height: expHeight,
  437. destWidth: expWidth,
  438. destHeight: expHeight,
  439. canvasId: 'avatar-canvas',
  440. fileType: 'png',
  441. quality: this.qlty,
  442. success: r => {
  443. r = r.tempFilePath;
  444. this.btop(r).then(r => {
  445. this.$emit('upload', {
  446. avatar: this.imgSrc,
  447. path: r,
  448. index: this.indx,
  449. data: this.rtn
  450. });
  451. });
  452. },
  453. fail: () => {}
  454. });
  455. });
  456. } else {
  457. this.$emit('upload', {
  458. avatar: this.imgSrc,
  459. path: r,
  460. index: this.indx,
  461. data: this.rtn
  462. });
  463. }
  464. });
  465. // #endif
  466. // #ifndef H5
  467. this.$emit('upload', {
  468. avatar: this.imgSrc,
  469. path: r,
  470. index: this.indx,
  471. data: this.rtn
  472. });
  473. // #endif
  474. },
  475. fail: () => {},
  476. complete: () => {
  477. uni.hideLoading();
  478. this.noBar || uni.showTabBar();
  479. }
  480. },
  481. this
  482. );
  483. },
  484. fDrawInit(ini = false) {
  485. let allWidth = this.windowWidth,
  486. allHeight = this.windowHeight,
  487. imgWidth = this.imgWidth,
  488. imgHeight = this.imgHeight,
  489. imgRadio = imgWidth / imgHeight,
  490. useWidth = allWidth - 40,
  491. useHeight = allHeight - tabHeight - 80,
  492. pixelRatio = this.pixelRatio,
  493. selWidth = parseInt(this.selStyle.width),
  494. selHeight = parseInt(this.selStyle.height);
  495. this.fixWidth = 0;
  496. this.fixHeight = 0;
  497. this.lckWidth = 0;
  498. this.lckHeight = 0;
  499. switch (this.stc) {
  500. case 'x':
  501. this.fixWidth = 1;
  502. break;
  503. case 'y':
  504. this.fixHeight = 1;
  505. break;
  506. case 'long':
  507. if (imgRadio > 1) this.fixWidth = 1;
  508. else this.fixHeight = 1;
  509. break;
  510. case 'short':
  511. if (imgRadio > 1) this.fixHeight = 1;
  512. else this.fixWidth = 1;
  513. break;
  514. case 'longSel':
  515. if (selWidth > selHeight) this.fixWidth = 1;
  516. else this.fixHeight = 1;
  517. break;
  518. case 'shortSel':
  519. if (selWidth > selHeight) this.fixHeight = 1;
  520. else this.fixWidth = 1;
  521. break;
  522. }
  523. switch (this.lck) {
  524. case 'x':
  525. this.lckWidth = 1;
  526. break;
  527. case 'y':
  528. this.lckHeight = 1;
  529. break;
  530. case 'long':
  531. if (imgRadio > 1) this.lckWidth = 1;
  532. else this.lckHeight = 1;
  533. break;
  534. case 'short':
  535. if (imgRadio > 1) this.lckHeight = 1;
  536. else this.lckWidth = 1;
  537. break;
  538. case 'longSel':
  539. if (selWidth > selHeight) this.lckWidth = 1;
  540. else this.lckHeight = 1;
  541. break;
  542. case 'shortSel':
  543. if (selWidth > selHeight) this.lckHeight = 1;
  544. else this.lckWidth = 1;
  545. break;
  546. }
  547. if (this.fixWidth) {
  548. useWidth = selWidth;
  549. useHeight = useWidth / imgRadio;
  550. } else if (this.fixHeight) {
  551. useHeight = selHeight;
  552. useWidth = useHeight * imgRadio;
  553. } else if (imgRadio < 1) {
  554. if (imgHeight < useHeight) {
  555. useWidth = imgWidth;
  556. useHeight = imgHeight;
  557. } else {
  558. useHeight = useHeight;
  559. useWidth = useHeight * imgRadio;
  560. }
  561. } else {
  562. if (imgWidth < useWidth) {
  563. useWidth = imgWidth;
  564. useHeight = imgHeight;
  565. } else {
  566. useWidth = useWidth;
  567. useHeight = useWidth / imgRadio;
  568. }
  569. }
  570. if (this.isin) {
  571. this.scaleWidth = 0;
  572. this.scaleHeight = 0;
  573. if (useWidth < selWidth) {
  574. useWidth = selWidth;
  575. useHeight = useWidth / imgRadio;
  576. this.lckHeight = 0;
  577. }
  578. if (useHeight < selHeight) {
  579. useHeight = selHeight;
  580. useWidth = useHeight * imgRadio;
  581. this.lckWidth = 0;
  582. }
  583. }
  584. this.scaleSize = 1;
  585. this.rotateDeg = 0;
  586. this.posWidth = (allWidth - useWidth) / 2;
  587. this.posHeight = (allHeight - useHeight - tabHeight) / 2;
  588. this.useWidth = useWidth;
  589. this.useHeight = useHeight;
  590. let style = this.selStyle,
  591. left = parseInt(style.left),
  592. top = parseInt(style.top),
  593. width = parseInt(style.width),
  594. height = parseInt(style.height),
  595. canvas = this.canvas,
  596. canvasOper = this.canvasOper,
  597. ctxCanvas = this.ctxCanvas,
  598. ctxCanvasOper = this.ctxCanvasOper;
  599. ctxCanvasOper.setLineWidth(3);
  600. ctxCanvasOper.setStrokeStyle('grey');
  601. ctxCanvasOper.setGlobalAlpha(0.4);
  602. ctxCanvasOper.setFillStyle('black');
  603. ctxCanvasOper.strokeRect(left, top, width, height);
  604. ctxCanvasOper.fillRect(0, 0, this.windowWidth, top);
  605. ctxCanvasOper.fillRect(0, top, left, height);
  606. ctxCanvasOper.fillRect(
  607. 0,
  608. top + height,
  609. this.windowWidth,
  610. this.windowHeight - height - top - tabHeight
  611. );
  612. ctxCanvasOper.fillRect(
  613. left + width,
  614. top,
  615. this.windowWidth - width - left,
  616. height
  617. );
  618. ctxCanvasOper.setStrokeStyle('red');
  619. ctxCanvasOper.moveTo(left + 20, top);
  620. ctxCanvasOper.lineTo(left, top);
  621. ctxCanvasOper.lineTo(left, top + 20);
  622. ctxCanvasOper.moveTo(left + width - 20, top);
  623. ctxCanvasOper.lineTo(left + width, top);
  624. ctxCanvasOper.lineTo(left + width, top + 20);
  625. ctxCanvasOper.moveTo(left + 20, top + height);
  626. ctxCanvasOper.lineTo(left, top + height);
  627. ctxCanvasOper.lineTo(left, top + height - 20);
  628. ctxCanvasOper.moveTo(left + width - 20, top + height);
  629. ctxCanvasOper.lineTo(left + width, top + height);
  630. ctxCanvasOper.lineTo(left + width, top + height - 20);
  631. ctxCanvasOper.stroke();
  632. ctxCanvasOper.draw(false, () => {
  633. if (ini) {
  634. this.styleDisplay = 'flex';
  635. // #ifdef H5
  636. this.styleTop = this.drawTop + 'px';
  637. // #endif
  638. // #ifndef H5
  639. this.styleTop = '0';
  640. // #endif
  641. ctxCanvas.setFillStyle('black');
  642. this.fDrawImage();
  643. }
  644. });
  645. this.$emit('avtinit');
  646. },
  647. fDrawImage() {
  648. let tm_now = Date.now();
  649. if (tm_now - this.drawTm < 20) return;
  650. this.drawTm = tm_now;
  651. let ctxCanvas = this.ctxCanvas;
  652. ctxCanvas.fillRect(0, 0, this.windowWidth, this.windowHeight - tabHeight);
  653. ctxCanvas.translate(
  654. this.posWidth + this.useWidth / 2,
  655. this.posHeight + this.useHeight / 2
  656. );
  657. ctxCanvas.scale(this.scaleSize, this.scaleSize);
  658. ctxCanvas.rotate((this.rotateDeg * Math.PI) / 180);
  659. ctxCanvas.drawImage(
  660. this.imgPath,
  661. -this.useWidth / 2,
  662. -this.useHeight / 2,
  663. this.useWidth,
  664. this.useHeight
  665. );
  666. ctxCanvas.draw(false);
  667. },
  668. fHideImg() {
  669. this.prvImg = '';
  670. this.prvTop = '-10000px';
  671. this.showOper = true;
  672. this.prvImgData = null;
  673. this.target = null;
  674. },
  675. fClose() {
  676. this.styleDisplay = 'none';
  677. this.styleTop = '-10000px';
  678. this.hasSel = false;
  679. this.fHideImg();
  680. this.noBar || uni.showTabBar();
  681. },
  682. fPreview() {
  683. if (this.fPreviewing) return;
  684. this.fPreviewing = true;
  685. setTimeout(() => {
  686. this.fPreviewing = false;
  687. }, 1000);
  688. let style = this.selStyle,
  689. x = parseInt(style.left),
  690. y = parseInt(style.top),
  691. width = parseInt(style.width),
  692. height = parseInt(style.height);
  693. // #ifdef H5
  694. x *= this.pixelRatio;
  695. y *= this.pixelRatio;
  696. // #endif
  697. uni.showLoading({ mask: true });
  698. uni.canvasToTempFilePath(
  699. {
  700. x: x,
  701. y: y,
  702. width: width,
  703. height: height,
  704. canvasId: 'avatar-canvas',
  705. fileType: 'png',
  706. quality: this.qlty,
  707. success: r => {
  708. this.prvImgTmp = r = r.tempFilePath;
  709. let ctxCanvasPrv = this.ctxCanvasPrv,
  710. prvX = this.windowWidth,
  711. prvY = parseInt(this.cvsStyleHeight),
  712. prvWidth = parseInt(this.selStyle.width),
  713. prvHeight = parseInt(this.selStyle.height),
  714. useWidth = prvX - 40,
  715. useHeight = prvY - 80,
  716. radio = useWidth / prvWidth,
  717. rHeight = prvHeight * radio;
  718. if (rHeight < useHeight) {
  719. prvWidth = useWidth;
  720. prvHeight = rHeight;
  721. } else {
  722. radio = useHeight / prvHeight;
  723. prvWidth *= radio;
  724. prvHeight = useHeight;
  725. }
  726. ctxCanvasPrv.setFillStyle('black');
  727. ctxCanvasPrv.fillRect(0, 0, prvX, prvY);
  728. this.prvX = prvX = (prvX - prvWidth) / 2;
  729. this.prvY = prvY = (prvY - prvHeight) / 2;
  730. this.prvWidth = prvWidth;
  731. this.prvHeight = prvHeight;
  732. ctxCanvasPrv.drawImage(r, prvX, prvY, prvWidth, prvHeight);
  733. ctxCanvasPrv.draw(false);
  734. // #ifdef H5
  735. this.btop(r).then(r => {
  736. this.showOper = false;
  737. this.prvTop = this.drawTop + 'px';
  738. });
  739. // #endif
  740. // #ifndef H5
  741. if (this.platform != 'android') {
  742. this.showOper = false;
  743. }
  744. this.prvTop = '0';
  745. // #endif
  746. },
  747. fail: () => {},
  748. complete: () => {
  749. uni.hideLoading();
  750. }
  751. },
  752. this
  753. );
  754. },
  755. fChooseImg(index = undefined, params = undefined, data = undefined) {
  756. if (params) {
  757. let selWidth = params.selWidth,
  758. selHeight = params.selHeight,
  759. expWidth = params.expWidth,
  760. expHeight = params.expHeight,
  761. quality = params.quality,
  762. canRotate = params.canRotate,
  763. canScale = params.canScale,
  764. minScale = params.minScale,
  765. maxScale = params.maxScale,
  766. stretch = params.stretch,
  767. inner = params.inner,
  768. lock = params.lock;
  769. expWidth &&
  770. (this.exportWidth =
  771. expWidth.indexOf('upx') >= 0
  772. ? parseInt(expWidth) * this.pxRatio
  773. : parseInt(expWidth));
  774. expHeight &&
  775. (this.exportHeight =
  776. expHeight.indexOf('upx') >= 0
  777. ? parseInt(expHeight) * this.pxRatio
  778. : parseInt(expHeight));
  779. this.letRotate = canRotate === 'false' ? 0 : 1;
  780. this.letScale = canScale === 'false' ? 0 : 1;
  781. this.qlty = parseInt(quality) || 0.9;
  782. this.mnScale = minScale || 0.3;
  783. this.mxScale = maxScale || 4;
  784. this.stc = stretch;
  785. this.isin = inner === 'true' ? 1 : 0;
  786. this.lck = lock;
  787. if (this.isin) {
  788. this.btnWidth = '24%';
  789. this.btnDsp = 'none';
  790. } else {
  791. this.btnWidth = '19%';
  792. this.btnDsp = 'flex';
  793. }
  794. if (selWidth && selHeight) {
  795. selWidth =
  796. selWidth.indexOf('upx') >= 0
  797. ? parseInt(selWidth) * this.pxRatio
  798. : parseInt(selWidth);
  799. selHeight =
  800. selHeight.indexOf('upx') >= 0
  801. ? parseInt(selHeight) * this.pxRatio
  802. : parseInt(selHeight);
  803. this.selStyle.width = selWidth + 'px';
  804. this.selStyle.height = selHeight + 'px';
  805. this.selStyle.top =
  806. (this.windowHeight - selHeight - tabHeight) / 2 + 'px';
  807. this.selStyle.left = (this.windowWidth - selWidth) / 2 + 'px';
  808. this.hasSel = true;
  809. }
  810. }
  811. this.rtn = data;
  812. this.indx = index;
  813. this.fSelect();
  814. },
  815. fRotate() {
  816. // #ifdef APP-PLUS
  817. if (this.platform === 'android') {
  818. if (this.fRotateing) return;
  819. this.fRotateing = true;
  820. setTimeout(() => {
  821. this.fRotateing = false;
  822. }, 500);
  823. }
  824. // #endif
  825. // if(this.letRotate) {
  826. this.rotateDeg += 90 - (this.rotateDeg % 90);
  827. this.fDrawImage();
  828. // }
  829. },
  830. fStart(e) {
  831. let touches = e.touches,
  832. touch0 = touches[0],
  833. touch1 = touches[1];
  834. this.touch0 = touch0;
  835. this.touch1 = touch1;
  836. if (touch1) {
  837. let x = touch1.x - touch0.x,
  838. y = touch1.y - touch0.y;
  839. this.fgDistance = Math.sqrt(x * x + y * y);
  840. }
  841. },
  842. fMove(e) {
  843. let touches = e.touches,
  844. touch0 = touches[0],
  845. touch1 = touches[1];
  846. if (touch1) {
  847. let x = touch1.x - touch0.x,
  848. y = touch1.y - touch0.y,
  849. fgDistance = Math.sqrt(x * x + y * y),
  850. scaleSize = 0.005 * (fgDistance - this.fgDistance),
  851. beScaleSize = this.scaleSize + scaleSize;
  852. do {
  853. if (!this.letScale) break;
  854. if (beScaleSize < this.mnScale) break;
  855. if (beScaleSize > this.mxScale) break;
  856. if (this.isin) {
  857. let imgWidth = this.useWidth * beScaleSize,
  858. imgHeight = this.useHeight * beScaleSize,
  859. rx0 = this.posWidth + this.useWidth / 2,
  860. ry0 = this.posHeight + this.useHeight / 2,
  861. l = rx0 - imgWidth / 2,
  862. t = ry0 - imgHeight / 2,
  863. r = l + imgWidth,
  864. b = t + imgHeight,
  865. left = parseInt(this.selStyle.left),
  866. top = parseInt(this.selStyle.top),
  867. width = parseInt(this.selStyle.width),
  868. height = parseInt(this.selStyle.height);
  869. if (left < l || left + width > r || top < t || top + height > b)
  870. break;
  871. this.scaleWidth = (this.useWidth - imgWidth) / 2;
  872. this.scaleHeight = (this.useHeight - imgHeight) / 2;
  873. }
  874. this.scaleSize = beScaleSize;
  875. } while (0);
  876. this.fgDistance = fgDistance;
  877. if (touch1.x !== touch0.x && this.letRotate) {
  878. x = (this.touch1.y - this.touch0.y) / (this.touch1.x - this.touch0.x);
  879. y = (touch1.y - touch0.y) / (touch1.x - touch0.x);
  880. this.rotateDeg += (Math.atan((y - x) / (1 + x * y)) * 180) / Math.PI;
  881. this.touch0 = touch0;
  882. this.touch1 = touch1;
  883. }
  884. this.fDrawImage();
  885. } else if (this.touch0) {
  886. let x = touch0.x - this.touch0.x,
  887. y = touch0.y - this.touch0.y,
  888. beX = this.posWidth + x,
  889. beY = this.posHeight + y;
  890. if (this.isin) {
  891. let imgWidth = this.useWidth * this.scaleSize,
  892. imgHeight = this.useHeight * this.scaleSize,
  893. rx0 = beX + this.useWidth / 2,
  894. ry0 = beY + this.useHeight / 2,
  895. l = rx0 - imgWidth / 2,
  896. t = ry0 - imgHeight / 2,
  897. r = l + imgWidth,
  898. b = t + imgHeight,
  899. left = parseInt(this.selStyle.left),
  900. top = parseInt(this.selStyle.top),
  901. width = parseInt(this.selStyle.width),
  902. height = parseInt(this.selStyle.height);
  903. if (!this.lckWidth && Math.abs(x) < 100) {
  904. if (left >= l && left + width <= r) {
  905. this.posWidth = beX;
  906. } else if (left < l) {
  907. this.posWidth = left - this.scaleWidth;
  908. } else if (left + width > r) {
  909. this.posWidth = left - (imgWidth - width) - this.scaleWidth;
  910. }
  911. }
  912. if (!this.lckHeight && Math.abs(y) < 100) {
  913. if (top >= t && top + height <= b) {
  914. this.posHeight = beY;
  915. } else if (top < t) {
  916. this.posHeight = top - this.scaleHeight;
  917. } else if (top + height > b) {
  918. this.posHeight = top - (imgHeight - height) - this.scaleHeight;
  919. }
  920. }
  921. } else {
  922. if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX;
  923. if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY;
  924. }
  925. this.touch0 = touch0;
  926. this.fDrawImage();
  927. }
  928. },
  929. fEnd(e) {
  930. let touches = e.touches,
  931. touch0 = touches && touches[0],
  932. touch1 = touches && touches[1];
  933. if (touch0) {
  934. this.touch0 = touch0;
  935. } else {
  936. this.touch0 = null;
  937. this.touch1 = null;
  938. }
  939. },
  940. fGetImgData() {
  941. return new Promise((resolve, reject) => {
  942. let prvX = this.prvX,
  943. prvY = this.prvY,
  944. prvWidth = this.prvWidth,
  945. prvHeight = this.prvHeight;
  946. // #ifdef APP-PLUS||H5
  947. prvX *= this.pixelRatio;
  948. prvY *= this.pixelRatio;
  949. prvWidth *= this.pixelRatio;
  950. prvHeight *= this.pixelRatio;
  951. // #endif
  952. uni.canvasGetImageData(
  953. {
  954. canvasId: 'prv-canvas',
  955. x: prvX,
  956. y: prvY,
  957. width: prvWidth,
  958. height: prvHeight,
  959. success(res) {
  960. resolve(res.data);
  961. },
  962. fail(err) {
  963. reject(err);
  964. }
  965. },
  966. this
  967. );
  968. });
  969. },
  970. async fColorChange(e) {
  971. let tm_now = Date.now();
  972. if (tm_now - this.prvTm < 100) return;
  973. this.prvTm = tm_now;
  974. uni.showLoading({ mask: true });
  975. if (!this.prvImgData) {
  976. if (!(this.prvImgData = await this.fGetImgData().catch(res => {})))
  977. return;
  978. this.target = new Uint8ClampedArray(this.prvImgData.length);
  979. }
  980. let data = this.prvImgData,
  981. target = this.target,
  982. i = e.detail.value,
  983. r,
  984. g,
  985. b,
  986. a,
  987. h,
  988. s,
  989. l,
  990. d,
  991. p,
  992. q,
  993. t,
  994. min,
  995. max,
  996. hK,
  997. tR,
  998. tG,
  999. tB;
  1000. if (i === 0) {
  1001. target = data;
  1002. } else {
  1003. i = (i + 100) / 200;
  1004. if (i < 0.005) i = 0;
  1005. if (i > 0.995) i = 1;
  1006. for (let n = data.length - 1; n >= 0; n -= 4) {
  1007. r = data[n - 3] / 255;
  1008. g = data[n - 2] / 255;
  1009. b = data[n - 1] / 255;
  1010. max = Math.max(r, g, b);
  1011. min = Math.min(r, g, b);
  1012. d = max - min;
  1013. if (max === min) {
  1014. h = 0;
  1015. } else if (max === r && g >= b) {
  1016. h = 60 * ((g - b) / d);
  1017. } else if (max === r && g < b) {
  1018. h = 60 * ((g - b) / d) + 360;
  1019. } else if (max === g) {
  1020. h = 60 * ((b - r) / d) + 120;
  1021. } else if (max === b) {
  1022. h = 60 * ((r - g) / d) + 240;
  1023. }
  1024. l = (max + min) / 2;
  1025. if (l === 0 || max === min) {
  1026. s = 0;
  1027. } else if (0 < l && l <= 0.5) {
  1028. s = d / (2 * l);
  1029. } else if (l > 0.5) {
  1030. s = d / (2 - 2 * l);
  1031. }
  1032. data[n] && (a = data[n]);
  1033. if (i < 0.5) {
  1034. s = (s * i) / 0.5;
  1035. } else if (i > 0.5) {
  1036. s = 2 * s + 2 * i - (s * i) / 0.5 - 1;
  1037. }
  1038. if (s === 0) {
  1039. r = g = b = Math.round(l * 255);
  1040. } else {
  1041. if (l < 0.5) {
  1042. q = l * (1 + s);
  1043. } else if (l >= 0.5) {
  1044. q = l + s - l * s;
  1045. }
  1046. p = 2 * l - q;
  1047. hK = h / 360;
  1048. tR = hK + 1 / 3;
  1049. tG = hK;
  1050. tB = hK - 1 / 3;
  1051. let correctRGB = t => {
  1052. if (t < 0) {
  1053. return t + 1.0;
  1054. }
  1055. if (t > 1) {
  1056. return t - 1.0;
  1057. }
  1058. return t;
  1059. };
  1060. let createRGB = t => {
  1061. if (t < 1 / 6) {
  1062. return p + (q - p) * 6 * t;
  1063. } else if (t >= 1 / 6 && t < 1 / 2) {
  1064. return q;
  1065. } else if (t >= 1 / 2 && t < 2 / 3) {
  1066. return p + (q - p) * 6 * (2 / 3 - t);
  1067. }
  1068. return p;
  1069. };
  1070. r = tR = Math.round(createRGB(correctRGB(tR)) * 255);
  1071. g = tG = Math.round(createRGB(correctRGB(tG)) * 255);
  1072. b = tB = Math.round(createRGB(correctRGB(tB)) * 255);
  1073. }
  1074. a && (target[n] = a);
  1075. target[n - 3] = r;
  1076. target[n - 2] = g;
  1077. target[n - 1] = b;
  1078. }
  1079. }
  1080. let prvX = this.prvX,
  1081. prvY = this.prvY,
  1082. prvWidth = this.prvWidth,
  1083. prvHeight = this.prvHeight;
  1084. this.ctxCanvasPrv.setFillStyle('black');
  1085. this.ctxCanvasPrv.fillRect(prvX, prvY, prvWidth, prvHeight);
  1086. this.ctxCanvasPrv.draw(true);
  1087. // #ifdef APP-PLUS||H5
  1088. prvX *= this.pixelRatio;
  1089. prvY *= this.pixelRatio;
  1090. prvWidth *= this.pixelRatio;
  1091. prvHeight *= this.pixelRatio;
  1092. // #endif
  1093. uni.canvasPutImageData(
  1094. {
  1095. canvasId: 'prv-canvas',
  1096. x: prvX,
  1097. y: prvY,
  1098. width: prvWidth,
  1099. height: prvHeight,
  1100. data: target,
  1101. fail() {},
  1102. complete() {
  1103. uni.hideLoading();
  1104. }
  1105. },
  1106. this
  1107. );
  1108. },
  1109. btop(base64) {
  1110. return new Promise(function(resolve, reject) {
  1111. var arr = base64.split(','),
  1112. mime = arr[0].match(/:(.*?);/)[1],
  1113. bstr = atob(arr[1]),
  1114. n = bstr.length,
  1115. u8arr = new Uint8Array(n);
  1116. while (n--) {
  1117. u8arr[n] = bstr.charCodeAt(n);
  1118. }
  1119. return resolve(
  1120. (window.URL || window.webkitURL).createObjectURL(
  1121. new Blob([u8arr], { type: mime })
  1122. )
  1123. );
  1124. });
  1125. }
  1126. }
  1127. };
  1128. </script>
  1129. <style>
  1130. .my-canvas {
  1131. display: flex;
  1132. position: fixed !important;
  1133. background: #000000;
  1134. left: 0;
  1135. z-index: 100000;
  1136. width: 100%;
  1137. }
  1138. .my-avatar {
  1139. width: 150upx;
  1140. height: 150upx;
  1141. border-radius: 100%;
  1142. }
  1143. .oper-canvas {
  1144. display: flex;
  1145. position: fixed !important;
  1146. left: 0;
  1147. z-index: 100001;
  1148. width: 100%;
  1149. }
  1150. .prv-canvas {
  1151. display: flex;
  1152. position: fixed !important;
  1153. background: #000000;
  1154. left: 0;
  1155. z-index: 200000;
  1156. width: 100%;
  1157. }
  1158. .oper-wrapper {
  1159. height: 50px;
  1160. position: fixed !important;
  1161. box-sizing: border-box;
  1162. border: 1px solid #f1f1f1;
  1163. background: #ffffff;
  1164. width: 100%;
  1165. left: 0;
  1166. bottom: 0;
  1167. z-index: 100009;
  1168. flex-direction: row;
  1169. }
  1170. .oper {
  1171. display: flex;
  1172. flex-direction: column;
  1173. justify-content: center;
  1174. padding: 10upx 20upx;
  1175. width: 100%;
  1176. height: 100%;
  1177. box-sizing: border-box;
  1178. align-self: center;
  1179. }
  1180. .btn-wrapper {
  1181. display: flex;
  1182. flex-direction: row;
  1183. /* #ifndef H5 */
  1184. flex-grow: 1;
  1185. /* #endif */
  1186. /* #ifdef H5 */
  1187. height: 50px;
  1188. /* #endif */
  1189. justify-content: space-between;
  1190. }
  1191. .btn-wrapper view {
  1192. display: flex;
  1193. align-items: center;
  1194. justify-content: center;
  1195. font-size: 16px;
  1196. color: #333;
  1197. border: 1px solid #f1f1f1;
  1198. border-radius: 6%;
  1199. }
  1200. .hover {
  1201. background: #f1f1f1;
  1202. border-radius: 6%;
  1203. }
  1204. .clr-wrapper {
  1205. display: flex;
  1206. flex-direction: row;
  1207. flex-grow: 1;
  1208. }
  1209. .clr-wrapper view {
  1210. display: flex;
  1211. align-items: center;
  1212. justify-content: center;
  1213. font-size: 16px;
  1214. color: #333;
  1215. border: 1px solid #f1f1f1;
  1216. border-radius: 6%;
  1217. }
  1218. .my-slider {
  1219. flex-grow: 1;
  1220. }
  1221. </style>