@@ -5,7 +5,6 @@ import React, { ComponentPropsWithoutRef } from 'react'
5
5
6
6
import useGetLatest from '../hooks/useGetLatest'
7
7
import useIsomorphicLayoutEffect from '../hooks/useIsomorphicLayoutEffect'
8
- import useRect from '../hooks/useRect'
9
8
import Area from '../seriesTypes/Area'
10
9
import Bar from '../seriesTypes/Bar'
11
10
import Line from '../seriesTypes/Line'
@@ -35,7 +34,6 @@ import AxisLinear from './AxisLinear'
35
34
import Cursors from './Cursors'
36
35
import Tooltip from './Tooltip'
37
36
import Voronoi from './Voronoi'
38
- import useIsScrolling from '../hooks/useIsScrolling'
39
37
40
38
//
41
39
@@ -74,6 +72,9 @@ function defaultChartOptions<TDatum>(
74
72
groupingMode : options . groupingMode ?? 'primary' ,
75
73
showVoronoi : options . showVoronoi ?? false ,
76
74
defaultColors : options . defaultColors ?? defaultColorScheme ,
75
+ useIntersectionObserver : options . useIntersectionObserver ?? true ,
76
+ intersectionObserverRootMargin :
77
+ options . intersectionObserverRootMargin ?? '1000px' ,
77
78
}
78
79
}
79
80
@@ -84,28 +85,107 @@ export function Chart<TDatum>({
84
85
...rest
85
86
} : ComponentPropsWithoutRef < 'div' > & { options : ChartOptions < TDatum > } ) {
86
87
const options = defaultChartOptions ( userOptions )
87
- const [ containerElement , setContainerElement ] =
88
+ const [ chartElement , setContainerElement ] =
88
89
React . useState < HTMLDivElement | null > ( null )
89
- const parentElement = containerElement ?. parentElement
90
90
91
- const isScrolling = useIsScrolling ( 200 )
91
+ const containerEl = chartElement ?. parentElement
92
92
93
- const { width, height } = useRect ( parentElement , {
94
- enabled : ! isScrolling ,
95
- initialWidth : options . initialWidth ,
96
- initialHeight : options . initialHeight ,
97
- dimsOnly : true ,
93
+ const nearestScrollableParent = React . useMemo ( ( ) => {
94
+ const run = ( el ?: Element | null ) : Element | null => {
95
+ if ( ! el ) {
96
+ return null
97
+ }
98
+
99
+ const grandParent = el . parentElement
100
+
101
+ if ( ! grandParent ) {
102
+ return null
103
+ }
104
+
105
+ if ( grandParent . scrollHeight > grandParent . clientHeight ) {
106
+ const { overflow } = window . getComputedStyle ( grandParent )
107
+
108
+ if ( overflow . includes ( 'scroll' ) || overflow . includes ( 'auto' ) ) {
109
+ return grandParent
110
+ }
111
+ }
112
+
113
+ return run ( grandParent )
114
+ }
115
+
116
+ return run ( containerEl )
117
+ } , [ containerEl ] )
118
+
119
+ const [ { width, height } , setDims ] = React . useState ( {
120
+ width : options . initialWidth ,
121
+ height : options . initialHeight ,
98
122
} )
99
123
100
124
useIsomorphicLayoutEffect ( ( ) => {
101
- if ( parentElement ) {
102
- const computed = window . getComputedStyle ( parentElement )
125
+ if ( containerEl ) {
126
+ const computed = window . getComputedStyle ( containerEl )
103
127
104
128
if ( ! [ 'relative' , 'absolute' , 'fixed' ] . includes ( computed . position ) ) {
105
- parentElement . style . position = 'relative'
129
+ containerEl . style . position = 'relative'
106
130
}
107
131
}
108
- } , [ parentElement ] )
132
+ } , [ containerEl ] )
133
+
134
+ React . useEffect ( ( ) => {
135
+ if ( ! containerEl ) {
136
+ return
137
+ }
138
+
139
+ const observer = new ResizeObserver ( ( ) => {
140
+ const rect = containerEl ?. getBoundingClientRect ( )
141
+
142
+ if ( rect ) {
143
+ setDims ( {
144
+ width : rect . width ,
145
+ height : rect . height ,
146
+ } )
147
+ }
148
+ } )
149
+
150
+ observer . observe ( containerEl )
151
+
152
+ return ( ) => {
153
+ observer . unobserve ( containerEl )
154
+ }
155
+ } , [ containerEl ] )
156
+
157
+ const [ isIntersecting , setIsIntersecting ] = React . useState ( true )
158
+
159
+ React . useEffect ( ( ) => {
160
+ if ( ! containerEl || ! options . useIntersectionObserver ) return
161
+
162
+ let observer = new IntersectionObserver (
163
+ entries => {
164
+ for ( let entry of entries ) {
165
+ if ( entry . isIntersecting ) {
166
+ setIsIntersecting ( true )
167
+ } else {
168
+ setIsIntersecting ( false )
169
+ }
170
+ }
171
+ } ,
172
+ {
173
+ root : nearestScrollableParent ,
174
+ rootMargin : options . intersectionObserverRootMargin ,
175
+ }
176
+ )
177
+
178
+ observer . observe ( containerEl )
179
+
180
+ return ( ) => {
181
+ observer . unobserve ( containerEl )
182
+ }
183
+ } , [
184
+ containerEl ,
185
+ nearestScrollableParent ,
186
+ options . intersectionObserverRootMargin ,
187
+ options . useIntersectionObserver ,
188
+ ] )
109
189
110
190
return (
111
191
< div
@@ -119,7 +199,9 @@ export function Chart<TDatum>({
119
199
height,
120
200
} }
121
201
>
122
- < ChartInner options = { options } { ...{ width, height } } />
202
+ { isIntersecting ? (
203
+ < ChartInner options = { options } { ...{ width, height } } />
204
+ ) : null }
123
205
</ div >
124
206
)
125
207
}
0 commit comments