AnnotationXY handles drawing very irregularly

A forum dedicated to WinForms version of LightningChart Ultimate.

Moderator: Arction_LasseP

greggorob64
Posts: 183
Joined: Tue Mar 18, 2014 2:55 pm

AnnotationXY handles drawing very irregularly

Post by greggorob64 » Thu Aug 18, 2016 3:54 pm

I'm using an annotationXY component, that I want the user to be able to resize and move (but not rotate). I'm running into issues where the handles are dissapearing a lot of the time, like this:

Image

Only two of the 8 handles are drawing. Its super inconsistant. Sometimes making it larger will fix it, sometimes moving it will fix it, but it happens a LOT. Any ideas of how to approach a solution here?

I am handling the size and location changed events to make sure you dont try to move the annotation off of the graph area, or resize it to get to small.

Here is how is the initialization of the annotation

Code: Select all

private AnnotationXY generateAnnotation()
      {
         var chart = this.Chart;
         this.YAxis = chart.ViewXY.YAxes[0];
         this.XAxis = chart.ViewXY.XAxes[0];

         var annotation = new AnnotationXY(
            chart.ViewXY,
            this.XAxis,
            this.YAxis);

         annotation.ResizeByMouse = true;
         annotation.MoveByMouse = true;
         annotation.AnchorAdjustByMouse = true;
         annotation.RotateByMouse = false;
         annotation.MouseInteraction = true;
         annotation.MouseHighlight = MouseOverHighlight.Simple;

         annotation.Style = AnnotationStyle.Rectangle;
         annotation.LocationCoordinateSystem = CoordinateSystem.ScreenCoordinates;
         annotation.Sizing = AnnotationXYSizing.ScreenCoordinates;


         annotation.Fill.Color = Color.FromArgb(64, 170, 204, 238);
         //annotation.Fill.GradientColor = Color.FromArgb(transarency, Color.Red);
         annotation.Fill.Style = RectFillStyle.ColorOnly;
         annotation.Fill.GradientFill = GradientFill.Solid;

         annotation.BorderLineStyle.Color = Color.FromArgb(51, 153, 255);
         annotation.BorderVisible = true;
         annotation.BorderLineStyle.Pattern = LinePattern.Dot;
         annotation.BorderLineStyle.Width = 2;


         annotation.TextStyle.Visible = false;
         annotation.Text = "N/A";
         annotation.Shadow.Visible = false;

         annotation.AnchorAdjustByMouse = false;
         annotation.ClipInsideGraph = true;

         //annotation.Anchor
         annotation.Anchor.SetValues(0, 0);
         annotation.Visible = true;


         int screenWidth = this.Chart.Width;
         int screenHeight = this.Chart.Height;

         int thirdWidth = screenWidth / 3;
         int thirdHeight = screenHeight / 3;

         annotation.LocationScreenCoords = new PointFloatXY(thirdWidth, thirdHeight);
         annotation.SizeScreenCoords = new SizeFloatXY(thirdWidth, thirdHeight);

         annotation.ResizedByMouse += Annotation_ResizedByMouse;
         annotation.LocationScreenCoordinatesChangedByMouse += Annotation_LocationScreenCoordinatesChangedByMouse;

         return annotation;
      }

User avatar
ArctionPasi
Posts: 1365
Joined: Tue Mar 26, 2013 10:57 pm
Location: Finland

Re: AnnotationXY handles drawing very irregularly

Post by ArctionPasi » Thu Aug 18, 2016 7:38 pm

Hi Greg,

I tested with 7.1.2.1 version, with your code, and I did not get the problem to appear. The handles are drawn correctly.

I commented out annotation.ResizedByMouse and annotation.LocationScreenCoordinatesChangedByMouse event handler setting rows as the handler code was not included. Maybe you are doing something there, that triggers this problem.

Please ensure your are running with 7.1.2.1. Older 7.1 may have caused this kind of problem as it had rendering data disposing problem.
LightningChart Support Team, PT

greggorob64
Posts: 183
Joined: Tue Mar 18, 2014 2:55 pm

Re: AnnotationXY handles drawing very irregularly

Post by greggorob64 » Fri Aug 19, 2016 3:05 pm

I'm using LightningChartUltimateSource v.7.1.2.zip August 12 2016 258.38 MB

Is this different that the 7.1.2.1 you mention?

Also, here's the logic for my move events, they make sure that the annotation won't get too big or small. Its probably relevant to the issue i'm guessing.

You might have to tweak a few things to get the code to compile. this.SelectionAnnotation is the annotation created, X and Y axis are just the X and Y axis used to create the annotation. The AutoAdjustMargins property is something I added, it allows for a margin in the chart even when using autoadjustmargins = true (for scrollbars)

Code: Select all

      float minimumPercentage = 0.10f;
      int screenEdgeLocationBufferPixels = 10;

      /// <summary>
      /// if the axis is reversed, make sure we have the two numbers ordered as increasing
      /// </summary>
      void makeValuesIncreasing(ref float f1, ref float f2)
      {
         if (f2 < f1)
         {
            float temp = f2;
            f2 = f1;
            f1 = temp;
         }
      }

      /// <summary>
      /// Make sure the size and locations are legit when the region is moved
      /// </summary>
      private void Annotation_LocationScreenCoordinatesChangedByMouse(object sender, LocationScreenCoordinatesChangedByMouseEventArgs e)
      {
         bool doCancel;
         PointFloatXY point;

         FixLocation(out doCancel, out point);

         if (doCancel)
         {
            e.CancelRendering = true;
            e.Annotation.LocationScreenCoords = point;
         }

         SizeFloatXY size;

         FixSize(out doCancel, out size);

         if (doCancel)
         {
            e.Annotation.SizeScreenCoords = size;
            e.CancelRendering = true;
         }
      }



      /// <summary>
      /// Make sure the size and locations are legit when the region is moved
      /// </summary>
      private void Annotation_ResizedByMouse(object sender, AnnotationResizedByMouseXYEventArgs e)
      {
         bool doCancel;
         SizeFloatXY size;

         FixSize(out doCancel, out size);

         if (doCancel)
         {
            e.Annotation.SizeScreenCoords = size;
            e.CancelRendering = true;
         }

         PointFloatXY point;

         FixLocation(out doCancel, out point);

         if (doCancel)
         {
            e.CancelRendering = true;
            e.Annotation.LocationScreenCoords = point;
         }
      }

      /// <summary>
      /// Make sure the rectangle isn't too big or small
      /// </summary>
      void FixSize(out bool doCancel, out SizeFloatXY newSize)
      {
         var margins = this.Chart.ViewXY.AxisLayout.AutoAdjustedMargins;
         int screenWidth = this.Chart.Width - margins.Left - margins.Right;
         int screenHeight = this.Chart.Height - margins.Top - margins.Bottom;

         var minWidth = minimumPercentage * screenWidth;
         var minHeight = minimumPercentage * screenHeight;

         var boxSize = this.SelectionAnnotation.SizeScreenCoords;
         var boxWidth = boxSize.Width;
         var boxHeight = boxSize.Height;

         float newWidth = boxWidth;
         float newHeight = boxHeight;

         doCancel = false;

         if (boxWidth < minWidth)
         {
            newWidth = minWidth;
            doCancel = true;
         }
         if (boxHeight < minHeight)
         {
            newHeight = minHeight;
            doCancel = true;
         }
         newSize = new SizeFloatXY(newWidth, newHeight);

      }

      /// <summary>
      /// Make sure the selection is on the screen
      /// </summary>
      void FixLocation(out bool doCancel, out PointFloatXY newLocation)
      {
         float screenXMin = this.XAxis.ValueToCoord(this.XAxis.Minimum, ChartPreferences.ValueToCoordinateUseDipVsPixel) +
         screenEdgeLocationBufferPixels;
         float screenXMax = this.XAxis.ValueToCoord(this.XAxis.Maximum, ChartPreferences.ValueToCoordinateUseDipVsPixel) -
            screenEdgeLocationBufferPixels;
         makeValuesIncreasing(ref screenXMin, ref screenXMax);

         float screenWidth = Math.Abs(screenXMax - screenXMin);

         float screenYMin = this.YAxis.ValueToCoord(this.YAxis.Minimum, ChartPreferences.ValueToCoordinateUseDipVsPixel) -
            screenEdgeLocationBufferPixels;
         float screenYMax = this.YAxis.ValueToCoord(this.YAxis.Maximum, ChartPreferences.ValueToCoordinateUseDipVsPixel) +
            screenEdgeLocationBufferPixels;
         makeValuesIncreasing(ref screenYMin, ref screenYMax);

         float screenHeight = Math.Abs(screenYMax - screenYMin);

         float minWidth = minimumPercentage * screenWidth;
         float minHeight = minimumPercentage * screenHeight;

         var boxSize = this.SelectionAnnotation.SizeScreenCoords;
         float boxWidth = boxSize.Width;
         float boxHeight = boxSize.Height;

         var boxLocation = this.SelectionAnnotation.LocationScreenCoords;
         float boxX = boxLocation.X;
         float boxY = boxLocation.Y;

         doCancel = false;
         float newX = boxX;
         float newY = boxY;

         if (boxX + boxWidth > screenXMax)
         {
            newX = screenXMax - boxWidth;
            doCancel = true;
         }
         if (boxX < screenXMin)
         {
            newX = screenXMin;
            doCancel = true;
         }
         if (boxY + boxHeight > screenYMax)
         {
            newY = screenYMax - boxHeight;
            doCancel = true;
         }
         if (boxY < screenYMin)
         {
            newY = screenYMin;
            doCancel = true;
         }

         newLocation = new PointFloatXY(newX, newY);
      }

      /// <summary>
      /// Get the location and size of the limit definition bounding rectangle
      /// </summary>
      /// <param name="selectionObject">Bounding information for the object</param>
      internal void DefineLimitsSelectionRectangleGet(out DefineTestpointLimitsSelectionObject selectionObject)
      {
         selectionObject = null;
         double[] xValues = null;
         double[] yValues = null;

         if (this._selectionRectangleInitialized &&
            this.SelectionAnnotation != null &&
            this.SelectionAnnotation.Visible)
         {
            var loc = this.SelectionAnnotation.LocationScreenCoords;
            var size = this.SelectionAnnotation.SizeScreenCoords;

            var yAxisToVerify = this.Chart.ViewXY.YAxes.FirstOrDefault(ax => ax.Visible);

            if(yAxisToVerify == null)
            {
               throw new ArgumentException("No y axis is visible.");
            }

            this.XAxis.CoordsToValues(
               new int[] { (int)loc.X, (int)(loc.X + size.Width) },
               out xValues,
               ChartPreferences.ValueToCoordinateUseDipVsPixel);

            yAxisToVerify.CoordsToValues(
               new float[] { loc.Y, (loc.Y + size.Height) },
               out yValues,
               ChartPreferences.ValueToCoordinateUseDipVsPixel);
            selectionObject = new DefineTestpointLimitsSelectionObject(
               this.XAxis.Units.Text, xValues[0], xValues[1],
               yAxisToVerify.Units.Text, yValues[0], yValues[1]);
         }
      }

User avatar
ArctionNikolai
Posts: 38
Joined: Fri Feb 05, 2016 11:37 am
Location: Finland

Re: AnnotationXY handles drawing very irregularly

Post by ArctionNikolai » Mon Aug 22, 2016 8:39 am

greggorob64 wrote:I'm using an annotationXY component, that I want the user to be able to resize and move (but not rotate). I'm running into issues where the handles are dissapearing a lot of the time, like this:

Image

Only two of the 8 handles are drawing. Its super inconsistant. Sometimes making it larger will fix it, sometimes moving it will fix it, but it happens a LOT. Any ideas of how to approach a solution here?

I am handling the size and location changed events to make sure you dont try to move the annotation off of the graph area, or resize it to get to small.

Here is how is the initialization of the annotation

Code: Select all

private AnnotationXY generateAnnotation()
      {
         var chart = this.Chart;
         this.YAxis = chart.ViewXY.YAxes[0];
         this.XAxis = chart.ViewXY.XAxes[0];

         var annotation = new AnnotationXY(
            chart.ViewXY,
            this.XAxis,
            this.YAxis);

         annotation.ResizeByMouse = true;
         annotation.MoveByMouse = true;
         annotation.AnchorAdjustByMouse = true;
         annotation.RotateByMouse = false;
         annotation.MouseInteraction = true;
         annotation.MouseHighlight = MouseOverHighlight.Simple;

         annotation.Style = AnnotationStyle.Rectangle;
         annotation.LocationCoordinateSystem = CoordinateSystem.ScreenCoordinates;
         annotation.Sizing = AnnotationXYSizing.ScreenCoordinates;


         annotation.Fill.Color = Color.FromArgb(64, 170, 204, 238);
         //annotation.Fill.GradientColor = Color.FromArgb(transarency, Color.Red);
         annotation.Fill.Style = RectFillStyle.ColorOnly;
         annotation.Fill.GradientFill = GradientFill.Solid;

         annotation.BorderLineStyle.Color = Color.FromArgb(51, 153, 255);
         annotation.BorderVisible = true;
         annotation.BorderLineStyle.Pattern = LinePattern.Dot;
         annotation.BorderLineStyle.Width = 2;


         annotation.TextStyle.Visible = false;
         annotation.Text = "N/A";
         annotation.Shadow.Visible = false;

         annotation.AnchorAdjustByMouse = false;
         annotation.ClipInsideGraph = true;

         //annotation.Anchor
         annotation.Anchor.SetValues(0, 0);
         annotation.Visible = true;


         int screenWidth = this.Chart.Width;
         int screenHeight = this.Chart.Height;

         int thirdWidth = screenWidth / 3;
         int thirdHeight = screenHeight / 3;

         annotation.LocationScreenCoords = new PointFloatXY(thirdWidth, thirdHeight);
         annotation.SizeScreenCoords = new SizeFloatXY(thirdWidth, thirdHeight);

         annotation.ResizedByMouse += Annotation_ResizedByMouse;
         annotation.LocationScreenCoordinatesChangedByMouse += Annotation_LocationScreenCoordinatesChangedByMouse;

         return annotation;
      }
Hello, Sir

My name is Nikolai and I am representative of Arction. Thank you for your question.

I could reproduce your problem with handles disappearing using your code mentioned in previous posts. It happens cause of logic inside your custom annotation events.
We can resize annotation until certain limit, after that limit, annotation starts to move and cursor position can be outside of annotation box - that automatically deselect annotation. After that, of course, handles disappears.

See picture:
MouseUp event outside annotation.
MouseUp event outside annotation.
MouseOutside.png (4.7 KiB) Viewed 7328 times
I would like to offer you to implement chart_MouseUp event, which selects annotation, if this event was handled outside Annotation after its move.

Something like that. But check, was the annotation clicked before, otherwise this event will always select annotation.

Code: Select all

var boxLocation = this.SelectionAnnotation.LocationScreenCoords;
if (e.Location.Y < boxLocation.Y || e.Location.X > boxLocation.X)
                this.SelectionAnnotation.Selected = true;
And do not forget to add .BeginUpdate() and .EndUpdate() each time when you update properties.

I hope it helps you in your projects. I am happy to answer all your further questions.

Best regards
Nikolai Arsenov
Software developer
Arction Ltd
Microkatu 1, 70210 Kuopio, Finland

greggorob64
Posts: 183
Joined: Tue Mar 18, 2014 2:55 pm

Re: AnnotationXY handles drawing very irregularly

Post by greggorob64 » Mon Aug 22, 2016 1:30 pm

Thanks Nikalia, the mouse up event you mentioned works nicely.