Hi,
We have a 3D plot where for the points different Pointer styles are used:
What is the best way to draw/add a (custom) legend showing the different used Pointers with some custom text?
The requirement is to display (legend like) what the meaning of the different pointers is.
best regards
How to best draw (custom) legend with used Pointers
Re: How to best draw (custom) legend with used Pointers
Hello,
The easier would probably be to hide all your series from the legend (ShowInLegend:=False) and then create as many new series as pointers+text you want to show in the legend. These new series won't have any value but you can set them your pointers and titles to show them in the legend.
The easier would probably be to hide all your series from the legend (ShowInLegend:=False) and then create as many new series as pointers+text you want to show in the legend. These new series won't have any value but you can set them your pointers and titles to show them in the legend.
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to best draw (custom) legend with used Pointers
Hi Yeray,
indeed that works nicely:
It's just that the pointers in the legend a painted 2D and in the graphics these are
painted 3D. Is there a way to get 3D pointers in legend too ?
Thanks and best regards,
indeed that works nicely:
It's just that the pointers in the legend a painted 2D and in the graphics these are
painted 3D. Is there a way to get 3D pointers in legend too ?
Thanks and best regards,
Re: How to best draw (custom) legend with used Pointers
Hello,
Drawing legend items in 3D as the series using OpenGL is not so easy because all the objects are drawn following the view (rotation and elevation) except for the default legend, where we disable the 3D to draw it as a plane.
This means you can't use the Legend.Symbols.OnDraw event to draw 3D figures.
Instead, you could hide the default legend and manually draw it at OnAfterDraw event.
Drawing legend items in 3D as the series using OpenGL is not so easy because all the objects are drawn following the view (rotation and elevation) except for the default legend, where we disable the 3D to draw it as a plane.
This means you can't use the Legend.Symbols.OnDraw event to draw 3D figures.
Instead, you could hide the default legend and manually draw it at OnAfterDraw event.
Code: Select all
uses TeePoin3, Math;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i: Integer;
R1, R2: TRect;
maxTitleWidth: Integer;
maxTitleHeight: Integer;
tmpZ: Integer;
begin
tmpZ:=Round(Chart1.DepthAxis.IAxisSize/2);
maxTitleWidth:=0;
maxTitleHeight:=0;
for i:=0 to Chart1.SeriesCount-1 do
begin
maxTitleWidth:=Max(maxTitleWidth, Chart1.Canvas.TextWidth(Chart1.SeriesTitleLegend(i))+TPoint3DSeries(Chart1[i]).Pointer.Size+15);
maxTitleHeight:=Max(Chart1.Canvas.TextHeight(Chart1.SeriesTitleLegend(i)),TPoint3DSeries(Chart1[i]).Pointer.Size);
end;
R1:=Rect(Chart1.ChartRect.Right+10,Chart1.ChartRect.Top,
Chart1.ChartRect.Right+10+maxTitleWidth,
Chart1.ChartRect.Top+5+Chart1.SeriesCount*(maxTitleHeight+5));
Chart1.Canvas.Rectangle(R1, tmpZ);
R1.Offset(3,5);
for i:=0 to Chart1.SeriesCount-1 do
begin
if Chart1[i] is TPoint3DSeries then
with Chart1.Canvas,TPoint3DSeries(Chart1[i]) do
begin
Pointer.PrepareCanvas(Chart1.Canvas,Color);
R2:=R1;
R2.Width:=Pointer.Size;
R2.Height:=Pointer.Size;
R2.Offset(0,3);
case Pointer.Style of
psRectangle: Cube(R2.Left,R2.Right,R2.Top,R2.Bottom,tmpZ-Pointer.Depth,tmpZ,True,0);
psCircle: Sphere(R2.Left+Pointer.Size div 2,R2.Top+Pointer.Size div 2,tmpZ-Pointer.Depth div 2,Pointer.Size div 2);
psTriangle: Pyramid(True,R2.Left,R2.Top,R2.Right,R2.Bottom,tmpZ-Pointer.Depth,tmpZ,True);
psDownTriangle: Pyramid(True,R2.Left,R2.Bottom,R2.Right,R2.Top,tmpZ-Pointer.Depth,tmpZ,True);
psCross: ;
psDiagCross: ;
psStar: ;
psDiamond: ;
psSmallDot: ;
psNothing: ;
psLeftTriangle: ;
psRightTriangle: ;
psHexagon: ;
psVisual: ;
psDonut: ;
psArrow: ;
end;
TextOut3D(R1.Left+Pointer.Size+5,R1.Top,tmpZ,Chart1.SeriesTitleLegend(i));
end;
R1.Offset(0,maxTitleHeight+5);
end;
end;
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |
Re: How to best draw (custom) legend with used Pointers
Hi Yeray,
thank you for the code, in principle that works.
But looking at the plot this still needs serious tweaking:
Distance and sizes are not Ok and also some pointers are missing.
I may for the next release rather stay with the 2D legend.
best regards
thank you for the code, in principle that works.
But looking at the plot this still needs serious tweaking:
Distance and sizes are not Ok and also some pointers are missing.
I may for the next release rather stay with the 2D legend.
best regards
Re: How to best draw (custom) legend with used Pointers
Hello,
Please arrange a simple example project we can run as-is to reproduce the problem here.
Here I'm adding psCross, psDiagCross and psStar:
This is probably due to some difference between your application and my test app.
Please arrange a simple example project we can run as-is to reproduce the problem here.
I only implemented a few pointer styles (psRectangle, psCircle, psTriangle and psDownTriangle). I see you also use psCross and psStar.
Here I'm adding psCross, psDiagCross and psStar:
Code: Select all
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var R2: TRect;
tmpZ: Integer;
procedure DrawCross;
begin
with Chart1.Canvas do
begin
VertLine3D(R2.Left+(R2.Right-R2.Left) div 2,R2.Top,R2.Bottom,tmpZ);
HorizLine3D(R2.Left,R2.Right,R2.Top+(R2.Bottom-R2.Top) div 2,tmpZ);
end;
end;
procedure DrawDiagonalCross;
begin
with Chart1.Canvas do
begin
LineWithZ(R2.Left,R2.Top,R2.Right,R2.Bottom,tmpZ);
LineWithZ(R2.Right,R2.Top,R2.Left,R2.Bottom,tmpZ);
end;
end;
var i: Integer;
R1: TRect;
maxTitleWidth: Integer;
maxTitleHeight: Integer;
begin
tmpZ:=Round(Chart1.DepthAxis.IAxisSize/2);
maxTitleWidth:=0;
maxTitleHeight:=0;
for i:=0 to Chart1.SeriesCount-1 do
begin
maxTitleWidth:=Max(maxTitleWidth, Chart1.Canvas.TextWidth(Chart1.SeriesTitleLegend(i))+TPoint3DSeries(Chart1[i]).Pointer.Size+15);
maxTitleHeight:=Max(Chart1.Canvas.TextHeight(Chart1.SeriesTitleLegend(i)),TPoint3DSeries(Chart1[i]).Pointer.Size);
end;
R1:=Rect(Chart1.ChartRect.Right+10,Chart1.ChartRect.Top,
Chart1.ChartRect.Right+10+maxTitleWidth,
Chart1.ChartRect.Top+5+Chart1.SeriesCount*(maxTitleHeight+5));
Chart1.Canvas.Rectangle(R1, tmpZ);
R1.Offset(3,5);
for i:=0 to Chart1.SeriesCount-1 do
begin
if Chart1[i] is TPoint3DSeries then
with Chart1.Canvas,TPoint3DSeries(Chart1[i]) do
begin
Pointer.PrepareCanvas(Chart1.Canvas,Color);
R2:=R1;
R2.Width:=Pointer.Size;
R2.Height:=Pointer.Size;
R2.Offset(0,3);
case Pointer.Style of
psRectangle: Cube(R2.Left,R2.Right,R2.Top,R2.Bottom,tmpZ-Pointer.Depth,tmpZ,True,0);
psCircle: Sphere(R2.Left+Pointer.Size div 2,R2.Top+Pointer.Size div 2,tmpZ-Pointer.Depth div 2,Pointer.Size div 2);
psTriangle: Pyramid(True,R2.Left,R2.Top,R2.Right,R2.Bottom,tmpZ-Pointer.Depth,tmpZ,True);
psDownTriangle: Pyramid(True,R2.Left,R2.Bottom,R2.Right,R2.Top,tmpZ-Pointer.Depth,tmpZ,True);
psCross: DrawCross;
psDiagCross: DrawDiagonalCross;
psStar: begin
DrawCross;
DrawDiagonalCross;
end;
psDiamond: ;
psSmallDot: ;
psNothing: ;
psLeftTriangle: ;
psRightTriangle: ;
psHexagon: ;
psVisual: ;
psDonut: ;
psArrow: ;
end;
TextOut3D(R1.Left+Pointer.Size+5,R1.Top,tmpZ,Chart1.SeriesTitleLegend(i));
end;
R1.Offset(0,maxTitleHeight+5);
end;
end;
Best Regards,
Yeray Alonso Development & Support Steema Software Av. Montilivi 33, 17003 Girona, Catalonia (SP) | |
Please read our Bug Fixing Policy |