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

0
1

Hello Friends ,

   Sync two Chart in Android Bottom chart can be change on top chart touch

We are looking a solution where we want show two chart at Top and Bottom in Android Screen.based on Top chart changed by gesture /finger touch should be expend/shrink like zoom in and out bottom chart

Assume at top chart data range has between 0 to 3,00,000 , I want to capture in bottom chart only selected/touched part in with expanded form.

I have attached below screen shot which may be helpful.

Solution can be like this but not able to get code for this implementation

https://blog.scichart.com/content/images/2021/06/Navigate-ECG-strip-with-Pocket-ECM.gif

https://blog.scichart.com/android-app-to-view-long-term-ecg-signals/

I appreciate any help regarding this issue.

Version
4.3.0.4660
Images
  • You must to post comments
0
0

Hi Vasim,

Well I think you can implement desired behavior by adding listener for top chart’s xAxis and changing VisibleRange of other bottom chart’s xAxis. Also I would suggest to take a look on Realtime Ticking Stock Chart example which has 2 charts, where one chart changes its state based on VisibleRange of other chart by using VisibleRangeChangeListener API.

Best regards,
Yura

  • Yura Khariton
    Well I understand that this isn’t exactly behavior that you’re trying to achieve. Example from link just a demonstration of how VisibleRangeListener API can be used to track changes in VisibleRange in one chart and based on this change update other chart. So in your case you’ll need need to add listener to xAxis of chart that you zoom, pan, and based on values received in listener update second chart
  • vasim simform
    Thank you for quick response I would request to you help me to provide more code which works for visible range listener code, As of now i can see only snippet code but couldn’t see actual implementation like passing touched (x,y) coordinate to next chart for panning and zooming
  • Yura Khariton
    OK, I probably misunderstood what you’re trying to achieve. I thought that one chart should be changed based on X range which is displayed by other chart. Could you provide more detailed description of how chart should react when something happens ( e.g. on gesture or adding new data )? It looks like you’re trying to achieve some complex behavior and in this case I can only give you links on documentation or examples which can be useful. If you need touch coordinates you’ll need to use ChartModifier API ( https://www.scichart.com/documentation/android/current/webframe.html#Custom%20Modifiers%20-%20ChartModifierBase%20API.html ), which is responsible for interaction with chart and override its onTouch() method to receive touch events from chart. Also here some useful links if you need to convert pixel coordinates to data coordinates (https://www.scichart.com/documentation/android/current/webframe.html#Axis%20APIs%20-%20Convert%20Pixel%20to%20Data%20Coordinates.html) or find data point from specific series ( https://www.scichart.com/example/android-chart-example-hit-test-api/ ).
  • vasim simform
    Hello Yura ,Thanks for quick response As you showed different ways to implementation for expected output but by doing this which takes enormous time to us which impacting to our business ,Although I couldn’t see your example with advance implementation , if we have to do this way then what’s benefits to purchase SciChart plan. Please I would request provide to more simple implementation technique Thanks
  • vasim simform
    Hello Yura Could you provide any other solution for above question?
0
0

Hi there,

I modified one of our examples to show to implement behavior from GIF that you attached before ( when you drag annotation on bottom chart this changes VisibleRange on top chart and when you pan top chart this changes position of line annotation on bottom chart ) :

public class SyncMultipleChartsFragment extends ExampleBaseFragment<ExampleSyncMultipleChartsFragmentBinding> {
    private final static int POINTS_COUNT = 500;
    private final static double RANGE_WINDOW = 5d;

    private final DoubleRange topXRange = new DoubleRange();

    @Override
    public boolean showDefaultModifiersInToolbar() { return false; }

    @Override
    protected ExampleSyncMultipleChartsFragmentBinding inflateBinding(LayoutInflater inflater) {
        return ExampleSyncMultipleChartsFragmentBinding.inflate(inflater);
    }

    @Override
    protected void initExample(ExampleSyncMultipleChartsFragmentBinding binding) {
        initBottomChart(binding.chart1);
        initTopChart(binding.chart0);
    }

    private void initTopChart(final SciChartSurface surface) {
        final IAxis xAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.1d, 0.1d).withVisibleRange(topXRange).withAutoRangeMode(AutoRange.Never).build();
        final IAxis yAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.1d, 0.1d).withAutoRangeMode(AutoRange.Always).build();

        final FastLineRenderableSeries line = sciChartBuilder.newLineSeries().withDataSeries(createDataSeries()).withStrokeStyle(ColorUtil.Green, 1f, true).build();

        UpdateSuspender.using(surface, new Runnable() {
            @Override
            public void run() {
                Collections.addAll(surface.getXAxes(), xAxis);
                Collections.addAll(surface.getYAxes(), yAxis);
                Collections.addAll(surface.getRenderableSeries(), line);
                Collections.addAll(surface.getChartModifiers(), sciChartBuilder.newModifierGroupWithDefaultModifiers().build());
            }
        });

    }

    private void initBottomChart(final SciChartSurface surface) {
        final IAxis xAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.1d, 0.1d).withAutoRangeMode(AutoRange.Always).build();
        final IAxis yAxis = sciChartBuilder.newNumericAxis().withGrowBy(0.1d, 0.1d).withAutoRangeMode(AutoRange.Always).build();

        final FastLineRenderableSeries line = sciChartBuilder.newLineSeries().withDataSeries(createDataSeries()).withStrokeStyle(ColorUtil.Green, 1f, true).build();

        final double initialValue = 5d;
        VerticalLineAnnotation lineAnnotation = sciChartBuilder.newVerticalLineAnnotation()
                .withStroke(5f, Color.RED)
                .withX1(initialValue)
                .withIsEditable(true)
                .withAnnotationLabel(LabelPlacement.Axis)
                .build();
        topXRange.setMinMaxDouble(initialValue - RANGE_WINDOW, initialValue + RANGE_WINDOW);

        topXRange.addRangeChangeObserver(new IRangeChangeObserver<Double>() {
            @Override
            public void onRangeChanged(Double oldMin, Double oldMax, Double newMin, Double newMax, int changedProperty) {
                lineAnnotation.setX1((newMax + newMin) / 2d); // update position of annotation when range changes
            }
        });

        lineAnnotation.setOnAnnotationDragListener(new OnAnnotationDragListener() {
            @Override
            public void onDragStarted(IAnnotation annotation) {

            }

            @Override
            public void onDragEnded(IAnnotation annotation) {

            }

            @Override
            public void onDragDelta(IAnnotation annotation, float horizontalOffset, float verticalOffset) {
                final double xValue = ComparableUtil.toDouble(annotation.getX1());

                // update X range of top axis when dragging line annotation 
                topXRange.setMinMaxDouble(xValue - RANGE_WINDOW, xValue + RANGE_WINDOW);
            }
        });

        UpdateSuspender.using(surface, new Runnable() {
            @Override
            public void run() {
                Collections.addAll(surface.getXAxes(), xAxis);
                Collections.addAll(surface.getYAxes(), yAxis);
                Collections.addAll(surface.getRenderableSeries(), line);
                Collections.addAll(surface.getAnnotations(), lineAnnotation);
            }
        });

    }

    private IDataSeries createDataSeries() {
        IXyDataSeries<Double, Double> dataSeries = new XyDataSeries<>(Double.class, Double.class);

        for (int i = 1; i < POINTS_COUNT; i++) {
            dataSeries.append((double) i, POINTS_COUNT * Math.sin(i * Math.PI * 0.1) / i);
        }

        return dataSeries;
    }
}

Hope this will help you!

Best regards,
Yura

  • vasim simform
    I modified this code to at top chart needs to move left-to-right and right – to – left based on that bottom chart should be move package com.app.flashback.ui.fragments;//****************************************************************************** // SCICHART® Copyright SciChart Ltd. 2011-2017. All rights reserved. // // Web: http://www.scichart.com // Support: support@scichart.com // Sales: sales@scichart.com // // CreateRealTimeTickingStockChartFragment.java is part of the SCICHART® Examples. Permission is hereby granted // to modify, create derivative works, distribute and publish any part of this source // code whether for commercial, private or personal use. // // The SCICHART® examples are distributed in the hope that they will be useful, but // without any warranty. It is provided “AS IS” without warranty of any kind, either // expressed or implied. //****************************************************************************** import android.os.Bundle; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.app.flashback.R; import com.app.flashback.databinding.FragmentCriHistoryBinding; import com.scichart.charting.Direction2D; import com.scichart.charting.model.dataSeries.IDataSeries; import com.scichart.charting.model.dataSeries.IDataSeriesCore; import com.scichart.charting.model.dataSeries.IDataSeriesObserver; import com.scichart.charting.model.dataSeries.IOhlcDataSeries; import com.scichart.charting.model.dataSeries.IXyDataSeries; import com.scichart.charting.visuals.SciChartSurface; import com.scichart.charting.visuals.annotations.AnnotationCoordinateMode; import com.scichart.charting.visuals.annotations.AxisMarkerAnnotation; import com.scichart.charting.visuals.annotations.BoxAnnotation; import com.scichart.charting.visuals.annotations.VerticalLineAnnotation; import com.scichart.charting.visuals.axes.AutoRange; import com.scichart.charting.visuals.axes.CategoryDateAxis; import com.scichart.charting.visuals.axes.IAxis; import com.scichart.charting.visuals.axes.IAxisCore; import com.scichart.charting.visuals.axes.NumericAxis; import com.scichart.charting.visuals.axes.VisibleRangeChangeListener; import com.scichart.charting.visuals.renderableSeries.FastMountainRenderableSeries; import com.scichart.core.annotations.Orientation; import com.scichart.core.framework.UpdateSuspender; import com.scichart.data.model.DoubleRange; import com.scichart.data.model.IRange; import com.scichart.drawing.utility.ColorUtil; import com.scichart.extensions.builders.SciChartBuilder; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Random; public class CreateRealTimeTickingStockChartFragment extends Fragment { private static final int SECONDS_IN_FIVE_MINUTES = 5 * 60; public static final int DEFAULT_POINT_COUNT = 150; public static final int SMA_SERIES_COLOR = 0xFFFFA500; public static final int STOKE_UP_COLOR = 0xFF00AA00; public static final int STROKE_DOWN_COLOR = 0xFFFF0000; public static final float STROKE_THICKNESS = 1.5f; SciChartBuilder sciChartBuilder = SciChartBuilder.instance(); private final IOhlcDataSeries ohlcDataSeries = sciChartBuilder.newOhlcDataSeries(Date.class, Double.class).withSeriesName(“Price Series”).build(); private final IXyDataSeries xyDataSeries = sciChartBuilder.newXyDataSeries(Date.class, Double.class).withSeriesName(“50-Period SMA”).build(); private AxisMarkerAnnotation smaAxisMarker = sciChartBuilder.newAxisMarkerAnnotation().withY1(0d).withBackgroundColor(SMA_SERIES_COLOR).build(); private AxisMarkerAnnotation ohlcAxisMarker = sciChartBuilder.newAxisMarkerAnnotation().withY1(0d).withBackgroundColor(STOKE_UP_COLOR).build(); private OverviewPrototype overviewPrototype; FragmentCriHistoryBinding binding; @Nullable @org.jetbrains.annotations.Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentCriHistoryBinding.inflate(inflater, container, false); return binding.getRoot(); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initChart(); } private void initChart() { initializeMainChart(binding.chartBottom); overviewPrototype = new OverviewPrototype(binding.chartBottom, binding.chartTop); } private void initializeMainChart(final SciChartSurface surface) { final CategoryDateAxis xAxis = sciChartBuilder.newCategoryDateAxis() .withBarTimeFrame(SECONDS_IN_FIVE_MINUTES) .withDrawMinorGridLines(false) .withGrowBy(0, 0.1) .build(); final NumericAxis yAxis = sciChartBuilder.newNumericAxis().withAutoRangeMode(AutoRange.Always).build(); final FastMountainRenderableSeries line = sciChartBuilder.newMountainSeries().withStrokeStyle(SMA_SERIES_COLOR, STROKE_THICKNESS).withDataSeries(xyDataSeries).build(); UpdateSuspender.using(surface, new Runnable() { @Override public synchronized void run() { Collections.addAll(surface.getXAxes(), xAxis); Collections.addAll(surface.getYAxes(), yAxis); Collections.addAll(surface.getRenderableSeries(), line); /* Collections.addAll(surface.getChartModifiers(), sciChartBuilder.newModifierGroup() .withXAxisDragModifier().build() .withZoomPanModifier().withReceiveHandledEvents(true).withXyDirection(Direction2D.XDirection).build() .withZoomExtentsModifier().build() .withLegendModifier().withOrientation(Orientation.HORIZONTAL).withPosition(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 20).withReceiveHandledEvents(true).build() .build());*/ } }); } @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); final SciChartSurface surface = binding.chartTop; UpdateSuspender.using(surface, this::createDataSeries); } private IDataSeries createDataSeries() { for (int i = 0; i <= 500; i++) { Date date = Calendar.getInstance().getTime(); Double aDouble = new Random().nextDouble(); xyDataSeries.append(date, aDouble); overviewPrototype.getOverviewDataSeries().append(date, aDouble); } return xyDataSeries; } @Override public void onDestroyView() { super.onDestroyView(); } private static class OverviewPrototype { private final SciChartBuilder builder = SciChartBuilder.instance(); private final VisibleRangeChangeListener topChartAxisVisibleRangeChangeListener = new VisibleRangeChangeListener() { @Override public void onVisibleRangeChanged(IAxisCore axis, IRange oldRange, IRange newRange, boolean isAnimating) { final double newMin = newRange.getMinAsDouble(); final double newMax = newRange.getMaxAsDouble(); if (!overviewXAxisVisibleRange.equals(new DoubleRange(0d, 10d))) { topChartXAxisVisibleRange.setMinMaxWithLimit(newMin, newMax, overviewXAxisVisibleRange); } else { topChartXAxisVisibleRange.setMinMax(newMin, newMax); } boxAnnotation.setX1(topChartXAxisVisibleRange.getMin()); boxAnnotation.setX2(topChartXAxisVisibleRange.getMax()); leftLineGrip.setX1(topChartXAxisVisibleRange.getMin()); leftBox.setX1(overviewXAxisVisibleRange.getMin()); leftBox.setX2(topChartXAxisVisibleRange.getMin()); rightLineGrip.setX1(topChartXAxisVisibleRange.getMax()); rightBox.setX1(topChartXAxisVisibleRange.getMax()); rightBox.setX2(overviewXAxisVisibleRange.getMax()); } }; private final BoxAnnotation leftBox = generateBoxAnnotation(R.drawable.example_grayed_out_box_annotation_background); private final BoxAnnotation rightBox = generateBoxAnnotation(R.drawable.example_grayed_out_box_annotation_background); private final BoxAnnotation boxAnnotation = generateBoxAnnotation(0); private final VerticalLineAnnotation leftLineGrip = generateVerticalLine(); private final VerticalLineAnnotation rightLineGrip = generateVerticalLine(); private final IRange topChartXAxisVisibleRange; private IRange overviewXAxisVisibleRange; private final IXyDataSeries overviewDataSeries = builder.newXyDataSeries(Date.class, Double.class).withAcceptsUnsortedData().build(); @SuppressWarnings(“unchecked”) OverviewPrototype(SciChartSurface topChartSurface, SciChartSurface bottomChartSurface) { final IAxis parentXAxisTopChart = topChartSurface.getXAxes().get(0); // parentXAxisTopChart.setVisibleRangeChangeListener(topChartAxisVisibleRangeChangeListener); topChartXAxisVisibleRange = parentXAxisTopChart.getVisibleRange(); initializeBottomChart(bottomChartSurface); overviewDataSeries.addObserver(new IDataSeriesObserver() { @Override public void onDataSeriesChanged(IDataSeriesCore dataSeries, int dataSeriesUpdate) { rightBox.setX1(topChartXAxisVisibleRange.getMax()); rightBox.setX2(overviewXAxisVisibleRange.getMax()); } }); } IXyDataSeries getOverviewDataSeries() { return overviewDataSeries; } private void initializeBottomChart(final SciChartSurface surface) { surface.setRenderableSeriesAreaBorderStyle(null); final CategoryDateAxis xAxis = builder.newCategoryDateAxis() .withBarTimeFrame(SECONDS_IN_FIVE_MINUTES) .withAutoRangeMode(AutoRange.Always) .withDrawMinorGridLines(false) .withVisibility(View.GONE) .withGrowBy(0, 0.1) .build(); overviewXAxisVisibleRange = xAxis.getVisibleRange(); final NumericAxis yAxis = builder.newNumericAxis().withAutoRangeMode(AutoRange.Always).withVisibility(View.INVISIBLE).build(); removeAxisGridLines(xAxis, yAxis); final FastMountainRenderableSeries mountain = builder.newMountainSeries().withDataSeries(overviewDataSeries).build(); UpdateSuspender.using(surface, new Runnable() { @Override public synchronized void run() { Collections.addAll(surface.getXAxes(), xAxis); Collections.addAll(surface.getYAxes(), yAxis); Collections.addAll(surface.getRenderableSeries(), mountain); Collections.addAll(surface.getAnnotations(), boxAnnotation, leftBox, rightBox, leftLineGrip, rightLineGrip); Collections.addAll(surface.getChartModifiers(), builder.newModifierGroup() .withXAxisDragModifier().build() .withZoomPanModifier().withReceiveHandledEvents(true).withXyDirection(Direction2D.XyDirection).build() .withZoomExtentsModifier().build() .build()); } }); } private BoxAnnotation generateBoxAnnotation(@DrawableRes int backgroundDrawable) { return builder.newBoxAnnotation() .withBackgroundDrawableId(backgroundDrawable) .withCoordinateMode(AnnotationCoordinateMode.RelativeY) .withIsEditable(false) .withY1(0).withY2(1) .build(); } private VerticalLineAnnotation generateVerticalLine() { return builder.newVerticalLineAnnotation().withCoordinateMode(AnnotationCoordinateMode.RelativeY) .withVerticalGravity(Gravity.CENTER_VERTICAL) .withStroke(5, ColorUtil.Grey) .withIsEditable(false) .withY1(0.3).withY2(0.7) .withX1(0) .build(); } private void removeAxisGridLines(IAxis… axes) { for (IAxis axis : axes) { axis.setDrawMajorGridLines(false); axis.setDrawMajorTicks(false); axis.setDrawMajorBands(false); axis.setDrawMinorGridLines(false); axis.setDrawMinorTicks(false); } } } }
  • Yura Khariton
    Can you tell me what is FragmentCriHistoryBinding? This is binding that I don’t have access to and as result I can’t compile your code. Can you provide entire project?
  • vasim simform
    You can use for XML code we need to manage top chart and bottom chart
  • Yura Khariton
    Can you provide it or project so I could run your code?
  • Yura Khariton
    Hi there, I removed link to your project, because it contains license key, but I took a look on code before that and posted updated code. Hope this will help you!
0
0

Hi there,

I modified your code and restored listener for VisibleRange + made BoxAnnotation interactive and added listener for dragging as well so bottom chart reacts when you drag BoxAnnotation on top chart:

public class CreateRealTimeTickingStockChartFragment extends Fragment {

private static final int SECONDS_IN_FIVE_MINUTES = 5 * 60;
public static final int SMA_SERIES_COLOR = 0xFFFFA500;
public static final float STROKE_THICKNESS = 1.5f;

SciChartBuilder sciChartBuilder = SciChartBuilder.instance();

private final IXyDataSeries<Date, Double> xyDataSeries = sciChartBuilder.newXyDataSeries(Date.class, Double.class).withSeriesName("50-Period SMA").build();

private OverviewPrototype overviewPrototype;
FragmentTwoChartHistoryBinding binding;

@Nullable
@org.jetbrains.annotations.Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    binding = FragmentTwoChartHistoryBinding.inflate(inflater, container, false);
    return binding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    initChart();
}


private void initChart() {
    initializeMainChart(binding.chartBottom);
    overviewPrototype = new OverviewPrototype(binding.chartBottom, binding.chartTop);
}

private void initializeMainChart(final SciChartSurface surface) {
    final CategoryDateAxis xAxis = sciChartBuilder.newCategoryDateAxis()
            .withBarTimeFrame(SECONDS_IN_FIVE_MINUTES)
            .withDrawMinorGridLines(false)
            .withGrowBy(0, 0.1)
            .build();
    final NumericAxis yAxis = sciChartBuilder.newNumericAxis().withAutoRangeMode(AutoRange.Always).build();
    final FastMountainRenderableSeries line = sciChartBuilder.newMountainSeries().withStrokeStyle(SMA_SERIES_COLOR, STROKE_THICKNESS).withDataSeries(xyDataSeries).build();

    UpdateSuspender.using(surface, new Runnable() {
        @Override
        public synchronized void run() {
            Collections.addAll(surface.getXAxes(), xAxis);
            Collections.addAll(surface.getYAxes(), yAxis);
            Collections.addAll(surface.getRenderableSeries(), line);
            Collections.addAll(surface.getChartModifiers(), sciChartBuilder.newModifierGroup()
                    .withXAxisDragModifier().build()
                    .withZoomPanModifier().withReceiveHandledEvents(true).withXyDirection(Direction2D.XDirection).build()
                    .withZoomExtentsModifier().build()
                    .withLegendModifier().withOrientation(Orientation.HORIZONTAL).withPosition(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 20).withReceiveHandledEvents(true).build()
                    .build());
        }
    });
}



@Override
public void onActivityCreated(final Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    final SciChartSurface surface = binding.chartTop;
    UpdateSuspender.using(surface, this::createDataSeries);
}

private IDataSeries createDataSeries() {
    for (int i = 0; i <= 500; i++) {
        Date date = Calendar.getInstance().getTime();
        Double aDouble = new Random().nextDouble();
        xyDataSeries.append(date, aDouble);
        overviewPrototype.getOverviewDataSeries().append(date,
                aDouble);
    }
    return xyDataSeries;
}

private static class OverviewPrototype {

    private final SciChartBuilder builder = SciChartBuilder.instance();

    private final VisibleRangeChangeListener topChartAxisVisibleRangeChangeListener = new VisibleRangeChangeListener() {
        @Override
        public void onVisibleRangeChanged(IAxisCore axis, IRange oldRange, IRange newRange, boolean isAnimating) {
            final double newMin = newRange.getMinAsDouble();
            final double newMax = newRange.getMaxAsDouble();

            if (!overviewXAxisVisibleRange.equals(new DoubleRange(0d, 10d))) {
                topChartXAxisVisibleRange.setMinMaxWithLimit(newMin, newMax, overviewXAxisVisibleRange);
            } else {
                topChartXAxisVisibleRange.setMinMax(newMin, newMax);
            }

            boxAnnotation.setX1(topChartXAxisVisibleRange.getMin());
            boxAnnotation.setX2(topChartXAxisVisibleRange.getMax());

            leftLineGrip.setX1(topChartXAxisVisibleRange.getMin());
            leftBox.setX1(overviewXAxisVisibleRange.getMin());
            leftBox.setX2(topChartXAxisVisibleRange.getMin());

            rightLineGrip.setX1(topChartXAxisVisibleRange.getMax());
            rightBox.setX1(topChartXAxisVisibleRange.getMax());
            rightBox.setX2(overviewXAxisVisibleRange.getMax());
        }
    };

    private final BoxAnnotation leftBox = generateBoxAnnotation(R.drawable.example_grayed_out_box_annotation_background);
    private final BoxAnnotation rightBox = generateBoxAnnotation(R.drawable.example_grayed_out_box_annotation_background);
    private final BoxAnnotation boxAnnotation = generateBoxAnnotation(0);
    private final VerticalLineAnnotation leftLineGrip = generateVerticalLine();
    private final VerticalLineAnnotation rightLineGrip = generateVerticalLine();

    private final IRange<Double> topChartXAxisVisibleRange;
    private IRange<Double> overviewXAxisVisibleRange;

    private final IXyDataSeries<Date, Double> overviewDataSeries = builder.newXyDataSeries(Date.class, Double.class).withAcceptsUnsortedData().build();

    @SuppressWarnings("unchecked")
    OverviewPrototype(SciChartSurface mainChart, SciChartSurface overviewChart) {
        final IAxis parentXAxisTopChart = mainChart.getXAxes().get(0);
        parentXAxisTopChart.setVisibleRangeChangeListener(topChartAxisVisibleRangeChangeListener);

        topChartXAxisVisibleRange = parentXAxisTopChart.getVisibleRange();

        initializeBottomChart(overviewChart);

        overviewDataSeries.addObserver(new IDataSeriesObserver() {
            @Override
            public void onDataSeriesChanged(IDataSeriesCore dataSeries, int dataSeriesUpdate) {
                rightBox.setX1(topChartXAxisVisibleRange.getMax());
                rightBox.setX2(overviewXAxisVisibleRange.getMax());
            }
        });

        boxAnnotation.setIsEditable(true);
        boxAnnotation.setDragDirections(Direction2D.XDirection);
        boxAnnotation.setOnAnnotationDragListener(new OnAnnotationDragListener() {
            @Override
            public void onDragStarted(IAnnotation iAnnotation) {
                updateRange(iAnnotation);
            }

            private void updateRange(IAnnotation iAnnotation) {
                final double x1 = ComparableUtil.toDouble(iAnnotation.getX1());
                final double x2 = ComparableUtil.toDouble(iAnnotation.getX2());
                topChartXAxisVisibleRange.setMinMaxDouble(x1, x2);
            }

            @Override
            public void onDragEnded(IAnnotation iAnnotation) {
                updateRange(iAnnotation);
            }

            @Override
            public void onDragDelta(IAnnotation iAnnotation, float v, float v1) {
                updateRange(iAnnotation);
            }
        });
    }

    IXyDataSeries<Date, Double> getOverviewDataSeries() {
        return overviewDataSeries;
    }

    private void initializeBottomChart(final SciChartSurface surface) {
        surface.setRenderableSeriesAreaBorderStyle(null);

        final CategoryDateAxis xAxis = builder.newCategoryDateAxis()
                .withBarTimeFrame(SECONDS_IN_FIVE_MINUTES)
                .withAutoRangeMode(AutoRange.Always)
                .withDrawMinorGridLines(false)
                .withVisibility(View.GONE)
                .withGrowBy(0, 0.1)
                .build();

        overviewXAxisVisibleRange = xAxis.getVisibleRange();

        final NumericAxis yAxis = builder.newNumericAxis().withAutoRangeMode(AutoRange.Always).withVisibility(View.INVISIBLE).build();
        removeAxisGridLines(xAxis, yAxis);

        final FastMountainRenderableSeries mountain = builder.newMountainSeries().withDataSeries(overviewDataSeries).build();

        UpdateSuspender.using(surface, new Runnable() {
            @Override
            public synchronized void run() {
                Collections.addAll(surface.getXAxes(), xAxis);
                Collections.addAll(surface.getYAxes(), yAxis);
                Collections.addAll(surface.getRenderableSeries(), mountain);
                Collections.addAll(surface.getAnnotations(), boxAnnotation, leftBox, rightBox, leftLineGrip, rightLineGrip);

                Collections.addAll(surface.getChartModifiers(), builder.newModifierGroup()
                        .withXAxisDragModifier().build()
                        .withZoomPanModifier().withReceiveHandledEvents(true).withXyDirection(Direction2D.XyDirection).build()
                        .withZoomExtentsModifier().build()
                        .build());
            }
        });
    }

    private BoxAnnotation generateBoxAnnotation(@DrawableRes int backgroundDrawable) {
        return builder.newBoxAnnotation()
                .withBackgroundDrawableId(backgroundDrawable)
                .withCoordinateMode(AnnotationCoordinateMode.RelativeY)
                .withIsEditable(false)
                .withY1(0).withY2(1)
                .build();
    }

    private VerticalLineAnnotation generateVerticalLine() {
        return builder.newVerticalLineAnnotation().withCoordinateMode(AnnotationCoordinateMode.RelativeY)
                .withVerticalGravity(Gravity.CENTER_VERTICAL)
                .withStroke(5, ColorUtil.Grey)
                .withIsEditable(false)
                .withY1(0.3).withY2(0.7)
                .withX1(0)
                .build();
    }

    private void removeAxisGridLines(IAxis... axes) {
        for (IAxis axis : axes) {
            axis.setDrawMajorGridLines(false);
            axis.setDrawMajorTicks(false);
            axis.setDrawMajorBands(false);
            axis.setDrawMinorGridLines(false);
            axis.setDrawMinorTicks(false);
        }
    }
}

}

Please can you try it and let me know if it suitable for your needs?

Best regards,
Yura

  • vasim simform
    By above solution almost we are near the solution by checking code we found few issues (1) As I changed Y-Axis code as below it gives unexpected behaviors which you can check in attached Video link final IAxis yAxis = sciChartBuilder.newNumericAxis().withDrawMinorGridLines(false) .withDrawMajorTicks(false) .withDrawMinorTicks(false) .withFlipCoordinates(false) .withIsCenterAxis(false) .withDrawMajorBands(false) .withAutoRangeMode(AutoRange.Never) .withVisibleRange(0.0, 1.0) .withAutoTicks(false) .withMajorDelta(0.1) .withMinorDelta(0.05).withDrawMinorTicks(false) .withDrawMajorGridLines(false).build(); Bottom chart moving not working https://easyupload.io/1hi6uj (2) Box rectangle should be start from right side with small size of rectangle then able to move left or right please check video link in that bottom chart Y-axis number should not be change and must be fixed https://easyupload.io/pozvbp
  • Yura Khariton
    I don’t know – I added your code into project you previosly provided and dragging still works. Maybe you removed/commented some code related to OnAnnotationDragListener for box annotation, that should update other chart’s range when you drag it? As for second question with changing yAxis – your code fixes it if you replace yAxis initialization for main chart ( your code sets AutoRange.Never instead of AutoRange.Always which was responsible for this behavior ).
  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.