Recent

Author Topic: Drawing on the chart  (Read 6589 times)

kapibara

  • Hero Member
  • *****
  • Posts: 610
Drawing on the chart
« on: December 12, 2013, 10:18:29 pm »
I want to to draw a straight line on the chart with the mouse. What Series is best to use here?
  • TFuncSeries
  • TLineSeries
  • TUserDrawnSeries
Or something else?

I dont know exactly how to do the drawing, just that a straight line should follow the mouse. When the mousebutton is released the slope of line should be finalized and stay on the chart. Any hint or code is appreciated.

The values of the line should be accessible as for a usual line series.
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 11923
Re: Drawing on the chart
« Reply #1 on: December 12, 2013, 11:11:27 pm »
The way how I understand your question is that you want to draw a straight line between the mouse-down point and the current mouse position and display the slope of this curve.

The most complete, ready-to-use solution in TAChart for this job is with a TDataPointDistanceTool. It has all the drawing code built-in and displays a label along the connecting line between the starting and current mouse point. By default, the text in the label is the distance between the points, but there is an event "GetDistanceText" to taylor the text:

Code: [Select]
procedure TForm1.ChartToolset1DataPointDistanceTool1GetDistanceText(
  ASender: TDataPointDistanceTool; var AText: String);
var
  m: Double;
begin
  with ASender do
    if PointStart.GraphPos.X = PointEnd.GraphPos.X then
      AText := 'Slope = Infinity'
    else begin
      m := (PointEnd.GraphPos.Y - PointStart.GraphPos.Y) /
              (PointEnd.GraphPos.X - PointStart.GraphPos.X);
      AText := Format('Slope = %f', [m]);
    end;
end;

To have more formatting options for the slope label I'd recommend to set the DrawingMode of the tool to dmNormal. You may want to turn off the begin and end markers of the connecting line (PointerEnd.Visible := false, PointerStart.Visible := false). And to see the slope label after mouse-up activate the Option dpdoPermanent. And of course, you have to select the Shift parameters to show the tool, e.g. ssShift+ssLeft for the Shift key together with mouse-down.

After that, TAChart does all the rest...

kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: Drawing on the chart
« Reply #2 on: December 13, 2013, 04:57:42 pm »
That's exactly what I wanted to do. Very convenient tool.

But I get an exception when using the tool if its created at runtime.

This is how I create the tool and add it to the ChartToolSet:

Code: [Select]
procedure TForm1.ToolButton1Click(Sender: TObject);
var
  aDataPointDistanceTool: TDataPointDistanceTool;
begin
  aDataPointDistanceTool:= TDataPointDistanceTool.Create(Self);
  aDataPointDistanceTool.Name:='RuntimeDataPointDistanceTool';
  aDataPointDistanceTool.Options:=[dpdoPermanent];
  aDataPointDistanceTool.Shift:=[ssCtrl,ssLeft];
  aDataPointDistanceTool.Marks.Visible:=False;

  ChartToolset1.Tools.Add(aDataPointDistanceTool);
end;


Attached an example that demonstrates good behavior at designtime and my problem at runtime.
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 11923
Re: Drawing on the chart
« Reply #3 on: December 13, 2013, 06:09:32 pm »
There was a similar discussion regarding run-time creation of transformations recently when someone had the same issue.

The solution is the same: Don't add the created tool to the Tools list of the toolset, but assign the Toolset to the Tools property of the tool instead.

Code: [Select]
  aDataPointdistanceTool.Tools := ChartToolset1;

In this way, the tool gets to know the toolset it belongs to. When, for example, a tool is activated it has to deactivate the other tools. Therefore, each tool must know its parent toolset. If it does not, the tool's Toolset is nil and the program crashes when the tool accesses the toolset.

kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: Drawing on the chart
« Reply #4 on: December 13, 2013, 07:14:30 pm »
There it is, now it works. Great!

Last year you had a discussion with Ask about moving the endpoints after the line is drawn.

Did you find a solution for this? I also need to reposition the endpoints. Sometimes the whole line must be dragged to new position.

Excuse me for too many questions. Many  features are sparingly documented and I try to learn as much as possible. TAChart is extensive and deserves more documentation. As my understanding increases, there will be more tutorials and demos to come. I like to write such stuff.

Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 11923
Re: Drawing on the chart
« Reply #5 on: December 13, 2013, 09:45:29 pm »
Quote
Last year you had a discussion with Ask about moving the endpoints after the line is drawn. Did you find a solution for this?
No, we did not continue that discussion as there was no immediate need for myself.

Quote
I also need to reposition the endpoints. Sometimes the whole line must be dragged to new position.
At the moment the only thing you can do is to redraw the entire line.

Or you re-build that feature piece by piece without the DataPointDistanceTool:
  • Use a userdefined ChartTool to be activated by ssShift and ssLeft (or similiar), initially not active
  • In the Before- or AfterMouseDown or Before- or AfterKeyDown events of the tool (whichever comes first) create a TLineSeries, add it to the chart. In the MouseDown event add the current mouse position to the series. Note that you have to transform the pixels of the mouse coordinates to graph coordinates by using ImageToGraph.
  • In the Before- or AfterMouseMove event: if the series contains only one point add the current mouse point (or skip if the point did not change). If there are already two points replace the second point with the current one. The series draws the connecting line.
  • In MouseUp or KeyUp calculate the slope of the line and prepare the text to be displayed as a marker. Then calculated the intermediate point between the end points, add it to the series and use the calculated slope text as a mark for this data point. Exchange it with the last point; in the end, the points must be in order start point - intermediate point with label - end point.
  • For later editing of the end points you can use a data point  drag tool. In its mouse move events you must make sure that the center point is not dragged, and when you drag one of the end points, the intermediate point must be recalculated to be always in the middle between both end points. Otherwise there will be a kink in the line. And of course, you must recalculate the slope and its label, and update the mark text of the intermediate point.
  • Maybe there should also be a toolbutton or so to hide the slope line.
Not tested, but it could work. It requires some coding, though...

If your main intention is to calculate the slope of a series of measured data, you could also consider using a TFitSeries set up for linear fitting with two parameters (=straight line). In one of my programs I added two vertical constant line series and a data point drag tool which allows to define the fitting range by dragging the vertical limiting bars. Works quite nicely.

Quote
As my understanding increases, there will be more tutorials and demos to come. I like to write such stuff.
Great!

 

TinyPortal © 2005-2018