Movable (drag-able) Annotation

Mar 19, 2012 at 8:25 PM


   I have a wpf plot with multiple, user-selectable line series.  The X axis is date time.  I have two vertical annotation lines.  I was wondering if it would be possible somehow to make those annotation lines drag-able along the X axis.  I want to do this so the user can then re-run my evaluation software using data between those two date points.


Mar 19, 2012 at 9:37 PM

Basically these annotation lines would function as a slider, (time slider in my case).

Mar 20, 2012 at 6:35 PM

I would like to add MouseDown, MouseMove and MouseUp events on the PlotElement class - then it should be possible to handle mouse events on both annotations, axes and series. This should not be difficult, but it is a little bit of work to implement the hit testing (I would not depend on the presentation layer to do this (wpf/silverlight/winforms)).

Mar 22, 2012 at 9:00 PM

Isn't there hit testing already on the series, since there is tracker functionality?


Would it be easier to put hit testing/mouse events on the annotation class or create a custom annotation class that is based on a (re-skinned) slider control?  (That way the needed functionality already exists.)  Just a thought.

Mar 30, 2012 at 12:29 PM

Series: yes, I would use the code from the hit testing - probably some refactoring is needed.

I would like to add mouse events to the PlotElement class, and implement the hit testing on each of the derived classes (annotations, axes, series). The hit testing should be done in the OxyPlot library to make it platform independent (which means I would not use the hit testing of the WPF/Silverlight elements...)

I think the mouse events should be sufficient to make the annotation lines draggable, no need for Slider controls here.

Mar 6, 2014 at 3:22 AM
Edited Mar 6, 2014 at 3:27 AM
Current Oxyplot example shows only one annotation is movable,
How to implement multiple annotations in one plot, and move one individually?
I try to for loop through all annotations and hittest each one, but hittest is protected.

Following code try to follow oxyplot design pattern, but have problem on finding which annotation currently focused.
Class PlotExample:Plot{
var arrow = new ArrowAnnotation();
arrow.StartPoint = new DataPoint(50, 0);
arrow.EndPoint = new DataPoint(50, 100);
arrow.MouseDown += NormalTool.OnMouseDown;
arrow.MouseMove += NormalTool.OnMouseMove;
arrow.MouseUp += NormalTool.OnMouseUp;

static class NormalTool {
        public static void OnMouseDown(object sender, OxyMouseEventArgs e) {
            if (e.ChangedButton == OxyMouseButton.Left) {
                // cannot access to arrow....
        public static void OnMouseMove(object sender, OxyMouseEventArgs e) { 

        public static void OnMouseUp(object sender, OxyMouseEventArgs e) { 

Mar 7, 2014 at 3:35 PM
Edited Mar 7, 2014 at 3:36 PM
Found one solution without changing original source.
made an new annotation that inherits from arrow annotation, and override mouse even in "new annotation" class.
In this way, don't need to use external tool class to modify annotation's properties.
public class SelectableArrowAnnotation:ArrowAnnotation { // any better name?

        DataPoint lastPoint = DataPoint.Undefined;
        bool moveStartPoint = false;
        bool moveEndPoint = false;
        OxyColor originalColor = OxyColors.White;

        protected override void OnMouseDown(object sender, OxyPlot.OxyMouseEventArgs e) {
            if (e.ChangedButton != OxyMouseButton.Left) {
            lastPoint = this.InverseTransform(e.Position);
            moveStartPoint = e.HitTestResult.Index != 2;
            moveEndPoint = e.HitTestResult.Index != 1;
            originalColor = this.Color;
            this.Color = OxyColors.Red;
            var model = this.PlotModel;
            e.Handled = true;
        protected override void OnMouseMove(object sender, OxyPlot.OxyMouseEventArgs e) {
            var thisPoint = this.InverseTransform(e.Position);
            double dx = thisPoint.X - lastPoint.X;
            double dy = thisPoint.Y - lastPoint.Y;
            if (moveStartPoint) {
                this.StartPoint = new DataPoint(this.StartPoint.X + dx, this.StartPoint.Y + dy);

            if (moveEndPoint) {
                this.EndPoint = new DataPoint(this.EndPoint.X + dx, this.EndPoint.Y + dy);

            lastPoint = thisPoint;
            var model = this.PlotModel;
            e.Handled = true;
        protected override void OnMouseUp(object sender, OxyPlot.OxyMouseEventArgs e) {
            this.Color = originalColor;
Jun 9, 2014 at 3:24 PM