WPF Charting Documentation - SciChart WPF Charts SDK v5.x
Custom Modifiers – ChartModifierBase API

The ChartModifierBase API is by far the most powerful API in the SciChart library.

Using this API you can create behaviours which you can attach to a chart to perform custom Zooming, Panning, Annotation & Markers, Legend output and much much more. Any time you want to do something in C# code to alter the behaviour of a SciChartSurface you should be thinking about creating a custom modifier to do it.

The ChartModifierBase type

The ChartModifierBase provides an abstract base class for all of the ChartModifiers within SciChart. All of our built-in modifiers such as ZoomPanModifierRolloverModifierTooltipModifierYAxisDragModifier inherit ChartModifierBase.

You can create your own ChartModifiers by inheriting this class. For example, you can declare a modifier like this:

The ChartModifierBase type
Copy Code
public class DoubleClickToZoomExtentsModifier : ChartModifierBase
{
    public override void OnModifierDoubleClick(ModifierMouseArgs e)
    {
        base.OnModifierDoubleClick(e);

        base.ParentSurface.AnimateZoomExtents(TimeSpan.FromMilliseconds(500));
    }
}

And apply it like this:

The ChartModifierBase type
Copy Code
<s:SciChartSurface>
    <s:SciChartSurface.ChartModifier>
       <local:DoubleClickToZoomExtentsModifier/>
    </s:SciChartSurface.ChartModifier>
</s:SciChartSurface>

... and you've just created your first custom Zoom Extents behaviour using the ChartModifier API!

The Most Important Methods / Properties in the ChartModifierBase class

The API Documentation will tell you everything that ChartModifierBase can do, but for your convenience we've listed the most important methods and properties below:

 

Property

Description

IsEnabled

Gets or sets a value indicating whether this ChartModifier is enabled

IsMouseLeftButtonDown

Gets if the Left mouse button is currently down

IsMouseMiddleButtonDown

Gets if the Middle mouse button is currently down

IsMouseRightButtonDown

Gets of the right mouse button is currently down

ModifierSurface

Gets the IChartModifierSurface instance on the parent SciChartSurface, which acts as a canvas to place UIElements

ParentSurface

Overridden. Gets or sets the parent SciChartSurface, to perform operations on

ReceiveHandledEvents

Gets or sets a value, indicates whether current modifier handles events which have already been marked as handled

XAxisXAxes

Returns the XAxes on the parent Abt.Controls.SciChart.Visuals.SciChartSurface

YAxisYAxes

Returns the YAxes on the parent Abt.Controls.SciChart.Visuals.SciChartSurface

 

Method

Description

GetPointRelativeTo

Transforms the input point relative to the IHitTestable element. Can be used to transform points relative to the

SciChartSurface.ModifierSurface, or SciChartSurface.XAxis for instance.

IsPointWithinBounds

Gets whether the mouse point is within the bounds of the hit-testable element. Assumes the mouse-point has not

been translated yet (performs translation)

OnAttached

Called when the element is attached to the Chart Surface

OnDetached

Called immediately before the element is detached from the Chart Surface

OnMasterMouseLeave

Called when the mouse leaves the Master of current MouseEventGroup

OnModifierDoubleClick

Called when a Mouse DoubleClick occurs on the parent SciChartSurface,

OnModifierMouseDown

Called when a Mouse Button is pressed on the parent SciChartSurface,

OnModifierMouseMove

Called when the Mouse is moved on the parent SciChartSurface,

OnModifierMouseUp

Called when a Mouse Button is released on the parent SciChartSurface,

OnModifierMouseWheel

Called when the Mouse Wheel is scrolled on the parent SciChartSurface,

OnModifierTouchDown

Called when a Multi-Touch Down interaction occurs on the parent SciChartSurface,

OnModifierTouchMove

Called when a Multi-Touch Move interaction occurs on the parent SciChartSurface,

OnModifierTouchUp

Called when a Multi-Touch Up interaction occurs on the parent SciChartSurface,

OnParentSurfaceRendered

Called when the parentSciChartSurface,is rendered

OnParentSurfaceResized

Called when the parent SciChartSurface, is resized

OnParentSurfaceMouseEnter

Called when the mouse enters the parent SciChartSurface,

OnParentSurfaceMouseLeave

Called when the mouse leaves the parent SciChartSurface,

OnSelectedSeriesChanged

Called when the parent surface SelectedSeries collection changes

OnXAxesCollectionChanged

Overridden. Called with the SciChartSurface.XAxes AxisCollection changes. Overridden in derived classes to get notification

of this event

OnYAxesCollectionChanged

Overridden. Called with the SciChartSurface.YAxes AxisCollection changes. Overridden in derived classes to get notification

 of this event

So you can see there are a lot of powerful API functions on the ChartModifierBase class!

 

Using this one base-class you can:

All of our Chart Modifiers are built with this API, the possibilities are really endless!

 

Overriding Mouse Events

To get a notification of mouse-event on the parent SciChartSurface, simply override OnModifierMouseDown, OnModifierMouseMove, OnModifierMouseUp:

Overriding Mouse Events
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Mouse Button is pressed on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseDown(ModifierMouseArgs e)
   {
      base.OnModifierMouseDown(e);
   }

   /// <summary>
   /// Called when the Mouse is moved on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse move operation</param>
   public override void OnModifierMouseMove(ModifierMouseArgs e)
   {
      base.OnModifierMouseMove(e);
   }

   /// <summary>
   /// Called when a Mouse Button is released on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseUp(ModifierMouseArgs e)
   {
      base.OnModifierMouseUp(e);
   }

   /// <summary>
   /// Called when the Mouse Wheel is scrolled on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse wheel operation</param>
   public override void OnModifierMouseWheel(ModifierMouseArgs e)
   {
      base.OnModifierMouseWheel(e);
   }

   /// <summary>
   /// Called when a Mouse DoubleClick occurs on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierDoubleClick(ModifierMouseArgs e)
   {
      base.OnModifierDoubleClick(e);
   }
}

When your chart modifier is attached to a SciChartSurface, mouse events on the chart will propagate to the TestChartModifier instance:

Overriding Mouse Events
Copy Code
<s:SciChartSurface>
   <s:SciChartSurface.ChartModifier>
      <s:TestChartModifier/>
   </s:SciChartSurface.ChartModifier>
</s:SciChartSurface>

 

ModifierMouseArgs Properties

The ModifierMouseArgs passed in to mouse-callbacks can tell you:

ModifierMouseArgs Properties
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Mouse Button is pressed on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseDown(ModifierMouseArgs e)
   {
      base.OnModifierMouseDown(e);

      Point mousePoint = e.MousePoint;
      MouseButtons mouseButtons = e.MouseButtons;
      bool isMaster = e.IsMaster;
      MouseModifier modifierKey = e.Modifier;
   }
}

Transforming Coordinates to the Viewport

Mouse coordinates are measured according to the top-left of the SciChartSurface. To effectively use these mouse-coordinates, they may need to be translated to the central viewport.

Transforming Coordinates to the Viewport
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Mouse Button is pressed on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseDown(ModifierMouseArgs e)
   {
       base.OnModifierMouseDown(e);

       Point xy = e.MousePoint;
        
       var scs = base.ParentSurface;
        
       // gets the bounds of the ModifierSurface with respect to the RootGrid
       // which hosts the SciChartSurface
        var modifierRect = ModifierSurface.GetBoundsRelativeTo(RootGrid);

        // Translates the mouse point (from root grid coords) to ModifierSurface coords
        var x1y1 = base.GetPointRelativeTo(xy, base.ModifierSurface);

        // you can now use this coordinate to convert to data values
        double dataValue = scs.XAxis.GetCurrentCoordinateCalculator()
                             .GetDataValue(x1y1.X);

   }
}

Given a SciChartSurface bounds and a mouse coordinate (x,y), you may need to transform to viewport coordinates (x’,y’)

Determining if Mouse Event occurred over an Axis or main chart surface

To determine if a mouse-point is over an element, we can use code similar to the following. This is useful if you want to start a modifier action only if the mouse-down occurred on an axis, or on the main chart.

Determining if Mouse Event occurred over an Axis or main chart surface
Copy Code
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}\n" +
            “Clicked Chart? {2}",
             isOnYAxis, isOnXAxis, isOnChart));

        base.OnModifierMouseDown(e);
    }

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

        var fe = (element as FrameworkElement);
        bool inBounds = (x1y1.X <= fe.ActualWidth && x1y1.X >= 0)
                            && (x1y1.Y <= fe.ActualHeight && x1y1.Y >= 0);

        return inBounds;
    }
}

Determining if the Mouse is over a RenderableSeries

To determine if a mouse-event occurred over a RenderableSeries, you can combine the ChartModifier API with the Hit-Test API, described in RenderableSeries Hit-Test API

Determining if the Mouse is over a RenderableSeries
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Mouse Button is pressed on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseDown(ModifierMouseArgs e)
   {
      base.OnModifierMouseDown(e);

      double hitTestRadius = 5d;
      bool interpolate = true;

      foreach (var rSeries in base.ParentSurface.RenderableSeries)
      {
         var hitResult = rSeries.HitTest(e.MousePoint, hitTestRadius, interpolate);

         if (hitResult.IsHit)
         {
            // Mouse is over series!
         }
      }
   }      
}

Determining Drag on the chart

Determining Drag on the chart is as simple as registering MouseDown, followed by MouseMove and MouseUp on the chart. To do this, we suggest using some Boolean flags to track the state of the current mouse. All the modifier callbacks are called on the UI thread so you can be assured of the thread safety of the API.

Overriding Touch Events

SciChart’s ChartModifierBase API also has a number of callbacks for processing touch events. These us the TouchPoint class in WPF4’s multi-touch API.

Overriding Touch Events
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Multi-Touch Down occurs on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the manipulation operation</param>
   public override void OnModifierTouchDown(ModifierTouchManipulationArgs e)
   {
      base.OnModifierTouchDown(e);

      IEnumerable<TouchPoint> touchPoints = e.Manipulators;           
   }

   /// <summary>
   /// Called when a Multi-Touch Move occurs on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the manipulation operation</param>
   public override void OnModifierTouchMove(ModifierTouchManipulationArgs e)
   {
      base.OnModifierTouchMove(e);
   }

   /// <summary>
   /// Called when a Multi-Touch Up occurs on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the manipulation operation</param>
   public override void OnModifierTouchUp(ModifierTouchManipulationArgs e)
   {
      base.OnModifierTouchUp(e);
   }
}

Similar notes apply to e.IsMaster and also translating TouchPoint.Position to the main central viewport as in  Transforming Coordinates to the Viewport

Overriding Key Events

SciChart also allows handling of Key events in the ChartModifier API. To get a notification of a key event, simply override OnModifierKeyDown, OnModifierKeyUp

Overriding Key Events
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when the KeyDown event is fired for the Master of the current <see cref="MouseEventGroup" />
   /// </summary>
   /// <param name="e">Arguments detailing the key event</param>
   public override void OnModifierKeyDown(ModifierKeyArgs e)
   {
      base.OnModifierKeyDown(e);

      Key key = e.Key;
      MouseModifier modifierKey = e.Modifier;
      bool isMaster = e.IsMaster;
   }

   /// <summary>
   /// Called when the KeyUp event is fired for the Master of the current <see cref="MouseEventGroup" />
   /// </summary>
   /// <param name="e">Arguments detailing the key event</param>
   public override void OnModifierKeyUp(ModifierKeyArgs e)
   {
      base.OnModifierKeyUp(e);
   }
}

Drawing Shapes over the Chart with the ModifierSurface

The ChartModifierBase API was primarily designed to facilitate behavior-like classes to give zoom and pan behaviours to the chart. This quickly evolved into tooltips and now any behavior which requires access to the underlying SciChartSurface visual or logical elements could be placed in a ChartModifier.

To draw shapes over the chart at the time of using a ChartModifier, you can use the SciChartSurface.ModifierSurface property.

The ModifierSurface is simply a canvas which is overlaid on top of the SciChartSurface. This is a great place to put tooltips or temporary UI such as zoom-box rectangles as you interact with the chart. The following code demonstrates how to add a Shape to the ModifierSurface on MouseDown for instance:

Drawing Shapes over the Chart with the ModifierSurface
Copy Code
public class TestChartModifier : ChartModifierBase
{
   /// <summary>
   /// Called when a Mouse Button is pressed on the parent <see cref="SciChartSurface" />
   /// </summary>
   /// <param name="e">Arguments detailing the mouse button operation</param>
   public override void OnModifierMouseDown(ModifierMouseArgs e)
   {
       base.OnModifierMouseDown(e);

       Point xy = e.MousePoint;
        
       var rect = new Rectangle() { Fill = new SolidColorBrush(Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF), Width = 10, Height = 10 };
          base.ParentSurface.ModifierSurface.Children.Add(rect);
         
          Canvas.SetLeft(rect, 100);
          Canvas.SetTop(rect, 200);
   }
}

Custom ChartModifier Tutorials

A number of custom chartmodifier examples and tutorials have been prepared at http://support.scichart.com/index.php?/Knowledgebase/List/Index/32


 

 

 

 


SCICHART ® is a Registered Trademark in the UK, US and EU. Copyright SciChart Ltd 2011-2018.

Email us to give feedback!