l-echart.uvue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. <template>
  2. <!-- #ifdef APP -->
  3. <web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[lStyle]" :webview-styles="[webviewStyles]"
  4. src="/uni_modules/lime-echart/static/app/uvue.html?v=10112">
  5. </web-view>
  6. <!-- #endif -->
  7. <!-- #ifdef WEB -->
  8. <div class="lime-echart" ref="chartRef"></div>
  9. <!-- #endif -->
  10. <!-- #ifndef WEB || APP-->
  11. <view class="lime-echart">
  12. <canvas style="width:100%; height:100%" v-if="canvasid" :id="canvasid" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
  13. </view>
  14. <!-- #endif -->
  15. </template>
  16. <script lang="uts" setup>
  17. // @ts-nocheck
  18. import { echartsProps } from './type';
  19. import { Echarts } from './uvue';
  20. // #ifdef WEB
  21. import { dispatch } from './canvas';
  22. import * as echartsLibrary from '@/uni_modules/lime-echart/static/web/echarts.esm.min.js';
  23. // #endif
  24. // #ifndef APP || WEB
  25. import { Canvas, setCanvasCreator, dispatch } from './canvas';
  26. import { wrapTouch, convertTouchesToArray, devicePixelRatio, sleep, canIUseCanvas2d, getRect } from './utils';
  27. // #endif
  28. type EChartsResolveCallback = (value : Echarts) => void
  29. const emits = defineEmits(['finished'])
  30. const props = withDefaults(defineProps<echartsProps>(), {
  31. isDisableScroll: false,
  32. isClickable: true,
  33. autoHideTooltip: false,
  34. enableHover: false,
  35. landscape: false,
  36. beforeDelay: 30,
  37. })
  38. const instance = getCurrentInstance()!;
  39. const canvasid = `lime-echart-${instance.uid}`
  40. const finished = ref(false)
  41. const initializationQueue = [] as EChartsResolveCallback[]
  42. const callbackQueue = [] as EChartsResolveCallback[]
  43. // let context = null as UniWebViewElement | null
  44. let chartInstance = null as Echarts | null
  45. let chartRef = ref<UniWebViewElement | null>(null)
  46. let canvasNode:any|null = null
  47. const processInitializationQueue = () => {
  48. // #ifdef APP
  49. if (finished.value) {
  50. if (chartInstance == null) {
  51. chartInstance = new Echarts(chartRef.value!)
  52. }
  53. while (initializationQueue.length > 0) {
  54. const resolve = initializationQueue.pop() as EChartsResolveCallback
  55. resolve(chartInstance!)
  56. }
  57. }
  58. // #endif
  59. // #ifndef APP
  60. while (initializationQueue.length > 0) {
  61. if (chartInstance != null) {
  62. const resolve = initializationQueue.pop() as EChartsResolveCallback
  63. resolve(chartInstance!)
  64. }
  65. }
  66. // #endif
  67. if (chartInstance != null) {
  68. while (callbackQueue.length > 0) {
  69. const callback = callbackQueue.pop() as EChartsResolveCallback
  70. callback(chartInstance!)
  71. }
  72. }
  73. }
  74. // #ifdef APP
  75. const loaded = (event : UniWebViewLoadEvent) => {
  76. event.stopPropagation()
  77. event.preventDefault()
  78. nextTick(()=> {
  79. chartRef.value?.getBoundingClientRectAsync()?.then(res => {
  80. if(res.width > 0 && res.height > 0) {
  81. finished.value = true
  82. processInitializationQueue()
  83. emits('finished')
  84. } else {
  85. console.warn('【lime-echart】获取尺寸失败,请检查代码样式')
  86. }
  87. })
  88. })
  89. }
  90. // #endif
  91. const checkInitialization = () : boolean => {
  92. if (chartInstance == null) {
  93. console.warn(`组件还未初始化,请先使用 init`)
  94. return true
  95. }
  96. return false
  97. }
  98. const setOption = (option : UTSJSONObject) => {
  99. if (checkInitialization()) return
  100. chartInstance!.setOption(option);
  101. }
  102. const showLoading = () => {
  103. if (checkInitialization()) return
  104. chartInstance!.showLoading();
  105. }
  106. const hideLoading = () => {
  107. if (checkInitialization()) return
  108. chartInstance!.hideLoading();
  109. }
  110. const clear = () => {
  111. if (checkInitialization()) return
  112. chartInstance!.clear();
  113. }
  114. const dispose = () => {
  115. if (checkInitialization()) return
  116. chartInstance!.dispose();
  117. }
  118. const resize = (size : UTSJSONObject) => {
  119. if (checkInitialization()) return
  120. chartInstance!.resize(size);
  121. }
  122. const canvasToTempFilePath = (opt : UTSJSONObject) => {
  123. if (checkInitialization()) return
  124. // #ifdef APP
  125. chartInstance!.canvasToTempFilePath(opt);
  126. // #endif
  127. // #ifdef WEB
  128. opt.success?.({
  129. // @ts-ignore
  130. tempFilePath: chartInstance!._api.getDataURL()
  131. })
  132. // #endif
  133. // #ifndef WEB || APP
  134. if(canvasNode) {
  135. opt.success?.({
  136. tempFilePath: canvasNode.toDataURL()
  137. })
  138. } else {
  139. uni.canvasToTempFilePath({
  140. ...opt,
  141. canvasId
  142. }, instance.proxy);
  143. }
  144. // #endif
  145. }
  146. // #ifdef APP
  147. function init(callback : ((chartInstance : Echarts) => void) | null) : Promise<Echarts> {
  148. if (callback != null) {
  149. callbackQueue.push(callback)
  150. }
  151. return new Promise<Echarts>((resolve) => {
  152. initializationQueue.push(resolve)
  153. processInitializationQueue()
  154. })
  155. }
  156. // #endif
  157. // #ifndef APP
  158. // #ifndef WEB
  159. let use2dCanvas = canIUseCanvas2d()
  160. const getContext = async () => {
  161. return new Promise((resolve, reject)=>{
  162. uni.createCanvasContextAsync({
  163. id: canvasid,
  164. component: instance.proxy!,
  165. success: (context : CanvasContext) => {
  166. canvasNode = context
  167. const canvasContext = context.getContext('2d')!;
  168. const canvas = canvasContext.canvas;
  169. let uniCanvas;
  170. const width = canvas.offsetWidth
  171. const height = canvas.offsetHeight
  172. // 处理高清屏逻辑
  173. const dpr = devicePixelRatio//uni.getDeviceInfo().devicePixelRatio ?? 1;
  174. canvas.width = canvas.offsetWidth * dpr;
  175. canvas.height = canvas.offsetHeight * dpr;
  176. canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
  177. if(use2dCanvas) {
  178. uniCanvas = new Canvas(canvasContext, instance.proxy, true, context);
  179. } else {
  180. uniCanvas = new Canvas(canvasContext, instance.proxy, false);
  181. }
  182. resolve({ canvas: uniCanvas, width, height, devicePixelRatio: dpr, node: context});
  183. },
  184. fail(err) {
  185. reject(err)
  186. console.log('err', err)
  187. }
  188. })
  189. })
  190. }
  191. // #endif
  192. const getTouch = (e) => {
  193. const touches = e.touches[0]
  194. // #ifdef WEB
  195. // @ts-ignore
  196. const rect = chart!.getZr().dom.getBoundingClientRect();
  197. const touch = {
  198. x: touches.clientX - rect.left,
  199. y: touches.clientY - rect.top
  200. }
  201. // #endif
  202. // #ifndef WEB
  203. const touch = {
  204. x: touches.x,
  205. y: touches.y
  206. }
  207. // #endif
  208. return touch
  209. }
  210. const touchstart = (e) => {
  211. if (chartInstance == null) return
  212. // @ts-ignore
  213. const handler = chartInstance.getZr().handler;
  214. const touch = getTouch(e)
  215. dispatch.call(handler, 'mousedown', touch)
  216. dispatch.call(handler, 'click', touch)
  217. }
  218. const touchmove = (e) => {
  219. if (chartInstance == null) return
  220. // @ts-ignore
  221. const handler = chartInstance.getZr().handler;
  222. const touch = getTouch(e)
  223. dispatch.call(handler, 'mousemove', touch)
  224. }
  225. const touchend = (e) => {
  226. if (chartInstance == null || !props.autoHideTooltip) return
  227. // @ts-ignore
  228. const handler = chartInstance.getZr().handler;
  229. const touch = {
  230. x: 999999999,
  231. y: 999999999
  232. }
  233. dispatch.call(handler, 'mousemove', touch)
  234. dispatch.call(handler, 'touchend', touch)
  235. }
  236. async function init(echarts : any, ...args : any[]) : Promise<Echarts> {
  237. const library = echarts || echartsLibrary
  238. if (library == null) {
  239. console.error('请确保已经引入了 ECharts 库');
  240. return Promise.reject('请确保已经引入了 ECharts 库');
  241. }
  242. let theme : string | null = null
  243. let opts = {}
  244. let callback : Function | null = null;
  245. args.forEach(item => {
  246. if (typeof item === 'function') {
  247. callback = item
  248. } else if (['string'].includes(typeof item)) {
  249. theme = item
  250. } else if (typeof item === 'object') {
  251. opts = item
  252. }
  253. })
  254. // #ifdef WEB
  255. library.env.domSupported = true
  256. library.env.hasGlobalWindow = true
  257. library.env.node = false
  258. library.env.pointerEventsSupported = false
  259. library.env.svgSupported = true
  260. library.env.touchEventsSupported = true
  261. library.env.transform3dSupported = true
  262. library.env.transformSupported = true
  263. library.env.worker = false
  264. library.env.wxa = false
  265. chartInstance = library.init(chartRef.value, theme, opts)
  266. // window.addEventListener('touchstart', touchstart)
  267. // window.addEventListener('touchmove', touchmove)
  268. // window.addEventListener('touchend', touchend)
  269. // #endif
  270. // #ifndef WEB
  271. let config = await getContext();
  272. setCanvasCreator(library, config)
  273. chartInstance = library.init(config.canvas, theme, Object.assign({}, config, opts))
  274. // #endif
  275. if (callback != null && typeof callback == 'function') {
  276. callbackQueue.push(callback)
  277. }
  278. return new Promise<Echarts>((resolve) => {
  279. initializationQueue.push(resolve)
  280. processInitializationQueue()
  281. })
  282. }
  283. onMounted(() => {
  284. nextTick(() => {
  285. finished.value = true
  286. processInitializationQueue()
  287. emits('finished')
  288. })
  289. })
  290. onUnmounted(() => {
  291. // #ifdef WEB
  292. // window.removeEventListener('touchstart', touchstart)
  293. // window.removeEventListener('touchmove', touchmove)
  294. // window.removeEventListener('touchend', touchend)
  295. // #endif
  296. })
  297. // #endif
  298. defineExpose({
  299. init,
  300. setOption,
  301. showLoading,
  302. hideLoading,
  303. clear,
  304. dispose,
  305. resize,
  306. canvasToTempFilePath
  307. })
  308. </script>
  309. <style lang="scss">
  310. .lime-echart {
  311. flex: 1;
  312. width: 100%;
  313. }
  314. </style>