TAChart: line series is drawn improperly for multi-value data sources
Original Reporter info from Mantis: Marcin Wiazowski
-
Reporter name:
Original Reporter info from Mantis: Marcin Wiazowski
- Reporter name:
Description:
There is a problem in TLineSeries, when using multi-value data source: every label and every error bar is drawn multiple times, overwriting other, already drawn chart elements - in particular pointers.
In TLineSeries.Draw(), there is a loop:
DrawSingleLineInStack(ADrawer, 0); <==== FIRST CALL (FOR Y0)
for i := 0 to Source.YCount - 2 do begin
if Source.IsYErrorIndex(i+1) then Continue;
UpdateGraphPoints(i, FStacked);
DrawSingleLineInStack(ADrawer, i + 1); <==== NEXT CALLS (FOR Y1, Y2, ...)
end;
In each call to TLineSeries.DrawSingleLineInStack(..., AIndex) we have:
case FColorEach of
ceNone, cePoint:
DrawDefaultLines; <==== draws a line requested by the AIndex parameter
else
DrawColoredLines; <==== draws a line requested by the AIndex parameter
end;
DrawErrorBars(ADrawer); <==== draws ALL error bars EACH TIME, regardless of the AIndex parameter
DrawLabels(ADrawer); <==== draws ALL marks EACH TIME, regardless of the AIndex parameter
if ShowPoints then <==== draws a pointer requested by the AIndex parameter
DrawPointers(ADrawer, AIndex, FColorEach in [cePoint, cePointAndLineBefore, cePointAndLineAfter]);
The attached "Reproduce" application uses DoubleBuffered = False for the chart, so each drawing phase can be seen immediately.
To see the problem:
- launch the application and move its window to such a location, that the window is fully visible
- place a breakpoint at the beginning of the TLineSeries.DrawSingleLineInStack() method
- minimize the application's window and restore it again - it will be repainted, so breakpoint will be reached
- step over (F8) the TLineSeries.DrawSingleLineInStack() code (it will be called 4 times) and observe chart's behavior.
Drawing phases will be:
- pink horizontal line is drawn for Y0 = 2; error bars are drawn for Y0 = 2; marks are drawn for ALL Y values (should be drawn only for Y0 = 2); two green pointers are drawn for Y0 = 2
- pink horizontal line is drawn for Y1 = 4; error bars are drawn for Y0 = 2 (should not be drawn anymore), so pink horizontal line for Y1 = 4 and green pointers for Y0 = 2 become partially overwritten; marks are drawn for ALL Y values (should be drawn only for Y1 = 4); two green pointers are drawn for Y1 = 4
- similarly to 2)
- similarly to 2)
Final result can be seen on the attached Reproduce.png image:
- mark links (short red lines) are (re)drawn OVER green pointers for Y = 2, 4 and 6 (but not 8) - although all of them should be always located BELOW the pointers
- error bars (black lines) are (re)drawn OVER green pointers for Y = 2 and 4 - although they should be located BELOW the pointers
- error bars (black lines) are (re)drawn OVER the pink horizontal line for Y = 4 - although they should be located BELOW the line
To see a line series that is drawn properly, change data source's YCount from 4 to 1.
The cause of the problem is: "DrawErrorBars(ADrawer)" and "DrawLabels(ADrawer)" calls internally ignore the AIndex parameter.
Regards