Search code examples
c#winformsmschart

How can I make a gannt chart with overlapping points in winforms


There is a time interval like 8:00-17:00.In this time interval happens a task several times for example 9:00-9:20 , 11:00-12:00, 13:00-13:20.I want to make a chart in winforms to show when the task happens like this. So can I do this with DEV gannt chart? Or is there any Control I can use to make it?

I want to do this in winforms.enter image description here


Solution

  • This is quite easy with MSChart and the ChartType RangeBar.

    Here is an example:

    enter image description here

    To get this result you need to

    • Add an MSChart control from the data toolbox
    • Add the using clause: using System.Windows.Forms.DataVisualization.Charting;
    • Then you can style the chart..
    • ..and maybe set a size limit

    Here is the code for setting it up:

    void setUpGantt(Chart chart)
    {
        chart.Series.Clear();
        Series s = chart.Series.Add("gantt");
        s.ChartType = SeriesChartType.RangeBar;
        s.YValueType = ChartValueType.DateTime;
        s.AxisLabel = "";
        s.IsVisibleInLegend = false;
        Axis ax = chart.ChartAreas[0].AxisX;
        Axis ay = chart.ChartAreas[0].AxisY;
        ax.MajorGrid.Enabled = false;
        ax.MajorTickMark.Enabled = false;
        ax.LabelStyle.Format = " ";
        ax.Enabled = AxisEnabled.False;
        ay.LabelStyle.Format = "HH:mm";
        ay.MajorGrid.Enabled = false;
        ay.MajorTickMark.Enabled = false;
        ay.LineColor = chart.BackColor;
        limitGantt(chart, "8:00", "17:00");
    }
    
    void limitGantt(Chart chart, string start, string end)
    {
        Axis ax = chart.ChartAreas[0].AxisX;
        ax.Minimum = 0.5;  // we have only one slot
        ax.Maximum = 1.5;  // the bar is centered on its value (1)
    
        Axis ay = chart.ChartAreas[0].AxisY;
        ay.Minimum = fromTimeString(start).ToOADate();  // we exclude all times..
        ay.Maximum = fromTimeString(end).ToOADate();    // ..outside a given range
    }
    

    Note that I used time strings for convenience. Of course you can change to using DateTimes directly. For the conversion of a time string to a DateTime of the current day this function is used:

    DateTime fromTimeString(string time)
    {
        var p = time.Split(':');
        int sec = p.Length == 3 ? Convert.ToInt16(p[2]) : 0;
        TimeSpan t = new TimeSpan(Convert.ToInt16(p[0]), Convert.ToInt16(p[1]), sec);
        return DateTime.Today.Add(t);
    }
    

    Note that all the code is lacking any checks!

    To add a task this method is used:

    void addGanttTask(Series s, string start, string end, Color c, int slot )
    {
        DateTime start_ = fromTimeString(start);
        DateTime end_ = fromTimeString(end);
        int pt = s.Points.AddXY(slot, start_, end_);
        s.Points[pt].Color = c;
    }
    

    Note that it contains both a Series and a 'slot'. The slots are used for the x-values, which in your case all are the same. But one can easily image a more comples planner with several bars for several resources, like various rooms or teams..

    The Series parameter would allow to overlay a second series like you can see in this nice example from MSDN..

    Here is how I filled the chart:

    setUpGantt(chart1);
    
    Series s = chart1.Series[0];
    addGanttTask(s, "8:00", "17:00", Color.LimeGreen, 1);
    addGanttTask(s, "9:00", "9:20", Color.DarkSlateBlue, 1);
    addGanttTask(s, "11:00", "12:00", Color.DarkSlateBlue, 1);
    addGanttTask(s, "13:00", "13:20", Color.DarkSlateBlue, 1);
    

    Note that different ranges may overlap and might hide each other. In our example the green bar is added first and the others lie on top. In the MSDN example you see how the yellow bars are narrower to keep the bars under them visible. They belong to a 2nd series.

    To change the bars' widths use

    series.SetCustomProperty("PixelPointWidth",  "15");