Get chart area bounds in C# - c#

Just to explain what I'm doing, I draw two selectors on a chart, and the part that will not be selected should appear under that blue rectangle. The part that will be selected will appear in the white area, between the two selectors. The figure below shows only the left selector.
Now, what I'm trying to do is to draw a rectangle inside a chart that always remain inside the plotting area, even when the windows is resized.
To get the top, left and bottom bounds, to draw the rectangle as shown in the figure below, I do the following:
(...)
int top = (int)(Chart.Height * 0.07);
int bottom = (int)(Chart.Height - 1.83 * top);
int left = (int)(0.083 * Chart.Width);
Brush b = new SolidBrush(Color.FromArgb(128, Color.Blue));
e.Graphics.FillRectangle(b, left, top, marker1.X - left, bottom - top);
(...)
But that's far from perfect, and it isn't drawn in the right place when the window is resized. I want the blue rectangle to always be bound on the top, left and bottom by the plotting area grid. Is that possible?

You probably want to use StripLine to achieve this.
Look into the Stripline Class Documentation.
Also I recommend downloading the Charting Samples which are a great help to understand the various features.
StripLine stripLine = new StripLine();
stripLine.Interval = 0; // Set Strip lines interval to 0 for non periodic stuff
stripLine.StripWidth = 10; // the width of the highlighted area
stripline.IntervalOffset = 2; // the starting X coord of the highlighted area
// pick you color etc ... before adding the stripline to the axis
chart.ChartAreas["Default"].AxisX.StripLines.Add( stripLine );
This assumes you are wanting something that is not what Cursor already does (see CursorX), such as letting the user mark up areas of the plot which provides some persistence. Combining the Cursor events with the striplines above would be a good way to do that.
So to highlight the start and end of the cursor you could do this
// this would most likely be done through the designer
chartArea1.AxisX.ScaleView.Zoomable = false;
chartArea1.CursorX.IsUserEnabled = true;
chartArea1.CursorX.IsUserSelectionEnabled = true;
this.chart1.SelectionRangeChanged += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CursorEventArgs>(this.chart1_SelectionRangeChanged);
...
private void chart1_SelectionRangeChanged(object sender, CursorEventArgs e)
{
chart1.ChartAreas[0].AxisX.StripLines.Clear();
StripLine stripLine1 = new StripLine();
stripLine1.Interval = 0;
stripLine1.StripWidth = chart1.ChartAreas[0].CursorX.SelectionStart - chart1.ChartAreas[0].AxisX.Minimum;
stripLine1.IntervalOffset = chart1.ChartAreas[0].AxisX.Minimum;
// pick you color etc ... before adding the stripline to the axis
stripLine1.BackColor = Color.Blue;
chart1.ChartAreas[0].AxisX.StripLines.Add(stripLine1);
StripLine stripLine2 = new StripLine();
stripLine2.Interval = 0;
stripLine2.StripWidth = chart1.ChartAreas[0].AxisX.Maximum - chart1.ChartAreas[0].CursorX.SelectionEnd;
stripLine2.IntervalOffset = chart1.ChartAreas[0].CursorX.SelectionEnd;
// pick you color etc ... before adding the stripline to the axis
stripLine2.BackColor = Color.Blue;
chart1.ChartAreas[0].AxisX.StripLines.Add(stripLine2);
}
Somehow I suspect you may not have discovered the cursor yet, and doing so will make all this irrelevant. But anyway, the above code will do what you described.

Related

How to get the location of AxisY and AxisY2 in a Windows Forms Chart

I need to get the location of AxisY and AxisY2 in a chart. There are a lot of things I would like to do with this information. However, as a simple example, I just want to draw a horizontal line between the two y axes, but not have it extend past them.
Using AxisX.Minimum and Maximum works, as long as all of the values appear on the chart. However, if the chart has a scroll bar, the lines extend to the left of axisY or the right of axisY2 depending on where the chart is scrolled. Therefore, what I need is the location of AxisY and AxisY2 as displayed.
public Form1()
{
InitializeComponent();
// Add an event handler
this.chart1.Paint += new PaintEventHandler(this.DrawLine);
// Add some values
for (int value = 0; value <= 10; value++)
chart1.Series[0].Points.AddXY(value, value);
// DrawLine no longer works when a scroll bar is added,
//chart1.ChartAreas[0].AxisX.ScaleView.Zoom(0, 5);
}
// Draw a line from axisY to axisY2
private void DrawLine(object sender, PaintEventArgs e)
{
// Get the left and right edges of the values
// This only works if all of the values appear on the chart at the same time, ie. there is no scroll bar
// How can I find the locations of axisY and axisY2 as drawn on the chart?
int axisYLocation = (int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(chart1.ChartAreas[0].AxisX.Minimum);
int axisY2Location = (int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(chart1.ChartAreas[0].AxisX.Maximum);
e.Graphics.DrawLine(new Pen(Color.Red, 5), new Point(axisYLocation, 50), new Point(axisY2Location, 50));
}
Thanks to kirsan31 at winforms-datavisualization, this does exactly what I want
int axisYLocation = (int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(chart1.ChartAreas[0].AxisX.ScaleView.ViewMinimum);
int axisY2Location = (int)chart1.ChartAreas[0].AxisX.ValueToPixelPosition(chart1.ChartAreas[0].AxisX.ScaleView.ViewMaximum);

WPF - Setting corner radius in code behind

I want to bring a some rectangles to my WPF-Pages, these Rectangles should have rounded corners. To bring a few of the rectangles to the page without having to write every single one in xaml I decided to do it with a loop in the code.
I tried this one:
for (int i = 0; i < 5; i++)
{
Rectangle rect = new Rectangle();
rect.Fill = System.Windows.Media.Brushes.Green;
var style = new Style(typeof(Border));
style.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(12.0, 0, 0 , 0)));
rect.Resources.Add(typeof(Border), style);
Grid.SetColumn(rect, 1);
Grid.SetRow(rect, 1);
mainGrid.Children.Add(rect);
}
but the corner radius of my rectangles won´t change. Do you have any suggestion?
Thanks for your help in advance!
To bring a few of the rectangles to the page without having to write every single one in xaml
Good problem to solve.
I decided to do it with a loop in the code
Absolutely bad solution. Use proper MVVM with an <ItemsControl> bound to your list of objects you're trying to display, stored in your view model. And then create a global style sheet and apply it to this either automatically or manually.
Anyway to answer your question, you're creating an unnamed style on Border and applying it to a Rectangle. That will never auto-apply, and good thing, because you reference Border.CornerRadiusProperty which doesn't exist on a Rectangle.
You want to either make your style override the Rectangle's template and add a Border around it, then set its corner border radius, or manually add the border above the rectangle and set its corner radius in your setter (only add the style to the Border's resources).
Your code doesn't really make sense to me though, Rectangle also has corner radius properties, RadiusX and RadiusY, you could just set those if that's what you want.
The rectangle is overflowing. If you do the same thing with a border it will work. When you add the rectangle inside the border you can see what its doing
Rectangle rect = new Rectangle();
rect.Fill = System.Windows.Media.Brushes.Green;
Border b = new Border();
b.Width = 100;
b.Height = 100;
b.Background = Brushes.White;
b.CornerRadius= new CornerRadius(12, 0, 0, 0);
b.BorderThickness = new Thickness(2);
b.BorderBrush = Brushes.Red;
b.Child = rect;//adding this rectangle will show you how the corner is overflowing
grid_Main.Children.Add(b);

I want to see remaining line annotation in mschart

In mschart, I use line annotation with SetAnchor(point 8, point 12).
If I scroll chart and hide point 8, I cannot see remaining line annotation(point 9 to 12).
I want to see remaining line annotation. help me!
my reference ; Samples Environments for Microsoft Chart Controls
--> Chart Features --> Annotations --> Annotation Anchoring
private void AddLineAnnotation()
{
// create a line annotation
LineAnnotation annotation = new LineAnnotation();
// setup visual attributes
annotation.StartCap = LineAnchorCapStyle.Arrow;
annotation.EndCap = LineAnchorCapStyle.Arrow;
annotation.LineWidth = 3;
annotation.LineColor = Color.OrangeRed;
annotation.ShadowOffset = 2;
annotation.ClipToChartArea = "Default";
// prevent moving or selecting
annotation.AllowMoving = false;
annotation.AllowAnchorMoving = false;
annotation.AllowSelecting = false;
if(Chart1.Series[0].Points.Count > 13)
{
// Use the Anchor Method to anchor to points 8 and 12...
annotation.SetAnchor(Chart1.Series[0].Points[8], Chart1.Series[0].Points[12]);
}
// add the annotation to the collection
Chart1.Annotations.Add(annotation);
}
This is a tricky one.
The bad news is: I don't think it is possible. I think MSChart will omit all annotations that start outside of the visible area. Maybe the reasoning was to avoid clutter, but who can tell..?
A workaround would have to take into acount the case when both endpoints are outside and we still would like to see the annotation..
The good news is that with ownerdrawing one can code a workaround that will indeed draw the lines for both cases.
The following example shows the drawing code. Make sure to separate the modes for dragging to zoom and dragging to draw a new annotation. I use a checkbox and its CheckChanged event.
Let's first see it in action:
When the start of an annotation is scrolled off, the line drawing sets in. Pretty hard to notice..
Here is the code for a xxxPaint event:
private void chart1_PostPaint(object sender, ChartPaintEventArgs e)
{
// loop only over line annotations:
List<LineAnnotation> annos =
chart1.Annotations.Where(x => x is LineAnnotation)
.Cast<LineAnnotation>().ToList();
if (!annos.Any()) return;
// a few short references
Graphics g = e.ChartGraphics.Graphics;
ChartArea ca = chart1.ChartAreas[0];
Axis ax = ca.AxisX;
Axis ay = ca.AxisY;
// we want to clip the line to the innerplotposition excluding the scrollbar:
Rectangle r = Rectangle.Round(InnerPlotPositionClientRectangle(chart1, ca));
g.SetClip(new Rectangle(r.X, r.Y, r.Width, r.Height - (int)ax.ScrollBar.Size));
g.InterpolationMode = InterpolationMode.NearestNeighbor; // pick your mode!
foreach (LineAnnotation la in annos)
{
if (Double.IsNaN(la.Width)) continue; // *
// calculate the coordinates
int x1 = (int)ax.ValueToPixelPosition(la.AnchorX);
int y1 = (int)ay.ValueToPixelPosition(la.AnchorY);
int x2 = (int)ax.ValueToPixelPosition(la.AnchorX + la.Width);
int y2 = (int)ay.ValueToPixelPosition(la.AnchorY + la.Height);
// now we draw the line if necessary:
if (x1 < r.X || x1 > r.Right)
using (Pen pen = new Pen(la.LineColor, 0.5f)) g.DrawLine(pen, x1, y1, x2, y2);
}
// reset the clip to allow the system drawing a scrollbar
g.ResetClip();
}
A few notes:
The code assumes (*) that the Annotations are all anchored with AnchorX/Y and have a Width/Height set. If you have used a different ways of anchoring you need to adapt the code.
For the clipping part we need to know the pixel size/positon of the InnerPlotPosition. For this you can use the code in e.g. at the bottom of this link.
I didn't code anything but a straight line. If you have adorned your annotation you may need to expand on the code;

Spline chart smooth corners

I am using Chart control from .NET framework in my project. I have added chart control to the form and configured as shown below.
// Add a new series.
chart1.Series.Add("1");
var series = chart1.Series[0];
series.ChartType = SeriesChartType.Spline;
// Hide the legend.
series.IsVisibleInLegend = false;
// configure x axis.
var cArea = chart1.ChartAreas[0];
cArea.AxisX.IntervalType = DateTimeIntervalType.Number;
cArea.AxisX.LabelStyle.Format = "00";
cArea.AxisY.LabelStyle.Format = "0.000";
cArea.AxisY.LabelStyle.IsEndLabelVisible = true;
cArea.AxisX.Minimum = 0;
cArea.AxisX.Maximum = 100;
cArea.AxisX.Interval = 20;
cArea.AxisY.Minimum = 0;
cArea.AxisY.Maximum = 100;
cArea.AxisX.Interval = 20;
Data point values are as below:
chart1.Series[0].Points.AddXY(0, 5);
chart1.Series[0].Points.AddXY(5, 10);
chart1.Series[0].Points.AddXY(10, 30);
chart1.Series[0].Points.AddXY(20, 100);
chart1.Series[0].Points.AddXY(30, 100);
chart1.Series[0].Points.AddXY(40, 90);
chart1.Series[0].Points.AddXY(50, 80);
For the above data points, series is not smooth. Upper edge is getting cut. Refer attached image.
How to make it smooth so that whole line is visible ?
It's not visible because of the smoothing, adapt the scale (using cArea.AxisX.Maximum = 150; for example) or remove the smoothing to make the whole curve visible.
As with the DrawCurves GDI+ method you can control the tension of the splines, i.e. how close they are to the points and their connecting lines and how much smoothing they create. Too much 'smoothing' creates the fantasy tops you see and also crazy whirls from even small bumps in the data..
Setting the tension it is done via the LineTension Custom attribute.
Lower it from the default of 0.8 to something smaller. Test to see what you prefer.
Here is an example for a Series S :
S.SetCustomProperty("LineTension", "0.4");
Note that you still should make the y-axis Maximum a little larger or else you may need to bring the tension down to 0, which will look like a line type..
Here are a few variations:

How to draw a stripline diagonally using MSChart?

Tweaking MS Charts. I have successfully draw a dynamic chart but need to draw a line (Yellow) across the chart. How will i draw (yellow) line. I have X and Y values.
Here is an example you can play with:
// we create a general LineAnnotation, ie not Vertical or Horizontal:
LineAnnotation lan = new LineAnnotation();
// we use Axis scaling, not chart scaling
lan.IsSizeAlwaysRelative = false;
lan.LineColor = Color.Yellow;
lan.LineWidth = 5;
// the coordinates of the starting point in axis measurement
lan.X = 3.5d;
lan.Y = 0d;
// the size:
lan.Width = -3.5d;
lan.Height = 5.5d;
// looks like we need an anchor point, no matter which..
lan.AnchorDataPoint = yourSeries.Points[0];
// now we can add the LineAnnotation;
chart1.Annotations.Add(lan);

Categories

Resources