Closed xsjcTony closed 9 months ago
I was wondering whether this is a issue with the official echarts
package, but seems like no, as I tried it with the minimum setup of a simple bar chart, and no errors are being printed in the console. https://stackblitz.com/edit/vitejs-vite-dyr5tr?file=src%2Fmain.ts,index.html&terminal=dev
@xsjcTony mmm definitely, I'll look into this.
@hugocxl have you had any chance to look into this. My current solution is just to add the required components but don't want to hurt performance
@brandanking-decently I'll try to find some time this weekend, I'm pretty busy at the time...
That would be great thanks, let me know if I can do anything to potentially assist with this
@hugocxl I've been able to figure out why this is happening. I tried creating a PR however, I was unable to due to restrictions as well as local problems with lint-staged (I don't use pnpm)
Below is the implemented code
To explain why I think this was happening, despite the modules being undefined, eChart still believed they where being used as undefined was explicitly passed in as a parameter. By removing the parameter all together if not required, then it works how it should. This also allows animations to work on first render as well.
So I believe it closes #20 as well as #19
You may want to do some additional improvements but hopefully you can get this merged in soon as it would be a great help on the project
// Dependencies
import { init, ECharts, use as echartsUse } from 'echarts/core'
import { useEffect, useRef, useState } from 'react'
// Constants
import { echartsEvents as ev } from './events'
// Types
import type { EChartEventsProps } from './events'
import type { EChartsOption, SetOptionOpts } from 'echarts'
export type UseEChartsOptions = EChartEventsProps &
SetOptionOpts &
EChartsOption &
Parameters<typeof init>[2] & {
group?: ECharts['group']
theme?: Parameters<typeof init>[1]
use?: Parameters<typeof echartsUse>[0]
}
export function useECharts<T extends HTMLElement>({
// Init
devicePixelRatio,
height,
locale,
pointerSize,
renderer,
theme,
use,
useCoarsePointer,
useDirtyRect,
width,
// eChartsInstance
group,
// SetOption
lazyUpdate,
notMerge,
replaceMerge,
silent,
transition,
darkMode,
media,
options,
stateAnimation,
// Option
angleAxis,
animation,
animationDelay,
animationDelayUpdate,
animationDuration,
animationDurationUpdate,
animationEasing,
animationEasingUpdate,
animationThreshold,
aria,
axisPointer,
backgroundColor,
blendMode,
brush,
calendar,
color,
dataZoom,
dataset,
geo,
graphic,
grid,
hoverLayerThreshold,
legend,
parallel,
parallelAxis,
polar,
progressive,
progressiveThreshold,
radar,
radiusAxis,
series,
singleAxis,
textStyle,
timeline,
title,
toolbox,
tooltip,
useUTC,
visualMap,
xAxis,
yAxis,
// Events
onAxisAreaSelected,
onBrush,
onBrushEnd,
onBrushSelected,
onClick,
onContextMenu,
onDataRangeSelected,
onDataViewChanged,
onDataZoom,
onDoubleClick,
onDownplay,
onFinished,
onGeoSelectChanged,
onGeoSelected,
onGeoUnselected,
onGlobalCursorTaken,
onGlobalOut,
onHighlight,
onLegendInverseSelect,
onLegendScroll,
onLegendSelectChanged,
onLegendSelected,
onLegendUnselected,
onMagicTypeChanged,
onMouseDown,
onMouseMove,
onMouseOut,
onMouseOver,
onRendered,
onRestore,
onSelectChanged,
onTimelineChanged,
onTimelinePlayChanged
}: UseEChartsOptions): [(node: T) => void, ECharts | undefined] {
const containerRef = useRef<T>()
const echartsRef = useRef<ECharts>()
const resizeObserverRef = useRef<ResizeObserver>()
const [started, setStarted] = useState(false)
const echartsInstance = echartsRef.current
async function setContainerRef(node: T) {
if (containerRef.current && echartsRef.current) return
containerRef.current = node
echartsRef.current = await startEcharts()
resizeObserverRef.current = startResizeObserver()
setStarted(true)
}
async function startEcharts() {
if (!containerRef.current) return
const useOpts = use || (await getGlobalUse())
echartsUse(useOpts)
return init(containerRef.current, theme, {
devicePixelRatio,
height,
locale,
pointerSize,
renderer,
useCoarsePointer,
useDirtyRect,
width
})
}
function startResizeObserver() {
const resizeObserver = new ResizeObserver(() => {
echartsRef.current?.resize()
})
if (containerRef.current) resizeObserver.observe(containerRef.current)
return resizeObserver
}
useEffect(() => {
if (!echartsInstance) return
if (group) echartsInstance.group = group
}, [group, started, echartsInstance])
useEffect(() => {
if (!echartsInstance) return
echartsInstance.clear()
echartsInstance.setOption(
{
series,
useUTC,
xAxis,
yAxis,
progressive,
blendMode,
hoverLayerThreshold,
progressiveThreshold,
...(angleAxis && { angleAxis }),
...(animation && { animation }),
...(animationDelay && { animationDelay }),
...(animationDelayUpdate && { animationDelayUpdate }),
...(animationDuration && { animationDuration }),
...(animationDurationUpdate && { animationDurationUpdate }),
...(animationEasing && { animationEasing }),
...(animationEasingUpdate && { animationEasingUpdate }),
...(animationThreshold && { animationThreshold }),
...(aria && { aria }),
...(axisPointer && { axisPointer }),
...(backgroundColor && { backgroundColor }),
...(brush && { brush }),
...(calendar && { calendar }),
...(color && { color }),
...(darkMode && { darkMode }),
...(dataset && { dataset }),
...(dataZoom && { dataZoom }),
...(geo && { geo }),
...(graphic && { graphic }),
...(grid && { grid }),
...(legend && { legend }),
...(media && { media }),
...(options && { options }),
...(parallel && { parallel }),
...(parallelAxis && { parallelAxis }),
...(polar && { polar }),
...(radar && { radar }),
...(radiusAxis && { radiusAxis }),
...(series && { series }),
...(singleAxis && { singleAxis }),
...(stateAnimation && { stateAnimation }),
...(textStyle && { textStyle }),
...(timeline && { timeline }),
...(title && { title }),
...(toolbox && { toolbox }),
...(tooltip && { tooltip }),
...(useUTC && { useUTC }),
...(visualMap && { visualMap }),
...(xAxis && { xAxis }),
...(yAxis && { yAxis })
},
{
lazyUpdate,
notMerge,
replaceMerge,
silent,
transition
}
)
}, [
angleAxis,
animation,
animationDelay,
animationDelayUpdate,
animationDuration,
animationDurationUpdate,
animationEasing,
animationEasingUpdate,
animationThreshold,
aria,
axisPointer,
backgroundColor,
blendMode,
brush,
calendar,
color,
darkMode,
dataset,
dataZoom,
geo,
graphic,
grid,
hoverLayerThreshold,
legend,
media,
options,
parallel,
parallelAxis,
polar,
progressive,
progressiveThreshold,
radar,
radiusAxis,
series,
singleAxis,
stateAnimation,
textStyle,
timeline,
title,
toolbox,
tooltip,
useUTC,
visualMap,
xAxis,
yAxis,
//
lazyUpdate,
notMerge,
replaceMerge,
silent,
transition,
//
started,
echartsInstance
])
useEffect(() => {
if (!echartsInstance) return
if (onAxisAreaSelected) {
echartsInstance.on(ev.onAxisAreaSelected, onAxisAreaSelected)
}
if (onBrush) {
echartsInstance.on(ev.onBrush, onBrush)
}
if (onBrushEnd) {
echartsInstance.on(ev.onBrushEnd, onBrushEnd)
}
if (onBrushSelected) {
echartsInstance.on(ev.onBrushSelected, onBrushSelected)
}
if (onClick) {
echartsInstance.on(ev.onClick, onClick)
}
if (onContextMenu) {
echartsInstance.on(ev.onContextMenu, onContextMenu)
}
if (onDataRangeSelected) {
echartsInstance.on(ev.onDataRangeSelected, onDataRangeSelected)
}
if (onDataViewChanged) {
echartsInstance.on(ev.onDataViewChanged, onDataViewChanged)
}
if (onDataZoom) {
echartsInstance.on(ev.onDataZoom, onDataZoom)
}
if (onDoubleClick) {
echartsInstance.on(ev.onDoubleClick, onDoubleClick)
}
if (onDownplay) {
echartsInstance.on(ev.onDownplay, onDownplay)
}
if (onFinished) {
echartsInstance.on(ev.onFinished, onFinished)
}
if (onGeoSelectChanged) {
echartsInstance.on(ev.onGeoSelectChanged, onGeoSelectChanged)
}
if (onGeoSelected) {
echartsInstance.on(ev.onGeoSelected, onGeoSelected)
}
if (onGeoUnselected) {
echartsInstance.on(ev.onGeoUnselected, onGeoUnselected)
}
if (onGlobalCursorTaken) {
echartsInstance.on(ev.onGlobalCursorTaken, onGlobalCursorTaken)
}
if (onGlobalOut) {
echartsInstance.on(ev.onGlobalOut, onGlobalOut)
}
if (onHighlight) {
echartsInstance.on(ev.onHighlight, onHighlight)
}
if (onLegendInverseSelect) {
echartsInstance.on(ev.onLegendInverseSelect, onLegendInverseSelect)
}
if (onLegendScroll) {
echartsInstance.on(ev.onLegendScroll, onLegendScroll)
}
if (onLegendScroll) {
echartsInstance.on(ev.onLegendScroll, onLegendScroll)
}
if (onLegendSelectChanged) {
echartsInstance.on(ev.onLegendSelectChanged, onLegendSelectChanged)
}
if (onLegendSelected) {
echartsInstance.on(ev.onLegendSelected, onLegendSelected)
}
if (onLegendUnselected) {
echartsInstance.on(ev.onLegendUnselected, onLegendUnselected)
}
if (onMagicTypeChanged) {
echartsInstance.on(ev.onMagicTypeChanged, onMagicTypeChanged)
}
if (onMouseDown) {
echartsInstance.on(ev.onMouseDown, onMouseDown)
}
if (onMouseMove) {
echartsInstance.on(ev.onMouseMove, onMouseMove)
}
if (onMouseOut) {
echartsInstance.on(ev.onMouseOut, onMouseOut)
}
if (onMouseOver) {
echartsInstance.on(ev.onMouseOver, onMouseOver)
}
if (onRendered) {
echartsInstance.on(ev.onRendered, onRendered)
}
if (onRestore) {
echartsInstance.on(ev.onRestore, onRestore)
}
if (onSelectChanged) {
echartsInstance.on(ev.onSelectChanged, onSelectChanged)
}
if (onTimelineChanged) {
echartsInstance.on(ev.onTimelineChanged, onTimelineChanged)
}
if (onTimelinePlayChanged) {
echartsInstance.on(ev.onTimelinePlayChanged, onTimelinePlayChanged)
}
}, [
onAxisAreaSelected,
onBrush,
onBrushEnd,
onBrushSelected,
onClick,
onContextMenu,
onDataRangeSelected,
onDataViewChanged,
onDataZoom,
onDoubleClick,
onDownplay,
onFinished,
onGeoSelectChanged,
onGeoSelected,
onGeoUnselected,
onGlobalCursorTaken,
onGlobalOut,
onHighlight,
onLegendInverseSelect,
onLegendScroll,
onLegendSelectChanged,
onLegendSelected,
onLegendUnselected,
onMagicTypeChanged,
onMouseDown,
onMouseMove,
onMouseOut,
onMouseOver,
onRendered,
onRestore,
onSelectChanged,
onTimelineChanged,
onTimelinePlayChanged,
//
started,
echartsInstance
])
return [setContainerRef, echartsRef.current]
}
async function getGlobalUse() {
const all = [
import('echarts/features'),
import('echarts/charts'),
import('echarts/components'),
import('echarts/renderers')
]
const promise = await Promise.all(all.map(m => m.then(m => Object.values(m))))
return promise.flat()
}
@brandanking-decently incredible contribution! I tested it and it solves all mentioned issues.
Already published under version v1.0.4
.
Thank you so much for taking care of it, really appreciate it 🙏
Description
Just a normal bar chart used, and
use
has been specified, however the console still reporting lots of unuseduse
cases. Worrying about this since that in dev mode it may accidentally let something run without specifying inuse
, hence will break in production if those are not imported in prod.Link to Reproduction
https://stackblitz.com/edit/vitejs-vite-ea2tby?file=src%2FApp.tsx,src%2FECharts.tsx&terminal=dev
Steps to reproduce
Visit the reprod link
JS Framework
React TS
Version
latest
Browser
Chrome 121
Operating System
Additional Information
No response