index.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <template>
  2. <canvas
  3. v-if="use2dCanvas"
  4. :id="canvasId"
  5. type="2d"
  6. :style="style"
  7. style='position: fixed;
  8. top: 100rpx;
  9. left: 750rpx;'
  10. >
  11. </canvas>
  12. <canvas
  13. v-else
  14. :canvas-id="canvasId"
  15. :style="style"
  16. :id="canvasId"
  17. :width="boardWidth * dpr"
  18. :height="boardHeight * dpr"
  19. style='position: fixed;
  20. top: 100rpx;
  21. left: 750rpx;'
  22. >
  23. </canvas>
  24. </template>
  25. <script>
  26. import { toPx, base64ToPath, compareVersion} from './utils';
  27. import { Draw } from './draw';
  28. import { Layout } from './layout';
  29. import { adaptor, expand } from './canvas';
  30. export default {
  31. // version: '1.5.9.7',
  32. name: 'l-painter',
  33. props: {
  34. board: Object,
  35. fileType: {
  36. type: String,
  37. default: 'png'
  38. },
  39. quality: {
  40. type: Number,
  41. default: 1
  42. },
  43. width: [Number, String],
  44. height: [Number, String],
  45. pixelRatio: Number,
  46. customStyle: String,
  47. isRenderImage: Boolean,
  48. isBase64ToPath: Boolean,
  49. isH5PathToBase64: Boolean,
  50. sleep: {
  51. type: Number,
  52. default: 1000/30
  53. },
  54. // #ifdef MP-WEIXIN
  55. type: {
  56. type: String,
  57. default: '2d',
  58. },
  59. // #endif
  60. },
  61. data() {
  62. return {
  63. // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU
  64. canvasId: `l-painter${this._uid}`,
  65. // #endif
  66. // #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
  67. canvasId: `l-painter`,
  68. // #endif
  69. // #ifdef MP-WEIXIN
  70. use2dCanvas: true,
  71. // #endif
  72. // #ifndef MP-WEIXIN
  73. use2dCanvas: false,
  74. // #endif
  75. draw: null,
  76. ctx: null,
  77. layout: new Layout()
  78. };
  79. },
  80. computed: {
  81. newboard() {
  82. console.log(1111,'board')
  83. return this.board && JSON.parse(JSON.stringify(this.board))
  84. },
  85. style() {
  86. console.log( `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`)
  87. return `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`;
  88. },
  89. dpr() {
  90. return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
  91. },
  92. boardWidth() {
  93. const { width = 200 } = this.board || {};
  94. return toPx(this.width || width);
  95. },
  96. boardHeight() {
  97. const { height = 200 } = this.board || {};
  98. var h=height.split('r')[0]
  99. let height1=uni.getStorageSync('dtheight')?Number(h)+Number(uni.getStorageSync('dtheight'))+'rpx':height
  100. return toPx(this.height || height1);
  101. }
  102. },
  103. watch: {
  104. style() {
  105. // #ifdef MP-WEIXIN
  106. if(this.use2dCanvas) {
  107. this.inited = false;
  108. }
  109. // #endif
  110. // #ifdef MP-ALIPAY
  111. this.inited = false;
  112. // #endif
  113. },
  114. },
  115. mounted() {
  116. // #ifdef MP-WEIXIN
  117. const {SDKVersion, version, platform} = wx.getSystemInfoSync()
  118. // ios wx7.0.20 createImage bug
  119. this.use2dCanvas = (this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0) && !(/ios/.test(platform) && /7.0.20/.test(version));
  120. // #endif
  121. this.$watch('board', async (val, old) => {
  122. if (JSON.stringify(val) === '{}' || !val) return;
  123. this.render();
  124. }, {
  125. deep: true,
  126. immediate: true,
  127. })
  128. },
  129. methods: {
  130. async render(args = {}, single = false) {
  131. const isArgsNoEmpty = JSON.stringify(args) != '{}'
  132. const ctx = await this.getContext()
  133. const { use2dCanvas, boardWidth, boardHeight, board, canvas, isBase64ToPath, isH5PathToBase64, sleep } = this;
  134. if (use2dCanvas && !canvas) {
  135. return Promise.reject(new Error('render: fail canvas has not been created'));
  136. }
  137. this.boundary = {
  138. top: 0,
  139. left: 0,
  140. width: boardWidth,
  141. height: boardHeight,
  142. }
  143. if(!single) {
  144. ctx.clearRect(0, 0, boardWidth, boardHeight);
  145. }
  146. if(!this.draw || isArgsNoEmpty) {
  147. this.draw = new Draw(ctx, canvas, use2dCanvas, isH5PathToBase64, sleep);
  148. }
  149. this.layout.init(ctx, this.boundary, this.isH5PathToBase64)
  150. if(isArgsNoEmpty || board && JSON.stringify(board) != '{}') {
  151. this.node = await this.layout.calcNode(isArgsNoEmpty ? args : board)
  152. }
  153. // console.log(this.node,'node')
  154. if(this.node) {
  155. await this.draw.drawNode(this.node);
  156. }
  157. await new Promise(resolve => this.$nextTick(resolve))
  158. if (!use2dCanvas && !single) {
  159. await this.canvasDraw(ctx);
  160. }
  161. this.$emit('done')
  162. if(this.isRenderImage && !single) {
  163. this.canvasToTempFilePath()
  164. .then(async res => {
  165. if(/^data:image\/(\w+);base64/.test(res.tempFilePath) && isBase64ToPath) {
  166. const img = await base64ToPath(res.tempFilePath)
  167. this.$emit('success', img)
  168. } else {
  169. this.$emit('success', res.tempFilePath)
  170. }
  171. })
  172. .catch(err => {
  173. this.$emit('fail', err)
  174. new Error(JSON.stringify(err))
  175. console.error(JSON.stringify(err))
  176. })
  177. }
  178. return Promise.resolve({ctx, draw: this.draw});
  179. },
  180. async custom(cb) {
  181. const {ctx, draw} = await this.render({}, true)
  182. ctx.save()
  183. await cb(ctx, draw)
  184. ctx.restore()
  185. return Promise.resolve(true);
  186. },
  187. async single(args = {}) {
  188. await this.render(args, true)
  189. return Promise.resolve(true);
  190. },
  191. canvasDraw(flag = false) {
  192. const {ctx} = this
  193. return new Promise(resolve => {
  194. ctx.draw(flag, () => {
  195. resolve(true);
  196. });
  197. });
  198. },
  199. async getContext() {
  200. if(this.ctx && this.inited) {
  201. return Promise.resolve(this.ctx)
  202. };
  203. const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
  204. await new Promise(resolve => this.$nextTick(resolve))
  205. const _getContext = () => {
  206. console.log(11111)
  207. return new Promise(resolve => {
  208. uni.createSelectorQuery()
  209. .in(this)
  210. .select('#' + this.canvasId)
  211. .boundingClientRect()
  212. .exec(res => {
  213. if(res) {
  214. const ctx = uni.createCanvasContext(this.canvasId, this);
  215. if (!this.inited) {
  216. this.inited = true;
  217. this.use2dCanvas = false;
  218. this.canvas = res
  219. }
  220. // #ifdef MP-ALIPAY
  221. ctx.scale(dpr, dpr);
  222. // #endif
  223. this.ctx = expand(ctx)
  224. }
  225. })
  226. })
  227. }
  228. // #ifndef MP-WEIXIN
  229. return _getContext()
  230. // #endif
  231. if(!use2dCanvas) {
  232. return _getContext()
  233. }
  234. return new Promise(resolve => {
  235. uni.createSelectorQuery()
  236. .in(this)
  237. .select('#l-painter')
  238. .node()
  239. .exec(res => {
  240. const canvas = res[0].node;
  241. if(!canvas) {
  242. this.use2dCanvas = false;
  243. return this.getContext()
  244. }
  245. const ctx = canvas.getContext(type);
  246. if (!this.inited) {
  247. this.inited = true;
  248. canvas.width = boardWidth * dpr;
  249. canvas.height = boardHeight * dpr;
  250. this.use2dCanvas = true;
  251. this.canvas = canvas
  252. ctx.scale(dpr, dpr);
  253. }
  254. this.ctx = adaptor(ctx)
  255. resolve(this.ctx);
  256. });
  257. });
  258. },
  259. canvasToTempFilePath(args = {}) {
  260. const {use2dCanvas, canvasId} = this
  261. return new Promise((resolve, reject) => {
  262. let { top: y = 0, left: x = 0, width, height } = this.boundary || this
  263. let destWidth = width * this.dpr
  264. let destHeight = height * this.dpr
  265. // #ifdef MP-ALIPAY
  266. width = width * this.dpr
  267. height = height * this.dpr
  268. // #endif
  269. const copyArgs = {
  270. x,
  271. y,
  272. width,
  273. height,
  274. destWidth,
  275. destHeight,
  276. canvasId,
  277. fileType: args.fileType || this.fileType,
  278. quality: /\d/.test(args.quality) ? args.quality : this.quality,
  279. success: resolve,
  280. fail: reject
  281. }
  282. if (use2dCanvas) {
  283. delete copyArgs.canvasId
  284. copyArgs.canvas = this.canvas
  285. }
  286. console.log(this)
  287. uni.canvasToTempFilePath(copyArgs, this)
  288. })
  289. }
  290. }
  291. };
  292. </script>
  293. <style></style>