works-poster.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <template>
  2. <view >
  3. <view class="postcontent" v-if="isShow" @click.stop="isShow=false">
  4. <canvas id='canvas' @click.stop="" :style="{ width: canvasW + 'px', height: canvasH + 'px' }" canvas-id="my-canvas"></canvas>
  5. <!-- <view class="text-center text-white">长按保存图片</view> -->
  6. </view>
  7. <u-popup v-model="imgShow" mode="center" width="640" height="990" >
  8. <image class="calloutImg" :src="imgUrl" @click="preViewImg(imgUrl)"></image>
  9. <view class="text-center text-lg text-white" style="line-height: 50upx;background-color: #666666;">点击海报,然后长按图片保存</view>
  10. </u-popup>
  11. </view>
  12. </template>
  13. <script>
  14. import { pathToBase64, base64ToPath } from '@/common/utils/index.js'
  15. export default{
  16. props:{
  17. works: {
  18. type: Object,
  19. default: {}
  20. }
  21. },
  22. data(){
  23. return {
  24. canvasW: 0,
  25. canvasH: 0,
  26. ctx: null,
  27. isShow: false,
  28. imgUrl:'',
  29. imgShow: false,
  30. }
  31. },
  32. methods:{
  33. //显示
  34. showCanvas(){
  35. this.isShow = true;
  36. this.imgShow = true;
  37. this.__init()
  38. },
  39. //初始化画布
  40. async __init(){
  41. uni.showLoading({
  42. title: '加载中...',
  43. mask: true
  44. })
  45. this.ctx = uni.createCanvasContext('my-canvas', this)
  46. // this.canvasW = uni.upx2px(550);
  47. this.canvasW = uni.getSystemInfoSync().windowWidth-uni.upx2px(120)
  48. this.canvasH = this.canvasW*2 - uni.upx2px(330)
  49. //设置画布背景透明
  50. this.ctx.setFillStyle('rgba(255, 255, 255, 0)')
  51. //设置画布大小
  52. this.ctx.fillRect(0,0,this.canvasW,this.canvasH)
  53. //绘制圆角背景
  54. this.drawRoundRect(this.ctx, 0, 0, this.canvasW, this.canvasH,uni.upx2px(18),'#FFFFFF')
  55. //获取标题图片
  56. let headerImg = await this.getImageInfo(this.works.image)
  57. let hW = uni.upx2px(560);
  58. let hH = uni.upx2px(360);
  59. //绘制标题
  60. //绘制标题
  61. // this.ctx.setFontSize(12); //设置标题字体大小
  62. // this.ctx.setFillStyle('#333'); //设置标题文本颜色
  63. // let titleWidth = this.ctx.measureText(this.works.title).width
  64. // if(titleWidth > hW){
  65. // this.ctx.fillText(this.works.title.slice(0,25),((this.canvasW-hW) / 2),((this.canvasW-hW) / 2))
  66. // this.ctx.fillText(this.works.title.slice(25,50),((this.canvasW-hW) / 2),((this.canvasW-hW) / 2) + uni.upx2px(46))
  67. // } else{
  68. // this.ctx.fillText(this.works.title,((this.canvasW-hW) / 2),((this.canvasW-hW) / 2))
  69. // }
  70. //绘制标题图
  71. this.drawRoundImg(this.ctx,headerImg.path,((this.canvasW-hW) / 2-uni.upx2px(10)),((this.canvasW-hW) / 2) - uni.upx2px(10),hW + uni.upx2px(20),hW + uni.upx2px(20),uni.upx2px(6))
  72. //绘制名称
  73. this.ctx.setFontSize(24);
  74. this.ctx.setFillStyle('#000000');
  75. this.ctx.fillText(this.works.title ,((this.canvasW-hW) / 2) + uni.upx2px(2),(((this.canvasW-hW) / 2) + hH + uni.upx2px(280)))
  76. //绘制副标题
  77. this.ctx.setFontSize(12);
  78. this.ctx.setFillStyle('#c7c7c7');
  79. this.ctx.fillText("赶紧为你的爱豆打榜吧" ,((this.canvasW-hW) / 2) + uni.upx2px(2),(((this.canvasW-hW) / 2) + hH + uni.upx2px(325)))
  80. //绘制热力值
  81. this.ctx.setFontSize(24);
  82. this.ctx.setFillStyle('#000000');
  83. this.ctx.fillText(this.works.hotValue ,((this.canvasW-hW) / 2) + uni.upx2px(2),(((this.canvasW-hW) / 2) + hH + uni.upx2px(390)))
  84. //绘制排名
  85. this.ctx.setFontSize(12);
  86. this.ctx.setFillStyle('#000000');
  87. this.ctx.fillText("热力榜第 "+this.works.rank ,((this.canvasW-hW) / 2) + uni.upx2px(2),(((this.canvasW-hW) / 2) + hH + uni.upx2px(430)))
  88. //提示文案
  89. this.ctx.setFontSize(12);
  90. this.ctx.setFillStyle('#858585');
  91. this.ctx.fillText('来自 '+ this.works.name +' 的分享',(((this.canvasW-hW) / 2)),(((this.canvasW-hW) / 2) + hH + uni.upx2px(500)))
  92. //底部广告
  93. // let BottomAdImg = await this.getImageInfo(this.abImg)
  94. // this.ctx.drawImage(BottomAdImg.path,(((this.canvasW-hW) / 2)),(((this.canvasW-hW) / 2) + hH + uni.upx2px(310)),uni.upx2px(350),uni.upx2px(110))
  95. //小程序码
  96. let qrcodeImg = await this.getImageInfo(this.works.qrcode)
  97. this.ctx.drawImage(qrcodeImg.path,uni.upx2px(450),(((this.canvasW-hW) / 2) + hH + uni.upx2px(360)), uni.upx2px(150), uni.upx2px(150))
  98. //延迟渲染
  99. setTimeout(()=>{
  100. this.ctx.draw(true,()=>{
  101. uni.hideLoading()
  102. this.saveImage();
  103. })
  104. },500)
  105. },
  106. //绘制实心圆
  107. drawEmptyRound(ctx,x,y,radius){
  108. ctx.save()
  109. ctx.beginPath();
  110. ctx.arc(x, y, radius, 0, 2 * Math.PI,true);
  111. ctx.setFillStyle('rgba(0, 0, 0, .4)')
  112. ctx.fill();
  113. ctx.restore()
  114. ctx.closePath()
  115. },
  116. //绘制虚线
  117. drawDashLine(ctx,x1,y1,x2,y2,dashLength){
  118. ctx.setStrokeStyle("#cccccc")//设置线条的颜色
  119. ctx.setLineWidth(1)//设置线条宽度
  120. var dashLen = dashLength,
  121. xpos = x2 - x1, //得到横向的宽度;
  122. ypos = y2 - y1, //得到纵向的高度;
  123. numDashes = Math.floor(Math.sqrt(xpos * xpos + ypos * ypos) / dashLen);
  124. //利用正切获取斜边的长度除以虚线长度,得到要分为多少段;
  125. for(var i=0; i<numDashes; i++){
  126. if(i % 2 === 0){
  127. ctx.moveTo(x1 + (xpos/numDashes) * i, y1 + (ypos/numDashes) * i);
  128. //有了横向宽度和多少段,得出每一段是多长,起点 + 每段长度 * i = 要绘制的起点;
  129. }else{
  130. ctx.lineTo(x1 + (xpos/numDashes) * i, y1 + (ypos/numDashes) * i);
  131. }
  132. }
  133. ctx.stroke();
  134. },
  135. //带圆角图片
  136. drawRoundImg(ctx, img, x, y, width, height, radius){
  137. ctx.beginPath()
  138. ctx.save()
  139. // 左上角
  140. ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5)
  141. // 右上角
  142. ctx.arc(x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2)
  143. // 右下角
  144. ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5)
  145. // 左下角
  146. ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI)
  147. ctx.stroke()
  148. ctx.clip()
  149. ctx.drawImage(img, x, y, width, height);
  150. ctx.restore()
  151. ctx.closePath()
  152. },
  153. //圆角矩形
  154. drawRoundRect(ctx, x, y, width, height, radius, color){
  155. ctx.save();
  156. ctx.beginPath();
  157. ctx.setFillStyle(color);
  158. ctx.setStrokeStyle(color)
  159. ctx.setLineJoin('round'); //交点设置成圆角
  160. ctx.setLineWidth(radius);
  161. ctx.strokeRect(x + radius/2, y + radius/2, width - radius , height - radius );
  162. ctx.fillRect(x + radius, y + radius, width - radius * 2, height - radius * 2);
  163. ctx.stroke();
  164. ctx.closePath();
  165. },
  166. //获取图片
  167. getImageInfo(imgSrc){
  168. return new Promise((resolve, reject) => {
  169. uni.getImageInfo({
  170. src: imgSrc,
  171. success: (image) => {
  172. resolve(image);
  173. console.log('获取图片成功',image)
  174. },
  175. fail: (err) => {
  176. reject(err);
  177. console.log('获取图片失败',err)
  178. }
  179. });
  180. });
  181. },
  182. //保存图片到相册
  183. saveImage(){
  184. this.isShow = false;
  185. uni.canvasToTempFilePath({
  186. canvasId: 'my-canvas',
  187. quality: 1,
  188. success: (res) => {
  189. base64ToPath(res.tempFilePath).then(res => {
  190. this.imgUrl = res;
  191. });
  192. // this.imgUrl = res.tempFilePath.replace(/[\r\n]/g, "");
  193. }
  194. },this);
  195. },
  196. preViewImg(url) {
  197. uni.previewImage({
  198. urls: [url]
  199. });
  200. }
  201. }
  202. }
  203. </script>
  204. <style scoped lang="scss">
  205. .postcontent{
  206. position: fixed;
  207. top: 0;
  208. left: 0;
  209. right: 0;
  210. bottom: 0;
  211. background: rgba(0,0,0,.4);
  212. display: flex;
  213. flex-direction: column;
  214. justify-content: center;
  215. align-items: center;
  216. z-index: 99999999;
  217. .save-btn{
  218. margin-top: 35rpx;
  219. color: #FFFFFF;
  220. background: linear-gradient(to right, #FE726B , #FE956B);
  221. padding: 15rpx 40rpx;
  222. border-radius: 50rpx;
  223. }
  224. }
  225. .calloutImg {
  226. width: 640rpx;
  227. height: 940rpx;
  228. -webkit-touch-callout: default;
  229. }
  230. </style>