Smooth scroling in chart with datetime x axis - c#

I have this simple graph plotted in a chart. On the X-axis the values are DateTime values.
public partial class Form1 : Form
{
List<double> valuelist = new List<double>();
List<DateTime> timelist = new List<DateTime>();
public Form1()
{
InitializeComponent();
// fill the lists with values
for (int i = 0; i < 2000; i++)
{
double value = Math.Sin(i/20.0);
valuelist.Add(value);
timelist.Add(DateTime.Now.AddMinutes(i + 2));
}
// add the Values to the chart
for (int i = 0; i < valuelist.Count; i++)
{
this.chart1.Series[0].Points.AddXY(timelist[i], valuelist[i]);
}
this.chart1.ChartAreas[0].AxisX.LabelStyle.Format = "dd.MM-hh:mm";
}
private void Form1_Load(object sender, EventArgs e)
{
chart1.Series[0].XValueType = ChartValueType.DateTime;
chart1.ChartAreas[0].AxisX.Maximum = timelist.Max().ToOADate();
chart1.ChartAreas[0].AxisX.Minimum = timelist.Min().ToOADate();
chart1.ChartAreas[0].CursorX.AutoScroll = true;
chart1.ChartAreas[0].CursorY.AutoScroll = true;
chart1.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
DateTime intervall = timelist.Min().AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(chart1.ChartAreas[0].AxisX.Minimum, intervall.ToOADate());
// disable zoom-reset button
chart1.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// set scrollbar small change to blockSize
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
}
}
My problem is that I cannot get the scrollbar to move smoothly. When I plot only the Y-Values and use just double values for the AxisX.Maximum, AxisX.Minimum, AxisX.ScaleView.Zoom and for AxisX.ScaleView.SmallScrollSize it works like a charm. But as soon as I use DateTime for the X-Values I can only scroll in steps. Does someone know how to surpass this? I have the feeling that this piece of code is the obstacle:
// set scrollbar small change to blockSize (e.g. 100)
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = intervall.ToOADate();
EDIT:
The Interval for the X-Axis is automatic, the range is set by the ZoomLevel of chart1.ChartAreas[0].AxisX.ScaleView.Zoom. Here is a picture:
EDIT 2:
The Values for the X-Axis are DateTime-Values simulating a sampling of 1 value every minute:
timelist.Add(DateTime.Now.AddMinutes(i + 2));
Because it is a lot of values I did not set an interval.
The code is posted this way, so that it can be copied as it is and run right away to try it out.

You scrolling interval is wrong.
It should not be the start of your data but the step you want to go when scrolling.
Looks like you want to scroll by 3 hours?
Here is what you do:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Hours;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = 3;
If you wanted to use a DateTime.ToOADate double to achieve the same you need it to start at the first day of the DataTime data type (0aka 'dawn of time' aka 1899-12-30) and then add 3 hours:
DateTime interval = DateTime.FromOADate(0).AddHours(3);
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Number;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = interval.ToOADate();
To allow dragging the lift smoothly this may work better than setting the SmallScrollSize:
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSizeType =DateTimeIntervalType.Minutes;
chart1.ChartAreas[0].AxisX.ScaleView.SmallScrollMinSize = 60;
Use your unit and numbers! This will only work if you don't set the SmallScrollMinSize.

Related

Scroll chart programmatically

I have a chart on my WinForm that displays an EKG signal from a vital sign monitor. The chart has a scrollbar on the X-axis that allows the user to scroll back and forth to see the signal at any point they wish. This works great. The chart gets updated in real time.
The data in the chart is displayed on form load. The problem that I have is that if the user closes and reopens the form, the scrollbar button resets itself to the far left. I want the scrollbar button to be positioned at the point in the chart that is equal to the current DateTime, but I cannot find any way to do that by looking at the chart controls. Googling has not been successful.
Here is my chart setup:
private void InitializeChartEKG() {
chartEKG.ChartAreas[0].AxisX.Title = "Time";
chartEKG.ChartAreas[0].AxisX.MajorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.MinorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.IsStartedFromZero = true;
chartEKG.ChartAreas[0].CursorX.LineColor = Color.LawnGreen;
chartEKG.ChartAreas[0].CursorY.LineColor = Color.LawnGreen;
chartEKG.ChartAreas[0].AxisX.MajorGrid.Enabled = true;
chartEKG.ChartAreas[0].AxisX.MajorGrid.Interval = 100;
chartEKG.ChartAreas[0].AxisX.IsStartedFromZero = true;
chartEKG.ChartAreas[0].AxisX.MajorTickMark.Enabled = true;
chartEKG.ChartAreas[0].AxisX.Minimum = 0;
chartEKG.ChartAreas[0].AxisY.Maximum = 600;
chartEKG.ChartAreas[0].AxisY.Minimum = -600;
chartEKG.ChartAreas[0].AxisX.Interval = 10000;
chartEKG.ChartAreas[0].AxisY.Title = "mV";
chartEKG.Series[0].XValueType = ChartValueType.DateTime;
chartEKG.Series[0].YValueType = ChartValueType.Int32;
chartEKG.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Auto;
chartEKG.ChartAreas[0].AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Auto;
chartEKG.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss tt";
chartArea = chartEKG.ChartAreas[0];
chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Auto;
int position = 0;
int blockSize = 10000;
int size = blockSize;
chartArea.AxisX.ScaleView.Zoom(position, size);
chartArea.AxisX.ScaleView.SmallScrollSize = blockSize;
chartArea.CursorX.AutoScroll = true;
chartArea.AxisX.ScrollBar.BackColor = Color.LightGray;
chartArea.AxisX.ScrollBar.ButtonColor = Color.LightSteelBlue;
chartArea.AxisX.ScrollBar.LineColor = Color.DarkBlue;
chartArea.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
CultureInfo culture = new CultureInfo("en-US");
}
In the method I call to add the points I think I can do:
chartEKG.Invoke(new Action(() => chartEKG.ChartAreas[0].AxisX.ScaleView.Position = chartEKG.ChartAreas[0].AxisX.Maximum - SomeNumber);
But I'm not sure how to calculate SomeNumber
Finally was able to locate a solution. In the method that adds the points to the chart, I modified the loop that adds the points:
foreach (string point in count) {
try {
time = time.AddMilliseconds(2);
chartEKG.Invoke(new Action(() => series1.Points.AddXY(time, Convert.ToDouble(point) * 0.61)));
}
catch (ArgumentException) { }
loopCount = loopCount + 1;
string timeFormat = "yyyyMMddHHmmssfff";
string timeNow = DateTime.Now.ToString(timeFormat);
if (time == DateTime.ParseExact(DateTime.Now.ToString(timeNow), timeFormat, CultureInfo.InvariantCulture)) {
loopToStopAt = loopCount;
}
}
Then below that foreach loop, I placed this code:
chartEKG.Invoke(new Action(() => chartEKG.ChartAreas[0].AxisX.ScaleView.Scroll(chartEKG.ChartAreas[0].AxisX.Maximum - Convert.ToDouble(loopToStopAt))));
This will programmatically drag the slider to the far right of the chart, which is exactly what I want.

Problem with X-Axis when Set to Logarithmic

I have a chart, it's a column chart that goes from 0.3 to 10.0 on the x-axis.
It works fine when set to linear.
I want to give the user the option to set it to a logarithmic scale. It does change the x-axis to a log scale, but the scaling isn't right. It's just showing 0 and 3 as points on my scale.
I'm guessing it's trying to do 0.3, 3, 30, 300, but I would like to show it as 0.001, 1, 10, 100, etc.
My Linear Chart:
My Log Chart of the same data:
My Code:
private void do_Size_PM10_Chart()
{
int currentBin = 0;
int prevBin = 0;
int countSum = 0;
if (MCAList.Count < 4095)
return;
this.BeginInvoke((MethodInvoker)delegate
{
chartSizePM10.ChartAreas[0].AxisX.IsLogarithmic = false;
chartSizePM10.Series.Clear();
});
Series s = new Series("Counts");
s.ChartType = SeriesChartType.Column;
s.IsVisibleInLegend = false;
for (double i = (Spline[0].Size + BinSize);
i <= Spline[Spline.Count - 1].Size; i += BinSize)
{
currentBin = mMath.getBin(i, Spline);
for (int j = prevBin; j < currentBin; j++)
{
countSum += MCAList[j];
}
s.Points.AddXY(i, countSum);
//Console.WriteLine("Size, {0}, Counts, {1}", i, countSum);
countSum = 0;
prevBin = currentBin;
}
this.BeginInvoke((MethodInvoker)delegate
{
chartSizePM10.ChartAreas[0].AxisX.Title = "Size (μ)";
chartSizePM10.ChartAreas[0].AxisY.Title = "Counts";
chartSizePM10.ChartAreas[0].AxisX.LabelStyle.Format = "{0.###}";
chartSizePM10.ChartAreas[0].AxisY.LabelStyle.Format = "{0}";
if (radioButtonLogSize.Checked)
{
chartSizePM10.ChartAreas[0].AxisX.Minimum = 0.001;
chartSizePM10.ChartAreas[0].AxisX.Maximum = Spline[Spline.Count - 1].Size;
chartSizePM10.ChartAreas[0].AxisX.Interval = 0;
}
else
{
chartSizePM10.ChartAreas[0].AxisX.Minimum = Spline[0].Size;
chartSizePM10.ChartAreas[0].AxisX.Maximum = Spline[Spline.Count - 1].Size;
chartSizePM10.ChartAreas[0].AxisX.Interval = 0;
}
chartSizePM10.ChartAreas[0].AxisX.IsLabelAutoFit = true;
chartSizePM10.ChartAreas[0].RecalculateAxesScale();
chartSizePM10.Series.Add(s);
if (radioButtonLogSize.Checked)
{
chartSizePM10.ChartAreas[0].AxisX.IsLogarithmic = true;
chartSizePM10.ChartAreas[0].AxisX.LogarithmBase = 10;
}
});
}
I've tried setting the axis interval, but it doesn't change anything, on the log scale it still showing just a 3 as a interval marker.
Edit: #TaW, I used the code you supplied in that answer and my axis would not change. I think it's because my chart is setup a specific way for linear plot. When I removed all my code for the min, max, and interval, it's working better, I'm getting better major tick marks now. But I still can't get the minor tick marks to show up using the code you supplied, any suggestion from here?
I tried:
chartSizePM10.ChartAreas[0].AxisX.MinorGrid.Interval = 0.1;
chartSizePM10.ChartAreas[0].AxisX.MinorGrid.Enabled = true;
But this did not work. Here is my current chart:
Any more suggestion?

Vertical line across multiple line charts with value display for each chart in Winforms

I am trying to create an application which will have four line charts on a single form. When user will drag mouse over these charts, there should be one vertical line crossing each chart and the current value will be shown for each chart. Is there any way how this can be done in C#/.NET and WinForms?
Here is an example of what I am trying to achieve:
I suggest to put your data into one MSChart control with four separate ChartAreas.
For this you need to set their positions because the default layout would be 2x2.
Then you add a VerticalLineAnnotation and make it movable.
In its moving events you trigger the Paint event of the chart, where you calculate the necessary data, i.e. the values to display and positions where to display them.
Here is an example:
The Paint event is coded like this:
private void chart_Paint(object sender, PaintEventArgs e)
{
double xv = VL.X; // get x-value of annotation
for (int i = 0; i < chart.ChartAreas.Count; i++)
{
ChartArea ca = chart.ChartAreas[i];
Series s = chart.Series[i];
int px = (int )ca.AxisX.ValueToPixelPosition(xv);
var dp = s.Points.Where(x => x.XValue >= xv).FirstOrDefault();
if (dp != null)
{
int py = (int )ca.AxisY.ValueToPixelPosition(s.Points[0].YValues[0]) - 20;
e.Graphics.DrawString(dp.YValues[0].ToString("0.00"),
Font, Brushes.Black, px, py);
}
}
}
Note the use of two axis functions to convert between two (of the three) coordinate systems in a chart: We start with data values and go to pixels. The third system is percentages, which we'll meet below when setting up the chartareas..
Also note that for simplicty's sake I assume that there is one Series per ChartArea; so I can use the same index. You could also find the respective Series by seaching for the Series with the right ChartArea.Name field (*).
Feel free to set a different y-position and of course font, formatting etc..
To bring it to live we code these two events:
private void chart_AnnotationPositionChanging(object sender,
AnnotationPositionChangingEventArgs e)
{
chart.Invalidate();
}
private void chart_AnnotationPositionChanged(object sender, EventArgs e)
{
chart.Invalidate();
}
The chart setup including test data creation is a little longer..:
First we declare a class level variable for the annotation. Of course we could also grab it from the chart.Annotations collection..:
VerticalLineAnnotation VL = null;
private void setupbutton_Click(object sender, EventArgs e)
{
chart.ChartAreas.Clear();
chart.Series.Clear();
for (int i = 0; i < 4; i++)
{
ChartArea ca = chart.ChartAreas.Add("CA" + (i+1));
ca.Position = new ElementPosition(0, i*23 + 5, 90, 25);
Series s = chart.Series.Add("S" + (i+1));
s.ChartType = SeriesChartType.Line;
s.MarkerStyle = MarkerStyle.Circle; // make the points stand out
s.MarkerSize = 3;
s.ChartArea = ca.Name; // where each series belongs (*)
for (int j = 0; j < 50; j++) // a few test data
{
s.Points.AddXY(j, Math.Sin((( (j + 1) *(i + 1) ) / 55f) * 10f));
}
}
VL = new VerticalLineAnnotation(); // the annotation
VL.AllowMoving = true; // make it interactive
VL.AnchorDataPoint = chart.Series[0].Points[0]; // start at the 1st point
VL.LineColor = Color.Red;
VL.IsInfinitive = true; // let it go all over the chart
chart.Annotations.Add(VL);
}
If you watch the animation closely you will see the values jump; that is because I only have 50 points. If you wanted to display interpolated values you could do that by finding the other neighbouring point and do some simple math. But in many cases this would be nonsense.
Note that I used some 'magic' numbers when setting the ChartArea.Position. It is in percentages of the Chart and I left a little slack at top and botton and also to the right for the Legend..

Zoomable, printable, scrollable train movement graphs in c#

I need to build a graphic train schedule visualisation tool in C#. Actually I have to rebuild this perfect tool in C#.
Marey's Trains
The graphs have to be zoomable, scrollable and printable/exportable to PDF with vector graphical elements.
Could you give me some tips? How should I start it? What sort of libraries should I use?
Is it worth to try using graphing libraries like OxyPlot? Maybe it's not the best because of the special axes and irregular grids - as I think. What's your opinion?
No matter which chart tool you use, once you need special types of display you will always have to add some extra coding.
Here is an example of using the MSChart control.
Do note that it has a limitation wrt to exporting vector formats:
It can export to various formats, including 3 EMF types; however only some application can actually use those. Not sure about the PDF libary you use..!
If you can't use the Emf formats you can get nice results by making the Chart control really big, exporting to Png and then making the Dpi resolution much larger the the default screen resolution it has after saving.. Setting it to 600 or 1200dpi should do for most pdf uses..
Now lets look at an example:
A few notes:
I have made my life easier in a number of ways. I have only coded for one direction and I have not reversed the rooster, so it goes only bottom to top.
I have not used real data but made them up.
I have not created one or more classes to hold the station data; instead I use a very simple Tuple.
I have not created a DataTable to hold the train data. Instead I make them up and add them to the chart on the fly..
I didn't test, but zooming and scrolling should work as well..
Here is the List<Tuple> that holds my station data:
// station name, distance, type: 0=terminal, 1=normal, 2=main station
List<Tuple<string, double, int>> TrainStops = null;
Here is how I set up the chart:
Setup24HoursAxis(chart1, DateTime.Today);
TrainStops = SetupTrainStops(17);
SetupTrainStopAxis(chart1);
for (int i = 0; i < 23 * 3; i++)
{
AddTrainStopSeries(chart1, DateTime.Today.Date.AddMinutes(i * 20),
17 - rnd.Next(4), i% 5 == 0 ? 1 : 0);
}
// this exports the image above:
chart1.SaveImage("D:\\trains.png", ChartImageFormat.Png);
This creates one train every 20 minutes with 14-17 stops and every 5th train a fast one.
Here are the routines I call:
Setting up the x-axis for hold one day's worth of data is straightforward.
public static void Setup24HoursAxis(Chart chart, DateTime dt)
{
chart.Legends[0].Enabled = false;
Axis ax = chart.ChartAreas[0].AxisX;
ax.IntervalType = DateTimeIntervalType.Hours;
ax.Interval = 1;
ax.Minimum = dt.ToOADate();
ax.Maximum = (dt.AddHours(24)).ToOADate();
ax.LabelStyle.Format = "H:mm";
}
Creating a List of stations with random distances is also very simple. I made the 1st and last ones terminals and every 5th a main station.
public List<Tuple<string, double, int>> SetupTrainStops(int count)
{
var stops = new List<Tuple<string, double, int>>();
Random rnd = new Random(count);
for (int i = 0; i < count; i++)
{
string n = (char)(i+(byte)'A') + "-Street";
double d = 1 + rnd.Next(3) + rnd.Next(4) + rnd.Next(5) / 10d;
if (d < 3) d = 3; // a minimum distance so the label won't touch
int t = (i == 0 | i == count-1) ? 0 : rnd.Next(5)==0 ? 2 : 1;
var ts = new Tuple<string, double, int>(n, d, t);
stops.Add(ts);
}
return stops;
}
Now that we have the train stops we can set up the y-axis:
public void SetupTrainStopAxis(Chart chart)
{
Axis ay = chart.ChartAreas[0].AxisY;
ay.LabelStyle.Font = new Font("Consolas", 8f);
double totalDist = 0;
for (int i = 0; i < TrainStops.Count; i++)
{
CustomLabel cl = new CustomLabel();
cl.Text = TrainStops[i].Item1;
cl.FromPosition = totalDist - 0.1d;
cl.ToPosition = totalDist + 0.1d;
totalDist += TrainStops[i].Item2;
cl.ForeColor = TrainStops[i].Item3 == 1 ? Color.DimGray : Color.Black;
ay.CustomLabels.Add(cl);
}
ay.Minimum = 0;
ay.Maximum = totalDist;
ay.MajorGrid.Enabled = false;
ay.MajorTickMark.Enabled = false;
}
A few notes are called for here:
As the values are quite dynamic we can't use normal Labels which would come with the fixed Interval spacing.
So we create CustomLabels instead.
For these we need two values to determine the space into which they shall be centered. So we create a small span by adding/subtracting 0.1d.
We have calculated the total distance and use it to set up the Maximum of the y-axis. Again: To mimick the schedule you show you will have to do some reversing here and there..
By adding CustomLabels the normal ones are turned off automatically. As we need MajorGridlines at the irregular intervals we also turn the normal ones off. Hence we must draw them ourselves. Not really hard as you can see..:
For this we code one of the xxxPaint events:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
Axis ay = chart1.ChartAreas[0].AxisY;
Axis ax = chart1.ChartAreas[0].AxisX;
int x0 = (int) ax.ValueToPixelPosition(ax.Minimum);
int x1 = (int) ax.ValueToPixelPosition(ax.Maximum);
double totalDist = 0;
foreach (var ts in TrainStops)
{
int y = (int)ay.ValueToPixelPosition(totalDist);
totalDist += ts.Item2;
using (Pen p = new Pen(ts.Item3 == 1 ? Color.DarkGray : Color.Black,
ts.Item3 == 1 ? 0.5f : 1f))
e.ChartGraphics.Graphics.DrawLine(p, x0 + 1, y, x1, y);
}
// ** Insert marker drawing code (from update below) here !
}
Note the use of the ValueToPixelPosition conversion functions of the axes!
Now for the last part: How to add a Series of train data..:
public void AddTrainStopSeries(Chart chart, DateTime start, int count, int speed)
{
Series s = chart.Series.Add(start.ToShortTimeString());
s.ChartType = SeriesChartType.Line;
s.Color = speed == 0 ? Color.Black : Color.Brown;
s.MarkerStyle = MarkerStyle.Circle;
s.MarkerSize = 4;
double totalDist = 0;
DateTime ct = start;
for (int i = 0; i < count; i++)
{
var ts = TrainStops[i];
ct = ct.AddMinutes(ts.Item2 * (speed == 0 ? 1 : 1.1d));
DataPoint dp = new DataPoint( ct.ToOADate(), totalDist );
totalDist += TrainStops[i].Item2;
s.Points.Add(dp);
}
}
Note that since my data don't contain real arrival/departure times I calculated them from the distance and some speed factor. You, of course, would use your data!
Also note that I have used a Line chart with extra Marker circles.
Also note that each train series can easily be disabled/hidden or brought back again.
Let's show only the fast trains:
private void cbx_ShowOnlyFastTrains_CheckedChanged(object sender, EventArgs e)
{
foreach (Series s in chart1.Series)
s.Enabled = !cbx_ShowOnlyFastTrains.Checked || s.Color == Color.Brown;
}
Of course for a robust application you will not rely ona magic color ;-)
Instead you could add a Tag object to the Series to hold all sorts of train info.
Update: As you noticed the drawn GridLines cover the Markers. You can insert this piece of code here (**); it will owner-draw the Markers at the end of the xxxPaint event.
int w = chart1.Series[0].MarkerSize;
foreach(Series s in chart1.Series)
foreach(DataPoint dp in s.Points)
{
int x = (int) ax.ValueToPixelPosition(dp.XValue) - w / 2;
int y = (int) ay.ValueToPixelPosition(dp.YValues[0])- w / 2;
using (SolidBrush b = new SolidBrush(dp.Color))
e.ChartGraphics.Graphics.FillEllipse(b, x, y, w, w);
}
Close-up:

Teechart multiple axis creation

I am new to C# programming. I am working in a firm, someone has completed some task and left with graph parts. Now i have to do this.
I am using steema chart in C#, I want to create chart with multiple axis on left side of the chart (y-axis) and comman x- axis for all. Each axis on lest side will be different axis lengths.
I have created six check boxes for different sensor, when i tick that box then regarding axis with default length should appear. I have created check box's but i am not able to set axis length and also i am not able to draw multiple axis.
I don't know this is the right way to ask? Please excuse me if i am wrong? if i haven't provided much information then please ask me i will do it.
I want to draw the type of chart as shown in the attached image. The X-axis(system time) is common for all series and Y-axis is different for each series. i have chek boxes for all series so when check box checked then that series Y-axis has to display with default axis range(for example min (0) and max (1000)).
Thanks in advance.
Something very similar was discussed in the Steema Support forums some time ago.
Give it a look here.
I post the same code here:
int nSeries = 3;
private void InitializeChart()
{
tChart1.Aspect.View3D = false;
tChart1.Header.Visible = false;
tChart1.Legend.Alignment = LegendAlignments.Bottom;
for (int i = 0; i < nSeries; i++)
{
new Steema.TeeChart.Styles.Line(tChart1.Chart);
tChart1.Axes.Custom.Add(new Steema.TeeChart.Axis(tChart1.Chart));
tChart1[i].CustomVertAxis = tChart1.Axes.Custom[i];
tChart1.Axes.Custom[i].AxisPen.Color = tChart1[i].Color;
tChart1.Axes.Custom[i].Grid.Visible = false;
tChart1.Axes.Custom[i].Title.Visible = true;
tChart1.Axes.Custom[i].Title.Caption = "Series" + i.ToString();
tChart1[i].FillSampleValues(20);
tChart1.Axes.Custom[i].PositionUnits = PositionUnits.Pixels;
}
tChart1.Panel.MarginUnits = PanelMarginUnits.Pixels;
tChart1.Draw();
PlaceAxes(0, 0, 0, 0, 0);
tChart1.Draw();
}
private void PlaceAxes(int nSeries, int NextXLeft, int NextXRight, int MargLeft, int MargRight)
{
const int extraPos = 12;
const int extraMargin = 105;
//Variable
int MaxLabelsWidth;
int lenghtTicks;
int extraSpaceBetweenTitleAndLabels;
if (tChart1[nSeries].Active)
{
MaxLabelsWidth = tChart1.Axes.Custom[nSeries].MaxLabelsWidth();
lenghtTicks = tChart1.Axes.Custom[nSeries].Ticks.Length;
extraSpaceBetweenTitleAndLabels = (tChart1.Axes.Custom[nSeries].Title.Width);//- tChart1.Axes.Custom[nSeries].MaxLabelsWidth());
if (tChart1.Axes.Custom[nSeries].OtherSide)
{
tChart1.Axes.Custom[nSeries].RelativePosition = NextXRight;
NextXRight = NextXRight - (MaxLabelsWidth + lenghtTicks + extraSpaceBetweenTitleAndLabels + extraPos);
MargRight = MargRight + extraMargin;
}
else
{
tChart1.Axes.Custom[nSeries].RelativePosition = NextXLeft;
NextXLeft = NextXLeft - (MaxLabelsWidth + lenghtTicks + extraSpaceBetweenTitleAndLabels + extraPos);
MargLeft = MargLeft + extraMargin;
}
tChart1.Panel.MarginLeft = MargLeft;
tChart1.Panel.MarginRight = MargRight;
nSeries++;
if (nSeries <= tChart1.Series.Count - 1)
{
PlaceAxes(nSeries, NextXLeft, NextXRight, MargLeft, MargRight);
}
}
}

Categories

Resources