How to draw rectangle (ViewXY)?
Sometimes there a need to draw rectangle on the chart with mouse-cursor. The purpose may be to select points in the range or just modify zoom behavior.
You can draw rectangle with mouse-cursor by creating Annotation and using Chart’s mouse events (e.g. MouseDown, MouseMove and MouseUp). Basic idea is to create Annotation on mouse down event, then change size of annotation-rectangle while mouse-cursor is dragged. Once mouse button is released, user take note of rectangle location and do action required for selection.
In the example below Annotation-rectangle is used to modify/replace default chart 'ZoomRectangle' behavior.
We start, first with disabling default chart 'ZoomRectangle' behavior, and subscribing to mouse events:
view.ZoomPanOptions.DevicePrimaryButtonAction = UserInteractiveDeviceButtonAction.None;
//Event to start drawing
_chart.PreviewMouseLeftButtonDown += _chart_MouseDown;
// event of actual drawing
_chart.MouseMove += _chart_MouseMove;
//Event to stop drawing
_chart.PreviewMouseLeftButtonUp += _chart_MouseUp;
If chart has many objects (like line-series or intensity-series), mouse-event may be handled by them (if AllowUserInteraction property is enabled for them). Therefore, to ensure that rectangle drawing will be handled properly, user may need to subscribe to PreviewMouse... events.
Next application needs few global variable to connect events handlers.
AnnotationXY _annZoomRectangle = null;
PointDouble _mouseDownValues = new PointDouble(0, 0);
bool _bDrawingRectangle = false;
MouseDown and MouseMove event handlers are used to create and resize Annotation rectangle.
/// <summary>
/// Start drawing Annotation-rectangle over the chart
/// </summary>
/// <param name="sender">Event sender</param>
/// <param name="e">Mouse arguments</param>
private void _chart_MouseDown(object sender, MouseButtonEventArgs e)
{
ViewXY viewXY = _chart.ViewXY;
AxisX xAxis = viewXY.XAxes[0];
AxisY yAxis = viewXY.YAxes[0];
System.Windows.Point position = e.GetPosition(this);
/******************************************************************************/
/* In WPF mouse-cursor position is received in DIPs. However, */
/* In WinForms chart mouse-event argument supply coordinates in screen PX. */
/* Therefore, coordinates<->value conversion methods should set flag */
/* UseDIP accordingly (UseDIP=true for WPF, UseDIP=false for WinForms). */
/******************************************************************************/
//Convert screen coordinates to axis values, and set annotation to point that place
double xValue, yValue;
xAxis.CoordToValue((int)position.X, out xValue, false, true);
yAxis.CoordToValue((int)position.Y, out yValue, true);
//Disable rendering
_chart.BeginUpdate();
AnnotationXY annotation = new AnnotationXY(_chart.ViewXY, _chart.ViewXY.XAxes[0], _chart.ViewXY.YAxes[0])
{
Tag = "ZoomRectangle",
Style = AnnotationStyle.Rectangle,
Shadow = new Shadow() { Visible = false },
TextStyle = new AnnotationTextStyle() { Visible = false },
BorderVisible = true,
BorderLineStyle = new LineStyle() { Width = 1, Pattern = LinePattern.Dot },
Fill = new Fill() { Style = RectFillStyle.ColorOnly, Color = Color.FromArgb(30, 255, 165, 0), GradientFill = GradientFill.Solid },
AllowUserInteraction = false,
Sizing = AnnotationXYSizing.AxisValuesBoundaries,
AxisValuesBoundaries = new BoundsDoubleXY(xValue, xValue, yValue, yValue),
};
_chart.ViewXY.Annotations.Add(annotation);
_annZoomRectangle = annotation;
_mouseDownValues = new PointDouble(xValue, yValue);
//Allow rendering
_chart.EndUpdate();
_bDrawingRectangle = true;
}
/// <summary>
/// Actual drawing by moving the mouse
/// </summary>
/// <param name="sender">Event sender</param>
/// <param name="e">Mouse arguments</param>
private void _chart_MouseMove(object sender, MouseEventArgs e)
{
if (_bDrawingRectangle)
{
ViewXY viewXY = _chart.ViewXY;
AxisX xAxis = viewXY.XAxes[0];
AxisY yAxis = viewXY.YAxes[0];
System.Windows.Point position = e.GetPosition(this);
/******************************************************************************/
/* In WPF mouse-cursor position is received in DIPs. However, */
/* In WinForms chart mouse-event argument supply coordinates in screen PX. */
/* Therefore, coordinates<->value conversion methods should set flag */
/* UseDIP accordingly (UseDIP=true for WPF, UseDIP=false for WinForms). */
/******************************************************************************/
//Convert screen coordinates to axis values,
double xValue, yValue;
xAxis.CoordToValue((int)position.X, out xValue, false, true);
yAxis.CoordToValue((int)position.Y, out yValue, true);
//Disable rendering
_chart.BeginUpdate();
_annZoomRectangle.AxisValuesBoundaries.XMin = Math.Min(xValue, _mouseDownValues.X);
_annZoomRectangle.AxisValuesBoundaries.XMax = Math.Max(xValue, _mouseDownValues.X);
_annZoomRectangle.AxisValuesBoundaries.YMin = Math.Min(yValue, _mouseDownValues.Y);
_annZoomRectangle.AxisValuesBoundaries.YMax = Math.Max(yValue, _mouseDownValues.Y);
_chart.EndUpdate();
}
}
Finally MouseUp event is used to do 'selection-action'. In this example, Annotation-rectangle is removed and new range is applied for X- and Y-axis.
/// <summary>
/// Stop drawing by mouse.
/// </summary>
/// <param name="sender">Event sender</param>
/// <param name="e">Mouse button event arguments</param>
private void _chart_MouseUp(object sender, MouseButtonEventArgs e)
{
double xMin = _annZoomRectangle.AxisValuesBoundaries.XMin;
double xMax = _annZoomRectangle.AxisValuesBoundaries.XMax;
double yMin = _annZoomRectangle.AxisValuesBoundaries.YMin;
double yMax = _annZoomRectangle.AxisValuesBoundaries.YMax;
ViewXY viewXY = _chart.ViewXY;
AxisX xAxis = viewXY.XAxes[0];
AxisY yAxis = viewXY.YAxes[0];
// check how big rectangle in PX, do nothing if it is too small
float[] xCoord = xAxis.ValuesToCoords(new double[] {xMin, xMax}, false);
float[] yCoord = yAxis.ValuesToCoords(new double[] {yMin, yMax}, false);
bool bApplyZoom = false;
float fZoomThreshold = 10;
if (Math.Abs(xCoord[0]- xCoord[1]) >= fZoomThreshold && Math.Abs(xCoord[0] - xCoord[1]) >= fZoomThreshold)
{
bApplyZoom = true;
}
_bDrawingRectangle = false;
_chart.BeginUpdate();
// dispose Annotation
_chart.ViewXY.Annotations.Remove(_annZoomRectangle);
_annZoomRectangle = null;
if (bApplyZoom)
{
yAxis.SetRange(yMin, yMax);
xAxis.SetRange(xMin, xMax);
}
_chart.EndUpdate();
}