@@ -43,10 +43,10 @@ function limitLineToArea(p1, p2, area) {
4343}
4444
4545export default class LineAnnotation extends Element {
46- intersects ( x , y , epsilon = 0.001 ) {
46+ intersects ( x , y , epsilon = 0.001 , useFinalPosition ) {
4747 // Adapted from https://stackoverflow.com/a/6853926/25507
4848 const sqr = v => v * v ;
49- const { x : x1 , y : y1 , x2, y2} = this ;
49+ const { x : x1 , y : y1 , x2, y2} = this . getProps ( [ 'x' , 'y' , 'x2' , 'y2' ] , useFinalPosition ) ;
5050 const dx = x2 - x1 ;
5151 const dy = y2 - y1 ;
5252 const lenSq = sqr ( dx ) + sqr ( dy ) ;
@@ -65,29 +65,28 @@ export default class LineAnnotation extends Element {
6565 return ( sqr ( x - xx ) + sqr ( y - yy ) ) < epsilon ;
6666 }
6767
68- labelIsVisible ( chartArea ) {
69- const label = this . options . label ;
70-
71- const inside = ! chartArea || isLineInArea ( this , chartArea ) ;
72- return inside && isLabelVisible ( label ) ;
68+ labelIsVisible ( useFinalPosition , chartArea ) {
69+ if ( ! this . labelVisible ) {
70+ return false ;
71+ }
72+ return ! chartArea || isLineInArea ( this . getProps ( [ 'x' , 'y' , 'x2' , 'y2' ] , useFinalPosition ) , chartArea ) ;
7373 }
7474
75- isOnLabel ( mouseX , mouseY ) {
76- const { labelRect} = this ;
77- if ( ! labelRect || ! this . labelIsVisible ( ) ) {
75+ isOnLabel ( mouseX , mouseY , useFinalPosition ) {
76+ if ( ! this . labelIsVisible ( useFinalPosition ) ) {
7877 return false ;
7978 }
80-
81- const { x, y} = rotated ( { x : mouseX , y : mouseY } , labelRect , - labelRect . rotation ) ;
82- const w2 = labelRect . width / 2 ;
83- const h2 = labelRect . height / 2 ;
84- return x >= labelRect . x - w2 && x <= labelRect . x + w2 &&
85- y >= labelRect . y - h2 && y <= labelRect . y + h2 ;
79+ const { labelX , labelY , labelWidth , labelHeight , labelRotation } = this . getProps ( [ 'labelX' , 'labelY' , 'labelWidth' , 'labelHeight' , 'labelRotation' ] , useFinalPosition ) ;
80+ const { x, y} = rotated ( { x : mouseX , y : mouseY } , { x : labelX , y : labelY } , - labelRotation ) ;
81+ const w2 = labelWidth / 2 ;
82+ const h2 = labelHeight / 2 ;
83+ return x >= labelX - w2 && x <= labelX + w2 &&
84+ y >= labelY - h2 && y <= labelY + h2 ;
8685 }
8786
88- inRange ( x , y ) {
87+ inRange ( mouseX , mouseY , useFinalPosition ) {
8988 const epsilon = this . options . borderWidth || 1 ;
90- return this . intersects ( x , y , epsilon ) || this . isOnLabel ( x , y ) ;
89+ return this . intersects ( mouseX , mouseY , epsilon , useFinalPosition ) || this . isOnLabel ( mouseX , mouseY , useFinalPosition ) ;
9190 }
9291
9392 getCenterPoint ( ) {
@@ -116,9 +115,9 @@ export default class LineAnnotation extends Element {
116115 }
117116
118117 drawLabel ( ctx , chartArea ) {
119- if ( this . labelIsVisible ( chartArea ) ) {
118+ if ( this . labelIsVisible ( false , chartArea ) ) {
120119 ctx . save ( ) ;
121- applyLabel ( ctx , this , chartArea ) ;
120+ applyLabel ( ctx , this ) ;
122121 ctx . restore ( ) ;
123122 }
124123 }
@@ -153,9 +152,15 @@ export default class LineAnnotation extends Element {
153152 }
154153 }
155154 const inside = isLineInArea ( { x, y, x2, y2} , chart . chartArea ) ;
156- return inside
155+ const properties = inside
157156 ? limitLineToArea ( { x, y} , { x : x2 , y : y2 } , chart . chartArea )
158157 : { x, y, x2, y2, width : Math . abs ( x2 - x ) , height : Math . abs ( y2 - y ) } ;
158+ const label = options . label ;
159+ properties . labelVisible = ! ! isLabelVisible ( label ) ;
160+ if ( properties . labelVisible ) {
161+ return loadLabelRect ( properties , chart , label ) ;
162+ }
163+ return properties ;
159164 }
160165}
161166
@@ -213,39 +218,51 @@ LineAnnotation.defaultRoutes = {
213218 borderColor : 'color'
214219} ;
215220
221+ function loadLabelRect ( line , chart , options ) {
222+ // TODO: v2 remove support for xPadding and yPadding
223+ const { padding : lblPadding , xPadding, yPadding, borderWidth} = options ;
224+ const padding = getPadding ( lblPadding , xPadding , yPadding ) ;
225+ const textSize = measureLabelSize ( chart . ctx , options ) ;
226+ const width = textSize . width + padding . width + borderWidth ;
227+ const height = textSize . height + padding . height + borderWidth ;
228+ const labelRect = calculateLabelPosition ( line , options , { width, height, padding} , chart . chartArea ) ;
229+ line . labelX = labelRect . x ;
230+ line . labelY = labelRect . y ;
231+ line . labelWidth = labelRect . width ;
232+ line . labelHeight = labelRect . height ;
233+ line . labelRotation = labelRect . rotation ;
234+ line . labelPadding = padding ;
235+ line . labelTextSize = textSize ;
236+ return line ;
237+ }
238+
216239function calculateAutoRotation ( line ) {
217240 const { x, y, x2, y2} = line ;
218241 const rotation = Math . atan2 ( y2 - y , x2 - x ) ;
219242 // Flip the rotation if it goes > PI/2 or < -PI/2, so label stays upright
220243 return rotation > PI / 2 ? rotation - PI : rotation < PI / - 2 ? rotation + PI : rotation ;
221244}
222245
223- function applyLabel ( ctx , line , chartArea ) {
224- const label = line . options . label ;
225- // TODO: v2 remove support for xPadding and yPadding
226- const { padding : lblPadding , xPadding, yPadding, borderWidth} = label ;
227- const padding = getPadding ( lblPadding , xPadding , yPadding ) ;
228- const labelSize = measureLabelSize ( ctx , label ) ;
229- const width = labelSize . width + padding . width + borderWidth ;
230- const height = labelSize . height + padding . height + borderWidth ;
231- const rect = line . labelRect = calculateLabelPosition ( line , { width, height, padding} , chartArea ) ;
246+ function applyLabel ( ctx , line ) {
247+ const { labelX, labelY, labelWidth, labelHeight, labelRotation, labelPadding, labelTextSize, options} = line ;
248+ const label = options . label ;
232249
233- ctx . translate ( rect . x , rect . y ) ;
234- ctx . rotate ( rect . rotation ) ;
250+ ctx . translate ( labelX , labelY ) ;
251+ ctx . rotate ( labelRotation ) ;
235252
236253 const boxRect = {
237- x : - ( width / 2 ) ,
238- y : - ( height / 2 ) ,
239- width,
240- height
254+ x : - ( labelWidth / 2 ) ,
255+ y : - ( labelHeight / 2 ) ,
256+ width : labelWidth ,
257+ height : labelHeight
241258 } ;
242259 drawBox ( ctx , boxRect , label ) ;
243260
244261 const labelTextRect = {
245- x : - ( width / 2 ) + padding . left + borderWidth / 2 ,
246- y : - ( height / 2 ) + padding . top + borderWidth / 2 ,
247- width : labelSize . width ,
248- height : labelSize . height
262+ x : - ( labelWidth / 2 ) + labelPadding . left + label . borderWidth / 2 ,
263+ y : - ( labelHeight / 2 ) + labelPadding . top + label . borderWidth / 2 ,
264+ width : labelTextSize . width ,
265+ height : labelTextSize . height
249266 } ;
250267 drawLabel ( ctx , labelTextRect , label ) ;
251268}
@@ -259,15 +276,14 @@ function getPadding(padding, xPadding, yPadding) {
259276 return toPadding ( tempPadding ) ;
260277}
261278
262- function calculateLabelPosition ( line , sizes , chartArea ) {
279+ function calculateLabelPosition ( line , label , sizes , chartArea ) {
263280 const { width, height, padding} = sizes ;
264- const label = line . options . label ;
265- const { xAdjust, yAdjust, position} = label ;
281+ const { xAdjust, yAdjust} = label ;
266282 const p1 = { x : line . x , y : line . y } ;
267283 const p2 = { x : line . x2 , y : line . y2 } ;
268284 const rotation = label . rotation === 'auto' ? calculateAutoRotation ( line ) : toRadians ( label . rotation ) ;
269285 const size = rotatedSize ( width , height , rotation ) ;
270- const t = calculateT ( line , position , { labelSize : size , padding} , chartArea ) ;
286+ const t = calculateT ( line , label , { labelSize : size , padding} , chartArea ) ;
271287 const pt = pointInLine ( p1 , p2 , t ) ;
272288 const xCoordinateSizes = { size : size . w , min : chartArea . left , max : chartArea . right , padding : padding . left } ;
273289 const yCoordinateSizes = { size : size . h , min : chartArea . top , max : chartArea . bottom , padding : padding . top } ;
@@ -290,13 +306,12 @@ function rotatedSize(width, height, rotation) {
290306 } ;
291307}
292308
293- function calculateT ( line , position , sizes , chartArea ) {
309+ function calculateT ( line , label , sizes , chartArea ) {
294310 let t = 0.5 ;
295311 const space = spaceAround ( line , chartArea ) ;
296- const label = line . options . label ;
297- if ( position === 'start' ) {
312+ if ( label . position === 'start' ) {
298313 t = calculateTAdjust ( { w : line . x2 - line . x , h : line . y2 - line . y } , sizes , label , space ) ;
299- } else if ( position === 'end' ) {
314+ } else if ( label . position === 'end' ) {
300315 t = 1 - calculateTAdjust ( { w : line . x - line . x2 , h : line . y - line . y2 } , sizes , label , space ) ;
301316 }
302317 return t ;
@@ -320,27 +335,23 @@ function spaceAround(line, chartArea) {
320335 return {
321336 x : Math . min ( l , r ) ,
322337 y : Math . min ( t , b ) ,
323- dx : l < r ? 1 : - 1 ,
324- dy : t < b ? 1 : - 1
338+ dx : l <= r ? 1 : - 1 ,
339+ dy : t <= b ? 1 : - 1
325340 } ;
326341}
327342
328343function adjustLabelCoordinate ( coordinate , labelSizes ) {
329344 const { size, min, max, padding} = labelSizes ;
330345 const halfSize = size / 2 ;
331-
332346 if ( size > max - min ) {
333347 // if it does not fit, display as much as possible
334348 return ( max + min ) / 2 ;
335349 }
336-
337350 if ( min >= ( coordinate - padding - halfSize ) ) {
338351 coordinate = min + padding + halfSize ;
339352 }
340-
341353 if ( max <= ( coordinate + padding + halfSize ) ) {
342354 coordinate = max - padding - halfSize ;
343355 }
344-
345356 return coordinate ;
346357}
0 commit comments