yq-avatar.vue 35 KB

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