@@ -41,22 +41,20 @@ export default class CandleAreaView extends ChildrenView {
4141 private readonly _animation = new Animation ( { iterationCount : Infinity } ) . doFrame ( ( time ) => {
4242 this . _animationFrameTime = time
4343 const pane = this . getWidget ( ) . getPane ( )
44- pane . getChart ( ) . updatePane ( UpdateLevel . Main , pane . getId ( ) )
44+ // Ripple lives on the overlay canvas; avoid full main-layer repaints at 60fps.
45+ pane . getChart ( ) . updatePane ( UpdateLevel . Overlay , pane . getId ( ) )
4546 } )
4647
4748 override drawImp ( ctx : CanvasRenderingContext2D ) : void {
4849 const widget = this . getWidget ( )
4950 const pane = widget . getPane ( )
5051 const chart = pane . getChart ( )
51- const dataList = chart . getDataList ( )
52- const lastDataIndex = dataList . length - 1
5352 const bounding = widget . getBounding ( )
5453 const yAxis = pane . getYAxisComponentById ( )
5554 const styles = chart . getStyles ( ) . candle . area
5655 const coordinates : Coordinate [ ] = [ ]
5756 let minY = Number . MAX_SAFE_INTEGER
5857 let areaStartX : number = Number . MIN_SAFE_INTEGER
59- let ripplePointCoordinate : Nullable < Coordinate > = null
6058 this . eachChildren ( ( data ) => {
6159 const x = data . x
6260 const { current : kLineData } = data . data
@@ -68,9 +66,6 @@ export default class CandleAreaView extends ChildrenView {
6866 }
6967 coordinates . push ( { x, y } )
7068 minY = Math . min ( minY , y )
71- if ( data . dataIndex === lastDataIndex ) {
72- ripplePointCoordinate = { x, y }
73- }
7469 }
7570 } )
7671
@@ -112,37 +107,90 @@ export default class CandleAreaView extends ChildrenView {
112107 }
113108
114109 const pointStyles = styles . point
110+ const ripplePointCoordinate = this . _getLastPointCoordinate ( )
115111 if ( pointStyles . show && isValid ( ripplePointCoordinate ) ) {
116112 this . createFigure ( {
117113 name : 'circle' ,
118114 attrs : {
119- x : ripplePointCoordinate ! . x ,
120- y : ripplePointCoordinate ! . y ,
115+ x : ripplePointCoordinate . x ,
116+ y : ripplePointCoordinate . y ,
121117 r : pointStyles . radius
122118 } ,
123119 styles : {
124120 style : 'fill' ,
125121 color : pointStyles . color
126122 }
127123 } ) ?. draw ( ctx )
128- let rippleRadius = pointStyles . rippleRadius
129124 if ( pointStyles . animation ) {
130- rippleRadius = pointStyles . radius + this . _animationFrameTime / pointStyles . animationDuration * ( pointStyles . rippleRadius - pointStyles . radius )
131125 this . _animation . setDuration ( pointStyles . animationDuration ) . start ( )
126+ } else {
127+ this . stopAnimation ( )
132128 }
133- this . _ripplePoint
134- ?. setAttrs ( {
135- x : ripplePointCoordinate ! . x ,
136- y : ripplePointCoordinate ! . y ,
137- r : rippleRadius
138- } )
139- . setStyles ( { style : 'fill' , color : pointStyles . rippleColor } ) . draw ( ctx )
129+ // Keep overlay ripple in sync after main paints (scroll/zoom/data).
130+ chart . updatePane ( UpdateLevel . Overlay , pane . getId ( ) )
140131 } else {
141132 this . stopAnimation ( )
142133 }
143134 }
144135
136+ /**
137+ * Draw the last-price ripple on the overlay canvas so animation does not
138+ * repaint candles, grid, and indicators on every frame.
139+ */
140+ drawRipple ( ctx : CanvasRenderingContext2D ) : void {
141+ const chart = this . getWidget ( ) . getPane ( ) . getChart ( )
142+ if ( chart . getStyles ( ) . candle . type !== 'area' ) {
143+ this . stopAnimation ( )
144+ return
145+ }
146+ const pointStyles = chart . getStyles ( ) . candle . area . point
147+ const ripplePointCoordinate = this . _getLastPointCoordinate ( )
148+ if ( ! pointStyles . show || ! isValid ( ripplePointCoordinate ) ) {
149+ this . stopAnimation ( )
150+ return
151+ }
152+
153+ let rippleRadius = pointStyles . rippleRadius
154+ if ( pointStyles . animation ) {
155+ rippleRadius = pointStyles . radius + this . _animationFrameTime / pointStyles . animationDuration * ( pointStyles . rippleRadius - pointStyles . radius )
156+ this . _animation . setDuration ( pointStyles . animationDuration ) . start ( )
157+ } else {
158+ this . stopAnimation ( )
159+ }
160+
161+ this . _ripplePoint
162+ ?. setAttrs ( {
163+ x : ripplePointCoordinate . x ,
164+ y : ripplePointCoordinate . y ,
165+ r : rippleRadius
166+ } )
167+ . setStyles ( { style : 'fill' , color : pointStyles . rippleColor } ) . draw ( ctx )
168+ }
169+
145170 stopAnimation ( ) : void {
146171 this . _animation . stop ( )
147172 }
173+
174+ private _getLastPointCoordinate ( ) : Nullable < Coordinate > {
175+ const widget = this . getWidget ( )
176+ const pane = widget . getPane ( )
177+ const chart = pane . getChart ( )
178+ const dataList = chart . getDataList ( )
179+ const lastDataIndex = dataList . length - 1
180+ if ( lastDataIndex < 0 ) {
181+ return null
182+ }
183+ const styles = chart . getStyles ( ) . candle . area
184+ const yAxis = pane . getYAxisComponentById ( )
185+ let coordinate : Nullable < Coordinate > = null
186+ this . eachChildren ( ( data ) => {
187+ if ( data . dataIndex === lastDataIndex ) {
188+ const value = data . data . current ?. [ styles . value ]
189+ if ( isNumber ( value ) ) {
190+ coordinate = { x : data . x , y : yAxis . convertToPixel ( value ) }
191+ }
192+ }
193+ } )
194+ return coordinate
195+ }
148196}
0 commit comments