0
votes

I want to allow the user to choose what values are shown in a chart with a pie serie values by displaying a check box in front of each serie's value.

There is an option to display a checkbox near each legend item but it's only working for series, not values in a serie ; and you can only have one serie of values in a single pie.

Does anyone have any idea on how to achieve this?

1
This is not possible with the current TeeChart legend. How would you expect the pie to look when you unselect a value in the legend?Yeray
The expected behaviour would be the same for values as it is for series with bar chart or stacked bar chart : the pie would display all checked values as if the unchecked values were not part of the serie (in bar chart or stacked bar chart, unchecking a serie removes it from the chart but not from the legend)Jean-Louis Senegas

1 Answers

3
votes

You could draw your custom legend manually. However, you should do some tricks:

  • use a dummy series to store the original values and show these values in the legend.
  • remove the values from the main series that have been clicked in the legend taking care with the indexes and the colors.

Here an example, even with mouse Hover:

example

uses Series, TeCanvas, Math;

var pieSeries: TPieSeries;
    dummySeries: TPieSeries;
    itemRect: array of TRect;
    itemIndex: Integer;

procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i, tmpH, tmpW: Integer;
    tmpR, tmpS: TRect;
begin
  with Chart1.Canvas do
  begin
    AssignFont(Chart1.Legend.Font);
    AssignBrush(Chart1.Legend.Brush);

    tmpW:=0;
    tmpH:=0;
    for i:=0 to dummySeries.Count-1 do
    begin
      tmpW:=Max(TextWidth(dummySeries.LegendString(i, Chart1.Legend.TextStyle)), tmpW);
      tmpH:=Max(TextHeight(dummySeries.LegendString(i, Chart1.Legend.TextStyle)), tmpH);
    end;

    Inc(tmpW, Chart1.Legend.Symbol.Width + TeeCheckBoxSize + 8);

    tmpR.Left:=Chart1.Width-tmpW-10;
    tmpR.Top:=50;
    tmpR.Right:=tmpR.Left+tmpW;
    tmpR.Bottom:=tmpR.Top + ((tmpH+4) * dummySeries.Count) + 4;

    Rectangle(tmpR);

    Inc(tmpR.Left, 4);
    tmpS.Left:=tmpR.Left+TeeCheckBoxSize+4;
    tmpS.Right:=tmpS.Left+TeeCheckBoxSize;
    for i:=0 to dummySeries.Count-1 do
    begin
      Brush.Color:=OperaPalette[i];
      Inc(tmpR.Top, 4);

      DrawCheckBox(tmpR.Left, tmpR.Top, not dummySeries.IsNull(i), clNone);

      if i=itemIndex then
      begin
        Pen.Color:=clRed;
        Font.Color:=clRed;
      end
      else
      begin
        Pen.Color:=Chart1.Legend.Symbol.Pen.Color;
        Font.Color:=Chart1.Legend.Font.Color;
      end;

      tmpS.Top:=tmpR.Top+1;
      tmpS.Bottom:=tmpS.Top+TeeCheckBoxSize;
      Rectangle(tmpS);

      TextOut(tmpS.Right + 2, tmpR.Top, StringReplace(dummySeries.LegendString(i, Chart1.Legend.TextStyle), TeeColumnSeparator, ' ', [rfReplaceAll, rfIgnoreCase]));

      itemRect[i]:=Rect(tmpR.Left, tmpS.Top, tmpR.Right, tmpS.Bottom);

      Inc(tmpR.Top, tmpH);
    end;
  end;
end;

procedure TForm1.Chart1Click(Sender: TObject);
var i, j: Integer;
begin
  if itemIndex>-1 then
  begin
     dummySeries.SetNull(itemIndex, not dummySeries.IsNull(itemIndex));

     pieSeries.CheckDataSource;

     for i:=pieSeries.Count-1 downto 0 do
       if pieSeries.IsNull(i) then
          pieSeries.Delete(i);

     //Fix colors
     j:=0;
     for i:=0 to dummySeries.Count-1 do
       if not dummySeries.IsNull(i) then
       begin
         pieSeries.ValueColor[j]:=OperaPalette[i];
         Inc(j);
       end;
  end;
end;

procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var i, j: Integer;
begin
  itemIndex:=-1;
  for i:=0 to length(itemRect)-1 do
    if PointInRect(itemRect[i], X, Y) then
    begin
      itemIndex:=i;
      break;
    end;

  if itemIndex>-1 then
  begin
    if dummySeries.IsNull(itemIndex) then
       pieSeries.Selected.HoverIndex:=-1
    else
    begin
      j:=0;
      for i:=0 to itemIndex-1 do
        if not dummySeries.IsNull(i) then
          Inc(j);

      pieSeries.Selected.HoverIndex:=j;
    end;
  end;

  Chart1.CancelMouse:=True;
  Chart1.Repaint;
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
  pieSeries:=Chart1.AddSeries(TPieSeries) as TPieSeries;
  pieSeries.FillSampleValues;

  for i:=0 to pieSeries.Count-1 do
    pieSeries.ValueColor[i]:=OperaPalette[i];

  dummySeries:=CloneChartSeries(pieSeries) as TPieSeries;
  dummySeries.ParentChart:=nil;

  pieSeries.DataSource:=dummySeries;

  Chart1.Legend.Visible:=False;
  Chart1.MarginRight:=20;

  SetLength(itemRect, dummySeries.Count);

  itemIndex:=-1;
end;