You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

yq-avatar.vue 34 KiB

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