yq-avatar.vue 31 KB

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