Search Results for

    Show / Hide Table of Contents

    Custom Modifiers - the GestureModifierBase API

    The GestureModifierBase provides an abstract base class for all Gesture-Based Modifiers within SciChart. Using this API, you can create gestures that you can attach to a chart to perform any gesture you like. Any time you want to do something to alter the behavior of any built-in gesture modifiers, you should be thinking about creating a custom gesture-based modifier to do it.

    Note

    Example of the Custom Gesture-Based Modifier can be found in the SciChart Android Examples Suite as well as on GitHub:

    Custom Gesture-Based Modifier

    An example below shows how to use GestureModifierBase API to create a chart custom gesture-based modifier.

    As an example, we will implement a single finger vertical pinch-zoom gesture-based modifier to zoom our chart on X-Axis. Also, we want to enable it by double-tap (similar to how it works in Google Maps App).

    Note

    It's highly recommended to inherit from GestureModifierBase since it gives you some of the base implementations for free.

    Let's get into the code.

    • Java
    • Java with Builders API
    • Kotlin
    class CustomZoomGestureModifier extends GestureModifierBase {
        private boolean isScrolling = false;
        private boolean isZoomEnabled = false;
    
        private float touchSlop;
        private final PointF start = new PointF();
        private float lastY;
    
        @Override
        public void attachTo(IServiceContainer services) {
            super.attachTo(services);
    
            final Context context = getContext();
            if (context == null) return;
    
            this.touchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
        }
    
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            start.set(e.getX(), e.getY());
            lastY = e.getY();
            isZoomEnabled = true;
    
            return true;
        }
    
        @Override
        public void onTouch(ModifierTouchEventArgs args) {
            super.onTouch(args);
    
            final MotionEvent motionEvent = args.e;
            if (isZoomEnabled && motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                onScrollInYDirection(motionEvent.getY());
            }
        }
    
        private void onScrollInYDirection(float y) {
            final float distance = Math.abs(y - start.y);
            if (distance < touchSlop || Math.abs(y - lastY) < 1f) return;
    
            this.isScrolling = true;
    
            final float prevDistance = Math.abs(lastY - start.y);
            final double diff = prevDistance > 0 ? distance / prevDistance - 1 : 0;
    
            growBy(start, getXAxis(), diff);
    
            this.lastY = y;
        }
    
        // zoom axis relative to the start point using fraction
        private void growBy(PointF point, IAxis axis, double fraction) {
            final int size = axis.getAxisViewportDimension();
            final float coord = size - point.y;
    
            double minFraction = (coord / size) * fraction;
            double maxFraction = (1 - coord / size) * fraction;
    
            axis.zoomBy(minFraction, maxFraction);
        }
    
        @Override
        protected void onUp(MotionEvent e) {
            // need to disable zoom after finishing scrolling
            if (isScrolling) {
                isScrolling = isZoomEnabled = false;
                start.set(Float.NaN, Float.NaN);
                lastY = Float.NaN;
            }
        }
    }
    
    class CustomZoomGestureModifier extends GestureModifierBase {
        private boolean isScrolling = false;
        private boolean isZoomEnabled = false;
    
        private float touchSlop;
        private final PointF start = new PointF();
        private float lastY;
    
        @Override
        public void attachTo(IServiceContainer services) {
            super.attachTo(services);
    
            final Context context = getContext();
            if (context == null) return;
    
            this.touchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
        }
    
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            start.set(e.getX(), e.getY());
            lastY = e.getY();
            isZoomEnabled = true;
    
            return true;
        }
    
        @Override
        public void onTouch(ModifierTouchEventArgs args) {
            super.onTouch(args);
    
            final MotionEvent motionEvent = args.e;
            if (isZoomEnabled && motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                onScrollInYDirection(motionEvent.getY());
            }
        }
    
        private void onScrollInYDirection(float y) {
            final float distance = Math.abs(y - start.y);
            if (distance < touchSlop || Math.abs(y - lastY) < 1f) return;
    
            this.isScrolling = true;
    
            final float prevDistance = Math.abs(lastY - start.y);
            final double diff = prevDistance > 0 ? distance / prevDistance - 1 : 0;
    
            growBy(start, getXAxis(), diff);
    
            this.lastY = y;
        }
    
        // zoom axis relative to the start point using fraction
        private void growBy(PointF point, IAxis axis, double fraction) {
            final int size = axis.getAxisViewportDimension();
            final float coord = size - point.y;
    
            double minFraction = (coord / size) * fraction;
            double maxFraction = (1 - coord / size) * fraction;
    
            axis.zoomBy(minFraction, maxFraction);
        }
    
        @Override
        protected void onUp(MotionEvent e) {
            // need to disable zoom after finishing scrolling
            if (isScrolling) {
                isScrolling = isZoomEnabled = false;
                start.set(Float.NaN, Float.NaN);
                lastY = Float.NaN;
            }
        }
    }
    
    class CustomZoomGestureModifier : GestureModifierBase() {
        private var isScrolling = false
        private var isZoomEnabled = false
    
        private var touchSlop = 0f
        private val start = PointF()
        private var lastY = 0f
    
        override fun attachTo(services: IServiceContainer) {
            super.attachTo(services)
    
            val context = context ?: return
            touchSlop = (ViewConfiguration.get(context).scaledTouchSlop * 2).toFloat()
        }
    
        // These methods fire on each gesture event
        override fun onDoubleTap(e: MotionEvent): Boolean {
            start.set(e.x, e.y)
            lastY = e.y
            isZoomEnabled = true
    
            return true
        }
    
        override fun onTouch(args: ModifierTouchEventArgs) {
            super.onTouch(args)
    
            val motionEvent = args.e
            if (isZoomEnabled && motionEvent.action == MotionEvent.ACTION_MOVE) {
                onScrollInYDirection(motionEvent.y)
            }
        }
    
        // Here, we put all our logic of calculation zoom in and out
        private fun onScrollInYDirection(y: Float) {
            val distance = abs(y - start.y)
            if (distance < touchSlop || abs(y - lastY) < 1f) return
    
            isScrolling = true
    
            val prevDistance = abs(lastY - start.y)
            val diff = if (prevDistance > 0) (distance / prevDistance - 1).toDouble() else 0.toDouble()
            growBy(start, xAxis, diff)
    
            lastY = y
        }
    
        // zoom axis relative to the start point using fraction
        private fun growBy(point: PointF, axis: IAxis, fraction: Double) {
            val size = axis.axisViewportDimension
            val coord = size - point.y
    
            val minFraction = coord / size * fraction
            val maxFraction = (1 - coord / size) * fraction
    
            axis.zoomBy(minFraction, maxFraction)
        }
    
        override fun onUp(e: MotionEvent) {
            // need to disable zoom after finishing scrolling
            if (isScrolling) {
                isZoomEnabled = false
                isScrolling = isZoomEnabled
                start[Float.NaN] = Float.NaN
                lastY = Float.NaN
            }
        }
    }
    

    Add it onto your chart like any other modifier to see how it works.

    Common Gesture Modifier Properties

    As mentioned above, all GestureModifiers within SciChart derive from the abstract GestureModifierBase class, which conforms to OnGestureListener, OnDoubleTapListener interfaces and uses a GestureDetector internally.

    Please see the list of common properties below:

    Note

    To learn more about common ChartModifier features - please read the Chart Modifier APIs article. Also visit related IChartModifier API documentation.

    Back to top © 2011-2025 SciChart. All rights reserved. | sitemap.xml