Search code examples
delphiteechart

Is there a real way to hide part of a series in TeeChart?


Delphi 10 with an Embedded TeeChart. I would like to hide a partial of tLineSeries and detect ONLY the visible parts by CalcClickedPart.

Assume a non sorted XY line with many cross among them, some of the points could be selected by user as not visible. I'm doing so by setting the color of the "hidden" points to clNone. When the user is moving the mouse, on MouseMove event, a CalcClickedPart is called, but it is response to the "hidden" points too, since it is not a real hidden way.

The chart creation:

procedure TForm1.FormCreate(Sender: TObject);
const
  clHideColor = {clDefault}clNone; // clNone, clDefault
begin
  Chart1.View3D := false;
  with Chart1.AddSeries(TLineSeries) as TLineSeries do
    begin
      // AddXY(Const AXValue, AYValue: TChartValue; Const ALabel: String; AColor: TColor):
      XValues.Order := loNone;
      YValues.Order := loNone;
      AddXY(  0,   0, '', clHideColor); // Origin point
      AddXY( 50,  50, '', clHideColor); // /    Cross point
      AddXY(100, 100);                  // /
      AddXY(100,   0);                  // |
      AddXY( 50,  50);                  // \    Cross point
      AddXY(  0, 100);                  // \ End point
    end;
 end;

The CalcClickedPart code in Chart's MouseMove event

procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
Var
  ClickedPart: tChartClickedPart;
  sCursorText: string;
begin
  sCursorText := '';

  Chart1.CalcClickedPart(Point(X, Y), ClickedPart); // Return information about the TeeChart component below the Mouse pointer at an X,Y location.
  Case ClickedPart.Part of
    cpNone          : sCursorText := 'cpNone';
    cpLegend        : sCursorText := 'cpLegend';
    cpAxis          : sCursorText := 'cpAxis';
    cpSeries        : sCursorText := 'cpSeries';
    cpTitle         : sCursorText := 'cpTitle';
    cpFoot          : sCursorText := 'cpFoot';
    cpChartRect     : sCursorText := 'cpChartRect';
    cpSeriesMarks   : sCursorText := 'cpSeriesMarks';
    cpSeriesPointer : sCursorText := 'cpSeriesPointer' + 
                                      ClickedPart.PointIndex.ToString;
    cpSubTitle      : sCursorText := 'cpSubTitle';
    cpSubFoot       : sCursorText := 'cpSubFoot';
    cpAxisTitle     : sCursorText := 'cpAxisTitle';
  end;

  Chart1.Title.Text.Text := sCursorText;
end;

In the above example, when the mouse on the middle (50,50) the shown point is #1 (which is hidden) instead of 4. I could go through all series points and find other closer points, but is there a "clean" way to hide partial series?

The entire series is visible: enter image description here First two points are "hidden", see title with point index 1 instead 4 (round red circle) enter image description here


Solution

  • I decided to write my own CalcClickedPart function which go through all series and value index and checking if series' ValueColor[Inx] <> clNone as follow:

    function CalcClickedPartHidenPoints(aChart: tChart; Pos: TPoint; Out Part: tChartClickedPart): boolean;
    var
      nSeriesInx, nValueInx: integer;
      aSeries: TCustomSeries;
    begin
      Result := false;
      for nSeriesInx := 0 to aChart.SeriesCount-1 do // Go through all series
        begin
          aSeries := aChart[nSeriesInx] as TCustomSeries;
          if aSeries.Visible then // Series is selected in Legend
            begin
              for nValueInx := 0 to aSeries.Count-1 do
                if (abs(aSeries.CalcXPos(nValueInx) - Pos.X) <= aSeries.ClickTolerance) and
                   (abs(aSeries.CalcYPos(nValueInx) - Pos.Y) <= aSeries.ClickTolerance) then
                  if aSeries.ValueColor[nValueInx] <> clNone then // A "visible" point
                    begin
                      Part.ASeries    := aSeries;
                      Part.Part       := cpSeriesPointer;
                      Part.PointIndex := nValueInx;
                      Result := true;
                      Break; // Stop searching for a visible point under the mouse
                    end;
            end;
          if Result then
            Break;
        end;
    end;
    

    Now the cursor in the example shows point #4 as should be: enter image description here

    Another option is to split a series to many series, but I don't like it.