@@ -64,67 +64,66 @@ const filterEventData = (gd, eventData, event) => {
64
64
return filteredEventData ;
65
65
} ;
66
66
67
- function generateId ( ) {
68
- const charAmount = 36 ;
69
- const length = 7 ;
70
- return (
71
- 'graph-' +
72
- Math . random ( )
73
- . toString ( charAmount )
74
- . substring ( 2 , length )
75
- ) ;
76
- }
77
-
78
67
/**
79
68
* Graph can be used to render any plotly.js-powered data visualization.
80
69
*
81
70
* You can define callbacks based on user interaction with Graphs such as
82
71
* hovering, clicking or selecting
83
72
*/
84
- const GraphWithDefaults = props => {
85
- const id = props . id ? props . id : generateId ( ) ;
86
- return < PlotlyGraph { ...props } id = { id } /> ;
87
- } ;
88
-
89
73
class PlotlyGraph extends Component {
90
74
constructor ( props ) {
91
75
super ( props ) ;
76
+ this . gd = React . createRef ( ) ;
92
77
this . bindEvents = this . bindEvents . bind ( this ) ;
93
78
this . _hasPlotted = false ;
79
+ this . _prevGd = null ;
94
80
this . graphResize = this . graphResize . bind ( this ) ;
95
81
}
96
82
97
83
plot ( props ) {
98
- const { figure, id , animate, animation_options, config} = props ;
99
- const gd = document . getElementById ( id ) ;
84
+ const { figure, animate, animation_options, config} = props ;
85
+ const gd = this . gd . current ;
100
86
101
87
if (
102
88
animate &&
103
89
this . _hasPlotted &&
104
90
figure . data . length === gd . data . length
105
91
) {
106
- return Plotly . animate ( id , figure , animation_options ) ;
92
+ return Plotly . animate ( gd , figure , animation_options ) ;
107
93
}
108
- return Plotly . react ( id , {
94
+ return Plotly . react ( gd , {
109
95
data : figure . data ,
110
96
layout : clone ( figure . layout ) ,
111
97
frames : figure . frames ,
112
98
config : config ,
113
99
} ) . then ( ( ) => {
114
- if ( ! this . _hasPlotted ) {
115
- // double-check gd hasn't been unmounted
116
- const gd = document . getElementById ( id ) ;
117
- if ( gd ) {
118
- this . bindEvents ( ) ;
119
- Plotly . Plots . resize ( gd ) ;
120
- this . _hasPlotted = true ;
100
+ const gd = this . gd . current ;
101
+
102
+ // double-check gd hasn't been unmounted
103
+ if ( ! gd ) {
104
+ return ;
105
+ }
106
+
107
+ // in case we've made a new DOM element, transfer events
108
+ if ( this . _hasPlotted && gd !== this . _prevGd ) {
109
+ if ( this . _prevGd && this . _prevGd . removeAllListeners ) {
110
+ this . _prevGd . removeAllListeners ( ) ;
111
+ Plotly . purge ( this . _prevGd ) ;
121
112
}
113
+ this . _hasPlotted = false ;
114
+ }
115
+
116
+ if ( ! this . _hasPlotted ) {
117
+ this . bindEvents ( ) ;
118
+ Plotly . Plots . resize ( gd ) ;
119
+ this . _hasPlotted = true ;
120
+ this . _prevGd = gd ;
122
121
}
123
122
} ) ;
124
123
}
125
124
126
125
extend ( props ) {
127
- const { id , extendData} = props ;
126
+ const { extendData} = props ;
128
127
let updateData , traceIndices , maxPoints ;
129
128
if ( Array . isArray ( extendData ) && typeof extendData [ 0 ] === 'object' ) {
130
129
[ updateData , traceIndices , maxPoints ] = extendData ;
@@ -143,20 +142,21 @@ class PlotlyGraph extends Component {
143
142
traceIndices = generateIndices ( updateData ) ;
144
143
}
145
144
146
- return Plotly . extendTraces ( id , updateData , traceIndices , maxPoints ) ;
145
+ const gd = this . gd . current ;
146
+ return Plotly . extendTraces ( gd , updateData , traceIndices , maxPoints ) ;
147
147
}
148
148
149
149
graphResize ( ) {
150
- const graphDiv = document . getElementById ( this . props . id ) ;
151
- if ( graphDiv ) {
152
- Plotly . Plots . resize ( graphDiv ) ;
150
+ const gd = this . gd . current ;
151
+ if ( gd ) {
152
+ Plotly . Plots . resize ( gd ) ;
153
153
}
154
154
}
155
155
156
156
bindEvents ( ) {
157
- const { id , setProps, clear_on_unhover} = this . props ;
157
+ const { setProps, clear_on_unhover} = this . props ;
158
158
159
- const gd = document . getElementById ( id ) ;
159
+ const gd = this . gd . current ;
160
160
161
161
gd . on ( 'plotly_click' , eventData => {
162
162
const clickData = filterEventData ( gd , eventData , 'click' ) ;
@@ -212,8 +212,10 @@ class PlotlyGraph extends Component {
212
212
}
213
213
214
214
componentWillUnmount ( ) {
215
- if ( this . eventEmitter ) {
216
- this . eventEmitter . removeAllListeners ( ) ;
215
+ const gd = this . gd . current ;
216
+ if ( gd && gd . removeAllListeners ) {
217
+ gd . removeAllListeners ( ) ;
218
+ Plotly . purge ( gd ) ;
217
219
}
218
220
window . removeEventListener ( 'resize' , this . graphResize ) ;
219
221
}
@@ -262,6 +264,7 @@ class PlotlyGraph extends Component {
262
264
< div
263
265
key = { id }
264
266
id = { id }
267
+ ref = { this . gd }
265
268
data-dash-is-loading = {
266
269
( loading_state && loading_state . is_loading ) || undefined
267
270
}
@@ -279,6 +282,7 @@ const graphPropTypes = {
279
282
* components in an app.
280
283
*/
281
284
id : PropTypes . string ,
285
+
282
286
/**
283
287
* Data from latest click event. Read-only.
284
288
*/
@@ -672,10 +676,8 @@ const graphDefaultProps = {
672
676
config : { } ,
673
677
} ;
674
678
675
- GraphWithDefaults . propTypes = graphPropTypes ;
676
679
PlotlyGraph . propTypes = graphPropTypes ;
677
680
678
- GraphWithDefaults . defaultProps = graphDefaultProps ;
679
681
PlotlyGraph . defaultProps = graphDefaultProps ;
680
682
681
- export default GraphWithDefaults ;
683
+ export default PlotlyGraph ;
0 commit comments