373 lines
9.6 KiB
Plaintext
373 lines
9.6 KiB
Plaintext
<template>
|
||
<!-- #ifdef APP -->
|
||
<web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[customStyle]" :webview-styles="[webviewStyles]"
|
||
src="/uni_modules/lime-echart/static/uvue.html?v=10112">
|
||
</web-view>
|
||
<!-- #endif -->
|
||
<!-- #ifdef H5 -->
|
||
<div class="lime-echart" ref="chartRef"></div>
|
||
<!-- #endif -->
|
||
<!-- #ifndef H5 || APP-->
|
||
<view class="lime-echart">
|
||
<canvas style="width:100%; height:100%" v-if="canvasid" :id="canvasid" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
|
||
</view>
|
||
<!-- #endif -->
|
||
</template>
|
||
|
||
<script lang="uts" setup>
|
||
// @ts-nocheck
|
||
import { getCurrentInstance, nextTick } from "vue";
|
||
import { Echarts } from './uvue';
|
||
// #ifdef WEB
|
||
import { dispatch } from './canvas';
|
||
// #endif
|
||
// #ifndef APP || WEB
|
||
import { Canvas, setCanvasCreator, dispatch } from './canvas';
|
||
import { wrapTouch, convertTouchesToArray, devicePixelRatio, sleep, canIUseCanvas2d, getRect } from './utils';
|
||
// #endif
|
||
type EchartsResolve = (value : Echarts) => void
|
||
defineOptions({
|
||
name: 'l-echart'
|
||
})
|
||
const emits = defineEmits(['finished'])
|
||
const props = defineProps({
|
||
// #ifdef APP
|
||
webviewStyles: {
|
||
type: Object
|
||
},
|
||
customStyle: {
|
||
type: Object
|
||
},
|
||
// #endif
|
||
// #ifndef APP
|
||
webviewStyles: {
|
||
type: Object
|
||
},
|
||
customStyle: {
|
||
type: [String, Object]
|
||
},
|
||
// #endif
|
||
isDisableScroll: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
isClickable: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
enableHover: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
beforeDelay: {
|
||
type: Number,
|
||
default: 30
|
||
}
|
||
})
|
||
const instance = getCurrentInstance()!;
|
||
const canvasid = `lime-echart-${instance.uid}`
|
||
const finished = ref(false)
|
||
const map = [] as EchartsResolve[]
|
||
const callbackMap = [] as EchartsResolve[]
|
||
// let context = null as UniWebViewElement | null
|
||
let chart = null as Echarts | null
|
||
let chartRef = ref<UniWebViewElement | null>(null)
|
||
|
||
const trigger = () => {
|
||
// #ifdef APP
|
||
if (finished.value) {
|
||
if (chart == null) {
|
||
chart = new Echarts(chartRef.value!)
|
||
}
|
||
while (map.length > 0) {
|
||
const resolve = map.pop() as EchartsResolve
|
||
resolve(chart!)
|
||
}
|
||
}
|
||
// #endif
|
||
// #ifndef APP
|
||
while (map.length > 0) {
|
||
if (chart != null) {
|
||
const resolve = map.pop() as EchartsResolve
|
||
resolve(chart!)
|
||
}
|
||
}
|
||
// #endif
|
||
|
||
if (chart != null) {
|
||
while (callbackMap.length > 0) {
|
||
const callback = callbackMap.pop() as EchartsResolve
|
||
callback(chart!)
|
||
}
|
||
}
|
||
}
|
||
|
||
// #ifdef APP
|
||
// const resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => {
|
||
// const rect = entries[0].target.getBoundingClientRect()
|
||
// if((rect.width > 0 || rect.height > 0) && !finished.value) {
|
||
// finished.value = true
|
||
// trigger()
|
||
// emits('finished')
|
||
// }
|
||
|
||
// })
|
||
|
||
// const stopWatch = watch(():UniElement|null => chartRef.value, (el:UniElement|null) => {
|
||
// if(el== null) return
|
||
// resizeObserver.observe(el)
|
||
// })
|
||
const loaded = (event : UniWebViewLoadEvent) => {
|
||
event.stopPropagation()
|
||
event.preventDefault()
|
||
nextTick(()=> {
|
||
chartRef.value?.getBoundingClientRectAsync()?.then(res => {
|
||
if(res.width > 0 && res.height > 0) {
|
||
finished.value = true
|
||
trigger()
|
||
emits('finished')
|
||
} else {
|
||
console.warn('【lime-echart】获取尺寸失败,请检查代码样式')
|
||
}
|
||
})
|
||
})
|
||
}
|
||
// #endif
|
||
|
||
|
||
const _next = () : boolean => {
|
||
if (chart == null) {
|
||
console.warn(`组件还未初始化,请先使用 init`)
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
const setOption = (option : UTSJSONObject) => {
|
||
if (_next()) return
|
||
chart!.setOption(option);
|
||
}
|
||
const showLoading = () => {
|
||
if (_next()) return
|
||
chart!.showLoading();
|
||
}
|
||
const hideLoading = () => {
|
||
if (_next()) return
|
||
chart!.hideLoading();
|
||
}
|
||
const clear = () => {
|
||
if (_next()) return
|
||
chart!.clear();
|
||
}
|
||
const dispose = () => {
|
||
if (_next()) return
|
||
chart!.dispose();
|
||
}
|
||
const resize = (size : UTSJSONObject) => {
|
||
if (_next()) return
|
||
chart!.resize(size);
|
||
}
|
||
const canvasToTempFilePath = (opt : UTSJSONObject) => {
|
||
if (_next()) return
|
||
chart!.canvasToTempFilePath(opt);
|
||
}
|
||
|
||
// #ifdef APP
|
||
function init(callback : ((chart : Echarts) => void) | null) : Promise<Echarts> {
|
||
|
||
if (callback != null) {
|
||
callbackMap.push(callback)
|
||
}
|
||
return new Promise<Echarts>((resolve) => {
|
||
map.push(resolve)
|
||
trigger()
|
||
})
|
||
}
|
||
// onUnmounted(()=>{
|
||
// stopWatch()
|
||
// resizeObserver.disconnect()
|
||
// })
|
||
// #endif
|
||
// #ifndef APP
|
||
// #ifndef WEB
|
||
let use2dCanvas = canIUseCanvas2d()
|
||
const getContext = async () => {
|
||
return new Promise((resolve, reject)=>{
|
||
uni.createCanvasContextAsync({
|
||
id: canvasid,
|
||
component: instance.proxy!,
|
||
success: (context : CanvasContext) => {
|
||
const canvasContext = context.getContext('2d')!;
|
||
const canvas = canvasContext.canvas;
|
||
let uniCanvas;
|
||
const width = canvas.offsetWidth
|
||
const height = canvas.offsetHeight
|
||
// 处理高清屏逻辑
|
||
const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
|
||
canvas.width = canvas.offsetWidth * dpr;
|
||
canvas.height = canvas.offsetHeight * dpr;
|
||
canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
|
||
if(use2dCanvas) {
|
||
uniCanvas = new Canvas(canvasContext, instance.proxy, true, context);
|
||
} else {
|
||
uniCanvas = new Canvas(canvasContext, instance.proxy, false);
|
||
}
|
||
resolve({ canvas: uniCanvas, width, height, devicePixelRatio: 1, node: context});
|
||
},
|
||
fail(err) {
|
||
reject(err)
|
||
console.log('err', err)
|
||
}
|
||
})
|
||
})
|
||
|
||
|
||
// return getRect(`#${canvasid}`, {context: instance.proxy!, type: use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
|
||
// if(res) {
|
||
// let dpr = uni.getWindowInfo().pixelRatio
|
||
// let {width, height, node} = res
|
||
// let canvas;
|
||
// if(node) {
|
||
// const ctx = node.getContext('2d');
|
||
// canvas = new Canvas(ctx, instance.proxy, true, node);
|
||
// } else {
|
||
// const ctx = uni.createCanvasContext(canvasid, instance.proxy);
|
||
// canvas = new Canvas(ctx, instance.proxy, false);
|
||
// }
|
||
|
||
// return { canvas, width, height, devicePixelRatio: dpr, node };
|
||
// } else {
|
||
// return {}
|
||
// }
|
||
// })
|
||
}
|
||
// #endif
|
||
const getTouch = (e) => {
|
||
const touches = e.touches[0]
|
||
// #ifdef WEB
|
||
const rect = chart!.getZr().dom.getBoundingClientRect();
|
||
const touch = {
|
||
x: touches.clientX - rect.left,
|
||
y: touches.clientY - rect.top
|
||
}
|
||
// #endif
|
||
// #ifndef WEB
|
||
const touch = {
|
||
x: touches.x,
|
||
y: touches.y
|
||
}
|
||
// #endif
|
||
return touch
|
||
}
|
||
const touchstart = (e) => {
|
||
if (chart == null) return
|
||
const handler = chart.getZr().handler;
|
||
const touch = getTouch(e)
|
||
dispatch.call(handler, 'mousedown', touch)
|
||
dispatch.call(handler, 'click', touch)
|
||
}
|
||
const touchmove = (e) => {
|
||
if (chart == null) return
|
||
const handler = chart.getZr().handler;
|
||
const touch = getTouch(e)
|
||
dispatch.call(handler, 'mousemove', touch)
|
||
// const rect = chart.getZr().dom.getBoundingClientRect()
|
||
// handler.dispatch('mousemove', {
|
||
// zrX: e.touches[0].clientX - rect.left,
|
||
// zrY: e.touches[0].clientY - rect.top
|
||
// })
|
||
}
|
||
const touchend = (e) => {
|
||
if (chart == null) return
|
||
const handler = chart.getZr().handler;
|
||
|
||
const touch = {
|
||
x: 999999999,
|
||
y: 999999999
|
||
}
|
||
|
||
dispatch.call(handler, 'mousemove', touch)
|
||
dispatch.call(handler, 'touchend', touch)
|
||
|
||
}
|
||
async function init(echarts : any, ...args : any[]) : Promise<Echarts> {
|
||
if (echarts == null) {
|
||
console.error('请确保已经引入了 ECharts 库');
|
||
return Promise.reject('请确保已经引入了 ECharts 库');
|
||
}
|
||
let theme : string | null = null
|
||
let opts = {}
|
||
let callback : Function | null = null;
|
||
|
||
args.forEach(item => {
|
||
if (typeof item === 'function') {
|
||
callback = item
|
||
} else if (['string'].includes(typeof item)) {
|
||
theme = item
|
||
} else if (typeof item === 'object') {
|
||
opts = item
|
||
}
|
||
})
|
||
|
||
// #ifdef WEB
|
||
echarts.env.domSupported = true
|
||
echarts.env.hasGlobalWindow = true
|
||
echarts.env.node = false
|
||
echarts.env.pointerEventsSupported = false
|
||
echarts.env.svgSupported = true
|
||
echarts.env.touchEventsSupported = true
|
||
echarts.env.transform3dSupported = true
|
||
echarts.env.transformSupported = true
|
||
echarts.env.worker = false
|
||
echarts.env.wxa = false
|
||
chart = echarts.init(chartRef.value, theme, opts)
|
||
// window.addEventListener('touchstart', touchstart)
|
||
// window.addEventListener('touchmove', touchmove)
|
||
// window.addEventListener('touchend', touchend)
|
||
// #endif
|
||
|
||
// #ifndef WEB
|
||
let config = await getContext();
|
||
setCanvasCreator(echarts, config)
|
||
chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
||
// #endif
|
||
if (callback != null && typeof callback == 'function') {
|
||
callbackMap.push(callback)
|
||
}
|
||
return new Promise<Echarts>((resolve) => {
|
||
map.push(resolve)
|
||
trigger()
|
||
})
|
||
}
|
||
onMounted(() => {
|
||
nextTick(() => {
|
||
finished.value = true
|
||
trigger()
|
||
emits('finished')
|
||
})
|
||
})
|
||
onUnmounted(() => {
|
||
// #ifdef WEB
|
||
// window.removeEventListener('touchstart', touchstart)
|
||
// window.removeEventListener('touchmove', touchmove)
|
||
// window.removeEventListener('touchend', touchend)
|
||
// #endif
|
||
})
|
||
// #endif
|
||
|
||
defineExpose({
|
||
init,
|
||
setOption,
|
||
showLoading,
|
||
hideLoading,
|
||
clear,
|
||
dispose,
|
||
resize,
|
||
canvasToTempFilePath
|
||
})
|
||
</script>
|
||
<style lang="scss">
|
||
.lime-echart {
|
||
flex: 1;
|
||
width: 100%;
|
||
}
|
||
</style> |