|
|
@@ -1,506 +1,484 @@
|
|
|
<template>
|
|
|
- <view class="lime-echart" :style="customStyle" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
|
|
|
- <!-- #ifndef APP-NVUE -->
|
|
|
- <canvas
|
|
|
- class="lime-echart__canvas"
|
|
|
- v-if="use2dCanvas"
|
|
|
- type="2d"
|
|
|
- :id="canvasId"
|
|
|
- :style="canvasStyle"
|
|
|
+ <!-- #ifndef APP-NVUE || WEB -->
|
|
|
+ <view class="lime-echart"
|
|
|
+ :style="[lStyle]"
|
|
|
+ v-if="canvasId"
|
|
|
+ ref="chartContainer"
|
|
|
+ :aria-label="'图表'">
|
|
|
+ <canvas class="lime-echart__canvas"
|
|
|
+ type="2d"
|
|
|
+ :style="[styles]"
|
|
|
+ :id="canvasId"
|
|
|
:disable-scroll="isDisableScroll"
|
|
|
- @touchstart="touchStart"
|
|
|
- @touchmove="touchMove"
|
|
|
- @touchend="touchEnd"
|
|
|
- />
|
|
|
- <!-- <canvas
|
|
|
- class="lime-echart__canvas"
|
|
|
- v-else-if="isPC"
|
|
|
- :style="canvasStyle"
|
|
|
- :id="canvasId"
|
|
|
:canvas-id="canvasId"
|
|
|
- :disable-scroll="isDisableScroll"
|
|
|
- @mousedown="touchStart"
|
|
|
- @mousemove="touchMove"
|
|
|
- @mouseup="touchEnd"
|
|
|
- /> -->
|
|
|
- <canvas
|
|
|
- class="lime-echart__canvas"
|
|
|
- v-else
|
|
|
- :width="nodeWidth"
|
|
|
- :height="nodeHeight"
|
|
|
- :style="canvasStyle"
|
|
|
- :canvas-id="canvasId"
|
|
|
- :id="canvasId"
|
|
|
- :disable-scroll="isDisableScroll"
|
|
|
- @touchstart="touchStart"
|
|
|
- @touchmove="touchMove"
|
|
|
- @touchend="touchEnd"
|
|
|
- />
|
|
|
- <view class="lime-echart__mask"
|
|
|
- v-if="isPC"
|
|
|
- @mousedown="touchStart"
|
|
|
- @mousemove="touchMove"
|
|
|
- @mouseup="touchEnd"
|
|
|
- @touchstart="touchStart"
|
|
|
- @touchmove="touchMove"
|
|
|
- @touchend="touchEnd">
|
|
|
- </view>
|
|
|
- <canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
|
|
|
- <!-- #endif -->
|
|
|
- <!-- #ifdef APP-NVUE -->
|
|
|
- <web-view
|
|
|
- class="lime-echart__canvas"
|
|
|
- :id="canvasId"
|
|
|
- :style="canvasStyle"
|
|
|
- :webview-styles="webviewStyles"
|
|
|
- ref="webview"
|
|
|
- src="/uni_modules/lime-echart/static/nvue.html?v=1"
|
|
|
- @pagefinish="finished = true"
|
|
|
- @onPostMessage="onMessage"
|
|
|
- ></web-view>
|
|
|
- <!-- #endif -->
|
|
|
+ @touchstart="handleTouchStart"
|
|
|
+ @touchmove="handleTouchMove"
|
|
|
+ @touchend="handleTouchEnd">
|
|
|
+ </canvas>
|
|
|
</view>
|
|
|
+ <!-- #endif -->
|
|
|
+ <!-- #ifdef WEB -->
|
|
|
+ <div class="lime-echart" ref="chartContainer" :style="[styles, lStyle]"></div>
|
|
|
+ <!-- #endif -->
|
|
|
+ <!-- #ifdef APP-NVUE -->
|
|
|
+ <view class="lime-echart" :style="[lStyle]">
|
|
|
+ <web-view class="lime-echart__canvas"
|
|
|
+ :webview-styles="webviewStyles"
|
|
|
+ :style="[styles]"
|
|
|
+ ref="chartContainer"
|
|
|
+ src="/uni_modules/lime-echart/static/app/uvue.html?v=1"
|
|
|
+ @pagefinish="isInitialized = true"
|
|
|
+ @onPostMessage="handleWebviewMessage"></web-view>
|
|
|
+ </view>
|
|
|
+ <!-- #endif -->
|
|
|
</template>
|
|
|
|
|
|
-<script>
|
|
|
-// #ifdef VUE3
|
|
|
-// #ifdef APP-PLUS
|
|
|
-global = {}
|
|
|
-// #endif
|
|
|
-// #endif
|
|
|
-// #ifndef APP-NVUE
|
|
|
-import {Canvas, setCanvasCreator, dispatch} from './canvas';
|
|
|
-import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect} from './utils';
|
|
|
-// #endif
|
|
|
-// #ifdef APP-NVUE
|
|
|
-import { base64ToPath, sleep } from './utils';
|
|
|
-import {Echarts} from './nvue'
|
|
|
-// #endif
|
|
|
-const charts = {}
|
|
|
-const echartsObj = {}
|
|
|
-export default {
|
|
|
- name: 'lime-echart',
|
|
|
- props: {
|
|
|
- // #ifdef MP-WEIXIN || MP-TOUTIAO
|
|
|
- type: {
|
|
|
- type: String,
|
|
|
- default: '2d'
|
|
|
- },
|
|
|
- // #endif
|
|
|
- // #ifdef APP-NVUE
|
|
|
- webviewStyles: Object,
|
|
|
- // hybrid: Boolean,
|
|
|
- // #endif
|
|
|
- customStyle: String,
|
|
|
- isDisableScroll: Boolean,
|
|
|
- isClickable: {
|
|
|
- type: Boolean,
|
|
|
- default: true
|
|
|
- },
|
|
|
- enableHover: Boolean,
|
|
|
- beforeDelay: {
|
|
|
- type: Number,
|
|
|
- default: 30
|
|
|
- }
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- // #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
|
|
- use2dCanvas: true,
|
|
|
- // #endif
|
|
|
- // #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
|
|
- use2dCanvas: false,
|
|
|
- // #endif
|
|
|
- ariaLabel: '图表',
|
|
|
- width: null,
|
|
|
- height: null,
|
|
|
- nodeWidth: null,
|
|
|
- nodeHeight: null,
|
|
|
- // canvasNode: null,
|
|
|
- config: {},
|
|
|
- inited: false,
|
|
|
- finished: false,
|
|
|
- file: '',
|
|
|
- platform: '',
|
|
|
- isPC: false,
|
|
|
- isDown: false,
|
|
|
- isOffscreenCanvas: false,
|
|
|
- offscreenWidth: 0,
|
|
|
- offscreenHeight: 0
|
|
|
- };
|
|
|
- },
|
|
|
- computed: {
|
|
|
- canvasId() {
|
|
|
- return `lime-echart${this._ && this._.uid || this._uid}`
|
|
|
- },
|
|
|
- offscreenCanvasId() {
|
|
|
- return `${this.canvasId}_offscreen`
|
|
|
- },
|
|
|
- offscreenStyle() {
|
|
|
- return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
|
|
|
- },
|
|
|
- canvasStyle() {
|
|
|
- return this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : ''
|
|
|
- }
|
|
|
- },
|
|
|
- // #ifndef VUE3
|
|
|
- beforeDestroy() {
|
|
|
- this.clear()
|
|
|
- this.dispose()
|
|
|
- // #ifdef H5
|
|
|
- if(this.isPC) {
|
|
|
- document.removeEventListener('mousewheel', this.mousewheel)
|
|
|
- }
|
|
|
- // #endif
|
|
|
- },
|
|
|
+<script lang="ts">
|
|
|
+ // @ts-nocheck
|
|
|
+ import { defineComponent, getCurrentInstance, ref, onMounted, nextTick, onBeforeUnmount, watch, computed } from './vue'
|
|
|
+ import echartProps from './props'
|
|
|
+
|
|
|
+ // #ifndef APP-NVUE || WEB
|
|
|
+ import { Canvas, setCanvasCreator, dispatch } from './canvas';
|
|
|
+ import { wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect, getDeviceInfo } from './utils';
|
|
|
// #endif
|
|
|
- // #ifdef VUE3
|
|
|
- beforeUnmount() {
|
|
|
- this.clear()
|
|
|
- this.dispose()
|
|
|
- // #ifdef H5
|
|
|
- if(this.isPC) {
|
|
|
- document.removeEventListener('mousewheel', this.mousewheel)
|
|
|
- }
|
|
|
- // #endif
|
|
|
- },
|
|
|
+ // #ifdef APP-NVUE
|
|
|
+ import { base64ToPath, sleep } from './utils';
|
|
|
+ import { Echarts } from './nvue'
|
|
|
// #endif
|
|
|
- created() {
|
|
|
- // #ifdef H5
|
|
|
- if(!('ontouchstart' in window)) {
|
|
|
- this.isPC = true
|
|
|
- document.addEventListener('mousewheel', this.mousewheel)
|
|
|
- }
|
|
|
- // #endif
|
|
|
- // #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
|
|
- const { platform } = uni.getSystemInfoSync();
|
|
|
- this.isPC = /windows/i.test(platform)
|
|
|
- // #endif
|
|
|
- this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- this.$nextTick(() => {
|
|
|
- this.$emit('finished')
|
|
|
- })
|
|
|
- },
|
|
|
- methods: {
|
|
|
- // #ifdef APP-NVUE
|
|
|
- onMessage(e) {
|
|
|
- const res = e?.detail?.data[0] || null;
|
|
|
- if (res?.event) {
|
|
|
- const data = JSON.parse(res.data)
|
|
|
- if(res.event === 'inited') {
|
|
|
- this.inited = true
|
|
|
- } else if(res.event.startsWith('@')){
|
|
|
- this.chart.dispatchAction(res.event.split('@')[1], data.options)
|
|
|
+ // #ifdef WEB
|
|
|
+ import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef APP-VUE
|
|
|
+ import '@/uni_modules/lime-echart/static/app/echarts.min.js';
|
|
|
+ const echartsLibrary = globalThis.echarts
|
|
|
+ // #endif
|
|
|
+
|
|
|
+
|
|
|
+ export default defineComponent({
|
|
|
+ props: echartProps,
|
|
|
+ emits: ['finished'],
|
|
|
+ setup(props, { emit, expose }) {
|
|
|
+ // #ifndef APP-NVUE || WEB || APP-VUE
|
|
|
+ let echartsLibrary = null
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ const instance = getCurrentInstance()!;
|
|
|
+ const canvasId = `lime-echart-${instance.uid}`
|
|
|
+ const isInitialized = ref(false)
|
|
|
+ const chartContainer = ref(null)
|
|
|
+
|
|
|
+ type ChartOptions = Record<string, any>
|
|
|
+ type EChartsInstance = typeof echartsLibrary
|
|
|
+ type EChartsResolveCallback = (value: EChartsInstance) => void
|
|
|
+
|
|
|
+ const initializationQueue = [] as EChartsResolveCallback[]
|
|
|
+ const callbackQueue = [] as EChartsResolveCallback[]
|
|
|
+
|
|
|
+ let chartInstance: null | EChartsInstance = null
|
|
|
+
|
|
|
+ const styles = computed(()=> {
|
|
|
+ if(props.landscape) {
|
|
|
+ return {
|
|
|
+ transform: 'translate(-50%,-50%) rotate(90deg)',
|
|
|
+ top: '50%',
|
|
|
+ left: '50%',
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- this.$emit(res.event, data);
|
|
|
- } else if(res?.file){
|
|
|
- this.file = res.data
|
|
|
- } else if(!res[0] && JSON.stringify(res[0]) != '{}'){
|
|
|
- console.error(res);
|
|
|
- } else {
|
|
|
- console.log(...res)
|
|
|
- }
|
|
|
- },
|
|
|
- // #endif
|
|
|
- setChart(callback) {
|
|
|
- if(!this.chart) {
|
|
|
+ return {}
|
|
|
+ })
|
|
|
+
|
|
|
+ const checkInitialization = (): boolean => {
|
|
|
+ if(chartInstance) return false
|
|
|
console.warn(`组件还未初始化,请先使用 init`)
|
|
|
- return
|
|
|
- }
|
|
|
- if(typeof callback === 'function' && this.chart) {
|
|
|
- callback(this.chart);
|
|
|
+ return true
|
|
|
}
|
|
|
- // #ifdef APP-NVUE
|
|
|
- if(typeof callback === 'function') {
|
|
|
- this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
|
|
|
- }
|
|
|
- // #endif
|
|
|
- },
|
|
|
- setOption() {
|
|
|
- if (!this.chart || !this.chart.setOption) {
|
|
|
- console.warn(`组件还未初始化,请先使用 init`)
|
|
|
- return
|
|
|
+
|
|
|
+ const setOption = (options: ChartOptions) => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartInstance!.setOption(options);
|
|
|
}
|
|
|
- this.chart.setOption(...arguments);
|
|
|
- },
|
|
|
- showLoading() {
|
|
|
- if(this.chart) {
|
|
|
- this.chart.showLoading(...arguments)
|
|
|
+
|
|
|
+ const hideLoading = () => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartInstance!.showLoading();
|
|
|
}
|
|
|
- },
|
|
|
- hideLoading() {
|
|
|
- if(this.chart) {
|
|
|
- this.chart.hideLoading()
|
|
|
+
|
|
|
+ const showLoading = () => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartInstance!.hideLoading();
|
|
|
}
|
|
|
- },
|
|
|
- clear() {
|
|
|
- if(this.chart) {
|
|
|
- this.chart.clear()
|
|
|
+
|
|
|
+ const clear = () => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartInstance!.clear();
|
|
|
}
|
|
|
- },
|
|
|
- dispose() {
|
|
|
- if(this.chart) {
|
|
|
- this.chart.dispose()
|
|
|
+
|
|
|
+ const dispose = () => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartInstance!.dispose();
|
|
|
}
|
|
|
- },
|
|
|
- resize(size) {
|
|
|
- if(size && size.width && size.height) {
|
|
|
- this.height = size.height
|
|
|
- this.width = size.width
|
|
|
- if(this.chart) {this.chart.resize(size)}
|
|
|
- } else {
|
|
|
- this.$nextTick(() => {
|
|
|
- uni.createSelectorQuery()
|
|
|
- .in(this)
|
|
|
- .select(`.lime-echart`)
|
|
|
- .boundingClientRect()
|
|
|
- .exec(res => {
|
|
|
- if (res) {
|
|
|
- let { width, height } = res[0];
|
|
|
- this.width = width = width || 300;
|
|
|
- this.height = height = height || 300;
|
|
|
- this.chart.resize({width, height})
|
|
|
- }
|
|
|
- });
|
|
|
- })
|
|
|
+ const processInitializationQueue = () => {
|
|
|
+ while (initializationQueue.length > 0) {
|
|
|
+ if (chartInstance != null) {
|
|
|
+ const resolve = initializationQueue.pop() as EChartsResolveCallback
|
|
|
+ resolve(chartInstance!)
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (chartInstance != null) {
|
|
|
+ while (callbackQueue.length > 0) {
|
|
|
+ const callback = callbackQueue.pop() as EChartsResolveCallback
|
|
|
+ callback(chartInstance!)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- },
|
|
|
- canvasToTempFilePath(args = {}) {
|
|
|
- // #ifndef APP-NVUE
|
|
|
- const { use2dCanvas, canvasId } = this;
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- const copyArgs = Object.assign({
|
|
|
- canvasId,
|
|
|
- success: resolve,
|
|
|
- fail: reject
|
|
|
- }, args);
|
|
|
- if (use2dCanvas) {
|
|
|
- delete copyArgs.canvasId;
|
|
|
- copyArgs.canvas = this.canvasNode;
|
|
|
- }
|
|
|
- uni.canvasToTempFilePath(copyArgs, this);
|
|
|
- });
|
|
|
- // #endif
|
|
|
- // #ifdef APP-NVUE
|
|
|
- this.file = ''
|
|
|
- this.$refs.webview.evalJs(`canvasToTempFilePath()`);
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- this.$watch('file', async (file) => {
|
|
|
- if(file) {
|
|
|
- const tempFilePath = await base64ToPath(file)
|
|
|
- resolve(args.success({tempFilePath}))
|
|
|
- } else {
|
|
|
- reject(args.fail({error: ``}))
|
|
|
- }
|
|
|
+ const resize = (dimensions?: { width?: number; height?: number }) => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ // #ifdef APP-NVUE || WEB
|
|
|
+ chartInstance!.resize(dimensions);
|
|
|
+ // #endif
|
|
|
+ // #ifndef APP-NVUE || WEB
|
|
|
+ getRect(`#${canvasId}`, instance.proxy).then(res => {
|
|
|
+ chartInstance!.resize({width: res.width, height: res.height});
|
|
|
})
|
|
|
- })
|
|
|
- // #endif
|
|
|
- },
|
|
|
- async init(echarts, ...args) {
|
|
|
- // #ifndef APP-NVUE
|
|
|
- if(arguments && arguments.length < 1) {
|
|
|
- console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
|
|
|
- return
|
|
|
+ // #endif
|
|
|
}
|
|
|
- // #endif
|
|
|
- let theme=null,opts={},callback;
|
|
|
|
|
|
- Array.from(arguments).forEach(item => {
|
|
|
- if(typeof item === 'function') {
|
|
|
- callback = item
|
|
|
+ // #ifdef APP-NVUE
|
|
|
+ let chartFile = ref(null);
|
|
|
+ const handleWebviewMessage = (e) => {
|
|
|
+ const detail = e?.detail?.data[0] || null;
|
|
|
+ const data = detail?.data
|
|
|
+ const key = detail?.event
|
|
|
+ const options = data?.options
|
|
|
+ const event = data?.event
|
|
|
+ const file = detail?.file
|
|
|
+ if (key == 'log' && data) {
|
|
|
+ console.log(data)
|
|
|
}
|
|
|
- if(['string'].includes(typeof item)) {
|
|
|
- theme = item
|
|
|
+ if(event) {
|
|
|
+ chartInstance.dispatchAction(event.replace(/"/g,''), options)
|
|
|
}
|
|
|
- if(typeof item === 'object') {
|
|
|
- opts = item
|
|
|
+ if(file) {
|
|
|
+ chartFile.value = file
|
|
|
}
|
|
|
- })
|
|
|
-
|
|
|
- if(this.beforeDelay) {
|
|
|
- await sleep(this.beforeDelay)
|
|
|
}
|
|
|
- let config = await this.getContext();
|
|
|
- // #ifndef APP-NVUE
|
|
|
- setCanvasCreator(echarts, config)
|
|
|
- this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
|
|
- if(typeof callback === 'function') {
|
|
|
- callback(this.chart)
|
|
|
- } else {
|
|
|
- return this.chart
|
|
|
- }
|
|
|
- // #endif
|
|
|
- // #ifdef APP-NVUE
|
|
|
- this.chart = new Echarts(this.$refs.webview)
|
|
|
- this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
|
|
|
- if(callback) {
|
|
|
- callback(this.chart)
|
|
|
- } else {
|
|
|
- return this.chart
|
|
|
+
|
|
|
+ const canvasToTempFilePath = (options: ChartOptions) => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ chartContainer.value.evalJs(`canvasToTempFilePath()`);
|
|
|
+ watch(chartFile, async (file) =>{
|
|
|
+ if(!file) return
|
|
|
+ const tempFilePath = await base64ToPath(file)
|
|
|
+ options.success({tempFilePath})
|
|
|
+ })
|
|
|
}
|
|
|
- // #endif
|
|
|
- },
|
|
|
- getContext() {
|
|
|
- // #ifdef APP-NVUE
|
|
|
- if(this.finished) {
|
|
|
- return Promise.resolve(this.finished)
|
|
|
+
|
|
|
+ const getContext = () => {
|
|
|
+ if(isInitialized.value) {
|
|
|
+ return Promise.resolve(isInitialized.value)
|
|
|
+ }
|
|
|
+ return new Promise(resolve => {
|
|
|
+ watch(isInitialized, (val) =>{
|
|
|
+ if(!val) return
|
|
|
+ resolve(val)
|
|
|
+ })
|
|
|
+ })
|
|
|
}
|
|
|
- return new Promise(resolve => {
|
|
|
- this.$watch('finished', (val) => {
|
|
|
- if(val) {
|
|
|
- resolve(this.finished)
|
|
|
+ const init = async (echarts, ...args) => {
|
|
|
+ let theme: string | null = null
|
|
|
+ let config:Record<string, any> = {}
|
|
|
+ let callback: Function | null = null;
|
|
|
+
|
|
|
+ args.forEach(item => {
|
|
|
+ if (typeof item === 'function') {
|
|
|
+ callback = item
|
|
|
+ } else if (typeof item === 'string') {
|
|
|
+ theme = item
|
|
|
+ } else if (typeof item === 'object') {
|
|
|
+ config = item
|
|
|
}
|
|
|
})
|
|
|
- })
|
|
|
+ if(props.beforeDelay) {
|
|
|
+ await sleep(props.beforeDelay)
|
|
|
+ }
|
|
|
+ await getContext();
|
|
|
+ chartInstance = new Echarts(chartContainer.value)
|
|
|
+ chartContainer.value.evalJs(`init(null, null, ${JSON.stringify(config)}, ${theme})`)
|
|
|
+ if (callback && typeof callback === 'function') {
|
|
|
+ callbackQueue.push(callback)
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Promise<EChartsInstance>((resolve) => {
|
|
|
+ nextTick(()=>{
|
|
|
+ initializationQueue.push(resolve)
|
|
|
+ processInitializationQueue()
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
// #endif
|
|
|
- // #ifndef APP-NVUE
|
|
|
- return getRect(`#${this.canvasId}`, {context: this, type: this.use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
|
|
|
- if(res) {
|
|
|
+
|
|
|
+
|
|
|
+ // #ifndef APP-NVUE || WEB
|
|
|
+ let canvasNode;
|
|
|
+ const canvasToTempFilePath = (options: ChartOptions) => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ if(canvasNode) {
|
|
|
+ options.success?.({
|
|
|
+ tempFilePath: canvasNode.toDataURL()
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.canvasToTempFilePath({
|
|
|
+ ...options,
|
|
|
+ canvasId
|
|
|
+ }, instance.proxy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const getContext = () => {
|
|
|
+ return getRect(`#${canvasId}`, instance.proxy).then(res => {
|
|
|
let dpr = devicePixelRatio
|
|
|
let {width, height, node} = res
|
|
|
- let canvas;
|
|
|
- this.width = width = width || 300;
|
|
|
- this.height = height = height || 300;
|
|
|
- if(node) {
|
|
|
+ let canvas: Canvas | null = null;
|
|
|
+ if(!(width || height)) {
|
|
|
+ return Promise.reject('no rect')
|
|
|
+ }
|
|
|
+ if(node && node.getContext) {
|
|
|
const ctx = node.getContext('2d');
|
|
|
- canvas = new Canvas(ctx, this, true, node);
|
|
|
- this.canvasNode = node
|
|
|
+ canvas = new Canvas(ctx, instance.proxy, true, node);
|
|
|
+ canvasNode = node
|
|
|
} else {
|
|
|
- // #ifdef MP-TOUTIAO
|
|
|
- dpr = !this.isPC ? devicePixelRatio : 1// 1.25
|
|
|
- // #endif
|
|
|
- // #ifndef MP-ALIPAY || MP-TOUTIAO
|
|
|
- dpr = this.isPC ? devicePixelRatio : 1
|
|
|
- // #endif
|
|
|
- // #ifdef MP-ALIPAY || MP-LARK
|
|
|
- dpr = devicePixelRatio
|
|
|
- // #endif
|
|
|
- this.rect = res
|
|
|
- this.nodeWidth = width * dpr;
|
|
|
- this.nodeHeight = height * dpr;
|
|
|
- const ctx = uni.createCanvasContext(this.canvasId, this);
|
|
|
- canvas = new Canvas(ctx, this, false);
|
|
|
+ dpr = 1
|
|
|
+ const ctx = uni.createCanvasContext(canvasId, instance.proxy);
|
|
|
+ canvas = new Canvas(ctx, instance.proxy, false);
|
|
|
}
|
|
|
- return { canvas, width, height, devicePixelRatio: dpr, node };
|
|
|
- } else {
|
|
|
- return {}
|
|
|
- }
|
|
|
- })
|
|
|
- // #endif
|
|
|
- },
|
|
|
- // #ifndef APP-NVUE
|
|
|
- getRelative(e, touches) {
|
|
|
- let { clientX, clientY } = e
|
|
|
- if(!(clientX && clientY) && touches && touches[0]) {
|
|
|
- clientX = touches[0].clientX
|
|
|
- clientY = touches[0].clientY
|
|
|
+ return { canvas, width, height, devicePixelRatio: dpr, node }
|
|
|
+ })
|
|
|
}
|
|
|
- return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
|
|
|
- },
|
|
|
- getTouch(e, touches) {
|
|
|
- const {x} = touches && touches[0] || {}
|
|
|
- return x ? touches[0] : this.getRelative(e, touches);
|
|
|
- },
|
|
|
- touchStart(e) {
|
|
|
- this.isDown = true
|
|
|
- const next = () => {
|
|
|
- const touches = convertTouchesToArray(e.touches)
|
|
|
- if(this.chart) {
|
|
|
- const touch = this.getTouch(e, touches)
|
|
|
- this.startX = touch.x
|
|
|
- this.startY = touch.y
|
|
|
- this.startT = new Date()
|
|
|
- const handler = this.chart.getZr().handler;
|
|
|
- dispatch.call(handler, 'mousedown', touch)
|
|
|
- dispatch.call(handler, 'mousemove', touch)
|
|
|
- handler.processGesture(wrapTouch(e), 'start');
|
|
|
- clearTimeout(this.endTimer);
|
|
|
+ const getTouch = (e) => {
|
|
|
+ const touches = e.touches[0]
|
|
|
+ const touch = props.landscape
|
|
|
+ ? {
|
|
|
+ x: touches.y,
|
|
|
+ y: touches.x
|
|
|
+ }
|
|
|
+ : {
|
|
|
+ x: touches.x,
|
|
|
+ y: touches.y
|
|
|
+ }
|
|
|
+ return touch
|
|
|
+ }
|
|
|
+ const handleTouchStart = (e) => {
|
|
|
+ if (chartInstance == null) return
|
|
|
+ const handler = chartInstance.getZr().handler;
|
|
|
+ const touch = getTouch(e)
|
|
|
+ dispatch.call(handler, 'mousedown', touch)
|
|
|
+ dispatch.call(handler, 'click', touch)
|
|
|
+ }
|
|
|
+ const handleTouchMove = (e) => {
|
|
|
+ if (chartInstance == null) return
|
|
|
+ const handler = chartInstance.getZr().handler;
|
|
|
+ const touch = getTouch(e)
|
|
|
+ dispatch.call(handler, 'mousemove', touch)
|
|
|
+ }
|
|
|
+ const handleTouchEnd = (e) => {
|
|
|
+ if (chartInstance == null || !props.autoHideTooltip) return
|
|
|
+ const handler = chartInstance.getZr().handler;
|
|
|
+
|
|
|
+ const touch = {
|
|
|
+ x: 999999999,
|
|
|
+ y: 999999999
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ dispatch.call(handler, 'mousemove', touch)
|
|
|
+ dispatch.call(handler, 'touchend', touch)
|
|
|
+
|
|
|
}
|
|
|
- if(this.isPC) {
|
|
|
- getRect(`#${this.canvasId}`, {context: this}).then(res => {
|
|
|
- this.rect = res
|
|
|
- next()
|
|
|
+ const init = async (echartsLib: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
|
|
|
+ const library = echartsLib || echartsLibrary
|
|
|
+ if (!library) {
|
|
|
+ console.error('ECharts library is required');
|
|
|
+ return Promise.reject('ECharts library is required');
|
|
|
+ }
|
|
|
+ let theme: string | null = null
|
|
|
+ let config:Record<string, any> = {}
|
|
|
+ let callback: Function | null = null;
|
|
|
+
|
|
|
+ args.forEach(item => {
|
|
|
+ if (typeof item === 'function') {
|
|
|
+ callback = item
|
|
|
+ } else if (typeof item === 'string') {
|
|
|
+ theme = item
|
|
|
+ } else if (typeof item === 'object') {
|
|
|
+ config = item
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if(props.beforeDelay) {
|
|
|
+ await sleep(props.beforeDelay)
|
|
|
+ }
|
|
|
+ let options = await getContext();
|
|
|
+ setCanvasCreator(library, options)
|
|
|
+ chartInstance = library.init(options.canvas, theme, Object.assign({}, options, config))
|
|
|
+ if (callback && typeof callback === 'function') {
|
|
|
+ callbackQueue.push(callback)
|
|
|
+ }
|
|
|
+ return new Promise<EChartsInstance>((resolve) => {
|
|
|
+ initializationQueue.push(resolve)
|
|
|
+ processInitializationQueue()
|
|
|
})
|
|
|
- return
|
|
|
}
|
|
|
- next()
|
|
|
- },
|
|
|
- touchMove(e) {
|
|
|
- if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
|
|
|
- const touches = convertTouchesToArray(e.touches)
|
|
|
- if (this.chart && this.isDown) {
|
|
|
- const handler = this.chart.getZr().handler;
|
|
|
- dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
|
|
|
- handler.processGesture(wrapTouch(e), 'change');
|
|
|
+
|
|
|
+ // #endif
|
|
|
+
|
|
|
+
|
|
|
+ // #ifdef WEB
|
|
|
+ const canvasToTempFilePath = (options: ChartOptions) => {
|
|
|
+ if (checkInitialization()) return
|
|
|
+ options.success?.({
|
|
|
+ tempFilePath: chartInstance._api.getDataURL()
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
- },
|
|
|
- touchEnd(e) {
|
|
|
- this.isDown = false
|
|
|
- if (this.chart) {
|
|
|
- const touches = convertTouchesToArray(e.changedTouches)
|
|
|
- const {x} = touches && touches[0] || {}
|
|
|
- const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
|
|
|
- const handler = this.chart.getZr().handler;
|
|
|
- const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
|
|
|
- dispatch.call(handler, 'mouseup', touch)
|
|
|
- handler.processGesture(wrapTouch(e), 'end');
|
|
|
- if(isClick) {
|
|
|
- dispatch.call(handler, 'click', touch)
|
|
|
- } else {
|
|
|
- this.endTimer = setTimeout(() => {
|
|
|
- dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
|
|
|
- dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
|
|
|
- },50)
|
|
|
+ const init = async (echarts: EChartsInstance = echartsLibrary, ...args: any[]): Promise<EChartsInstance> => {
|
|
|
+ const library = echarts || echartsLibrary
|
|
|
+ if (!library) {
|
|
|
+ console.error('ECharts library is required');
|
|
|
+ return Promise.reject('ECharts library is required');
|
|
|
+ }
|
|
|
+
|
|
|
+ let theme: string | null = null
|
|
|
+ let config = {}
|
|
|
+ let callback: Function | null = null;
|
|
|
+
|
|
|
+ args.forEach(item => {
|
|
|
+ if (typeof item === 'function') {
|
|
|
+ callback = item
|
|
|
+ } else if (typeof item === 'string') {
|
|
|
+ theme = item
|
|
|
+ } else if (typeof item === 'object') {
|
|
|
+ config = item
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // Configure ECharts environment
|
|
|
+ library.env.domSupported = true
|
|
|
+ library.env.hasGlobalWindow = true
|
|
|
+ library.env.node = false
|
|
|
+ library.env.pointerEventsSupported = false
|
|
|
+ library.env.svgSupported = true
|
|
|
+ library.env.touchEventsSupported = true
|
|
|
+ library.env.transform3dSupported = true
|
|
|
+ library.env.transformSupported = true
|
|
|
+ library.env.worker = false
|
|
|
+ library.env.wxa = false
|
|
|
+
|
|
|
+ chartInstance = library.init(chartContainer.value, theme, config)
|
|
|
+
|
|
|
+ if (callback != null && typeof callback === 'function') {
|
|
|
+ callbackQueue.push(callback)
|
|
|
}
|
|
|
+
|
|
|
+ return new Promise<EChartsInstance>((resolve) => {
|
|
|
+ initializationQueue.push(resolve)
|
|
|
+ processInitializationQueue()
|
|
|
+ })
|
|
|
}
|
|
|
- },
|
|
|
- // #endif
|
|
|
- // #ifdef H5
|
|
|
- mousewheel(e){
|
|
|
- if(this.chart) {
|
|
|
- dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
|
|
|
+ // #endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ nextTick(() => {
|
|
|
+ // #ifndef APP-NVUE
|
|
|
+ isInitialized.value = true
|
|
|
+ // #endif
|
|
|
+ emit('finished')
|
|
|
+ processInitializationQueue()
|
|
|
+ })
|
|
|
+ })
|
|
|
+ onBeforeUnmount(()=> {
|
|
|
+ clear()
|
|
|
+ dispose()
|
|
|
+ })
|
|
|
+
|
|
|
+ // #ifdef VUE3
|
|
|
+ expose({
|
|
|
+ init,
|
|
|
+ setOption,
|
|
|
+ hideLoading,
|
|
|
+ showLoading,
|
|
|
+ clear,
|
|
|
+ dispose,
|
|
|
+ resize,
|
|
|
+ canvasToTempFilePath
|
|
|
+ })
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ return {
|
|
|
+ canvasId,
|
|
|
+ chartContainer,
|
|
|
+ styles,
|
|
|
+ // #ifndef WEB || APP-NVUE
|
|
|
+ handleTouchStart,
|
|
|
+ handleTouchMove,
|
|
|
+ handleTouchEnd,
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef APP-NVUE
|
|
|
+ handleWebviewMessage,
|
|
|
+ isInitialized,
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifdef VUE2
|
|
|
+ init,
|
|
|
+ setOption,
|
|
|
+ hideLoading,
|
|
|
+ showLoading,
|
|
|
+ clear,
|
|
|
+ dispose,
|
|
|
+ resize,
|
|
|
+ canvasToTempFilePath,
|
|
|
+ // #endif
|
|
|
}
|
|
|
}
|
|
|
- // #endif
|
|
|
- }
|
|
|
-};
|
|
|
+ })
|
|
|
</script>
|
|
|
-<style>
|
|
|
-.lime-echart {
|
|
|
- position: relative;
|
|
|
- /* #ifndef APP-NVUE */
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- /* #endif */
|
|
|
- /* #ifdef APP-NVUE */
|
|
|
- flex: 1;
|
|
|
- /* #endif */
|
|
|
-}
|
|
|
-.lime-echart__canvas {
|
|
|
+
|
|
|
+<style>
|
|
|
+ .lime-echart {
|
|
|
+ position: relative;
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ /* #endif */
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
+ flex: 1;
|
|
|
+ /* #endif */
|
|
|
+ }
|
|
|
+
|
|
|
+ .lime-echart__canvas {
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ /* #endif */
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
+ flex: 1;
|
|
|
+ /* #endif */
|
|
|
+ }
|
|
|
+
|
|
|
/* #ifndef APP-NVUE */
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- /* #endif */
|
|
|
- /* #ifdef APP-NVUE */
|
|
|
- flex: 1;
|
|
|
+ .lime-echart__mask {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
/* #endif */
|
|
|
-}
|
|
|
-/* #ifndef APP-NVUE */
|
|
|
-.lime-echart__mask {
|
|
|
- position: absolute;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- left: 0;
|
|
|
- top: 0;
|
|
|
- z-index: 1;
|
|
|
-}
|
|
|
-/* #endif */
|
|
|
-</style>
|
|
|
+</style>
|