Pre loader

Horizontal offset in modifier across multiple charts if Surface Margin

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

0
1

Hello,

i have multiple charts stacked, each can have a different number of axes. Since all of them have only one X-Axis i try to align them. This works by adding NumericAxis.ActualWidth for all axes for each diagram on every change in axis configuration. Then, all diagrams with smaller left and right axes area than the maximum get an extra margin.

This works perfect for the diagrams, but the modifiers (RollOver, Cursor) do not account for the offset. I added a screenshot to show it. The margin for each diagram can be different for each diagram for each side and is bound directly to the Margin property of SciChartSurface.

Thanks, Robin

Images
  • You must to post comments
0
0

Hi Robin,

The SciChartSurface measures pixels relative to its root element (not relative to the gridlines panel) hence the offset when trying to synchronise two charts with different numbers of axis.

A very simple solution to this is put the axis on the right, that will mean pixels are measured relative to the left edge which will be the same for both charts. Then, set the padding to 20,20,50,20 (or substitute your own right value in there). Padding will pad the inside of the chart and stretch the background over the original area as opposed to Margin which will show through the underlying control in the empty space.

However, there is another way to solve it properly (WPF Only) using the Grid.IsSharedSizeGroup attached property.

I’ve taken our existing Synchronize Multiple Charts example and modified it slightly.

XAML

Here I’ve added LayoutRoot to the grid, and both SciChartSurface’s subscribe their Loaded event to a shared handler in code-behind. I’ve also added a second axis to the top chart and aligned them all to the left.

<UserControl x:Class="Abt.Controls.SciChart.Example.Examples.IWantTo.ZoomAndPanAChart.SynchronizeMouseAcrossCharts"
        xmlns=" http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x=" http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:s=" http://schemas.abtsoftware.co.uk/scichart" 
        xmlns:common="clr-namespace:Abt.Controls.SciChart.Example.Common">

    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="32"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>

        <!-- Define Toolbar -->
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <ToggleButton Content="Zoom" Margin="3" IsChecked="{Binding ZoomEnabled, Mode=TwoWay}"></ToggleButton>
            <TextBlock Text="or" Foreground="#EEE" Margin="3,8"></TextBlock>
            <ToggleButton Content="Pan" Margin="3" IsChecked="{Binding PanEnabled, Mode=TwoWay}"></ToggleButton>
            <Line Margin="3,1,3,1" VerticalAlignment="Stretch" Stroke="#EEE" StrokeThickness="1" X1="0" X2="0" Y1="6" Y2="25"></Line>
            <ToggleButton Content="MouseWheel" Margin="3" IsChecked="{Binding MouseWheelEnabled, Mode=TwoWay}"></ToggleButton>
            <Line Margin="3,1,3,1" VerticalAlignment="Stretch" Stroke="#EEE" StrokeThickness="1" X1="0" X2="0" Y1="6" Y2="25"></Line>
            <ToggleButton Content="Rollover" Margin="3" IsChecked="{Binding RolloverEnabled, Mode=TwoWay}"></ToggleButton>
            <TextBlock Text="or" Foreground="#EEE" Margin="3,8"></TextBlock>
            <ToggleButton Content="Cursor" Margin="3" IsChecked="{Binding CursorEnabled, Mode=TwoWay}"></ToggleButton>
            <Line Margin="3,1,3,1" VerticalAlignment="Stretch" Stroke="#EEE" StrokeThickness="1" X1="0" X2="0" Y1="6" Y2="25"></Line>
            <Button Margin="3" Content="Zoom Extents" Click="ZoomExtentsClick"></Button>
        </StackPanel>

        <!-- Define Chart 0 -->
        <s:SciChartSurface x:Name="chart0" Grid.Row="1" s:ThemeManager.Theme="Chrome" Loaded="ChartLoaded">
            <s:SciChartSurface.RenderableSeries>
                <s:FastLineRenderableSeries SeriesColor="DarkBlue" DataSeries="{Binding ChartData0}"/>
            </s:SciChartSurface.RenderableSeries>

            <!-- Define X and Y Axis. Optional bands give a cool look and feel for minimal performance impact  -->
            <s:SciChartSurface.YAxes>
                <s:NumericAxis VisibleRange="0,1" GrowBy="0.1,0.1" MinorsPerMajor="2" AxisAlignment="Left"/>
                <s:NumericAxis VisibleRange="0,1" GrowBy="0.1,0.1" MinorsPerMajor="2" AxisAlignment="Left" Id="Second"/>
            </s:SciChartSurface.YAxes>
            <s:SciChartSurface.XAxis>
                <s:NumericAxis VisibleRange="{Binding SharedXVisibleRange, Mode=TwoWay}" GrowBy="0.1,0.1"  MinorsPerMajor="4" DrawMajorBands="True" />
            </s:SciChartSurface.XAxis>
            <s:SciChartSurface.ChartModifier>
                
                <!-- Whats going on here? -->
                <!-- We share the mouse events by using MouseManager.MouseEventGroup="..." -->
                <!-- We ensure modifiers receive events even when another has handled by setting ReceiveHandledEvents=true -->
                <!-- We bind both charts XAxis to shared property on the viewmodel to ensure they stay in sync -->
                <s:ModifierGroup s:MouseManager.MouseEventGroup="myCustomGroup">
                    <s:RubberBandXyZoomModifier ReceiveHandledEvents="True" IsEnabled="{Binding ZoomEnabled, Mode=TwoWay}" IsXAxisOnly="True" />
                    <s:ZoomPanModifier ReceiveHandledEvents="True" IsEnabled="{Binding PanEnabled, Mode=TwoWay}" />
                    <s:MouseWheelZoomModifier IsEnabled="{Binding MouseWheelEnabled, Mode=TwoWay}" />
                    <s:RolloverModifier ReceiveHandledEvents="True" IsEnabled="{Binding RolloverEnabled, Mode=TwoWay}" />
                    <s:CursorModifier ReceiveHandledEvents="True" IsEnabled="{Binding CursorEnabled, Mode=TwoWay}" />
                    <s:YAxisDragModifier Tag="FirstYAxis" />
                    <s:XAxisDragModifier />
                    <s:ZoomExtentsModifier />
                </s:ModifierGroup>
            </s:SciChartSurface.ChartModifier>
        </s:SciChartSurface>

        <!-- Define Chart 1 -->
        <s:SciChartSurface x:Name="chart1" Grid.Row="2" s:ThemeManager.Theme="Chrome" Loaded="ChartLoaded">
            <s:SciChartSurface.RenderableSeries>
                <s:FastLineRenderableSeries SeriesColor="DarkBlue" DataSeries="{Binding ChartData1}"/>
            </s:SciChartSurface.RenderableSeries>

            <!-- Define X and Y axis. Optional bands give a cool look and feel for minimal performance impact  -->
            <s:SciChartSurface.YAxis>
                <s:NumericAxis VisibleRange="0,1" GrowBy="0.1,0.1" MinorsPerMajor="2" AxisAlignment="Left" />
            </s:SciChartSurface.YAxis>
            <s:SciChartSurface.XAxis>
                <s:NumericAxis VisibleRange="{Binding SharedXVisibleRange, Mode=TwoWay}" GrowBy="0.1,0.1"  MinorsPerMajor="4" DrawMajorBands="True"/>
            </s:SciChartSurface.XAxis>
            <s:SciChartSurface.ChartModifier>
                <s:ModifierGroup s:MouseManager.MouseEventGroup="myCustomGroup">
                    <s:RubberBandXyZoomModifier Tag="SecondYAxis" ReceiveHandledEvents="True" IsEnabled="{Binding ZoomEnabled, Mode=TwoWay}" IsXAxisOnly="True"></s:RubberBandXyZoomModifier>
                    <s:ZoomPanModifier Tag="SecondYAxis" ReceiveHandledEvents="True" IsEnabled="{Binding PanEnabled, Mode=TwoWay}" />
                    <s:MouseWheelZoomModifier Tag="SecondYAxis" IsEnabled="{Binding MouseWheelEnabled, Mode=TwoWay}" />
                    <s:RolloverModifier Tag="SecondYAxis" ReceiveHandledEvents="True" IsEnabled="{Binding RolloverEnabled, Mode=TwoWay}" />
                    <s:CursorModifier Tag="SecondYAxis" ReceiveHandledEvents="True" IsEnabled="{Binding CursorEnabled, Mode=TwoWay}" />
                    <s:YAxisDragModifier Tag="SecondYAxis" />
                    <s:XAxisDragModifier Tag="SecondYAxis" />
                    <s:ZoomExtentsModifier Tag="SecondYAxis" />
                </s:ModifierGroup>
            </s:SciChartSurface.ChartModifier>

        </s:SciChartSurface>

    </Grid>
</UserControl>

Code Behind

In code behind you can see where I’ve used the Grid.IsSharedSizeScope property and SharedSizeGroup to synchronize the left column.

using System;
using System.Windows;
using System.Windows.Controls;

namespace Abt.Controls.SciChart.Example.Examples.IWantTo.ZoomAndPanAChart
{
    public partial class SynchronizeMouseAcrossCharts : UserControl
    {
        public SynchronizeMouseAcrossCharts()
        {
            InitializeComponent();

            this.Loaded += MultiChartMouseEvents_Loaded;
        }

        void MultiChartMouseEvents_Loaded(object sender, RoutedEventArgs e)
        {
            chart0.AnimateZoomExtents(TimeSpan.FromMilliseconds(1000));
            chart1.AnimateZoomExtents(TimeSpan.FromMilliseconds(1000));
        }

        private void ZoomExtentsClick(object sender, EventArgs e)
        {
            chart0.AnimateZoomExtents(TimeSpan.FromMilliseconds(500));
            chart1.AnimateZoomExtents(TimeSpan.FromMilliseconds(500));
        }


        private void ChartLoaded(object sender, EventArgs e)
        {
#if !SILVERLIGHT
            if (!chart0.IsLoaded || !chart1.IsLoaded) return;

            // SciChartSurface has a Grid at its root. This has 3 columns, for left axis, centre area and right axis
            // We can get these column definitions out and use Grid.IsSharedSizeScope
            Grid rootGrid0 = (Grid)chart0.RootGrid;
            Grid rootGrid1 = (Grid)chart1.RootGrid;

            // Using Grid.SharedSizeGroup  http://stackoverflow.com/questions/9977838/how-to-use-sharedsizescope-between-2-wpf-controls-with-parent-child-relation 
            // property must be on the parent of both children
            Grid.SetIsSharedSizeScope(LayoutRoot, true);

            rootGrid0.ColumnDefinitions[0].SharedSizeGroup = "LeftAxisGroup";
            //rootGrid0.ColumnDefinitions[2].SharedSizeGroup = "RightAxisGroup";

            rootGrid1.ColumnDefinitions[0].SharedSizeGroup = "LeftAxisGroup";
            //rootGrid1.ColumnDefinitions[2].SharedSizeGroup = "RightAxisGroup";
#endif
        }

    }
}

That’ll produce a result like this (attached).

Tah dah!

Images
  • Andreas Mueller-Bluemlein
    Hi Andrew, excellent solution, thank you very much for this. I'm very new to WPF, so i didn't even get close to this. It works perfect, for left and right axes and even if the number of chart is dynamic in an itemscontrol. Thanks, Robin
  • johnnyp112
    Hi, Can this be done using MVVM?
  • johnnyp112
    I should be more specific. How can I expose the SciChartSurface's root grid in XAML?
  • Andrew Burnett-Thompson
    Hi Johnny, I wouldn't recommend doing that. I would suggest leaving the solution in code-behind (since its view code anyway, and unrelated to the business logic in your viewmodel). If you want to wrap it up somewhere neatly perhaps you can create an attached property and move the logic to there. Best regards, Andrew
  • johnnyp112
    Andrew, Thanks for your suggestion, I was able to implement this in the code behind as in your example and it works well. Johnny
  • You must to post comments
Showing 1 result
Your Answer

Please first to submit.

Try SciChart Today

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

Start TrialCase Studies