How do you create an Annotation on-the-run and how do you enable end-user placement with Annotation.BeginPlacement()
? I've tried to do this in multiple ways, but cannot get it working. It should render itself in real-time after the BeginPlacement() has been called.
Documentations on this subject is little to none - and mostly none - so I'm not able to find any help for this problem.
What I've tried so far, is to create an annotation and place it with AnchorX/Y, set all Allow- flags to true and called BeginPlacement() while mouse is moving, but cannot see the annotation while placing it nor will it go in it's place accordingly. For example, LineAnnotation starts in right position, but doesn't end where I left it. When I move it so it starts from my ChartAreas {0,0}, it will hit the end-point.
What I want to know, is when and how to use these tools available? What I am trying to do, is to let the user draw annotations on a chart and use as tools when analyzing the charts.
You need to calculate the right positions. Remember that the MouseMove will not give you positions (percentages) or values(data) but pixels. You can transform them using the various axis functions. Officially they only work in a xxxPaint event, but during mouse events they also work fine.
Update: There two ways to do the anchoring:
- Either by using the 'Positions', i.e. the percentages or the 'Values', i.e. the data values.
Here is an example of the 1st kind:
LineAnnotation laNew = null;
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
if (cbx_drawAnnotation.Checked)
{
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
laNew = new LineAnnotation();
chart1.Annotations.Add(laNew);
double vx = ax.ValueToPosition(ax.PixelPositionToValue(e.X));
double vy = ay.ValueToPosition(ay.PixelPositionToValue(e.Y));
laNew.X = vx;
laNew.Y = vy;
}
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left) && cbx_drawAnnotation.Checked)
{
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
double vx = ax.ValueToPosition(ax.PixelPositionToValue(e.X))- laNew.X;
double vy = ay.ValueToPosition(ay.PixelPositionToValue(e.Y)) - laNew.Y;
laNew.Width = Math.Min(100, vx);
laNew.Height = Math.Min(100, vy);
laNew.LineColor = rb_green.Checked ? Color.Green : Color.Red;
laNew.AllowMoving = true; // optional
}
}
This works fine unles you need to rescale the axis in some way, like changing the axis minimum and/or maximum values.
- In the case you need to anchor to data values.
First we need to relate the Annotation
to the Axes
and also set IsSizeAlwaysRelative
to false
. Then we can calculate the anchor and size values:
private void chart1_MouseDown(object sender, MouseEventArgs e)
{
if (cbx_drawAnnotation.Checked)
{
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
laNew = new LineAnnotation();
chart1.Annotations.Add(laNew);
laNew.IsSizeAlwaysRelative = false;
laNew.AxisX = ax;
laNew.AxisY = ay;
laNew.AnchorX = ax.PixelPositionToValue(e.X);
laNew.AnchorY = ay.PixelPositionToValue(e.Y);
laNew.LineColor = rb_green.Checked ? Color.Green : Color.Red;
laNew.AllowMoving = true;
}
}
private void chart1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left) && cbx_drawAnnotation.Checked)
{
Axis ax = chart1.ChartAreas[0].AxisX;
Axis ay = chart1.ChartAreas[0].AxisY;
laNew.Width = ax.PixelPositionToValue(e.X) - laNew.AnchorX; // values
laNew.Height = ay.PixelPositionToValue(e.Y) - laNew.AnchorY;
}
}
Note how I now can scale the maximum and also still resize the the chart and the annotations stay with the data points..:
Update: To restrict the line to the ChartArea
add this to the definition in the MouseDown
event:
laNew.ClipToChartArea = chart1.ChartAreas[0].Name;
To prevent an exception from leaving the Chart, add this to the condition in the MouseMove
..:
.. && chart1.ClientRectangle.Contains(e.Location)