wm-poster.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <template>
  2. <view style="background: #FFFFFF;">
  3. <!-- <view v-if="loading"></view> -->
  4. <canvas v-if="!tempFilePath" :canvas-id="CanvasID" :style="{ width: canvasW + 'px', height: canvasH + 'px' }"></canvas>
  5. <image v-else lazy-load :src="tempFilePath" mode="widthFix" class="is-response" @longpress="toSave(tempFilePath)"></image>
  6. </view>
  7. </template>
  8. <script>
  9. var _this;
  10. export default {
  11. name: 'wm-poster',
  12. props: {
  13. CanvasID: {
  14. //CanvasID 等同于 canvas-id
  15. Type: String,
  16. default: 'PosterCanvas'
  17. },
  18. imgSrc: {
  19. //展示图
  20. Type: String,
  21. default: ''
  22. },
  23. QrSrc: {
  24. //二维码
  25. Type: String,
  26. default: ''
  27. },
  28. Title: {
  29. //文本内容
  30. Type: String,
  31. default: '匠库科技'
  32. },
  33. TitleColor: {
  34. //标题颜色
  35. Type: String,
  36. default: '#000000'
  37. },
  38. LineType: {
  39. //标题显示行数 (注超出2行显示会导致画布布局絮乱)
  40. Type: [String, Boolean],
  41. default: true
  42. },
  43. PriceTxt: {
  44. //价格值
  45. Type: String,
  46. default: ''
  47. },
  48. PriceColor: {
  49. //价格颜色
  50. Type: String,
  51. default: '#e31d1a'
  52. },
  53. OriginalTxt: {
  54. //原价值
  55. Type: String,
  56. default: ''
  57. },
  58. OriginalColor: {
  59. //默认颜色(如原价与扫描二维码颜色)
  60. Type: String,
  61. default: '#b8b8b8'
  62. },
  63. Width: {
  64. //画布宽度 (高度根据图片比例计算 单位upx)
  65. Type: String,
  66. default: 700
  67. },
  68. CanvasBg: {
  69. //canvas画布背景色
  70. Type: String,
  71. default: '#ffffff'
  72. },
  73. Referrer: {
  74. //推荐人信息
  75. Type: String,
  76. default: '匠库科技精选好物'
  77. },
  78. ViewDetails: {
  79. //描述提示文字
  80. Type: String,
  81. default: '长按或扫描识别二维码领券'
  82. }
  83. },
  84. data() {
  85. return {
  86. loading: false,
  87. tempFilePath: '',
  88. canvasW: 0,
  89. canvasH: 0,
  90. canvasImgSrc: '',
  91. ctx: null
  92. };
  93. },
  94. methods: {
  95. toSave(url) {
  96. //#ifndef H5
  97. uni.getImageInfo({
  98. src: url,
  99. success: function(image) {
  100. console.log('图片信息:', JSON.stringify(image));
  101. uni.saveImageToPhotosAlbum({
  102. filePath: image.path,
  103. success: function() {
  104. console.log('save success');
  105. uni.showToast({
  106. title: '海报已保存相册',
  107. icon: 'success',
  108. duration: 2000
  109. });
  110. }
  111. });
  112. }
  113. });
  114. //#endif
  115. },
  116. async OnCanvas() {
  117. this.loading = true;
  118. // this.$queue.showLoading('海报生成中...');
  119. _this.ctx = uni.createCanvasContext(_this.CanvasID, this);
  120. const C_W = uni.upx2px(_this.Width), //canvas宽度
  121. C_P = uni.upx2px(30), //canvas Paddng 间距
  122. C_Q = uni.upx2px(150); //二维码或太阳码宽高
  123. let _strlineW = 0; //文本宽度
  124. let _imgInfo = await _this.getImageInfo({
  125. imgSrc: _this.imgSrc
  126. }); //广告图
  127. let _QrCode = await _this.getImageInfo({
  128. imgSrc: _this.QrSrc
  129. }); //二维码或太阳码
  130. let r = [_imgInfo.width, _imgInfo.height];
  131. let q = [_QrCode.width, _QrCode.height];
  132. let imgW = C_W - C_P * 2;
  133. if (r[0] != imgW) {
  134. r[1] = Math.floor((imgW / r[0]) * r[1]);
  135. r[0] = imgW;
  136. }
  137. if (q[0] != C_Q) {
  138. q[1] = Math.floor((C_Q / q[0]) * q[1]);
  139. q[0] = C_Q;
  140. }
  141. _this.canvasW = C_W;
  142. _this.canvasH = r[1] + q[1] + 128;
  143. _this.ctx.setFillStyle(_this.CanvasBg); //canvas背景颜色
  144. _this.ctx.fillRect(0, 0, C_W, _this.canvasH); //canvas画布大小
  145. //添加图片展示
  146. _this.ctx.drawImage(_imgInfo.path, C_P, C_P, r[0], r[1]);
  147. //添加图片展示 end
  148. //设置文本
  149. //#ifdef H5
  150. _this.ctx.setFontSize(uni.upx2px(32)); //设置标题字体大小
  151. //#endif
  152. //#ifdef APP-PLUS
  153. _this.ctx.setFontSize(uni.upx2px(36)); //设置标题字体大小
  154. _this.Title=_this.Title.substring(0,20)
  155. //#endif
  156. _this.ctx.setFillStyle(_this.TitleColor); //设置标题文本颜色
  157. let _strLastIndex = 0; //每次开始截取的字符串的索引
  158. let _strHeight = r[1] + C_P * 2 + 10; //绘制字体距离canvas顶部的初始高度
  159. let _num = 1;
  160. for (let i = 0; i < _this.Title.length; i++) {
  161. _strlineW += _this.ctx.measureText(_this.Title[i]).width;
  162. if (_strlineW > r[0]) {
  163. if (_num == 2 && _this.LineType) {
  164. //文字换行数量大于二进行省略号处理
  165. _this.ctx.fillText(_this.Title.substring(_strLastIndex, i - 8) + '...', C_P, _strHeight);
  166. _strlineW = 0;
  167. _strLastIndex = i;
  168. _num++;
  169. break;
  170. } else {
  171. _this.ctx.fillText(_this.Title.substring(_strLastIndex, i), C_P, _strHeight);
  172. _strlineW = 0;
  173. _strHeight += 20;
  174. _strLastIndex = i;
  175. _num++;
  176. }
  177. } else if (i == _this.Title.length - 1) {
  178. _this.ctx.fillText(_this.Title.substring(_strLastIndex, i + 1), C_P, _strHeight);
  179. _strlineW = 0;
  180. }
  181. }
  182. //设置文本 end
  183. //设置价格
  184. _strlineW = C_P;
  185. _strHeight += uni.upx2px(60);
  186. if (_num == 1) {
  187. _strHeight += 20; //单行标题时占位符
  188. }
  189. if (_this.PriceTxt != '') {
  190. //判断是否有销售价格
  191. _this.ctx.setFillStyle(_this.PriceColor);
  192. _this.ctx.setFontSize(uni.upx2px(38));
  193. _this.ctx.fillText('券后价 ¥' + _this.PriceTxt, _strlineW, _strHeight); //商品价格
  194. _strlineW += _this.ctx.measureText('券后价 ¥' + _this.PriceTxt).width + uni.upx2px(10);
  195. }
  196. // #ifdef H5
  197. if (_this.PriceTxt != '' && _this.OriginalTxt != '') {
  198. //判断是否有销售价格且原价
  199. _this.ctx.setFillStyle(_this.OriginalColor);
  200. _this.ctx.setFontSize(uni.upx2px(24));
  201. _this.ctx.fillText(_this.OriginalTxt, _strlineW, _strHeight); //商品原价
  202. }
  203. // #endif
  204. _this.ctx.strokeStyle = _this.OriginalColor;
  205. _this.ctx.moveTo(_strlineW, _strHeight - uni.upx2px(10)); //起点
  206. _this.ctx.lineTo(_strlineW + _this.ctx.measureText(_this.OriginalTxt).width, _strHeight - uni.upx2px(10)); //终点
  207. _this.ctx.stroke();
  208. //设置价格 end
  209. //添加二维码
  210. _strHeight += uni.upx2px(20);
  211. _this.ctx.drawImage(_QrCode.path, r[0] - q[0] + C_P, _strHeight, q[0], q[1]);
  212. //添加二维码 end
  213. //添加推荐人与描述
  214. _this.ctx.setFillStyle(_this.TitleColor);
  215. _this.ctx.setFontSize(uni.upx2px(30));
  216. _this.ctx.fillText(_this.Referrer, C_P, _strHeight + q[1] / 2);
  217. _this.ctx.setFillStyle(_this.OriginalColor);
  218. _this.ctx.setFontSize(uni.upx2px(24));
  219. _this.ctx.fillText(_this.ViewDetails, C_P, _strHeight + q[1] / 2 + 20);
  220. //添加推荐人与描述 end
  221. //延迟后渲染至canvas上
  222. setTimeout(function() {
  223. _this.ctx.draw(true, ret => {
  224. _this.getNewImage();
  225. });
  226. }, 600);
  227. },
  228. async getImageInfo({
  229. imgSrc
  230. }) {
  231. return new Promise((resolve, errs) => {
  232. uni.getImageInfo({
  233. src: imgSrc,
  234. success: function(image) {
  235. resolve(image);
  236. },
  237. fail(err) {
  238. errs(err);
  239. _this.$queue.showToast('海报生成失败');
  240. uni.hideLoading()
  241. }
  242. });
  243. });
  244. },
  245. getNewImage() {
  246. uni.canvasToTempFilePath({
  247. canvasId: _this.CanvasID,
  248. quality: 1,
  249. complete: res => {
  250. _this.tempFilePath = res.tempFilePath;
  251. _this.$emit('success', res);
  252. _this.loading = false;
  253. _this.$queue.showToast('长按图片保存海报');
  254. uni.hideLoading()
  255. }
  256. },
  257. this
  258. );
  259. }
  260. },
  261. mounted() {
  262. _this = this;
  263. this.OnCanvas();
  264. }
  265. };
  266. </script>
  267. <style></style>