echarts-uniapp.vue 6.11 KB
<template>
	<!-- #ifdef MP-WEIXIN || MP-TOUTIAO -->
	<canvas type="2d" class="echarts" :canvas-id="canvasId" :id="canvasId" @touchstart="touchStart"
		@touchmove="touchMove" @touchend="touchEnd" />
	<!-- #endif -->
	<!-- #ifndef MP-WEIXIN || MP-TOUTIAO -->
	<canvas class="echarts" :canvas-id="canvasId" :id="canvasId" @touchstart="touchStart" @touchmove="touchMove"
		@touchend="touchEnd" />
	<!-- #endif -->

</template>
<script>
	
	/**
	 * echartsForUniApp echart兼容uni-app
	 * @description echart兼容uni-app
	 * @property {Object} option 图表数据
	 * @property {String} canvasId 画布id
	 * @example <echarts ref="echarts" :option="option" canvasId="echarts"></echarts>
	 */
	import WxCanvas from './wx-canvas.js';
	import * as echarts from './echarts.min.js';	
	
	var chartList = {}
	export default {
		props: {
			canvasId: {
				type: String,
				default: 'echarts'
			},
			option: {
				type: Object,
				default: () => {
					return {}
				}
			},
		},
		watch: {
			option(newValue, oldValue) {
				if(newValue.series){
					this.initChart(newValue)
				}
			}
		},
		data() {
			return {
				ctx:null
			}
		},
		
		mounted() {
			// Disable prograssive because drawImage doesn't support DOM as parameter
			// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
			echarts.registerPreprocessor(option => {
				if (option && option.series) {
					if (option.series.length > 0) {
						option.series.forEach(series => {
							series.progressive = 0;
						});
					} else if (typeof option.series === 'object') {
						option.series.progressive = 0;
					}
				}
			});

		},

		methods: {
			getCanvasAttr2d() {
				return new Promise((resolve, reject) => {
					const query = uni.createSelectorQuery().in(this)
					query
						.select('#' + this.canvasId)
						.fields({
							node: true,
							size: true
						})
						.exec(res => {
							const canvasNode = res[0].node
							this.canvasNode = canvasNode
							const canvasDpr = uni.getSystemInfoSync().pixelRatio
							const canvasWidth = res[0].width
							const canvasHeight = res[0].height
							this.ctx = canvasNode.getContext('2d')
			
							const canvas = new WxCanvas(this.ctx, this.canvasId, true, canvasNode)
							echarts.setCanvasCreator(() => {
								return canvas
							})
							resolve({
								canvas,
								canvasWidth,
								canvasHeight,
								canvasDpr
							})
						})
				});
			},
			getCanvasAttr() {
				return new Promise((resolve, reject) => {
					this.ctx = uni.createCanvasContext(this.canvasId, this);
					var canvas = new WxCanvas(this.ctx, this.canvasId, false);
					echarts.setCanvasCreator(() => {
						return canvas;
					});
					const canvasDpr = 1
					var query = uni.createSelectorQuery()
						// #ifndef MP-ALIPAY
						.in(this)
					// #endif
					query.select('#' + this.canvasId).boundingClientRect(res => {
						const canvasWidth = res.width
						const canvasHeight = res.height
						resolve({
							canvas,
							canvasWidth,
							canvasHeight,
							canvasDpr
						})
					}).exec();
				});
			},
			// #ifdef H5
			//H5绘制图表
			initChart(option) {
				this.ctx = uni.createCanvasContext(this.canvasId, this);
				chartList[this.canvasId] = echarts.init(document.getElementById(this.canvasId));
				chartList[this.canvasId].setOption(option?option:this.option);
			},
			//H5生成图片
			canvasToTempFilePath(opt) {
				const base64 = chartList[this.canvasId].getDataURL()
				opt.success && opt.success({tempFilePath:base64})
			},
			// #endif
			// #ifndef H5
			//绘制图表
			async initChart(option) {
				// #ifdef MP-WEIXIN || MP-TOUTIAO 
				const canvasAttr = await this.getCanvasAttr2d();
				// #endif
				// #ifndef MP-WEIXIN || MP-TOUTIAO
				const canvasAttr = await this.getCanvasAttr();
				// #endif
				const {
					canvas,
					canvasWidth,
					canvasHeight,
					canvasDpr
				} = canvasAttr
				chartList[this.canvasId] = echarts.init(canvas, null, {
					width: canvasWidth,
					height: canvasHeight,
					devicePixelRatio: canvasDpr // new
				});
				canvas.setChart(chartList[this.canvasId]);
				chartList[this.canvasId].setOption(option?option:this.option);
			},
			//生成图片
			canvasToTempFilePath(opt) {
				// #ifdef MP-WEIXIN || MP-TOUTIAO
				var query = uni.createSelectorQuery()
				// #ifndef MP-ALIPAY
					.in(this)
				// #endif
				query.select('#' + this.canvasId).fields({ node: true, size: true }).exec(res => {
					const canvasNode = res[0].node
					opt.canvas = canvasNode
					uni.canvasToTempFilePath(opt, this)
				})
				// #endif
				// #ifndef MP-WEIXIN || MP-TOUTIAO
				if (!opt.canvasId) {
					opt.canvasId = this.canvasId;
				}
				this.ctx.draw(true, () => {
					uni.canvasToTempFilePath(opt, this);
				});
				// #endif
			},
			// #endif
			
			touchStart(e) {
				if (chartList[this.canvasId] && e.touches.length > 0) {
					var touch = e.touches[0];
					var handler = chartList[this.canvasId].getZr().handler;
					handler.dispatch('mousedown', {
						zrX: touch.x,
						zrY: touch.y
					});
					handler.dispatch('mousemove', {
						zrX: touch.x,
						zrY: touch.y
					});
					handler.processGesture(wrapTouch(e), 'start');
				}
			},
			touchMove(e) {
				if (chartList[this.canvasId] && e.touches.length > 0) {
					var touch = e.touches[0];
					var handler = chartList[this.canvasId].getZr().handler;
					handler.dispatch('mousemove', {
						zrX: touch.x,
						zrY: touch.y
					});
					handler.processGesture(wrapTouch(e), 'change');
				}
			},

			touchEnd(e) {
				if (chartList[this.canvasId]) {
					const touch = e.changedTouches ? e.changedTouches[0] : {};
					var handler = chartList[this.canvasId].getZr().handler;
					handler.dispatch('mouseup', {
						zrX: touch.x,
						zrY: touch.y
					});
					handler.dispatch('click', {
						zrX: touch.x,
						zrY: touch.y
					});
					handler.processGesture(wrapTouch(e), 'end');
				}
			}
		}
	}

	function wrapTouch(event) {
		for (let i = 0; i < event.touches.length; ++i) {
			const touch = event.touches[i];
			touch.offsetX = touch.x;
			touch.offsetY = touch.y;
		}
		return event;
	}
</script>
<style lang="scss" scoped>
	.echarts {
		width: 100%;
		height: 100%;
	}
</style>