SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, and now iOS Charting & Android Chart Components

0
0

To whom this may concern:

I’ve been reading through the following posts:

https://www.scichart.com/questions/question/how-to-draw-oval-circle-annotation
https://www.scichart.com/questions/question/resizing-a-custom-annotation

Unfortunately, I’m no closer to generating a re-sizable oval ellipse: mainly because techman234’s response is all gibberish and I’ve no clue how to re-template a box annotation. I’ve observed your “create annotations dynamically” and “composite annotations.”

Could you give a more thorough tutorial on this? I would like to design a resizable custom annotation like I would a regular custom annotation without the AnchorPointAnnotations limitations.

Thanks kindly!

— Ari

EDIT: Found a resource but still need help

https://www.scichart.com/documentation/v4.x/webframe.html#The%20CustomAnnotation%20Type.html

So after doing some deeper digging, I came across this link that sufficiently explains how to make a box template. I was able to make an ellipse but the heights and widths are fixed. I can re-size the outer limits of the invisible “box” but the ellipse itself remains the same size.

I would like to be able to re-size and re-shape the ellipse along with the box. I would also, if possible, have a mechanism to rotate the ellipse to a certain angle.

Can you please advise?

Thanks!

  • You must to post comments
0
0

I was going to suggest to you our Custom Annotation documentation page, which you found.

So what’s the issue? you simply need to set an Ellipse inside the Border and stretch it to fill. For instance:

<s:SciChartSurface.Annotations>
   <s:BoxAnnotation X1="2" X2="8" Y1="2" Y2="8" Background="#33FFFFFF"
                    BorderBrush="#55FFFFFF" BorderThickness="3" Padding="5">
      <s:BoxAnnotation.Template>
         <ControlTemplate TargetType="s:BoxAnnotation">
            <Border x:Name="PART_BoxAnnotationRoot"
               Margin="{TemplateBinding Margin}">
               <Ellipse Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}"
                               Width="{Binding ElementName=PART_BoxAnnotationRoot, Path=ActualWidth" 
                               Height="{Binding ElementName=PART_BoxAnnotationRoot, Path=ActualHeight" />
            </Border>
         </ControlTemplate>
      </s:BoxAnnotation.Template>
   </s:BoxAnnotation>
</s:SciChartSurface.Annotations>

Does that work?

  • Ari Sagiv
    Andrew — I’ve posted another issue as one of the answers.
  • You must to post comments
0
0

Andrew —

Thank you for you quick response. I’ve managed to get the ellipse to change its form as I liked, but I am having trouble accessing something from the Template in the CodeBehind.

My code is as follows:

<s:BoxAnnotation.Template>
    <ControlTemplate TargetType="s:BoxAnnotation">
        <Border x:Name="PART_BoxAnnotationRoot">
            <Ellipse RenderTransformOrigin="0.5, 0.5" x:Name="Ellipse"
                 Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
                 Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}" 
                 Stroke="LightBlue" StrokeThickness="4">
                <Ellipse.RenderTransform>
                    <RotateTransform Angle="-45" x:Name="Angle"/> <-- This is what I need access to in the codebehind -->
                </Ellipse.RenderTransform>
            </Ellipse>
        </Border>
    </ControlTemplate>
</s:BoxAnnotation.Template>

I am trying to access the “Angle” parameter from the “RotateTransform” markup using the Template.FindName() method, as follows:

var control = (Ellipse)this.Template.FindName("Ellipse", this);

but it is not retrieving the control. I’m not that experienced in XAML/code-behind. Could you please advise?

Thanks kindly! đŸ™‚

— Ari

  • Andrew
    You can’t access something in a template from codebehind. It’s just not possible in WPF.What I suggest you do is create an attached property, set it on BoxAnnotation and bind from the RotateTransform Angle to BoxAnnotation via TemplateBinding..
  • Ari Sagiv
    Andrew — I am doing my research and attempting a few solutions, but am having trouble doing this, can you please elaborate further?
  • Ari Sagiv
    Never mind — it took me maybe 100-something tries but I think I’ve got it. I’ll post my code in the answer as soon as I’m sure it works.
  • Ari Sagiv
    Andrew —I’ve posted an update to my answer, maybe this is something you’d want to look into? I can submit a ticket if needs be.— Ari
  • You must to post comments
0
0

So here’s what I’ve discovered. Using the following class for creating an attached property, bound to the BoxAnnotation class:

public class AngleDependency : DependencyObject
{
    public static readonly DependencyProperty AngleProperty = DependencyProperty.RegisterAttached("Angle", typeof(object), typeof(BoxAnnotation), new PropertyMetadata(false));

    public static void SetAngle(BoxAnnotation obj, double value)
    {
        obj.SetValue(AngleProperty, value.ToString());
    }

    public static double GetAngle(BoxAnnotation obj)
    {
        return double.Parse(obj.GetValue(AngleProperty).ToString());
    }
}

And then using the following

<s:BoxAnnotation ... (all assembly declarations) ... 
    local:AngleDependency.Angle="0"> <!-- Attached Property -->

    <s:BoxAnnotation.Template>
        <ControlTemplate TargetType="s:BoxAnnotation">
            <Border x:Name="PART_BoxAnnotationRoot">
                <Ellipse RenderTransformOrigin="0.5, 0.5" x:Name="Ellipse"
                     Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}"
                     Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Border}}" 
                     Stroke="LightBlue" StrokeThickness="4">
                    <Ellipse.RenderTransform>
                        <RotateTransform Angle="{Binding Path=(local:CovarianceEllipse.Angle), RelativeSource={RelativeSource TemplatedParent}}"/> <!-- More complex TemplateBinding to Angle, NOTE: CovarianceEllipse, not AngleDependency -->
                    </Ellipse.RenderTransform>
                </Ellipse>
            </Border>
        </ControlTemplate>
    </s:BoxAnnotation.Template>

</s:BoxAnnotation>

And then I run the following function:

private void showEllipse(object sender, System.Windows.RoutedEventArgs e)
{
    var covarianceEllipse = new CovarianceEllipse
    {
        X1 = //some value
        Y1 = //some value
        X2 = //some value
        Y2 = //some value
        IsEditable = true
    };

    var item = AngleDependency.GetAngle(covarianceEllipse); // Just to see what the value set is, should be 0
    AngleDependency.SetAngle(covarianceEllipse, -45);

    processEquivalencyChart.Annotations.Add(covarianceEllipse);
}

And it seems to work, as shown in the attached image (You can see the ellipse is angled at 45 degrees instead of 0).

This is pretty bizzare, since I have to use “object” as the propertyType even though it’s a double that I’m working with, and the “TemplateBinding” binds to a “CovarianceEllipse.Angle” instead of an “AngleDependency.Angle” as in the primary markup. (Changing either brings an exception.)

I know it works, I just want to make sure this is the right way to do it. I would appreciate any comments or suggestions.

— Ari

EDIT: — So while this works, it’s very tricky to transform and it’s not static (meaning it changes shape as I try to zoom). Sometimes only a partial ellipse will appear, and everything outside the bounds of the BoxAnnotation disappears. I’ve attached some more figures to show.

6.png shows the ellipses after some transformation. You can see the top right (larger) ellipse is cut off. The bottom left (smaller) ellipse is still intact. Zooming in on that ellipse, you can see the shape changes in 7.png (some points are now outside the ellipse) and it’s also only partial.

Maybe it’s time to make a new “EllipseAnnotation?” đŸ™‚

Images
  • Andrew
    It is exactly the right way to do it, well done!! Except … I think you should try using LayoutTransform not RenderTransform. There is a good article here on the difference http://blog.scottlogic.com/2008/12/19/layouttransform-vs-rendertransform-whats-the-difference.html
  • Ari Sagiv
    Andrew — Actually LayoutTransform doesn’t quite work.. 8.png shows an ellipse with the width and height set as you specified in your second answer (relative to the Border boundaries), and it gets cut off. Changing CenterX and CenterY as part of the RotateTransform function doesn’t really do anything. Another issue is shown in 9, 10, and 11 png, which is when I resize the BoxAnnotation boundaries after removing the width and height constraints. The angle in this case is 35 degrees, as 45 will always get you a circle no matter how the ellipse is shaped. When I shrink the size of the box, the size of the entirety of the ellipse changes, until it becomes a perfect square, where the ellipse becomes a circle. When shrinking the width even lower, the diretion of the ellipse changes. Is there some way that I can just keep the ellipse inscribed by the boundaries of the BoxAnnotation? Thanks kindly! — Ari
  • Ari Sagiv
    Andrew —I’ve attached a schematic of what I’m trying to achieve with creating an ellipse (12.png). Hopefully it makes some sense. I would, of course, like to be able to adjust the aspect ratio (long radius/short radius ratio) of the ellipse. These are primarly for showing the covariance of the scattered data.— Ari
  • Ari Sagiv
    Andrew —I figured out a way of doing this without using annotation: I use the FastMountainRenderableSeries after calculating the necessary parameters. It’s not an annotation, but at least it’s static works well when zooming. Unfortunately it involves setting the “AcceptsUnsortedData” to true, but there are only 100 data points in the ellipse, hardly anything that makes a major difference.If you’d like any more information. I’m happy to share.— Ari
  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.