Pre loader

1

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

4 votes
In reply to: Vertical X axis

Hello there,

As of SciChart v2.0 this is now possible. ScIChart supports unlimited X or Y Axes on the left, top, right, bottom of the chart. You can use this feature to place XAxis on the Left and YAxis on the Top as per our Vertical Charts Example.

enter image description here

Best regards,
Yuriy

4 votes

Hey guys,

We actually have a reproduction of this bug that occurs on some computers – without using SciChart.dll. It appears to be an issue with some Intel Graphics drivers and WriteableBitmap / .NET4/4.5.

Please download the attached solution and run it on computers where you see problems. Click on the main form. If all is working, you should see a coloured square drawn, which changes colour on each click. However, in systems with this problem, the form will be blank.

What we believe is happening is the WriteableBitmap once locked/unlocked once is not allowing any further updates. The same code works perfectly well on many other machines and the only other workaround is to disable hardware rendering for the WPF process on systems that exhibit this problem.

We have contacted Microsoft and Intel to see if any will take ownership of the fix. In the meantime, as a workaround you will have to disable WPF hardware rendering for the process.

Best regards,
Andrew

4 votes

UPDATE JUNE 2014

Hi Everyone,

Axis Label styling was introduced in SciChart v3.0. You can now set a Style for a label including margins, LayoutTransforms etc…

Please see our SciChart v3.0 Release Notes.

5. Axis Styling improvements

  • Chart Titles, Axis Titles and Labels can now be styled
  • Can set font size, font style, font weight on Axis labels
  • Now supports optional rotation of axis tick labels (e.g. 90 degrees)

Usage:

<!-- Styling Tick Labels with rotation and custom font-size and foreground -->
<s:DateTimeAxis>
    <s:DateTimeAxis.TickLabelStyle>
        <Style TargetType="s:DefaultTickLabel">
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="FontSize" Value="25" />
            <Setter Property="LayoutTransform">
                <Setter.Value>
                    <RotateTransform Angle="45" />
                </Setter.Value>
            </Setter>
        </Style>
    </s:DateTimeAxis.TickLabelStyle>
</s:DateTimeAxis>

<!-- Styling Numeric Axis Tick Labels -->
<s:NumericAxis>
    <s:NumericAxis.TickLabelStyle>
        <Style TargetType="s:NumericTickLabel">
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="FontSize" Value="25" />
        </Style>
    </s:NumericAxis.TickLabelStyle>
</s:NumericAxis>
</pre>

<!-- Declare an Axis Title Template -->
<Style x:Key="BottomAxisTitleStyle" TargetType="s:AxisTitle">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Margin="0,3,0,0"
                                Style="{StaticResource TitleTextStyle}"
                                Text="Showing time on"/>
                    <TextBlock HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Text="{Binding}" />
                    <TextBlock Margin="0,0,0,3"
                                Style="{StaticResource TitleTextStyle}"
                                Text="(daily Timeframe)"/>
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

<!-- Apply an Axis Title Template -->
<s:DateTimeAxis AxisTitle="Time Axis Title" TitleStyle="{StaticResource BottomAxisTitleStyle}"  Style="{StaticResource AxisStyle}"/>

Also the XAML Styling application demonstrates this.

Best regards,
Andrew

4 votes

OK, for the archives, in case someone doesn’t have enough reading to do:

So this was not the simplest of issues to solve, though perhaps I made it more complex than it needed to be. The basic requirement was that I had to find a way to get arbitrary metadata into a tooltip based on the results invoked by a viewmodel method, when that metadata had no

I ended up creating a SortedList in which I store my series data (I have a lot of pre-processing to do). DataPoint, and one of its properties, DataPointMetadata, are both structs.

Now, RolloverModifer generates the SeriesInfo DTO, which contains the DataSeriesIndex property — as far as I can tell, the index of the datapoint in SciChart’s underlying collection. This, along with the SeriesName, allow me to uniquely identify a datapoint in very quick time.

The remaining challenge is find a way to look up the value using the viewmodel from inside RolloverModifier.ToolTipLabelTemplate. One option was to use MultiBinding, but I’m not sure that would have worked. I instead decided to use a BindingProxy technique and pass the viewmodel as a staticresource to the converter which is responsible for realizing the data.

<scichart:RolloverModifier
    x:Name="rollover"
    DrawVerticalLine="False"
    ShowAxisLabels="False"
    SourceMode="AllVisibleSeries"
    ShowTooltipOn="MouseRightButtonDown"
    >
    <scichart:RolloverModifier.TooltipLabelTemplate>
        <ControlTemplate>
            <Border x:Name="bdToolTip"
                BorderThickness="1.25"
                Background="#341B0B" Opacity="0.85"
                    >
                <Border.Resources>
                    <Style TargetType="{x:Type TextBlock}">
                        <Setter Property="FontSize" Value="12" />
                        <Setter Property="Margin" Value="3" />
                    </Style>
                </Border.Resources>
                <Border.BorderBrush>
                    <StaticResource ResourceKey="bControlAltBackground"/>
                </Border.BorderBrush>
                <Grid >
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>

                    <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Text="{Binding SeriesName}" />
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="X: " />
                    <TextBlock Grid.Row="1" Grid.Column="1"
                        Text="{Binding XValue, Converter={StaticResource convIComparable}, StringFormat=\{0:N3\}}"
                                                                    />

                    <TextBlock Grid.Row="2" Grid.Column="0" Text="Y: " />
                    <TextBlock Grid.Row="2" Grid.Column="1"
                        Text="{Binding YValue, Converter={StaticResource convIComparable}, StringFormat=\{0:N3\}}" />
                    
                    <!-- A UC that shows the specially-retrieved metadata -->
                    <uc:DataPointMetadata Grid.Row="3" Grid.ColumnSpan="2"
                                          DataContext="{Binding
                                                        Converter={StaticResource convSeriesInfoToMetadata},
                                                        ConverterParameter={StaticResource proxy},
                                                        Mode=OneWay}"
                                          />

                </Grid>
            </Border>
        </ControlTemplate>
    </scichart:RolloverModifier.TooltipLabelTemplate>
</scichart:RolloverModifier>
/// <summary>
/// Converts a SeriesInfo Object to a <c>DataPointMetadata</c> struct
/// by invoking a method on the viewmodel. One way only.
/// </summary>
public class SeriesInfoToMetadataConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //cast to viewmodel from proxy
        var vmodel = (vm.SciChartPlotViewModel)((lib.BindingProxy)parameter).Data;
        
        //cast to SeriesInfo from value
        var si = (Abt.Controls.SciChart.SeriesInfo)value;

        //retrieve metadata using viewmodel; viewmodel will query our own series builder facade to retrive the correct
        //data point object, which will contain the metadata
        Pellion.Notebook.Plotting.DataPoint dp = vmodel.GetDataPoint(si.SeriesName, si.DataSeriesIndex);
        return dp.Metadata; //that was easy!
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); }
}
  • dsantimore answered 10 years ago
  • last active 10 years ago
4 votes

Hi,

Please, try translating the mouse point relative to ModifierSurface before using it. Refer to the following code:

_startPoint = GetPointRelativeTo(e.MousePoint, ModifierSurface);

Thing are done in this way in modifiers code. Also, maybe you need to play around with the ReceiveHandledEvents property (if your modifiers are connected together via MouseEventGroup).

Regarding the second question, we don’t provide such an event, but there is the SciChartSurface.Rendered event, which will be fired after each redraw (initiated either by pan, or zoom, or resize operation). Alternatively, you can subscribe to the AxisBase.VisibleRangeChanged event or extend modifiers classes and introduce your own events for them. So in this case you need to subscribe to the SizeChanged event.

Hope this helps,

Best regards,
Yuriy

4 votes

UPDATE

SciChart v3.0 now supports a VerticalSliceModifier, which provides a draggable Vertical line which shows series values as Rollover style tooltips as you drag the line. You can see an example of it in action here:

Series Vertical Slices Example

4 votes

(I’m fairly new with SciChart myself, so I’m not sure if this is the best way to do it…)
You can look at what I’m building for a start. (Functional, but no comments yet. Hopefully the names are obvious enough)
I’m sure there will be a few extensions missing, but hopefully it’ll be obvious what they do.

When you add an annotation, it will show the textbox and tail pointers at an offset from the referenced data point.
When you zoom in and out and pan around, the annotation components will retain their relative size and offset to the point.
In edit mode, you can drag the text and reference points to new locations.

Here are two of the main extensions I know of:

    public static void AddHandler(this DependencyProperty prop, object component, EventHandler handler)
    {
        DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(prop, component.GetType());
        if (dpd != null)
            dpd.AddValueChanged(component, handler);
    }
    public static void AddHandler(this object component, DependencyProperty prop, EventHandler handler)
    {
        DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(prop, component.GetType());
        if (dpd != null)
            dpd.AddValueChanged(component, handler);
    }
4 votes

Hello Joerg,

we created an example for you. You only need to add reference on scichart.dll to run this code.

Best regards,
Yuriy

4 votes

Hi there, and thanks for your enquiry!

It just so happens we have a sample for this already in our internal test-suite. Please see the attached.

What it does is append LabelAnnotations for the values on a Histogram plot. The solution is quite simple, it just uses this code to ensure label annotations are placed centred and above columns:

private void HistogramExampleView_Loaded(object sender, System.Windows.RoutedEventArgs e)
{            
    var series = new XyDataSeries<double, double>();
    series.SeriesName = "Histogram";

    var yValues = new double[] { 0.0, 0.1, 0.2, 0.4, 0.8, 1.1, 1.5, 2.4, 4.6, 8.1, 11.7, 14.4, 16.0, 13.7, 10.1, 6.4, 3.5, 2.5, 1.4, 0.4, 0.1, 0.0, 0.0 };

    for (int i = 0; i < yValues.Length; i++ )
    {
        // DataSeries for appending data
        series.Append(i, yValues[i]);   
 
        // Annotations for text labels
        var labelAnnotation = new TextAnnotation()
                                    {
                                        FontSize = 10,
                                        X1 = i,
                                        Y1 = yValues[i],
                                        Text = yValues[i].ToString(),
                                        Foreground = new SolidColorBrush(Color.FromArgb(0xFF,0x33,0x33,0x33)),
                                        FontWeight = FontWeights.Bold,
                                        VerticalAnchorPoint = VerticalAnchorPoint.Bottom,
                                        HorizontalAnchorPoint = HorizontalAnchorPoint.Center
                                    };

        this.sciChart.Annotations.Add(labelAnnotation);
    }

    columnSeries.DataSeries = series;
}

If you wanted to do something more complex, maybe dynamically place annotations based on changing data, then you could look at this post, which describes an architecture for managing and keeping track of annotations using custom chartmodifiers.

Andrew

4 votes

Hi there,

Please see our KB article on How to Add Mouse Interaction to SciChart, the section on ChartModifier Precedence and Handled mouse events.

ChartModifier Precedence (Handled Events)

ChartModifiers obey a precedence, rather like WPF RoutedEvents. If you have a number of modifiers in a SciChartSurface, then the first modifier that handles an event marks it as e.Handled. Subsequent modifiers will not receive the event.

For instance, consider the following code:


    
        
        
             
             
             
             
        
    

If you drag the chart, then the series will not be selected too, because the RubberBandXyZoomModiifer marks MouseUp as Handled. The SeriesSelectionModifier relies on MouseUp to select. If the event is handled then it will not select.

So far this is all intuitive and good. But what about this case?


    
        
        
             
             
             
             
        
    

Working around event handling with ReceiveHandledEvents

The solution to the above problem is to set ReceiveHandledEvents=True on a modifier. This way the modifier will receive all events, even those marked as handled. Try the following code for instance:


    
        
        
             
             
             
             
        
    

Be careful with this flag though as it could enable event handling where it should not occur.

4 votes

SciChart v3.0 now allows detection of whether VisibleRangeChanged was fired during animation or not. Try this code below:

public void Foo()
{
    var axis = new NumericAxis();

    axis.VisibleRangeChanged += (s, e) =>
        {
            if (e.IsAnimating)
            {
                // VisibleRangeChanged occurred during animation                        
            }
            else
            {
                // VisibleRangeChanged did not occur during animation
            }
        };
}
4 votes

Hi Manish,

I’ve just investigated this now – you’re absolutely right! The above code doesn’t work on the axes. Here. Try this – its a custom modifier I’ve developed which demonstrates hit testing of the YAxis and XAxis.

This code lets you detect click on axis.

public class HitTestingModifier : ChartModifierBase
{
    public override void OnModifierMouseDown(ModifierMouseArgs e)
    {
        bool isOnChart = IsPointWithinBounds(e.MousePoint, ModifierSurface);
        bool isOnYAxis = IsPointWithinBounds(e.MousePoint, YAxis);
        bool isOnXAxis = IsPointWithinBounds(e.MousePoint, XAxis);

        MessageBox.Show(string.Format("Clicked YAxis? {0}\nClicked XAxis? {1}\nClicked Chart? {2}", isOnYAxis,
                                        isOnXAxis, isOnChart));

        base.OnModifierMouseDown(e);
    }

    public bool IsPointWithinBounds(Point point, IHitTestable element)
    {
        var tPoint = ParentSurface.RootGrid.TranslatePoint(point, element);

        bool withinBounds = (tPoint.X <= (element as FrameworkElement).ActualWidth && tPoint.X >= 0)
                            && (tPoint.Y <= (element as FrameworkElement).ActualHeight && tPoint.Y >= 0);

        return withinBounds;
    }
}

If you click in the XAxis, YAxis or chart region you will get a message box showing what element has been clicked.

Example attached

Thanks!

4 votes

Thanks to Andrew, setting the ResamplingMode to Auto seems to have fixed the problem

  • kewur answered 9 years ago
4 votes

Hello there,

I’m investigating this now.

I can confirm if I run the application on my pc, while it doesn’t lock up by 16,000 points, it is certainly slower. What hardware do you have out of interest? It shouldn’t make much difference (unless its really slow). Mine is quad-core i7. 2.4GHz, so nothing stellar, but no sluggard either.

(BTW I’m really impressed with the SciChart application you’ve written in such a short period of time as in the trial. Nice application & really impressive job!)

Now, I ran your test application through DotTrace. The results are attached.

They make interesting reading! Basically the SciChartOverview is responsible for 40% of the time spent on the main thread. Particularly where the overview control is zooming itself to extents on each point added (on each redraw). We haven’t really optimized the overview for performance as it never raised itself as a bottleneck – it has now!

So, my first piece of advice is, remove the overview

The next interesting thing is that the axis drawing takes 10% of the time. In particular, Axis tick-drawing takes 6.4%. Remember if we remove overview all these figures double, so the tick drawing alone is quite significant.

My second recommendation is to Set AxisBase.DrawMinorTicks = false on all XAxes and YAxes

This will reduce the number of lines these are adding to the screen per frame. Axis ticks and labels are drawn using WPF canvases which are far slower than bitmap renderered series, so we want to minimise these if at all possible. If you can handle it setting AxisBase.DrawMinorGridLines = false will further improve performance since it will reduce the number of elements on the screen, however, there is only one set of gridlines for N axes and there are N sets of minor ticks, so minor ticks are the low hanging fruit here.

My third recommendation is to set SciChartSurface.RenderPriority = RenderPriority.Low

What does this do? It puts the priority of the render thread below the priority of mouse and keyboard input. This is really important as once the UI thread approaches saturation you will lose keyboard and mouse interactivity. This will really annoy your users and give you the impression that the application is ‘locked up’. By using priority low for rendering you give control back to the message loop to process mouse and key events and make your application a lot happier. The trade off is the chart rendering may appear more stuttery but it is because redraws are postponed slightly while the WPF message loop is flushed, resulting in a more fluid application experience.

If you want you can go one further and set RenderPriority.Manual. Then you are responsible for calling SciChartSurface.InvalidateElement() after appending points. For instance, you could set a timer and call InvalidateElement() every 1/10th of a second, rather than for each point appended.

My final recommendation is to throttle data appended to the chart, using the DataSeries.Append(IEnumerable<TX> xValues, IEnumerable<TY> yValues) API

The chart dataseries already do a good job of throttling data. For instance, there is not necessarily 1 redraw for each point appended. However, on each point appended some calculations are performed, such as Min Max calculations of the DataSeries, and checking internal state of the chart before pushing a redraw message onto a stack for the renderer thread to pick up. This is a small overhead but if you are calling DataSeries.Append in a tight loop it will soon add up. You can buffer or throttle appends but using the DataSeries.Append(IEnumerable<TX> xValues, IEnumerable<TY> yValues) method. Passing in arrays here of even size 10 or 100 points at a time can significantly improve throughput.


I’ve just tried the above (except for buffering Appends since that would require bigger changes to the code than I can do here) and I’m seeing task manager report a more healthy 7% CPU at ~16k points rather than the 29% I was seeing before. Can you try these and see if you get the same?

Regarding the overview, we’ll work on that. I suggest leaving it out for now and replacing with a scrollbar, calculating the offset based on XAxis.VisibleRange vs. the known DataSeries.XValues

Best regards,
Andrew

4 votes

Update June 2014: The Short Answer

We’ve now integrated the X and Y Values to the Rollovermodifier natively, and this is demonstrated in our examples. Please see the Realtime Cursors Example which demonstrates a Rollover with X and Y Values in the Legend area.

The Long Answer

The way it works is like this. The RolloverModifier and LegendModifier are simply data-sources, which give you an ObservableCollection<SeriesInfo> to bind to in XAML.

The Series Info classes are defined in the API documentation here:

Each Series has its own SeriesInfo type. All of them inherit from SeriesInfo, which is the base type. So given you are binding to a collection of SeriesInfo when you use the RolloverModifier or LegendModifier, it becomes possible to expose almost any info about the underlying RenderableSeries or DataSeries.

As a starting point please see our RolloverModifier demo, in particular the source code where we create the ItemsControl to consume SeriesInfo objects:

<!-- Binds to SeriesInfo, outputs Y-Values only -->
<!-- By modifying this and using knowledge of SeriesInfo class definition above, -->
<!-- you can theoretically do anything! --> 
<Border Grid.Row="1" Margin="23,23" HorizontalAlignment="Left" VerticalAlignment="Top" Background="#77FFFFFF" BorderBrush="#55000000" BorderThickness="2" Padding="5">
    <ItemsControl DataContext="{Binding ElementName=rolloverModifier}" ItemsSource="{Binding RolloverData.SeriesInfo}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <TextBlock Grid.Column="0"
                               Margin="3,3,20,3"
                               FontSize="13"
                               FontWeight="Bold"
                               Foreground="{Binding SeriesColor,
                                                    Converter={StaticResource ColorToBrushConverter}}"
                               Text="{Binding SeriesName}" />
                    <TextBlock Grid.Column="1"
                               Margin="3,3,3,3"
                               FontSize="13"
                               FontWeight="Bold"
                               Foreground="{Binding SeriesColor,
                                                    Converter={StaticResource ColorToBrushConverter}}"
                               Text="{Binding Value}" />
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Border>

Note that when you bind to XValue / YValue which are of type IComparable, you will need a converter or a StringFormat to convert from IComparable to the display value. Yes believe it or not, in XAML if you bind an IComparable which is actually a double to a TextBlock it won’t display! Please use an IComparable converter if you get blank values when binding to these properties.

In the RealTimeCursors example we see this code to convert the XValue, YValue to doubles:

<!-- When binding to XValue, YValue of type IComparable, StringFormat is mandatory due to a -->
<!-- XAML bug that cannot convert IComparable to text, even though underlying type is double -->
<StackPanel Orientation="Horizontal" Grid.Column="2">
    <TextBlock Text="X: " Style="{StaticResource tbStyle}"/>
    <TextBlock Text="{Binding XValue, StringFormat=\{0:0.00\}}" Style="{StaticResource tbStyle}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="3">
    <TextBlock Text="Y: " Margin="3" Style="{StaticResource tbStyle}"/>
    <TextBlock Text="{Binding YValue, StringFormat=\{0:0.00\}}" Style="{StaticResource tbStyle}"/>
</StackPanel>

Advanced SeriesInfo Binding

Finally, many people ask us how to bind to a specific property on the RenderableSeries or DataSeries. Well, the SeriesInfo exposes the RenderableSeries too so its possible to expose any property from the RenderableSeries. Don’t forget RenderableSeries.DataSeries also allows access from SeriesInfo right back to the original DataSeries.

  • Andrew
3 votes
In reply to: Polar Chart X-Axis

Hi and thanks for your detailed & clear question,

I’ve spoken with the team today at the morning stand-up and asked ‘what would it take to natively support rotation of the polar X-Axis in SciChart v3.x?’

The answer is, it’s not a simple job, but it can of course be done. The difficulty comes in the zoom functionality and transformation of coordinates for drawing. There’s a lot of code that needs to be touched to ensure everything works well, including zoom, tooltips, annotations, not just series drawing.

What I’ve done is created a feature-request in our task tracker. We’re not going to do it straight away, but, if enough people comment here +1 ‘me too’ style we will do it!

Sorry I couldn’t be more help at this time but I hope we can in the future,

Best regards,
Andrew

3 votes

UPDATE

SciChart v3.0 now supports a VerticalSliceModifier, which provides a draggable Vertical line which shows series values as Rollover style tooltips as you drag the line. You can see an example of it in action here:

Series Vertical Slices Example

3 votes

Hi Miles,

SciChart is only configured to draw two gridlines, major and minor. There are three ways I can suggest you do this (or close enough)

a.) Simplest way, manually calculate Major, MinorDelta

Configure the chart by setting AutoTicks=False and set the MajorDelta, MinorDelta to weeks and months.

See this KB article on Axis Gridlines, Ticks, Label Formatting which shows how to set MajorDelta, MinorDelta and AutoTicks to get simple adjustment of the tick frequency.

In SciChart a TimeSpan of one month is defined as this:

private const double DaysInMonth = 365.2425 / 12.0;

// Usage, 3 month timespan defined by Timespan t = FromMonths(3)
public static TimeSpan FromMonths(int numberMonths)
{
    return TimeSpan.FromDays(numberMonths * DaysInMonth);
}

This would achieve you month, week gridlines but not day. As you zoom in you could however switch the Major,Minor delta of the chart to show weeks and days.

more b. Complex way, use the TickProvider API

In SciChart v3.0 and above, there is now a way to override the exact Tick Intervals.

See this KB article on Advanced Tick Frequency Overriding which introduces the TickProvider API. This allows exact calculation of ticks (Axis Major, Minor gridlines and labels) as the axis is drawn.

Hope this helps!

3 votes

Hi Marcel,

Keyboard input for ChartModifiers is a hotly requested feature. We haven’t implemented this yet, but you can achieve the same effect by a workaround.

Start by inheriting RolloverModifier and subscribing to the KeyDown event of the parent Window. E.g.

public class KeydownRolloverModifier : RolloverModifier
{
    private double positionFraction = 0.0;

    void KeydownRolloverModifier_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Right)
        {
            positionFraction += 0.01;
        }
        if (e.Key == Key.Left)
        {
            positionFraction -= 0.01;
        }

        // Constrain to 0.0, 1.0
        positionFraction = positionFraction > 1.0 ? 1.0 : positionFraction < 0.0 ? 0.0 : positionFraction;

        UpdateRollover(positionFraction);
    }

    public override void OnAttached()
    {
        base.OnAttached();
        var scichart = (ParentSurface as SciChartSurface);
        scichart.FindLogicalParent<Window>().PreviewKeyDown +=
            new KeyEventHandler(KeydownRolloverModifier_PreviewKeyDown);
    }

    public override void OnModifierMouseMove(ModifierMouseArgs e)
    {
        // Don't call base. This way the mouse does not change the cursor position
        // base.OnModifierMouseMove(e);
    }

    private void UpdateRollover(double fraction)
    {
        var point = new Point(ModifierSurface.Width * fraction, 0);
        point = ModifierSurface.TranslatePoint(point, RootGrid);
        base.OnModifierMouseMove(new ModifierMouseArgs(point, MouseButtons.None, MouseModifier.None, true));
    }
}

The code for FindLogicalParent is as follows:

public static class FrameworkElementExtensions
{
    public static T FindLogicalParent<T>(this FrameworkElement element) where T : FrameworkElement
    {
        var parent = (FrameworkElement)element.Parent;

        if (parent is T)
            return (T)parent;

        return parent.FindLogicalParent<T>();
    }
}

Using the above you should get a key right/left response by moving the rollover. It’ll move by a percentage each time, not to the next data-point. If you wish to achieve data-point by point moves, then maybe take a look at the HitTest API (BaseRenderableSeries.HitTest). This is used in the base RolloverModifier class to get the X,Y values of data-points.

Best regards,
Andrew

3 votes

Hi Deepak, Andrew

There is also another way of achieving this. SciChart allows you to build “mixed charts”, where you have two X axis with different orientation. I compiled a small sample for you, maybe you will find it a bit easier to implement. Please, find the code and screenshot attached.

Also, you can find the example of a histogram implementation in this post.

Hope this helps!

Best regards,
Yuriy

Showing 21 - 40 of 6k results

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies