I would like to display the 2 different stacked area elements according to their parameters. But the chart area displays it not as specified and puts the second block at the top right corner of the first stacked area. They should be displayed side by side not stacked.
...
using System.Windows.Forms.DataVisualization.Charting;
namespace Gantt_Tool
{
public partial class ReadModel : Form
{
public ReadModel()
{
InitializeComponent();
CreateChart();
}
private void ReadModel_Load(object sender, EventArgs e)
{
}
private void CreateChart()
{
chart1.Series.Add($"a");
chart1.Series[$"a"].Points.Add(new DataPoint(0, 2));
chart1.Series[$"a"].Points.Add(new DataPoint(2, 2));
chart1.Series[$"a"].ChartType = SeriesChartType.StackedArea;
chart1.Series.Add($"b");
chart1.Series[$"b"].Points.Add(new DataPoint(2, 3));
chart1.Series[$"b"].Points.Add(new DataPoint(5, 3));
chart1.Series[$"b"].ChartType = SeriesChartType.StackedArea;
}
}
How can I set the blocks to a side by side order or placed freely? And how can I get unfilled rectangles?
Update: Here is an example of how it should look like:
From your comments, I take that you want to have a chart with freely-placed, unfilled rectangles and labels.
None of the MSChart
types will do that.
Here is how to use a Point
chart with a few lines of owner-drawing. Note how nicely this will behave when resizing the chart...
Here is the setup:
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
ax.Maximum = 9; // pick or calculate
ay.Maximum = 6; // minimum and..
ax.Interval = 1; // maximum values..
ay.Interval = 1; // .. needed
ax.MajorGrid.Enabled = false;
ay.MajorGrid.Enabled = false;
Series s1 = chart1.Series.Add("A");
s1.ChartType = SeriesChartType.Point;
Now we add your five boxes. I use a sepcial function that adds the points and stuffs the box size into the Tag
of each point..:
AddBox(s1, 1, 0, 3, 1, "# 1");
AddBox(s1, 2, 1, 2, 2, "# 2");
AddBox(s1, 4, 0, 4, 2, "# 3");
AddBox(s1, 4, 2, 2, 2, "# 4");
AddBox(s1, 4, 4, 1, 1, "# 5");
int AddBox(Series s, float x, float y, float w, float h, string label)
{
return AddBox(s, new PointF(x, y), new SizeF(w, h), label);
}
int AddBox(Series s, PointF pt, SizeF sz, string label)
{
int i = s.Points.AddXY(pt.X, pt.Y);
s.Points[i].Tag = sz;
s.Points[i].Label = label;
s.Points[i].LabelForeColor = Color.Transparent;
s.Points[i].Color = Color.Transparent;
return i;
}
The drawing is also simple; only the use of the Axes
function ValueToPixelPosition
is noteworthy..:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
if (chart1.Series[0].Points.Count <= 0) return;
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
Graphics g = e.ChartGraphics.Graphics;
using (StringFormat fmt = new StringFormat()
{ Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center})
foreach (Series s in chart1.Series)
{
foreach (DataPoint dp in s.Points)
{
if (dp.Tag == null) break;
SizeF sz = (SizeF)dp.Tag;
double vx2 = dp.XValue + sz.Width;
double vy2 = dp.YValues[0] + sz.Height;
int x1 = (int)ax.ValueToPixelPosition(dp.XValue);
int y1 = (int)ay.ValueToPixelPosition(dp.YValues[0]);
int x2 = (int)ax.ValueToPixelPosition(vx2);
int y2 = (int)ay.ValueToPixelPosition(vy2);
Rectangle rect = Rectangle.FromLTRB(x1, y2, x2, y1);
using (Pen pen = new Pen(s.Color, 2f))
g.DrawRectangle(pen, rect);
g.DrawString(dp.Label, Font, Brushes.Black, rect, fmt);
}
}
}
Here is a little Linq
to calculate the Minimum
and Maximum
values for the Axes
to hold just the right size; chart won't do it by itself since the size in the tags of the points is not known...
private void setMinMax(Chart chart, ChartArea ca)
{
var allPoints = chart.Series.SelectMany(x => x.Points);
double minx = allPoints.Select(x => x.XValue).Min();
double miny = allPoints.Select(x => x.YValues[0]).Min();
double maxx = allPoints.Select(x => x.XValue + ((SizeF)x.Tag).Width).Max();
double maxy = allPoints.Select(x => x.YValues[0] + ((SizeF)x.Tag).Height).Max();
ca.AxisX.Minimum = minx;
ca.AxisX.Maximum = maxx;
ca.AxisY.Minimum = miny;
ca.AxisY.Maximum = maxy;
}