| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- <template>
- <!-- #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"
- :canvas-id="canvasId"
- @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 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 APP-NVUE
- import { base64ToPath, sleep } from './utils';
- import { Echarts } from './nvue'
- // #endif
- // #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%',
- }
- }
- return {}
- })
-
- const checkInitialization = (): boolean => {
- if(chartInstance) return false
- console.warn(`组件还未初始化,请先使用 init`)
- return true
- }
-
- const setOption = (options: ChartOptions) => {
- if (checkInitialization()) return
- chartInstance!.setOption(options);
- }
-
- const hideLoading = () => {
- if (checkInitialization()) return
- chartInstance!.showLoading();
- }
-
- const showLoading = () => {
- if (checkInitialization()) return
- chartInstance!.hideLoading();
- }
-
- const clear = () => {
- if (checkInitialization()) return
- chartInstance!.clear();
- }
-
- const dispose = () => {
- if (checkInitialization()) return
- chartInstance!.dispose();
- }
- 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!)
- }
- }
- }
-
- 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
- }
-
- // #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(event) {
- chartInstance.dispatchAction(event.replace(/"/g,''), options)
- }
- if(file) {
- chartFile.value = file
- }
- }
-
- 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})
- })
- }
-
- const getContext = () => {
- if(isInitialized.value) {
- return Promise.resolve(isInitialized.value)
- }
- return new Promise(resolve => {
- watch(isInitialized, (val) =>{
- if(!val) return
- resolve(val)
- })
- })
- }
- 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 || 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: Canvas | null = null;
- if(!(width || height)) {
- return Promise.reject('no rect')
- }
- if(node && node.getContext) {
- const ctx = node.getContext('2d');
- canvas = new Canvas(ctx, instance.proxy, true, node);
- canvasNode = node
- } else {
- dpr = 1
- const ctx = uni.createCanvasContext(canvasId, instance.proxy);
- canvas = new Canvas(ctx, instance.proxy, false);
- }
- return { canvas, width, height, devicePixelRatio: dpr, node }
- })
- }
- 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)
-
- }
- 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()
- })
- }
-
- // #endif
-
-
- // #ifdef WEB
- const canvasToTempFilePath = (options: ChartOptions) => {
- if (checkInitialization()) return
- options.success?.({
- tempFilePath: chartInstance._api.getDataURL()
- })
- }
-
- 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
-
-
-
-
- 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
- }
- }
- })
- </script>
- <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 */
- .lime-echart__mask {
- position: absolute;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- z-index: 1;
- }
- /* #endif */
- </style>
|