Page 1 of 1
Dynamic LinePen
Posted: Wed May 20, 2015 4:57 pm
by 16573504
Hi.
I am using TLineSeries to display a series of X/Y values. My customer wants the LineStyle for the connecting lines between values for all x-values below a certain threshold value to be drawn in the "dotted" style.
In my first attempts I tried to "misuse" the "OnGetPointerStyle" event like this:
Code: Select all
Teengine::TSeriesPointerStyle __fastcall ResultDiagramCompositeView::OnGetPointerStyle(Teengine::TChartSeries* sender, int valueIndex)
{
TSeriesPointerStyle pointerStyle = TSeriesPointerStyle::psCircle;
if(TLineSeries* const lineSeries = dynamic_cast<TLineSeries*>(sender))
{
double n = lineSeries->XValues->Items[valueIndex];
if(n >= 1.5)
{
lineSeries->LinePen->Style = psSolid;
}
else
lineSeries->LinePen->Style = psDot;
}
return pointerStyle;
}
However this is far from optimal because not always are there points near the threshold value (currently I generate some via interpolation) and the LineStyle changes when I move the mosue cursor over the diagram (redraw problems).
Is there a way to achieve this in a clean way?
Thanks a lot!
Best Regards
Eike Petersen
P.S: I am using TeeChart Pro 2015 VCL with C++ Builder XE7
Re: Dynamic LinePen
Posted: Thu May 21, 2015 2:39 pm
by yeray
Hello,
Here it is a similar question discussed. It's on Java but the same applies here:
http://www.teechart.net/support/viewtop ... 86&p=59469
FYI, here it is an improved version of the Interpolation algorithm:
http://www.teechart.net/support/viewtop ... 220#p68220
If you still find problems with it, don't hesitate to let us know.
Re: Dynamic LinePen
Posted: Fri May 22, 2015 3:43 pm
by 16573504
Uhm. I'm not sure that's the same problem. I need to change the LineStyle (psSolid, psDash etc.) - not the color. Or did I miss something? Can you provide me with a actual example (Delphi or C++) in which you change the line style for each x/y value?
Re: Dynamic LinePen
Posted: Tue May 26, 2015 11:44 am
by yeray
Hello,
Take a look at the attached Delphi example:
I'm calculating the interpolation XValues (interpPoints) for a given YValue (determined by the colorLine) and adding them to a secondary series (interpLine). Then, maintaining this series I can hide the original series (sourceLine).
This is how it looks:
- interpolated.png (33.56 KiB) Viewed 16840 times
Re: Dynamic LinePen
Posted: Tue May 26, 2015 2:15 pm
by 16573504
Hi Yeray.
Thank you for your example. In your example you are using 'GetPointerStyle' too (as I do), and unfortunately you do not change the LineStyle in that example.
Here is my current code:
-- snip --
Code: Select all
Teengine::TSeriesPointerStyle __fastcall ResultDiagramCompositeView::OnGetPointerStyle(Teengine::TChartSeries* sender, int valueIndex)
{
TSeriesPointerStyle pointerStyle = TSeriesPointerStyle::psNothing;
if(TLineSeries* const lineSeries = dynamic_cast<TLineSeries*>(sender))
{
lineSeries->LinePen->Style = psDot;
if(valueIndex > 0)
{
double n = lineSeries->XValues->Items[valueIndex];
if(n >= 1.5)
{
lineSeries->LinePen->Style = psSolid;
}
}
}
return pointerStyle;
}
-- snap --
This works, but there seems to be a refresh problem. It is drawn correctly the first time, but if you move the mouse cursor over the diagram window the 'dotted' style disappears.
I attached two screenshots to illustrate that.
I am using the latest version of TeeChart 2015 Pro for VCL.
Re: Dynamic LinePen
Posted: Wed May 27, 2015 8:17 am
by yeray
Hello,
I see I have misread the initial post. The example I did was considering a threshold given by an horizontal line (an Y value) so I was calculating all the points crossing that line. Besides, I was changing the line color instead of the style.
To consider a threshold given by a vertical line (an X value) - since we are talking about a regular line series, and not a THorizLineSeries - we only have to calculate one crossing point. This part would be a simpler than what I did in that example.
To change the line style instead of changing the line color you should do it at OnGetPointerStyle. Changing the color of the line/pointer can be done through the according arrays but there isn't an array in the series to determine the line style; there's a unique LinePen.Style property in the series, so you should use the OnGetPointerStyle to change that series property depending on the valueindex being drawn.
Here note when OnGetPointerStyle is fired for a ValueIndex the line segment from ValueIndex-1 to ValueIndex+1 has been already drawn. So, at the time OnGetPointerStyle is fired you should interrogate XValue[ValueIndex+1] to set the series LinePen.Style for the next segment that will be drawn.
With this trick, the only question open is what happens with the first segment; how to set the according LinePen.Style for the first segment? You can use OnBeforeDrawSeries for that.
It would be something like this:
Code: Select all
const threshold = 1.5;
function TForm1.LineGetPointerStyle(Sender:TChartSeries; ValueIndex:Integer): TSeriesPointerStyle;
begin
lineSeries.LinePen.Style:=psSolid;
if (ValueIndex+1>-1) and (ValueIndex+1<Sender.Count) then
begin
if Sender.XValue[ValueIndex+1] < threshold then
lineSeries.LinePen.Style:=psDot;
end;
end;
procedure TForm1.BeforeDrawSeries(Sender: TObject);
begin
if (lineSeries<>nil) and (lineSeries.Count>0) and (lineSeries.XValue[0] < threshold) then
interpLine.LinePen.Style:=psDot
else
interpLine.LinePen.Style:=psSolid;
end;
So, your code snipped looks fine to me. I'd only change valueIndex for valueIndex+1 at OnGetPointerStyle and use BeforeDrawSeries as above.
If you still find problems with it, don't hesitate to let us know and keep in mind a simple example project we can run as-is would help us to reproduce the situation and try to find a more concrete solution for you.
Re: Dynamic LinePen
Posted: Wed May 27, 2015 10:37 am
by 16573504
Sigh. I appreciate your efforts, but did you read my last posting? I have everything working *except* that the changed "LineStyle" reverts when you move the mouse cursor over the diagram window (you don't even have to click or interact, just moving the cursor is enough). I even posted two screenshots where you can see that in one picture the line series have a first segment with the "dot" line style and a second picture in which the line style is solid again. This seems to be a refresh problem. As soon as the mouse cursor enters the diagram any manipulation of the line style in "OnGetPointerStyle" is discarded.
Re: Dynamic LinePen
Posted: Wed May 27, 2015 12:21 pm
by yeray
Hello,
ix07 wrote:Sigh. I appreciate your efforts, but did you read my last posting? I have everything working *except* that the changed "LineStyle" reverts when you move the mouse cursor over the diagram window (you don't even have to click or interact, just moving the cursor is enough). I even posted two screenshots where you can see that in one picture the line series have a first segment with the "dot" line style and a second picture in which the line style is solid again. This seems to be a refresh problem. As soon as the mouse cursor enters the diagram any manipulation of the line style in "OnGetPointerStyle" is discarded.
I'm sorry, I was trying to explain the theory of the solution. I don't know if that's exactly what you've implemented but I assume it's similar. So the explanation was for anyone trying to achieve a similar effect than the one you explained.
I've modified the example to also implement what I tried to explain in the last post. So now the example includes two ColorLines, an horizontal and a vertical. The horizontal line does the same than before: the points/line segments below the colorline are drawn in red.
The vertical line does what I understand you are trying to achieve: the points/line segments on the left of the colorline are drawn using a circle pointer and dashed line.
It seems to work fine for me here, and I can move the mouse around the chart without missing any of the features:
- interpolate.png (37.84 KiB) Viewed 16802 times
If you find your solution should be correct but it still doesn't work as expected, I'd ask you to arrange a simple example project we can run as-is to reproduce the problem here, as mentioned at the end of my last post.
Re: Dynamic LinePen
Posted: Thu May 28, 2015 1:16 pm
by 16573504
Hi.
I made an example project where you can (hopefully) see the problem.
If you start the resulting application and make sure that the mouse cursor is not above the diagram when starting the application you will see a correctly drawn diagram. If you move the mouse cursor over the diagram window the first segment line style reverts to psSolid.
Thank you for help so far.
Re: Dynamic LinePen
Posted: Thu May 28, 2015 1:59 pm
by 16573504
I simplified the example project and removed all unnecessary code.
Re: Dynamic LinePen
Posted: Fri May 29, 2015 9:40 am
by yeray
Hello,
Note OnBeforeDrawSeries is called once and it's called by the TChart. It's not called from the Series.
So TObject* sender is the chart, not the Series.
This works for me:
Code: Select all
void __fastcall TForm1::OnBeforeDrawSeries(TObject* sender)
{
if(TChart* const chart = dynamic_cast<TChart*>(sender)) {
for (int i = 0; i < chart->SeriesCount(); i++) {
if(TLineSeries* const lineSeries = dynamic_cast<TLineSeries*>(chart->Series[i]))
lineSeries->LinePen->Style = psDot;
}
}
/*if(TLineSeries* const lineSeries = dynamic_cast<TLineSeries*>(sender))
lineSeries->LinePen->Style = psDot;*/
}
Re: Dynamic LinePen
Posted: Fri May 29, 2015 10:27 am
by 16573504
You are absolutely right - i didn't see that.
Thank you very much for your help. Much appreciated!
Re: Dynamic LinePen
Posted: Fri May 29, 2015 10:38 am
by yeray
Hi,
ix07 wrote:You are absolutely right - i didn't see that.
Thank you very much for your help. Much appreciated!
You are welcome! I'm glad to hear it finally works as you wish.