| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 | 
							- <template>
 
- 	<view class="lime-painter" ref="limepainter">
 
- 		<view v-if="canvasId && size" :style="styles">
 
- 			<!-- #ifndef APP-NVUE -->
 
- 			<canvas class="lime-painter__canvas" v-if="use2dCanvas" :id="canvasId" type="2d" :style="size"></canvas>
 
- 			<canvas class="lime-painter__canvas" v-else :id="canvasId" :canvas-id="canvasId" :style="size"
 
- 				:width="boardWidth * dpr" :height="boardHeight * dpr" :hidpi="hidpi"></canvas>
 
- 			<!-- #endif -->
 
- 			<!-- #ifdef APP-NVUE -->
 
- 			<web-view :style="size" ref="webview"
 
- 				src="/uni_modules/lime-painter/hybrid/html/index.html"
 
- 				class="lime-painter__canvas" @pagefinish="onPageFinish" @error="onError" @onPostMessage="onMessage">
 
- 			</web-view>
 
- 			<!-- #endif -->
 
- 		</view>
 
- 		<slot />
 
- 	</view>
 
- </template>
 
- <script>
 
- 	import { parent } from '../common/relation'
 
- 	import props from './props'
 
- 	import {toPx, base64ToPath, pathToBase64, isBase64, sleep, getImageInfo }from './utils';
 
- 	//  #ifndef APP-NVUE
 
- 	import { canIUseCanvas2d, isPC} from './utils';
 
- 	import Painter from './painter';
 
- 	// import Painter from '@painter'
 
- 	const nvue = {}
 
- 	//  #endif
 
- 	//  #ifdef APP-NVUE
 
- 	import nvue from './nvue'
 
- 	//  #endif
 
- 	export default {
 
- 		name: 'lime-painter',
 
- 		mixins: [props, parent('painter'), nvue],
 
- 		data() {
 
- 			return {
 
- 				use2dCanvas: false,
 
- 				canvasHeight: 150,
 
- 				canvasWidth: null,
 
- 				parentWidth: 0,
 
- 				inited: false,
 
- 				progress: 0,
 
- 				firstRender: 0,
 
- 				done: false,
 
- 				tasks: []
 
- 			};
 
- 		},
 
- 		computed: {
 
- 			styles() {
 
- 				return `${this.size}${this.customStyle||''};` + (this.hidden && 'position: fixed; left: 1500rpx;')
 
- 			},
 
- 			canvasId() {
 
- 				return `l-painter${this._ && this._.uid || this._uid}`
 
- 			},
 
- 			size() {
 
- 				if (this.boardWidth && this.boardHeight) {
 
- 					return `width:${this.boardWidth}px; height: ${this.boardHeight}px;`;
 
- 				}
 
- 			},
 
- 			dpr() {
 
- 				return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
 
- 			},
 
- 			boardWidth() {
 
- 				const {width = 0} = (this.elements && this.elements.css) || this.elements || this
 
- 				const w = toPx(width||this.width)
 
- 				return w || Math.max(w, toPx(this.canvasWidth));
 
- 			},
 
- 			boardHeight() {
 
- 				const {height = 0} = (this.elements && this.elements.css) || this.elements || this
 
- 				const h = toPx(height||this.height)
 
- 				return h || Math.max(h, toPx(this.canvasHeight));
 
- 			},
 
- 			hasBoard() {
 
- 				return this.board && Object.keys(this.board).length
 
- 			},
 
- 			elements() {
 
- 				return this.hasBoard ? this.board : JSON.parse(JSON.stringify(this.el))
 
- 			}
 
- 		},
 
- 		created() {
 
- 			this.use2dCanvas = this.type === '2d' && canIUseCanvas2d() && !isPC
 
- 		},
 
- 		async mounted() {
 
- 			await sleep(30)
 
- 			await this.getParentWeith()
 
- 			this.$nextTick(() => {
 
- 				setTimeout(() => {
 
- 					this.$watch('elements', this.watchRender, {
 
- 						deep: true,
 
- 						immediate: true
 
- 					});
 
- 				}, 30)
 
- 			})
 
- 		},
 
- 		// #ifdef VUE3
 
- 		unmounted() {
 
- 			this.done = false
 
- 			this.inited = false
 
- 			this.firstRender = 0
 
- 			this.progress = 0
 
- 			this.painter = null
 
- 			clearTimeout(this.rendertimer)
 
- 		},
 
- 		// #endif
 
- 		// #ifdef VUE2
 
- 		destroyed() {
 
- 			this.done = false
 
- 			this.inited = false
 
- 			this.firstRender = 0
 
- 			this.progress = 0
 
- 			this.painter = null
 
- 			clearTimeout(this.rendertimer)
 
- 		},
 
- 		// #endif
 
- 		methods: {
 
- 			async watchRender(val, old) {
 
- 				if (!val || !val.views || (!this.firstRender ? !val.views.length : !this.firstRender) || !Object.keys(val).length || JSON.stringify(val) == JSON.stringify(old)) return;
 
- 				this.firstRender = 1
 
- 				this.progress = 0
 
- 				this.done = false
 
- 				clearTimeout(this.rendertimer)
 
- 				this.rendertimer = setTimeout(() => {
 
- 					this.render(val);
 
- 				}, this.beforeDelay)
 
- 			},
 
- 			async setFilePath(path, param) {
 
- 				let filePath = path
 
- 				const {pathType = this.pathType} =  param || this
 
- 				if (pathType == 'base64' && !isBase64(path)) {
 
- 					filePath = await pathToBase64(path)
 
- 				} else if (pathType == 'url' && isBase64(path)) {
 
- 					filePath = await base64ToPath(path)
 
- 				}
 
- 				if (param && param.isEmit) {
 
- 					this.$emit('success', filePath);
 
- 				}
 
- 				return filePath
 
- 			},
 
- 			async getSize(args) {
 
- 				const {width} = args.css || args
 
- 				const {height} = args.css || args
 
- 				if (!this.size) {
 
- 					if (width || height) {
 
- 						this.canvasWidth = width || this.canvasWidth
 
- 						this.canvasHeight = height || this.canvasHeight
 
- 						await sleep(30);
 
- 					} else {
 
- 						await this.getParentWeith()
 
- 					}
 
- 				}
 
- 			},
 
- 			canvasToTempFilePathSync(args) {
 
- 				// this.stopWatch && this.stopWatch()
 
- 				// this.stopWatch = this.$watch('done', (v) => {
 
- 				// 	if (v) {
 
- 				// 		this.canvasToTempFilePath(args)
 
- 				// 		this.stopWatch && this.stopWatch()
 
- 				// 	}
 
- 				// }, {
 
- 				// 	immediate: true
 
- 				// })
 
- 				this.tasks.push(args)
 
- 				if(this.done){
 
- 					this.runTask()
 
- 				}
 
- 			},
 
- 			runTask(){
 
- 				while(this.tasks.length){
 
- 					const task = this.tasks.shift()	
 
- 					 this.canvasToTempFilePath(task)
 
- 				}
 
- 			},
 
- 			// #ifndef APP-NVUE
 
- 			getParentWeith() {
 
- 				return new Promise(resolve => {
 
- 					uni.createSelectorQuery()
 
- 						.in(this)
 
- 						.select(`.lime-painter`)
 
- 						.boundingClientRect()
 
- 						.exec(res => {
 
- 							const {width, height} = res[0]||{}
 
- 							this.parentWidth = Math.ceil(width||0)
 
- 							this.canvasWidth = this.parentWidth || 300
 
- 							this.canvasHeight = height || this.canvasHeight||150
 
- 							resolve(res[0])
 
- 						})
 
- 				})
 
- 			},
 
- 			async render(args = {}) {
 
- 				if(!Object.keys(args).length) {
 
- 					return console.error('空对象')
 
- 				}
 
- 				this.progress = 0
 
- 				this.done = false
 
- 				// #ifdef APP-NVUE
 
- 				this.tempFilePath.length = 0
 
- 				// #endif
 
- 				await this.getSize(args)
 
- 				const ctx = await this.getContext();
 
- 				
 
- 				let {
 
- 					use2dCanvas,
 
- 					boardWidth,
 
- 					boardHeight,
 
- 					canvas,
 
- 					afterDelay
 
- 				} = this;
 
- 				if (use2dCanvas && !canvas) {
 
- 					return Promise.reject(new Error('canvas 没创建'));
 
- 				}
 
- 				this.boundary = {
 
- 					top: 0,
 
- 					left: 0,
 
- 					width: boardWidth,
 
- 					height: boardHeight
 
- 				};
 
- 				this.painter = null
 
- 				if (!this.painter) {
 
- 					const {width} = args.css || args
 
- 					const {height} = args.css || args
 
- 					if(!width && this.parentWidth) {
 
- 						Object.assign(args, {width: this.parentWidth})
 
- 					}
 
- 					const param = {
 
- 						context: ctx,
 
- 						canvas,
 
- 						width: boardWidth,
 
- 						height: boardHeight,
 
- 						pixelRatio: this.dpr,
 
- 						useCORS: this.useCORS,
 
- 						createImage: getImageInfo.bind(this),
 
- 						performance: this.performance,
 
- 						listen: {
 
- 							onProgress: (v) => {
 
- 								this.progress = v
 
- 								this.$emit('progress', v)
 
- 							},
 
- 							onEffectFail: (err) => {
 
- 								this.$emit('faill', err)
 
- 							}
 
- 						}
 
- 					}
 
- 					this.painter = new Painter(param)
 
- 				} 
 
- 				try{
 
- 					// vue3 赋值给data会引起图片无法绘制
 
- 					const { width, height } = await this.painter.source(JSON.parse(JSON.stringify(args)))
 
- 					this.boundary.height = this.canvasHeight = height
 
- 					this.boundary.width = this.canvasWidth = width
 
- 					await sleep(this.sleep);
 
- 					await this.painter.render()
 
- 					await new Promise(resolve => this.$nextTick(resolve));
 
- 					if (!use2dCanvas) {
 
- 						await this.canvasDraw();
 
- 					}
 
- 					if (afterDelay && use2dCanvas) {
 
- 						await sleep(afterDelay);
 
- 					}
 
- 					this.$emit('done');
 
- 					this.done = true
 
- 					if (this.isCanvasToTempFilePath) {
 
- 						this.canvasToTempFilePath()
 
- 							.then(res => {
 
- 								this.$emit('success', res.tempFilePath)
 
- 							})
 
- 							.catch(err => {
 
- 								this.$emit('fail', new Error(JSON.stringify(err)));
 
- 							});
 
- 					}
 
- 					this.runTask()
 
- 					return Promise.resolve({
 
- 						ctx,
 
- 						draw: this.painter,
 
- 						node: this.node
 
- 					});
 
- 				}catch(e){
 
- 					//TODO handle the exception
 
- 				}
 
- 				
 
- 			},
 
- 			canvasDraw(flag = false) {
 
- 				return new Promise((resolve, reject) => this.ctx.draw(flag, () => setTimeout(() => resolve(), this
 
- 					.afterDelay)));
 
- 			},
 
- 			async getContext() {
 
- 				if (!this.canvasWidth) {
 
- 					this.$emit('fail', 'painter no size')
 
- 					console.error('[lime-painter]: 给画板或父级设置尺寸')
 
- 					return Promise.reject();
 
- 				}
 
- 				if (this.ctx && this.inited) {
 
- 					return Promise.resolve(this.ctx);
 
- 				}
 
- 				const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
 
- 				const _getContext = () => {
 
- 					return new Promise(resolve => {
 
- 						uni.createSelectorQuery()
 
- 							.in(this)
 
- 							.select(`#${this.canvasId}`)
 
- 							.boundingClientRect()
 
- 							.exec(res => {
 
- 								if (res) {
 
- 									const ctx = uni.createCanvasContext(this.canvasId, this);
 
- 									if (!this.inited) {
 
- 										this.inited = true;
 
- 										this.use2dCanvas = false;
 
- 										this.canvas = res;
 
- 									}
 
- 									
 
- 									// 钉钉小程序框架不支持 measureText 方法,用此方法 mock
 
- 									if (!ctx.measureText) {
 
- 										function strLen(str) {
 
- 											let len = 0;
 
- 											for (let i = 0; i < str.length; i++) {
 
- 												if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
 
- 													len++;
 
- 												} else {
 
- 													len += 2;
 
- 												}
 
- 											}
 
- 											return len;
 
- 										}
 
- 										ctx.measureText = text => {
 
- 											let fontSize = ctx.state && ctx.state.fontSize || 12;
 
- 											const font = ctx.__font
 
- 											if (font && fontSize == 12) {
 
- 												fontSize = parseInt(font.split(' ')[3], 10);
 
- 											}
 
- 											fontSize /= 2;
 
- 											return {
 
- 												width: strLen(text) * fontSize
 
- 											};
 
- 										}
 
- 									}
 
- 									
 
- 									// #ifdef MP-ALIPAY
 
- 									ctx.scale(dpr, dpr);
 
- 									// #endif
 
- 									this.ctx = ctx
 
- 									resolve(this.ctx);
 
- 								} else {
 
- 									console.error('[lime-painter] no node')
 
- 								}
 
- 							});
 
- 					});
 
- 				};
 
- 				if (!use2dCanvas) {
 
- 					return _getContext();
 
- 				}
 
- 				return new Promise(resolve => {
 
- 					uni.createSelectorQuery()
 
- 						.in(this)
 
- 						.select(`#${this.canvasId}`)
 
- 						.node()
 
- 						.exec(res => {
 
- 							let {node: canvas} = res && res[0]||{};
 
- 							if(canvas) {
 
- 								const ctx = canvas.getContext(type);
 
- 								if (!this.inited) {
 
- 									this.inited = true;
 
- 									this.use2dCanvas = true;
 
- 									this.canvas = canvas;
 
- 								}
 
- 								this.ctx = ctx
 
- 								resolve(this.ctx);
 
- 							} else {
 
- 								console.error('[lime-painter]: no size')
 
- 							}
 
- 						});
 
- 				});
 
- 			},
 
- 			canvasToTempFilePath(args = {}) {
 
- 				return new Promise(async (resolve, reject) => {
 
- 					const { use2dCanvas, canvasId, dpr, fileType, quality } = this;
 
- 					const success = async (res) => {
 
- 						try {
 
- 							const tempFilePath = await this.setFilePath(res.tempFilePath || res, args)
 
- 							const result = Object.assign(res, {tempFilePath})
 
- 							args.success && args.success(result)
 
- 							resolve(result)
 
- 						} catch (e) {
 
- 							this.$emit('fail', e)
 
- 						}
 
- 					}
 
- 					
 
- 					let { top: y = 0, left: x = 0, width, height } = this.boundary || this;
 
- 					// let destWidth = width * dpr;
 
- 					// let destHeight = height * dpr;
 
- 					// #ifdef MP-ALIPAY
 
- 					// width = destWidth;
 
- 					// height = destHeight;
 
- 					// #endif
 
- 					
 
- 					const copyArgs = Object.assign({
 
- 						// x,
 
- 						// y,
 
- 						// width,
 
- 						// height,
 
- 						// destWidth,
 
- 						// destHeight,
 
- 						canvasId,
 
- 						id: canvasId,
 
- 						fileType,
 
- 						quality,
 
- 					}, args, {success});
 
- 					// if(this.isPC || use2dCanvas) {
 
- 					// 	copyArgs.canvas = this.canvas
 
- 					// }
 
- 					if (use2dCanvas) {
 
- 						copyArgs.canvas = this.canvas
 
- 						try{
 
- 							// #ifndef MP-ALIPAY
 
- 							const oFilePath = this.canvas.toDataURL(`image/${args.fileType||fileType}`.replace(/pg/, 'peg'), args.quality||quality)
 
- 							if(/data:,/.test(oFilePath)) {
 
- 								uni.canvasToTempFilePath(copyArgs, this);
 
- 							} else {
 
- 								const tempFilePath = await this.setFilePath(oFilePath, args)
 
- 								args.success && args.success({tempFilePath})
 
- 								resolve({tempFilePath})
 
- 							}
 
- 							// #endif
 
- 							// #ifdef MP-ALIPAY
 
- 							this.canvas.toTempFilePath(copyArgs)
 
- 							// #endif
 
- 						}catch(e){
 
- 							args.fail && args.fail(e)
 
- 							reject(e)
 
- 						}
 
- 					} else {
 
- 						// #ifdef MP-ALIPAY
 
- 						if(this.ctx.toTempFilePath) {
 
- 							// 钉钉
 
- 							const ctx = uni.createCanvasContext(canvasId);
 
- 							ctx.toTempFilePath(copyArgs);
 
- 						} else {
 
- 							my.canvasToTempFilePath(copyArgs);
 
- 						}
 
- 						// #endif
 
- 						// #ifndef MP-ALIPAY
 
- 						uni.canvasToTempFilePath(copyArgs, this);
 
- 						// #endif
 
- 					}
 
- 				})
 
- 			}
 
- 			// #endif
 
- 		}
 
- 	};
 
- </script>
 
- <style>
 
- 	.lime-painter,
 
- 	.lime-painter__canvas {
 
- 		// #ifndef APP-NVUE
 
- 		width: 100%;
 
- 		// #endif
 
- 		// #ifdef APP-NVUE
 
- 		flex: 1;
 
- 		// #endif
 
- 	}
 
- </style>
 
 
  |