Recent

Author Topic: LineTool  (Read 5635 times)

kapibara

  • Hero Member
  • *****
  • Posts: 610
LineTool
« on: December 14, 2013, 11:25:57 pm »
wp, your last message gave me ideas. I have started to work on a TLineTool with features I need:

  • Multiple lines on the chart.
  • Lines are selectable, movable and resizable.
  • Toggling of line visibility.
  • Derived from TUserDefinedTool

The position of the line is decided by the user when he is doing the drawing. There could be an option to calculate the line in relation to a series. But I dont need that yet, so manual drawing should work first.

Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: LineTool
« Reply #1 on: December 15, 2013, 08:47:35 pm »
Here is the first pre-alpha version of the LineTool with limited functionality. The code is in a separate unit with three small classes and doesnt yet descend from TUserDefinedTool.

Click and hold while moving mouse gives a permanent line when the mouse button is released.

If also Ctrl is pressed then you get the wanted rubberband effect.

It puzzles me why the charts mousemove event doesnt fire if not Ctrl key is pressed? I want chart mousemove to fire by pressing just the ssLeft mousebutton. Shift and ALT also make the event fire if ssLeft is pressed. I must have missed something obvious. :)

Tomorrow I will try to make the line selectable and movable. When selected, it will be "dotted line" until it is deselected and goes back to solid. Any idea how to find the lineseries when clicking in the chart?
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: LineTool
« Reply #2 on: December 16, 2013, 10:36:38 am »

kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: LineTool
« Reply #3 on: December 17, 2013, 09:54:46 pm »
TChartSeries has two functions that I now use from the MouseDown event to select the TrendLine:

Series.GetXImgValue(Index)
Series.GetYImgValue(Index)

That returns Image values for the series points at Index, and makes selection of the line work.

So far so good. But for the moving and resizing of the line I need to convert mouse x,y integer values and put into the series points. This is done from the MouseMove event of TChart.

How to do that? Is there a function that converts from mouse position to series values?

EDIT: Probably ImageToGraph? To send in the X,Y as a TPoint and use the X,Y of the returned TDoublePoint?
« Last Edit: December 17, 2013, 10:26:48 pm by kapibara »
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: LineTool
« Reply #4 on: December 17, 2013, 11:41:02 pm »
Quote
Series.GetXImgValue(Index)
Series.GetYImgValue(Index)
These are just wrappers for Chart.XImageToGraph and Chart.YImageToGraph. Use whatever is convenient.

Quote
Is there a function that converts from mouse position to series values?
EDIT: Probably ImageToGraph?
Certainly. I think you used that in the other projects we discussed here.

Please note however, that this is not the most general case. If you use transformations you have to consider these as well. The "graph" coordinates are relative to the unique x/y coordinates spanning some kind of invisible axes behind the chart. When you use a transformation the values stored in the series ("axis coordinates") are mapped to this axis. Create a simple project with a logarithmic axis, and you'll see the difference: if your data points range between 1 and 1 million ("axis" coordinates), the "graph" coordinates range between 0 (= log(1)) and 6 (= log (1 million)).

The transformations class does all the conversions. It has methods AxisToGraph and GraphToAxis. The axis, moreover, provides the method GetTransform to determine the selected transformation chain (there can be several transformations per axis) (or 1:1 identity if transformations are not used). The most general way therefore is

Code: [Select]
var
  x,y: Integer;  // Mouse coordinates, in pixels (or "image coordinates")
  P: TDoublePoint;
begin
  P.x := Chart.XImageToGraph(x);  // P is in "graph" coordinates
  P.y := Chart.YImageToGraph(y);
  // Now convert "graph" to "axis" coordinates
  P.x := Chart.BottomAxis.GetTransform.GraphToAxis(P.X);  // P is in "axis" coordinates now
  P.y := Chart.LeftAxis.GetTransform.GraphToAxis(P.Y);

  { or, in a single line:
  P.x :=  Chart.BottomAxis.GetTransform.GraphToAxis(Chart.XImageToGraph(x));
  P.y := Chart.LeftAxis.GetTransform.GraphToAxis(Chart.YImageToGraph(y));}
end;

 

TinyPortal © 2005-2018