Search code examples
c#winformsteechart

How to set the color of the legendbox in 3D TeeChart to that of the underlying data series?


I am using Teechart to create 3D plots in winforms. When I add the first surface to the chart, the legend box displays legend items (for values) with boxes filled with colors. However when I add more than one surface, the legend item boxes (representing the surfaces) in the legend are white. I expect them to be filled with the surface/series color.

I have managed to set the color of the legend items' text by setting the

tChart.Legend.FontSeriesColor

to true, but I could not figure how to fill the legend boxes with color.

I have attached screenshots of both the scenarios -

One surface. Two surfaces

Thanks everyone.

Sample code:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            DisplayChart();
        }

        private void DisplayChart()
        {
            tChart1.Series.Clear();
            tChart1.Legend.FontSeriesColor = true;
            CreateSurface(new Plot3DSurface("X", "Y", "Z", new List<double> { 1.0, 2.0, 3.0 }, new List<double> { 3, 4, 7 }, new List<double> { 3, 5, 7 }, GetPoints(3, 3), "First", Color.Blue));
            CreateSurface(new Plot3DSurface("X", "Y", "Z", new List<double> { 1.0, 3.0, 6.0 }, new List<double> { 3, 5, 8 }, new List<double> { 5, 8, 10.5 }, GetPoints(3, 3), "Second", Color.Green));

        }


        private static List<Point> GetPoints(int x, int y)
        {
            var points = new List<Point>();

            for (var p = 0; p < x; p++)
            {
                for (var t = 0; t < y; t++)
                {
                    points.Add(new Point(p, t));
                }
            }

            return points;

        }
        private void CreateSurface(IPlot3DSurface surfaceInfo)
        {
            Custom3D surface;

            var xCount = surfaceInfo.IndexesUsed.Select(index => index.X).Distinct().Count();
            var yCount = surfaceInfo.IndexesUsed.Select(index => index.Y).Distinct().Count();


            if (xCount < 2 || yCount < 2)
            {
                surface = new Points3D(tChart1.Chart);
            }
            else
            {
                surface = new Surface(tChart1.Chart)
                {
                    Title = surfaceInfo.Title,
                    WireFrame = false,
                    DotFrame = false,
                    UseColorRange = true,
                    UsePalette = false,
                    ColorEach = false,
                    IrregularGrid = true,
                    PaletteStyle = PaletteStyles.Strong,
                    StartColor = surfaceInfo.Color,
                    Color = surfaceInfo.Color,

                };
            }

            DrawPoints(surfaceInfo, surface);

        }

        private void DrawPoints(IPlot3DSurface surfaceInfo, Custom3D surface)
        {
            foreach (var point in surfaceInfo.IndexesUsed)
            {
                surface.Add(surfaceInfo.GetXValue(point.X), surfaceInfo.GetZValue(point.X), surfaceInfo.GetYValue(point.Y));

            }
        }
    }

public class Plot3DSurface : IPlot3DSurface
    {
        public Plot3DSurface(string xCoordinatePropertyName, string yCoordinatePropertyName, string zCoordinatePropertyName,
            List<double> dataSourceListXCoordinate, List<double> dataSourceListYCoordinate, List<double> dataSourceZCoordinate,
            List<Point> dataSourceIndexList, string title, Color color)
        {
            DataSourceListXCoordinate = dataSourceListXCoordinate;
            DataSourceListYCoordinate = dataSourceListYCoordinate;

            DataSourceListZCoordinate = dataSourceZCoordinate;

            XCoordinatePropertyName = xCoordinatePropertyName;
            YCoordinatePropertyName = yCoordinatePropertyName;
            ZCoordinatePropertyName = zCoordinatePropertyName;

            Title = title;
            Color = color;

            IndexesUsed = dataSourceIndexList;
        }

        private List<Point> _indexesUsed;

        public List<Point> IndexesUsed
        {
            get
            {
                if (_indexesUsed != null) return _indexesUsed;

                var ind = new List<Point>();

                for (var i = 0; i < DataCountXCoordinate; i++)
                    for (var j = 0; j < DataCountYCoordinate; j++)
                        ind.Add(new Point(i, j));

                return ind;
            }
            private set { _indexesUsed = value; }
        }

        private IList<double> DataSourceListXCoordinate { get; set; }

        private IList<double> DataSourceListYCoordinate { get; set; }

        private IList<double> DataSourceListZCoordinate { get; set; }

        private int DataCountXCoordinate
        {
            get { return DataSourceListXCoordinate.Count; }
        }

        private int DataCountYCoordinate
        {
            get { return DataSourceListYCoordinate.Count; }
        }

        private string XCoordinatePropertyName { get; set; }

        private string YCoordinatePropertyName { get; set; }

        private string ZCoordinatePropertyName { get; set; }

        public string XCoordinatePropertyDisplayName
        {
            get { return XCoordinatePropertyName + " (" + DataSourceListXCoordinate[0] + ")"; }
        }

        public string YCoordinatePropertyDisplayName
        {
            get { return YCoordinatePropertyName + " (" + DataSourceListYCoordinate[0] + ")"; }
        }

        public string ZCoordinatePropertyDisplayName
        {
            get { return ZCoordinatePropertyName + " (" + DataSourceListZCoordinate[0] + ")"; }
        }

        public string Title { get; private set; }

        public Color Color { get; private set; }

        public double? GetXValue(int i)
        {
            return DataSourceListXCoordinate[i];
        }

        public double? GetYValue(int i)
        {
            return DataSourceListYCoordinate[i];
        }

        public double? GetZValue(int i)
        {
            return DataSourceListZCoordinate[i];
        }

        public double GetMinX
        {
            get { return DataSourceListXCoordinate.Min(v => v); }
        }

        public double GetMaxX
        {
            get { return DataSourceListXCoordinate.Max(v => v); }
        }

        public double GetMinY
        {
            get { return DataSourceListYCoordinate.Min(v => v); }
        }

        public double GetMaxY
        {
            get { return DataSourceListYCoordinate.Max(v => v); }
        }

        public double GetMinZ
        {
            get { return DataSourceListZCoordinate.Min(v => v); }
        }

        public double GetMaxZ
        {
            get { return DataSourceListZCoordinate.Max(v => v); }
        }



    }

    public interface IPlot3DSurface
    {
        List<Point> IndexesUsed { get; }

        string XCoordinatePropertyDisplayName { get; }

        string YCoordinatePropertyDisplayName { get; }

        string ZCoordinatePropertyDisplayName { get; }

        string Title { get; }

        double? GetXValue(int i);

        double? GetYValue(int i);

        double? GetZValue(int i);

        double GetMinX { get; }

        double GetMaxX { get; }

        double GetMinY { get; }

        double GetMaxY { get; }

        double GetMinZ { get; }

        double GetMaxZ { get; }

        Color Color { get; }
    }

Solution

  • The Surface series draws the legend symbol without brush when it uses a ColorRange to draw the cells.
    If you want to force the series color to be drawn at the legend symbol, you could use the OnSymbolDraw event:

    tChart1.Legend.Symbol.OnSymbolDraw += Symbol_OnSymbolDraw;
    

    And manually draw the symbols in it:

    private void Symbol_OnSymbolDraw(object sender, SymbolDrawEventArgs e)
    {
      if (e.Series != null)
      {
        tChart1.Graphics3D.Brush.Color = e.Series.Color;
      }
      tChart1.Graphics3D.Rectangle(e.Rect);
    }