mosowe-canvas-image.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <!-- mosowe-canvas-image -->
  2. <template>
  3. <view class='mosowe-canvas-image'>
  4. <view class="slot-view" @click="createCanvas">
  5. <slot></slot>
  6. </view>
  7. <view class="canvas-wrap">
  8. <canvas class="canvas-wrap" canvas-id="canvas" :style="'width: '+ width +'; height: '+ height +';'"></canvas>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. import QR from './wxqrcode.js';
  14. export default {
  15. name: 'mosowe-canvas-image',
  16. components: {},
  17. props: {
  18. showPreview: { // 生成图像后是否预览
  19. type: Boolean,
  20. default: false
  21. },
  22. height: { // canvas高度
  23. type: [String, Number],
  24. default: 200
  25. },
  26. width: { // canvas宽度
  27. type: [String, Number],
  28. default: 200
  29. },
  30. lists: {
  31. type: Array,
  32. default: () => {
  33. return [// 图片,图片有先后,叠加画图
  34. {
  35. type: 'image',
  36. content: 'https://www.zhonglixunqing.cn/images/uniapp/1.jpg', // 图片url
  37. width: 200, // 图片绘制宽度
  38. height: 200, // 图片绘制高度
  39. x: 0, // 图片绘制X轴位置
  40. y: 0, // 图片绘制Y轴位置
  41. arc: false, // 圆形
  42. arcX: 0, // 圆的x坐标
  43. arcY: 0, // 圆的y坐标
  44. arcR: 0 // 圆的半径
  45. },
  46. {
  47. type: 'image',
  48. content: 'https://www.zhonglixunqing.cn/images/uniapp/2.jpg', // 图片url
  49. width: 100, // 图片绘制宽度
  50. height: 100, // 图片绘制高度
  51. x: 0, // 图片绘制X轴位置
  52. y: 0, // 图片绘制Y轴位置
  53. arc: false, // 圆形,如果需要圆形图片绘制,请放在列表最后,否则后续绘制将在此圆形内
  54. arcX: 0, // 圆的x坐标
  55. arcY: 0, // 圆的y坐标
  56. arcR: 0 // 圆的半径
  57. },
  58. {
  59. type: 'text',
  60. content: '你好', // 文字
  61. x: 10, // X轴
  62. y: 50, // Y轴
  63. color: '#ff0000', // 颜色
  64. size: 20, // 字号
  65. maxWidth: 100, // 最大宽度
  66. align: 'left', // 对齐方式
  67. },
  68. {
  69. type: 'image',
  70. content: 'https://www.zhonglixunqing.cn/images/uniapp/3.jpg', // 图片url
  71. width: 100, // 图片绘制宽度
  72. height: 100, // 图片绘制高度
  73. x: 150, // 图片绘制X轴位置
  74. y: 150, // 图片绘制Y轴位置
  75. arc: true, // 圆形,如果需要圆形图片绘制,请放在列表最后,否则后续绘制将在此圆形内
  76. arcX: 200, // 圆的x坐标
  77. arcY: 200, // 圆的y坐标
  78. arcR: 50 // 圆的半径
  79. },
  80. ];
  81. }
  82. }
  83. },
  84. data () {
  85. return {
  86. canvas: null,
  87. listsIndex: 0,
  88. listsLength: 0
  89. };
  90. },
  91. watch: {},
  92. // 组件实例化之前
  93. beforeCreate () {},
  94. // 组件创建完成
  95. created () {
  96. this.canvas = uni.createCanvasContext('canvas', this);
  97. },
  98. // 组件挂载之前
  99. beforeMount () {},
  100. // 组件挂载之后
  101. mounted () {},
  102. // 组件数据更新时
  103. beforeUpdate () {},
  104. // 组价更新
  105. updated () {},
  106. // 组件销毁前
  107. beforeDestroy () {},
  108. // 组件销毁后
  109. destroyed () {},
  110. // 页面方法
  111. methods: {
  112. // 开始绘制
  113. createCanvas () {
  114. this.listsIndex = 0;
  115. this.listsLength = this.lists.length - 1;
  116. // #ifndef H5
  117. uni.showLoading();
  118. // #endif
  119. // #ifdef H5
  120. uni.showLoading({
  121. mask: true
  122. });
  123. // #endif
  124. this.dataDrawCanvas();
  125. },
  126. // 数据绘制
  127. dataDrawCanvas () {
  128. let item = this.lists[this.listsIndex];
  129. if (item.type === 'image') { // 图片
  130. // #ifndef H5
  131. // 非H5
  132. this.downloadImageNotH5(item);
  133. // #endif
  134. // #ifdef H5
  135. // H5
  136. this.downloadImageH5(item);
  137. // #endif
  138. } else if (item.type === 'text') { // 文本
  139. this.drawText(item);
  140. } else if (item.type === 'rect') { // 矩形(线条)
  141. this.drawRect(item);
  142. } else if (item.type === 'arc') { // 圆形
  143. this.drawArc(item);
  144. } else if (item.type === 'qr') { // 二维码
  145. this.drawQR(item);
  146. }
  147. },
  148. // #ifndef H5
  149. // 图片下载本地并绘制,非H5
  150. downloadImageNotH5 (item) {
  151. uni.downloadFile({
  152. url: item.content,
  153. header: {
  154. 'Access-Control-Allow-Origin': '*',
  155. },
  156. success: (res) => {
  157. if (item.hasOwnProperty('arc') && item.arc) { // 绘制圆形
  158. this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
  159. this.canvas.clip();
  160. this.canvas.closePath();
  161. }
  162. this.canvas.drawImage(
  163. res.tempFilePath,
  164. item.x,
  165. item.y,
  166. item.hasOwnProperty('width') ? item.width : this.width,
  167. item.hasOwnProperty('height') ? item.height : this.height
  168. );
  169. this.checkDrawOver();
  170. },
  171. fail: (res) => {
  172. console.log(res);
  173. uni.hideLoading();
  174. }
  175. });
  176. },
  177. // #endif
  178. // #ifdef H5
  179. // 图片下载本地并绘制,H5
  180. downloadImageH5 (item) {
  181. let image = new Image();
  182. image.setAttribute('crossOrigin', 'anonymous');
  183. image.src = item.content;
  184. image.onload = () => {
  185. if (item.arc) { // 绘制圆形
  186. this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
  187. this.canvas.clip();
  188. this.canvas.closePath();
  189. }
  190. this.canvas.drawImage(
  191. item.content,
  192. item.x,
  193. item.y,
  194. item.hasOwnProperty('width') ? item.width : this.width,
  195. item.hasOwnProperty('height') ? item.height : this.height
  196. );
  197. this.checkDrawOver();
  198. };
  199. },
  200. // #endif
  201. // 文本绘制
  202. drawText (item) {
  203. this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
  204. this.canvas.setFontSize(item.hasOwnProperty('size')? item.size : 20);
  205. this.canvas.setTextAlign(item.hasOwnProperty('align') ? item.align: 'left');
  206. if (item.maxWidth) {
  207. this.canvas.fillText(item.content, item.x, item.y, item.maxWidth);
  208. } else {
  209. this.canvas.fillText(item.content, item.x, item.y);
  210. }
  211. this.checkDrawOver();
  212. },
  213. // 矩形(线条)绘制
  214. drawRect (item) {
  215. this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
  216. this.canvas.fillRect(item.x, item.y, item.width, item.height);
  217. this.checkDrawOver();
  218. },
  219. // 圆形绘制
  220. drawArc (item) {
  221. this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
  222. this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
  223. this.canvas.fill();
  224. this.canvas.closePath();
  225. this.checkDrawOver();
  226. },
  227. // 二维码绘制
  228. drawQR (item) {
  229. item['qr'] = QR.createQrCodeImg(item.content, {
  230. size: parseInt(300)
  231. });
  232. this.canvas.drawImage(
  233. item.qr,
  234. item.x,
  235. item.y,
  236. item.hasOwnProperty('width') ? item.width : this.width,
  237. item.hasOwnProperty('height') ? item.height : this.height
  238. );
  239. this.checkDrawOver();
  240. },
  241. // 判断是否绘制完
  242. checkDrawOver () {
  243. if (this.listsIndex < this.listsLength) { // lists未画完
  244. this.listsIndex++;
  245. this.dataDrawCanvas();
  246. } else {
  247. this.canvasImage();
  248. }
  249. },
  250. // 绘制到画布并生成图片
  251. canvasImage () {
  252. this.canvas.draw(false, setTimeout(() => {
  253. setTimeout(() => {
  254. // #ifndef MP-ALIPAY
  255. uni.canvasToTempFilePath({
  256. x: 0,
  257. y: 0,
  258. width: Number(this.width),
  259. height: Number(this.height),
  260. fileType: 'jpg',
  261. canvasId: 'canvas',
  262. success: (res) => {
  263. this.$emit('canvasImage', res.tempFilePath);
  264. if (this.showPreview) {
  265. this.showPreviewFn(res.tempFilePath);
  266. }
  267. },
  268. fail: (res) => {
  269. console.log(res);
  270. },
  271. complete: () => {
  272. uni.hideLoading();
  273. }
  274. }, this);
  275. // #endif
  276. // #ifdef MP-ALIPAY
  277. // 支付宝的
  278. // #endif
  279. }, 500);
  280. }));
  281. },
  282. // 预览图
  283. showPreviewFn (img) {
  284. uni.previewImage({
  285. current: 0,
  286. urls: [img]
  287. });
  288. },
  289. }
  290. };
  291. </script>
  292. <style lang='scss' scoped>
  293. .mosowe-canvas-image{
  294. overflow: hidden;
  295. .canvas-wrap {
  296. overflow: hidden;
  297. height: 0;
  298. width: 0;
  299. }
  300. }
  301. </style>