Updating autoScrollingDelta resets chart postion

Hello i am using the autoScrollingDelta to set the amount of days that are visible at one point, my problem is i allow users to update the amount of days they want to have visible just with a simple button that updates the zoomDays variable and when updating the value all the charts positions reset to the end of the chart any way around this? i have added one of the chart widgets

Widget dChart1(
    List<FastLineSeries<Chart, DateTime>> data,
    bool showLabel,
  ) {
    return SizedBox(
      width: double.infinity,
      child: SfCartesianChart(
        margin: const EdgeInsets.only(bottom: 15),
        plotAreaBackgroundColor: Theme.of(context).brightness == Brightness.dark
            ? Colors.grey[900]
            : null,
        primaryXAxis: DateTimeAxis(
          autoScrollingDelta: zoomDays,
          autoScrollingDeltaType: DateTimeIntervalType.days,
          onRendererCreated: (DateTimeAxisController c) {
            axis1X = c;
          },
          initialZoomFactor: zoomF1X,
          initialZoomPosition: zoomP1X,
          name: 'primaryXAxis',
          labelPosition: ChartDataLabelPosition.inside,
          labelStyle: showLabel
              ? null
              : const TextStyle(color: Colors.transparent, fontSize: 1),
          // interval: 1,
          dateFormat: DateFormat('dd MMM HH:mm'),
          minimum: startCharts,
          maximum: DateTime.now().add(const Duration(days: 7)),
          labelIntersectAction: AxisLabelIntersectAction.hide,
          majorGridLines: const MajorGridLines(width: 1),
        ),
        primaryYAxis: NumericAxis(
          name: 'primaryYAxis',
          onRendererCreated: (NumericAxisController c) {
            axis1Y = c;
          },
          desiredIntervals: 10,
          decimalPlaces: 0,
          initialZoomFactor: zoomF1Y,
          initialZoomPosition: zoomP1Y,
          anchorRangeToVisiblePoints: true,
          isInversed: true,
          axisLine: const AxisLine(width: 0),
          majorGridLines: const MajorGridLines(width: 1, dashArray: [400, 1]),
          majorTickLines: const MajorTickLines(color: Colors.black),
        ),
        series: data,
        trackballBehavior: TrackballBehavior(
          enable: true,
          shouldAlwaysShow: true,
          tooltipDisplayMode: TrackballDisplayMode.groupAllPoints,
          activationMode: ActivationMode.singleTap,
          tooltipSettings: const InteractiveTooltip(
            enable: true,
            arrowLength: 0,
            format: 'point.y mm',
          ),
        ),
        zoomPanBehavior: ZoomPanBehavior(
          enableMouseWheelZooming: true,
          enablePanning: true,
          enableSelectionZooming: true,
          zoomMode: ZoomMode.x,
        ),
        onZooming: (ZoomPanArgs args) {
          if (args.axis!.name == 'primaryXAxis') {
            zoomP1X = args
                .currentZoomPosition; // Storing the zoomPosition and the zoomFactor
            zoomF1X = args.currentZoomFactor; // of the first chart.
            // Updating zoomFactor and zoomPosition for second chart by using axis controller.

            axis2X!.zoomPosition = zoomP1X;
            axis2X!.zoomFactor = zoomF1X;

            axis3X!.zoomPosition = zoomP1X;
            axis3X!.zoomFactor = zoomF1X;

            axis4X!.zoomPosition = zoomP1X;
            axis4X!.zoomFactor = zoomF1X;

            axis5X!.zoomPosition = zoomP1X;
            axis5X!.zoomFactor = zoomF1X;

            axis6X!.zoomPosition = zoomP1X;
            axis6X!.zoomFactor = zoomF1X;

            axisTX!.zoomPosition = zoomP1X;
            axisTX!.zoomFactor = zoomF1X;

            axisBX!.zoomPosition = zoomP1X;
            axisBX!.zoomFactor = zoomF1X;

            axisMX!.zoomPosition = zoomP1X;
            axisMX!.zoomFactor = zoomF1X;

            axisEX!.zoomPosition = zoomP1X;
            axisEX!.zoomFactor = zoomF1X;
          }
        },
      ),
    );
  }

6 Replies

TH The43Joker July 30, 2024 09:56 AM UTC

So i have done some fiddling and now i have it at a point where it is doing what i am looking for,for a second and then resets to the end of the chart. I am not storing the last date the trackball was on before the user changes the autoscrollingdelta amount and then i update the autoscrollingdelta amount and after i set the vis max to the latest date where the trackball was but it shows the correct range for a short while and then resets. video exam

Chart Video Example

Widget dChartB(
    List<FastLineSeries<Chart, DateTime>> data,
    bool showLabel,
  ) {
    return SizedBox(
      width: double.infinity,
      child: SfCartesianChart(
        margin: EdgeInsets.zero,
        legend: const Legend(
          position: LegendPosition.top,
          height: '20%',
          isVisible: true,
          textStyle: TextStyle(
            fontSize: 10,
          ),
        ),
        plotAreaBackgroundColor: Theme.of(context).brightness == Brightness.dark
            ? Colors.grey[900]
            : null,
        primaryXAxis: DateTimeAxis(
          autoScrollingDelta: zoomDays,
          autoScrollingDeltaType: DateTimeIntervalType.days,
          initialVisibleMaximum: DateTime.now().add(const Duration(days: 7)),
          initialVisibleMinimum:
              DateTime.now().subtract(Duration(days: zoomDays!)),
          onRendererCreated: (DateTimeAxisController c) {
            axisBX = c;
          },
          // initialZoomFactor: zoomF1X,
          // initialZoomPosition: zoomP1X,
          labelPosition: ChartDataLabelPosition.inside,
          name: 'primaryXAxis',
          labelStyle: showLabel
              ? null
              : const TextStyle(color: Colors.transparent, fontSize: 1),
          // interval: 1,
          dateFormat: DateFormat('dd MMM HH:mm'),
          minimum: startCharts,
          maximum: DateTime.now().add(const Duration(days: 7)),
          labelIntersectAction: AxisLabelIntersectAction.hide,
          majorGridLines: const MajorGridLines(width: 1),
        ),
        primaryYAxis: NumericAxis(
          name: 'primaryYAxis',
          onRendererCreated: (NumericAxisController c) {
            axisBY = c;
          },
          desiredIntervals: 10,
          decimalPlaces: 0,
          // initialZoomFactor: zoomF1Y,
          // initialZoomPosition: zoomP1Y,
          anchorRangeToVisiblePoints: true,
          isInversed: true,
          axisLine: const AxisLine(width: 0),
          majorGridLines: const MajorGridLines(width: 1, dashArray: [400, 1]),
          majorTickLines: const MajorTickLines(color: Colors.black),
        ),
        series: data,
        trackballBehavior: TrackballBehavior(
          enable: true,
          shouldAlwaysShow: true,
          tooltipDisplayMode: TrackballDisplayMode.groupAllPoints,
          activationMode: ActivationMode.singleTap,
          tooltipSettings: const InteractiveTooltip(
            enable: true,
            arrowLength: 0,
            format: 'series.name - point.y mm',
          ),
        ),
        zoomPanBehavior: ZoomPanBehavior(
          enableMouseWheelZooming: true,
          enablePanning: true,
          enableSelectionZooming: true,
          zoomMode: ZoomMode.x,
        ),
        onTrackballPositionChanging: (trackballArgs) {
          posT = trackballArgs.chartPointInfo.dataPointIndex;

          lastDate = data[1]
              .dataSource!
              .elementAt(trackballArgs.chartPointInfo.dataPointIndex!)
              .date;
        },
        onZooming: (ZoomPanArgs args) {
          if (args.axis!.name == 'primaryXAxis') {
            zoomP1X = args
                .currentZoomPosition; // Storing the zoomPosition and the zoomFactor
            zoomF1X = args.currentZoomFactor; // of the first chart.
            // Updating zoomFactor and zoomPosition for second chart by using axis controller.

            axis1X!.zoomPosition = zoomP1X;
            axis1X!.zoomFactor = zoomF1X;

            axis2X!.zoomPosition = zoomP1X;
            axis2X!.zoomFactor = zoomF1X;

            axis3X!.zoomPosition = zoomP1X;
            axis3X!.zoomFactor = zoomF1X;

            axis4X!.zoomPosition = zoomP1X;
            axis4X!.zoomFactor = zoomF1X;

            axis5X!.zoomPosition = zoomP1X;
            axis5X!.zoomFactor = zoomF1X;

            axis6X!.zoomPosition = zoomP1X;
            axis6X!.zoomFactor = zoomF1X;

            axisTX!.zoomPosition = zoomP1X;
            axisTX!.zoomFactor = zoomF1X;

            axisMX!.zoomPosition = zoomP1X;
            axisMX!.zoomFactor = zoomF1X;

            axisEX!.zoomPosition = zoomP1X;
            axisEX!.zoomFactor = zoomF1X;
          }
        },
      ),
    );
  }


LP Lokesh Palani Syncfusion Team August 1, 2024 02:08 PM UTC

Hi,


We have validated the shared code snippet, but it is not in a runnable state. We have tried to replicate the reported issue in the SfCartesianChart using chart version 26.2.7. We tested the following scenarios on the Windows platform, and it was working fine on our end.



However, we were unable to reproduce the reported issue at our end. We kindly request you to share more details to check the reported issue.


  • What you have done in the TextButton when updating the axis visible range for 1 day and 7 days.


We kindly request you replicate the reported issue in the sample attached below and provide us with more details regarding the specific scenario in which you encounter with a screen recording. This will help us to assist you more effectively.


Regards,
Lokesh P.


Attachment: multiplechart_livedata_d18125cd.zip


TH The43Joker August 22, 2024 07:18 AM UTC

Hello thanks but i have tested it and the above code also resets the charts please keep in mind the charts also have sync scrolling and busy implementing sync tooltip for it, the button is same as yours except i dont have it in a separate function

Padding(
                  padding: const EdgeInsets.only(left: 10),
                  child: GestureDetector(
                    onTap: () {
                      setState(() {
                        zoomDays = 100;
                      });
                    },
                    child: Text(
                      '100',
                      style: TextStyle(
                          color: zoomDays == 100 ? Colors.blue : null),
                    ),
                  ),
                ),


TH The43Joker replied to Lokesh Palani August 26, 2024 06:33 AM UTC

Hello is there a way for me to limit the amount of days that can be seen at once like the autoscrollingdelta without using the autoscrollingdelta?



PS Preethika Selvam Syncfusion Team August 27, 2024 10:50 AM UTC

Hi The43Joker,


Query 1: How to synchronize zooming, panning and auto-scrolling delta across multiple charts?


To synchronize zooming, panning and auto-scrolling delta across multiple charts are achieved using zoomPanBehavior. Each chart is controlled by a DateTimeAxisController that manages the zoom factor and position of the primary X-axis. The zoomPanBehavior enables panning, pinching, double tap zooming, and selection zooming, all restricted to the X-axis. Synchronization is achieved by updating the zoom factor and position across all charts whenever one chart is zoomed or panned. This is handled within the onZooming, onZoomStart, and onZoomEnd callbacks. Additionally, the autoScrollingDelta is dynamically adjusted via a set of buttons, allowing the user to change the auto-scrolling interval for the X-axis, effectively controlling how the charts scroll through data over specific time intervals. The use of GlobalKey ensures that each chart's state can be accessed and manipulated, maintaining synchronized behavior across all charts. We have shared a sample for your reference. You can modify the sample based on your needs.


Output:




Query 2: How achieve the autoScrollingDelta behavior without using autoScrollingDelta?


We are checking the possibility to achieve your requirement, and we will update further details within August 29, 2024. We appreciate your patience until then.


Regards,

Preethika Selvam.


Attachment: fr191309_7e5f2999.zip


PS Preethika Selvam Syncfusion Team August 29, 2024 10:08 AM UTC

Hi The43Joker,


Currently, we do not have direct support for your requirement. However, we have prepared a workaround to achieve the auto-scrolling delta behavior without using the autoScrollingDelta property. We have utilized a text input field and a dropdown menu to dynamically control the visible range (initialVisibleMinimum and initialVisibleMaximum) of the chart. The text field specifies the number of days, while the dropdown determines whether the range starts from the beginning ("Start") or ends at the last date ("End"). For any number of days entered, the range adjusts accordingly based on the selected option. To update the visible range dynamically, we use the DateTimeCategoryAxisController. This controller provides access to the axis properties that define the visible range of the chart. By setting visibleMinimum and visibleMaximum through this controller, we can adjust the displayed date range based on user input. When the "Start" option is selected, the range starts from the earliest date and extends for the specified number of days. Conversely, when the "End" option is selected, the range extends backward from the latest date by the specified number of days. We have shared a code snippet and a sample for your reference. You can modify the sample based on your needs.



Code snippet:


DateTimeCategoryAxisController? _xAxisRenderer;

  final ZoomPanBehavior _zoomPanBehavior = ZoomPanBehavior(

    enablePinching: true,

    enableMouseWheelZooming: true,

    enablePanning: true,

  );

  final List<ChartData> chartData = [

    ChartData(DateTime(2023, 01, 01), 35),

    ChartData(DateTime(2023, 01, 02), 28),

    ChartData(DateTime(2023, 01, 03), 34),

    ChartData(DateTime(2023, 01, 04), 32),

    ChartData(DateTime(2023, 01, 05), 42),

    ChartData(DateTime(2023, 01, 06), 35),

    ChartData(DateTime(2023, 01, 07), 28),

    ChartData(DateTime(2023, 01, 08), 34),

    ChartData(DateTime(2023, 01, 09), 32),

    ChartData(DateTime(2023, 01, 10), 42),

    ChartData(DateTime(2023, 01, 11), 35),

    ChartData(DateTime(2023, 01, 12), 28),

    ChartData(DateTime(2023, 01, 13), 34),

    ChartData(DateTime(2023, 01, 14), 32),

    ChartData(DateTime(2023, 01, 15), 42),

    ChartData(DateTime(2023, 01, 16), 35),

    ChartData(DateTime(2023, 01, 17), 28),

    ChartData(DateTime(2023, 01, 18), 34),

    ChartData(DateTime(2023, 01, 19), 32),

    ChartData(DateTime(2023, 01, 20), 42),

  ];

 

  String dropdownValue = 'Start';

  final TextEditingController _textController = TextEditingController();

 

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(

        title: const Text('DateTimeCategoryAxis'),

      ),

      body: Column(

        children: <Widget>[

          Expanded(

            child: SfCartesianChart(

              zoomPanBehavior: _zoomPanBehavior,

              primaryXAxis: DateTimeCategoryAxis(

                dateFormat: DateFormat.d(),

                onRendererCreated: (DateTimeCategoryAxisController controller) {

                  _xAxisRenderer = controller;

                },

                initialVisibleMinimum: DateTime(2023, 1, 1),

                initialVisibleMaximum: DateTime(2023, 1, 20),

              ),

              series: <LineSeries<ChartData, DateTime>>[

                LineSeries<ChartData, DateTime>(

                  animationDuration: 0,

                  dataSource: chartData,

                  xValueMapper: (ChartData chartData, _) => chartData.x,

                  yValueMapper: (ChartData chartData, _) => chartData.y,

                ),

              ],

            ),

          ),

          Row(

            children: [

              // Text input for the number of days

              Expanded(

                child: TextField(

                  controller: _textController,

                  keyboardType: TextInputType.number,

                  decoration: const InputDecoration(

                    labelText: 'Enter Days',

                  ),

                ),

              ),

              // Dropdown to select Start or End

              DropdownButton<String>(

                value: dropdownValue,

                onChanged: (String? newValue) {

                  setState(() {

                    dropdownValue = newValue!;

                  });

                },

                items: <String>['Start', 'End']

                    .map<DropdownMenuItem<String>>((String value) {

                  return DropdownMenuItem<String>(

                    value: value,

                    child: Text(value),

                  );

                }).toList(),

              ),

              // Button to apply the range

              ElevatedButton(

                onPressed: () {

                  int days = int.tryParse(_textController.text) ?? 1;

                  days = days.clamp(1, chartData.length); // Ensure valid range

 

                  if (dropdownValue == 'Start') {

                    // Adjust for Start button

                    _xAxisRenderer?.visibleMinimum = chartData[0].x;

                    _xAxisRenderer?.visibleMaximum = chartData[days - 1].x;

                  } else {

                    // Adjust for End button

                    _xAxisRenderer?.visibleMinimum =

                        chartData[chartData.length - days].x;

                    _xAxisRenderer?.visibleMaximum = chartData.last.x;

                  }

                },

                child: const Text('Apply'),

              ),

            ],

          ),

        ],

      ),

    );

  }

}


Output:


Please let us know if you need any further assistance.


Regards,

Preethika Selvam.


Attachment: fr191309_e03cbf90.zip

Loader.
Up arrow icon