diff --git a/packages/syncfusion_flutter_barcodes/CHANGELOG.md b/packages/syncfusion_flutter_barcodes/CHANGELOG.md
index 97fa8292d..f05e00385 100644
--- a/packages/syncfusion_flutter_barcodes/CHANGELOG.md
+++ b/packages/syncfusion_flutter_barcodes/CHANGELOG.md
@@ -1,3 +1,8 @@
+## [20.3.50] - 10/18/2022
+
+**Bugs**
+* #FB38178 - Now, the QR code generated for the input string contains spaces with `medium` [errorCorrectionLevel](https://pub.dev/documentation/syncfusion_flutter_barcodes/latest/barcodes/QRCode/errorCorrectionLevel.html) and `07` [codeVersion](https://pub.dev/documentation/syncfusion_flutter_barcodes/latest/barcodes/QRCode/codeVersion.html) will be scannable.
+
## [18.3.35] - 10/01/2020
No changes.
@@ -99,4 +104,4 @@ Initial release.
* **One-dimensional barcodes** - Barcode Generator supports different one-dimensional barcode symbologies such as Code128, EAN8, EAN13, UPA-C, UPA-E, Code39, Code39 Extended, Code93 and Codabar.
* **Two-dimensional barcode** - Barcode Generator supports popular QR Code and Data Matrix.
* **Barcode customization** - Customize the visual appearance of barcodes using the backgroundColor and barColor properties, and adjust the size of smallest line or dot of the code using the module property.
-* **Text customization** -Configure to display the barcode value and customize the position and style of the barcode text.
\ No newline at end of file
+* **Text customization** -Configure to display the barcode value and customize the position and style of the barcode text.
diff --git a/packages/syncfusion_flutter_barcodes/README.md b/packages/syncfusion_flutter_barcodes/README.md
index 0a6ae4f48..2ed755483 100644
--- a/packages/syncfusion_flutter_barcodes/README.md
+++ b/packages/syncfusion_flutter_barcodes/README.md
@@ -36,9 +36,6 @@ Explore the full capabilities of our Flutter widgets on your device by installin
-
-
-
@@ -127,11 +124,11 @@ The following screenshot illustrates the result of the previous code sample.
### Support and feedback
-* For any other queries, reach our [Syncfusion support team](https://www.syncfusion.com/support/directtrac/incidents/newincident) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
+* For any other queries, reach our [Syncfusion support team](https://support.syncfusion.com/support/tickets/create) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
* To renew the subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at sales@syncfusion.com | Toll Free: 1-888-9 DOTNET.
### About Syncfusion
Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 20,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies.
-Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls) and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to- deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
+Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([Flutter](https://www.syncfusion.com/flutter-widgets), [WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to- deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
diff --git a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.cc
index e71a16d23..d38195aa0 100644
--- a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.h
index e0f0a47bc..9bf747894 100644
--- a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugins.cmake
index 2e1de87a7..51436ae8c 100644
--- a/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_barcodes/example/linux/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_barcodes/example/pubspec.yaml b/packages/syncfusion_flutter_barcodes/example/pubspec.yaml
index f9456b13a..8ee2a082f 100644
--- a/packages/syncfusion_flutter_barcodes/example/pubspec.yaml
+++ b/packages/syncfusion_flutter_barcodes/example/pubspec.yaml
@@ -14,7 +14,7 @@ description: A new Flutter project.
version: 1.0.0
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
diff --git a/packages/syncfusion_flutter_barcodes/example/windows/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_barcodes/example/windows/flutter/generated_plugins.cmake
index b93c4c30c..4d10c2518 100644
--- a/packages/syncfusion_flutter_barcodes/example/windows/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_barcodes/example/windows/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart
index a2d8ee406..3e61dc94c 100644
--- a/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart
+++ b/packages/syncfusion_flutter_barcodes/lib/src/barcode_generator/renderers/two_dimensional/error_correction_codewords.dart
@@ -1616,7 +1616,7 @@ class ErrorCorrectionCodeWords {
/// Converts decimal to binary value
List _convertDecimalToBinary(List decimalRepresentation) {
final List toBinary = [];
- for (int i = 0; i < eccw; i++) {
+ for (int i = 0; i < decimalRepresentation.length; i++) {
final String temp = decimalRepresentation[i].toRadixString(2);
String text = '';
@@ -1679,7 +1679,8 @@ class ErrorCorrectionCodeWords {
}
}
- eccw = leadTermSource.length;
+ // QR code is not scannable when the input string contains spaces.
+ // eccw = leadTermSource.length;
final List returnValue = [];
for (int i = 0; i < leadTermSource.length; i++) {
returnValue.add(leadTermSource.entries.elementAt(i).value);
diff --git a/packages/syncfusion_flutter_barcodes/pubspec.yaml b/packages/syncfusion_flutter_barcodes/pubspec.yaml
index f7f8ec32e..6ecc1eda6 100644
--- a/packages/syncfusion_flutter_barcodes/pubspec.yaml
+++ b/packages/syncfusion_flutter_barcodes/pubspec.yaml
@@ -1,15 +1,15 @@
name: syncfusion_flutter_barcodes
description: Flutter Barcodes generator library is used to generate and display data in the machine-readable, industry-standard 1D and 2D barcodes.
-version: 20.3.47
+version: 20.4.38
homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_barcodes
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
- syncfusion_flutter_core: ^20.3.47
+ syncfusion_flutter_core: ^20.4.38
dev_dependencies:
flutter_test:
diff --git a/packages/syncfusion_flutter_calendar/CHANGELOG.md b/packages/syncfusion_flutter_calendar/CHANGELOG.md
index 4e7e87a43..66f408a75 100644
--- a/packages/syncfusion_flutter_calendar/CHANGELOG.md
+++ b/packages/syncfusion_flutter_calendar/CHANGELOG.md
@@ -1,3 +1,7 @@
+## [20.3.56]
+**Features**
+* Provided text style customization support for the text in the placeholder (`No events` and `No selected date`) in the month agenda view and (`No events`) in the schedule view of the flutter event calendar.
+
## [20.2.43]
**Enhancements**
* Now, we have improved the behavior of the `appointmentBuilder` details `date` value to hold the start date of the appointment view in the Flutter event calendar.
diff --git a/packages/syncfusion_flutter_calendar/README.md b/packages/syncfusion_flutter_calendar/README.md
index 83512fa6e..a4bf4656c 100644
--- a/packages/syncfusion_flutter_calendar/README.md
+++ b/packages/syncfusion_flutter_calendar/README.md
@@ -133,15 +133,12 @@ Explore the full capabilities of our Flutter widgets on your device by installin
-
-
+
+
-
-
-
@@ -316,11 +313,11 @@ class Meeting {
## Support and Feedback
-* For any other queries, reach our [Syncfusion support team](https://www.syncfusion.com/support/directtrac/incidents/newincident) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
+* For any other queries, reach our [Syncfusion support team](https://support.syncfusion.com/support/tickets/create) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
* To renew the subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at salessupport@syncfusion.com | Toll Free: 1-888-9 DOTNET.
## About Syncfusion
Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 20,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies.
-Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), and [Blazor](https://www.syncfusion.com/blazor-components), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls) and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
+Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([Flutter](https://www.syncfusion.com/flutter-widgets), [WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
diff --git a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.cc
index e71a16d23..d38195aa0 100644
--- a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.h
index e0f0a47bc..9bf747894 100644
--- a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugins.cmake
index 2e1de87a7..51436ae8c 100644
--- a/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_calendar/example/linux/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_calendar/example/pubspec.yaml b/packages/syncfusion_flutter_calendar/example/pubspec.yaml
index 59a28a5ee..110702420 100644
--- a/packages/syncfusion_flutter_calendar/example/pubspec.yaml
+++ b/packages/syncfusion_flutter_calendar/example/pubspec.yaml
@@ -3,7 +3,7 @@ description: Syncfusion calendar example.
version: 1.0.0+1
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
diff --git a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.cc
index 8b6d4680a..4bfa0f3a3 100644
--- a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.h
index dc139d85a..9846246b4 100644
--- a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugins.cmake
index b93c4c30c..4d10c2518 100644
--- a/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_calendar/example/windows/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart
index 227086d90..f8d0144b3 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/agenda_view_layout.dart
@@ -30,6 +30,7 @@ class AgendaViewLayout extends StatefulWidget {
this.appointmentBuilder,
this.width,
this.height,
+ this.placeholderTextStyle,
this.calendar);
/// Defines the month view customization details.
@@ -84,6 +85,9 @@ class AgendaViewLayout extends StatefulWidget {
/// Defines the calendar widget.
final SfCalendar calendar;
+ /// Defines the text style of the no events and no selected date.
+ final TextStyle placeholderTextStyle;
+
@override
// ignore: library_private_types_in_public_api
_AgendaViewLayoutState createState() => _AgendaViewLayoutState();
@@ -159,6 +163,7 @@ class _AgendaViewLayoutState extends State {
_appointmentCollection,
widget.width,
widget.height,
+ widget.placeholderTextStyle,
widgets: _children);
}
@@ -254,6 +259,7 @@ class _AgendaViewRenderWidget extends MultiChildRenderObjectWidget {
this.appointmentCollection,
this.width,
this.height,
+ this.placeholderTextStyle,
{List widgets = const []})
: super(children: widgets);
@@ -273,26 +279,29 @@ class _AgendaViewRenderWidget extends MultiChildRenderObjectWidget {
final List appointmentCollection;
final double width;
final double height;
+ final TextStyle placeholderTextStyle;
@override
_AgendaViewRenderObject createRenderObject(BuildContext context) {
return _AgendaViewRenderObject(
- monthViewSettings,
- scheduleViewSettings,
- selectedDate,
- appointments,
- isRTL,
- locale,
- localizations,
- calendarTheme,
- agendaViewNotifier,
- appointmentTimeTextFormat,
- timeLabelWidth,
- textScaleFactor,
- isMobilePlatform,
- appointmentCollection,
- width,
- height);
+ monthViewSettings,
+ scheduleViewSettings,
+ selectedDate,
+ appointments,
+ isRTL,
+ locale,
+ localizations,
+ calendarTheme,
+ agendaViewNotifier,
+ appointmentTimeTextFormat,
+ timeLabelWidth,
+ textScaleFactor,
+ isMobilePlatform,
+ appointmentCollection,
+ width,
+ height,
+ placeholderTextStyle,
+ );
}
@override
@@ -313,7 +322,8 @@ class _AgendaViewRenderWidget extends MultiChildRenderObjectWidget {
..textScaleFactor = textScaleFactor
..appointmentCollection = appointmentCollection
..width = width
- ..height = height;
+ ..height = height
+ ..placeholderTextStyle = placeholderTextStyle;
}
}
@@ -334,7 +344,8 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject {
this.isMobilePlatform,
this._appointmentCollection,
this._width,
- this._height);
+ this._height,
+ this._placeholderTextStyle);
final bool isMobilePlatform;
@@ -351,6 +362,19 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject {
markNeedsLayout();
}
+ TextStyle _placeholderTextStyle;
+
+ TextStyle get placeholderTextStyle => _placeholderTextStyle;
+
+ set placeholderTextStyle(TextStyle value) {
+ if (_placeholderTextStyle == value) {
+ return;
+ }
+
+ _placeholderTextStyle = value;
+ markNeedsPaint();
+ }
+
double _width;
double get width => _width;
@@ -1172,8 +1196,7 @@ class _AgendaViewRenderObject extends CustomCalendarRenderObject {
text: selectedDate == null
? localizations.noSelectedDateCalendarLabel
: localizations.noEventsCalendarLabel,
- style: const TextStyle(
- color: Colors.grey, fontSize: 15, fontFamily: 'Roboto'),
+ style: placeholderTextStyle,
);
_updateTextPainterProperties(span);
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart
index 5c8103869..c9598f0a1 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/appointment_layout/appointment_layout.dart
@@ -730,6 +730,17 @@ class _AppointmentLayoutState extends State {
/// 8 PM to 9 PM and the calendar end time is 6 PM then skip the
/// rendering).
continue;
+ }
+
+ if (yPosition < 0 && yPosition + height > widget.height) {
+ /// Change the start position and height when appointment start time
+ /// before the calendar start time and appointment end time after the
+ /// calendar end time.(Eg., appointment start and end date as 6 AM to
+ /// 9 PM and the calendar start time is 8 AM and end time is 6 PM then
+ /// calculate the new size from 8 AM to 6 MM, if we does not calculate
+ /// the new size then the appointment text drawn on hidden place).
+ height = widget.height;
+ yPosition = 0;
} else if (yPosition + height > widget.height) {
/// Change the height when appointment end time greater than calendar
/// time slot end time(Eg., calendar end time is 4 PM and appointment
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart
index 63f5af3cc..a7edf467c 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/common/calendar_view_helper.dart
@@ -1031,7 +1031,7 @@ class CalendarAppointment {
otherAppointment.isAllDay == isAllDay &&
otherAppointment.notes == notes &&
otherAppointment.location == location &&
- !CalendarViewHelper.isCollectionEqual(
+ CalendarViewHelper.isCollectionEqual(
otherAppointment.resourceIds, resourceIds) &&
otherAppointment.recurrenceId == recurrenceId &&
otherAppointment.id == id &&
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/month_view_settings.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/month_view_settings.dart
index e4d638c3e..e5c241510 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/month_view_settings.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/month_view_settings.dart
@@ -743,7 +743,9 @@ class AgendaStyle with Diagnosticable {
{this.appointmentTextStyle,
this.dayTextStyle,
this.dateTextStyle,
- this.backgroundColor});
+ this.backgroundColor,
+ this.placeholderTextStyle = const TextStyle(
+ color: Colors.grey, fontSize: 15, fontFamily: 'Roboto')});
/// The text style for the text in the [Appointment] view in [SfCalendar]
/// month agenda view.
@@ -798,6 +800,34 @@ class AgendaStyle with Diagnosticable {
/// ```
final TextStyle? appointmentTextStyle;
+ /// The text style for the text in the placeholder (no event text and
+ /// no selected date text) of the [SfCalendar] month agenda view.
+ ///
+ /// See also:
+ /// * [MonthViewSettings], to customize the month view of the calendar.
+ /// * [ScheduleViewSettings], to customize the schedule view of the calendar.
+ /// * [AgendaStyle], to customize the month agenda view of the calendar.
+ ///
+ /// ``` dart
+ ///
+ /// Widget build(BuildContext context) {
+ /// return Container(
+ /// child: SfCalendar(
+ /// view: CalendarView.month,
+ /// monthViewSettings: const MonthViewSettings(showAgenda: true,
+ /// agendaStyle: AgendaStyle(
+ /// placeholderTextStyle:TextStyle(
+ /// color: Colors.white,
+ /// fontSize: 20,
+ /// backgroundColor:
+ /// Colors.red),)),
+ /// ),
+ /// );
+ /// }
+ ///
+ ///
+ final TextStyle placeholderTextStyle;
+
/// The text style for the text in the day text of [SfCalendar] month agenda
/// view.
///
@@ -967,7 +997,8 @@ class AgendaStyle with Diagnosticable {
return otherStyle.appointmentTextStyle == appointmentTextStyle &&
otherStyle.dayTextStyle == dayTextStyle &&
otherStyle.dateTextStyle == dateTextStyle &&
- otherStyle.backgroundColor == backgroundColor;
+ otherStyle.backgroundColor == backgroundColor &&
+ otherStyle.placeholderTextStyle == placeholderTextStyle;
}
@override
@@ -980,6 +1011,8 @@ class AgendaStyle with Diagnosticable {
properties
.add(DiagnosticsProperty('dayTextStyle', dayTextStyle));
properties.add(ColorProperty('backgroundColor', backgroundColor));
+ properties.add(DiagnosticsProperty(
+ 'placeholderTextStyle', placeholderTextStyle));
}
@override
@@ -989,6 +1022,7 @@ class AgendaStyle with Diagnosticable {
dayTextStyle,
dateTextStyle,
backgroundColor,
+ placeholderTextStyle,
);
}
}
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/schedule_view_settings.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/schedule_view_settings.dart
index 350084012..32ee8a5c1 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/schedule_view_settings.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/settings/schedule_view_settings.dart
@@ -52,7 +52,9 @@ class ScheduleViewSettings with Diagnosticable {
this.hideEmptyScheduleWeek = false,
this.monthHeaderSettings = const MonthHeaderSettings(),
this.weekHeaderSettings = const WeekHeaderSettings(),
- this.dayHeaderSettings = const DayHeaderSettings()})
+ this.dayHeaderSettings = const DayHeaderSettings(),
+ this.placeholderTextStyle = const TextStyle(
+ color: Colors.grey, fontSize: 15, fontFamily: 'Roboto')})
: assert(appointmentItemHeight >= -1);
/// Sets the style to customize month label in [SfCalendar] schedule view.
@@ -223,6 +225,32 @@ class ScheduleViewSettings with Diagnosticable {
/// ```
final TextStyle? appointmentTextStyle;
+ /// The text style for the text in the placeholder (no event
+ /// text) of the [SfCalendar] schedule view.
+ ///
+ /// See also:
+ /// * [MonthViewSettings], to customize the month view of the calendar.
+ /// * [ScheduleViewSettings], to customize the schedule view of the calendar.
+ /// * [AgendaStyle], to customize the month agenda view of the calendar.
+ ///
+ /// ``` dart
+ ///
+ /// Widget build(BuildContext context) {
+ /// return Container(
+ /// child: SfCalendar(
+ /// view: CalendarView.schedule,
+ /// scheduleViewSettings: const ScheduleViewSettings(
+ /// placeholderTextStyle: TextStyle(
+ /// color: Colors.white,
+ /// fontSize: 20,
+ /// backgroundColor: Colors.red)),
+ /// ),
+ /// );
+ /// }
+ ///
+ ///
+ final TextStyle placeholderTextStyle;
+
/// The height for each appointment view to layout within this in schedule
/// view of [SfCalendar],.
///
@@ -304,7 +332,8 @@ class ScheduleViewSettings with Diagnosticable {
otherStyle.hideEmptyScheduleWeek == hideEmptyScheduleWeek &&
otherStyle.monthHeaderSettings == monthHeaderSettings &&
otherStyle.weekHeaderSettings == weekHeaderSettings &&
- otherStyle.dayHeaderSettings == dayHeaderSettings;
+ otherStyle.dayHeaderSettings == dayHeaderSettings &&
+ otherStyle.placeholderTextStyle == placeholderTextStyle;
}
@override
@@ -322,6 +351,8 @@ class ScheduleViewSettings with Diagnosticable {
.add(DoubleProperty('appointmentItemHeight', appointmentItemHeight));
properties.add(DiagnosticsProperty(
'hideEmptyScheduleWeek', hideEmptyScheduleWeek));
+ properties.add(DiagnosticsProperty(
+ 'placeholderTextStyle', placeholderTextStyle));
}
@override
@@ -332,7 +363,8 @@ class ScheduleViewSettings with Diagnosticable {
hideEmptyScheduleWeek,
monthHeaderSettings,
weekHeaderSettings,
- dayHeaderSettings);
+ dayHeaderSettings,
+ placeholderTextStyle);
}
}
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart
index 72735b564..35485b580 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/sfcalendar.dart
@@ -3879,7 +3879,7 @@ class _SfCalendarState extends State
/// loads the time zone data base to handle the time zone for calendar
Future _loadDataBase() async {
final ByteData byteData =
- await rootBundle.load('packages/timezone/data/2020a.tzf');
+ await rootBundle.load('packages/timezone/data/latest_all.tzf');
initializeDatabase(byteData.buffer.asUint8List());
_timeZoneLoaded = true;
return true;
@@ -6059,6 +6059,7 @@ class _SfCalendarState extends State
widget.appointmentBuilder,
_minWidth - viewPadding,
panelHeight,
+ widget.monthViewSettings.agendaStyle.placeholderTextStyle,
widget),
)),
onTapUp: (TapUpDetails details) {
@@ -9039,6 +9040,8 @@ class _SfCalendarState extends State
widget.appointmentBuilder,
width,
height,
+ widget
+ .monthViewSettings.agendaStyle.placeholderTextStyle,
widget),
onTapUp: (TapUpDetails details) {
_handleTapForAgenda(details, null);
@@ -9149,6 +9152,8 @@ class _SfCalendarState extends State
widget.appointmentBuilder,
width - _agendaDateViewWidth,
painterHeight,
+ widget.monthViewSettings.agendaStyle
+ .placeholderTextStyle,
widget),
],
),
@@ -10493,8 +10498,7 @@ class _ScheduleLabelPainter extends CustomPainter {
final TextSpan span = TextSpan(
text: _localizations.noEventsCalendarLabel,
style: scheduleViewSettings.weekHeaderSettings.weekTextStyle ??
- const TextStyle(
- color: Colors.grey, fontSize: 15, fontFamily: 'Roboto'),
+ scheduleViewSettings.placeholderTextStyle,
);
double xPosition = 10;
diff --git a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart
index 1119ed50e..5be572291 100644
--- a/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart
+++ b/packages/syncfusion_flutter_calendar/lib/src/calendar/views/calendar_view.dart
@@ -787,7 +787,6 @@ class _CustomCalendarScrollViewState extends State
widget.width,
widget.height,
currentState.widget.visibleDates.length,
- currentState._allDayHeight,
widget.isMobilePlatform);
_dragDetails.value.appointmentView = appointmentView;
_dragDifferenceOffset = null;
@@ -926,7 +925,6 @@ class _CustomCalendarScrollViewState extends State
widget.width,
widget.height,
currentState.widget.visibleDates.length,
- currentState._allDayHeight,
widget.isMobilePlatform);
if (isTimelineView) {
_updateAutoScrollDragTimelineView(
@@ -1961,7 +1959,6 @@ class _CustomCalendarScrollViewState extends State
widget.width,
widget.height,
currentState.widget.visibleDates.length,
- currentState._allDayHeight,
widget.isMobilePlatform);
double xPosition = details.dx;
double yPosition = appointmentPosition.dy;
@@ -3095,7 +3092,8 @@ class _CustomCalendarScrollViewState extends State
);
_children[index] = view;
- } // check and update the visible appointments in the view
+ }
+ // check and update the visible appointments in the view
else if (!CalendarViewHelper.isCollectionEqual(
appointmentLayout.visibleAppointments.value,
_updateCalendarStateDetails.visibleAppointments)) {
@@ -3133,6 +3131,43 @@ class _CustomCalendarScrollViewState extends State
},
key: viewKey,
);
+ _children[index] = view;
+ } else if (view.calendar != widget.calendar) {
+ /// Update the calendar view when calendar properties like appointment
+ /// text style dynamically changed.
+ view = _CalendarView(
+ widget.calendar,
+ widget.view,
+ visibleDates,
+ widget.width,
+ widget.height,
+ widget.agendaSelectedDate,
+ widget.locale,
+ widget.calendarTheme,
+ view.regions,
+ view.blackoutDates,
+ _focusNode,
+ widget.removePicker,
+ widget.calendar.allowViewNavigation,
+ widget.controller,
+ widget.resourcePanelScrollController,
+ widget.resourceCollection,
+ widget.textScaleFactor,
+ widget.isMobilePlatform,
+ widget.minDate,
+ widget.maxDate,
+ widget.localizations,
+ widget.timelineMonthWeekNumberNotifier,
+ _dragDetails,
+ (UpdateCalendarStateDetails details) {
+ _updateCalendarViewStateDetails(details);
+ },
+ (UpdateCalendarStateDetails details) {
+ _getCalendarViewStateDetails(details);
+ },
+ key: viewKey,
+ );
+
_children[index] = view;
} else if (view.visibleDates == _currentViewVisibleDates) {
/// Remove the appointment selection when the selected
@@ -3393,9 +3428,12 @@ class _CustomCalendarScrollViewState extends State
} else if (_currentChildIndex == 2) {
_currentChildIndex = 0;
}
+
+ // resets position to zero on the swipe end to avoid the
+ // unwanted date updates.
+ _position = 0;
});
- _resetPosition();
_updateAppointmentPainter();
}
@@ -3427,9 +3465,12 @@ class _CustomCalendarScrollViewState extends State
} else if (_currentChildIndex == 2) {
_currentChildIndex = 1;
}
+
+ // resets position to zero on the swipe end to avoid the
+ // unwanted date updates.
+ _position = 0;
});
- _resetPosition();
_updateAppointmentPainter();
}
@@ -3644,15 +3685,6 @@ class _CustomCalendarScrollViewState extends State
_updateAppointmentPainter();
}
- // resets position to zero on the swipe end to avoid the unwanted date updates
- void _resetPosition() {
- SchedulerBinding.instance.addPostFrameCallback((_) {
- if (_position.abs() == widget.width || _position.abs() == widget.height) {
- _position = 0;
- }
- });
- }
-
void _updateScrollPosition() {
SchedulerBinding.instance.addPostFrameCallback((_) {
if (_previousViewKey.currentState == null ||
@@ -5623,7 +5655,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
if (widget.view != CalendarView.month) {
_horizontalLinesCount = CalendarViewHelper.getHorizontalLinesCount(
@@ -5693,6 +5724,8 @@ class _CalendarViewState extends State<_CalendarView>
_scrollToPosition();
}
+ widget.getCalendarState(_updateCalendarStateDetails);
+
/// Method called to update all day height, when the view changed from
/// day to week views to avoid the blank space at the bottom of the view.
final bool isCurrentView =
@@ -5706,7 +5739,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
/// Clear the all day panel selection when the calendar view changed
@@ -5737,7 +5769,6 @@ class _CalendarViewState extends State<_CalendarView>
/// When view switched from any other view to timeline view, and resource
/// enabled the selection must render the first resource view.
- widget.getCalendarState(_updateCalendarStateDetails);
if (!CalendarViewHelper.isTimelineView(oldWidget.view) &&
_updateCalendarStateDetails.selectedDate != null &&
CalendarViewHelper.isResourceEnabled(
@@ -5919,6 +5950,31 @@ class _CalendarViewState extends State<_CalendarView>
final bool isCurrentView =
_updateCalendarStateDetails.currentViewVisibleDates ==
widget.visibleDates;
+
+ // Check and update the time interval height while the all day panel
+ // appointments updated(all day height is default value) for current view.
+ if (isCurrentView && _updateCalendarStateDetails.allDayPanelHeight != 0) {
+ final bool isDayView = CalendarViewHelper.isDayView(
+ widget.view,
+ widget.calendar.timeSlotViewSettings.numberOfDaysInView,
+ widget.calendar.timeSlotViewSettings.nonWorkingDays,
+ widget.calendar.monthViewSettings.numberOfWeeksInView);
+ final double viewHeaderHeight = CalendarViewHelper.getViewHeaderHeight(
+ widget.calendar.viewHeaderHeight, widget.view);
+ // Default all day height is 0 on week and work week view
+ // Default all day height is view header height on day view.
+ final double defaultAllDayHeight = isDayView ? viewHeaderHeight : 0;
+ if (_allDayHeight == defaultAllDayHeight) {
+ _timeIntervalHeight = _getTimeIntervalHeight(
+ widget.calendar,
+ widget.view,
+ widget.width,
+ widget.height,
+ widget.visibleDates.length,
+ widget.isMobilePlatform);
+ }
+ }
+
_updateAllDayHeight(isCurrentView);
return MouseRegion(
@@ -6135,7 +6191,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
visibleDatesCount,
- _allDayHeight,
widget.isMobilePlatform);
double timeToPosition = 0;
final bool isTimelineView = CalendarViewHelper.isTimelineView(widget.view);
@@ -6661,7 +6716,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
final double overAllHeight = _timeIntervalHeight * _horizontalLinesCount!;
@@ -6958,7 +7012,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
if (isTimelineView) {
@@ -7264,7 +7317,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
final double timeLabelWidth = CalendarViewHelper.getTimeLabelWidth(
@@ -7571,7 +7623,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
if (yPosition! <= viewHeaderHeight + allDayPanelHeight &&
@@ -7960,7 +8011,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
double minimumTimeIntervalSize = timeIntervalSize / 4;
if (minimumTimeIntervalSize < 20) {
@@ -8001,7 +8051,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
double minimumTimeIntervalSize = timeIntervalSize /
(widget.view == CalendarView.timelineMonth ? 2 : 4);
@@ -8078,7 +8127,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
late DateTime resizingTime;
CalendarResource? resource;
@@ -9160,8 +9208,15 @@ class _CalendarViewState extends State<_CalendarView>
widget.calendar.onSelectionChanged);
if (canRaiseLongPress || canRaiseTap || canRaiseSelectionChanged) {
- final DateTime selectedDate =
- _getDateFromPosition(xDetails, yDetails - viewHeaderHeight, 0)!;
+ final DateTime? selectedDate =
+ _getDateFromPosition(xDetails, yDetails - viewHeaderHeight, 0);
+
+ /// Restrict the tap/long press callback while interact after
+ /// the timeslots.
+ if (selectedDate == null) {
+ return null;
+ }
+
final int timeInterval = CalendarViewHelper.getTimeInterval(
widget.calendar.timeSlotViewSettings);
if (appointmentView == null) {
@@ -9767,10 +9822,16 @@ class _CalendarViewState extends State<_CalendarView>
yPosition,
timeLabelWidth);
+ /// Restrict the tap/long press callback while interact after
+ /// the timeslots.
+ if (selectedDate == null) {
+ return null;
+ }
+
if (!CalendarViewHelper.isDateTimeWithInDateTimeRange(
widget.calendar.minDate,
widget.calendar.maxDate,
- selectedDate!,
+ selectedDate,
timeInterval)) {
return null;
}
@@ -9863,7 +9924,6 @@ class _CalendarViewState extends State<_CalendarView>
widget.width,
widget.height,
widget.visibleDates.length,
- _allDayHeight,
widget.isMobilePlatform);
final double minuteHeight = timeIntervalSize /
@@ -9950,7 +10010,6 @@ class _CalendarViewState extends State<_CalendarView>
double width,
double height,
int visibleDatesCount,
- double allDayHeight,
bool isMobilePlatform) {
final bool isTimelineView = CalendarViewHelper.isTimelineView(view);
final bool isDayView = CalendarViewHelper.isDayView(
@@ -9970,20 +10029,40 @@ class _CalendarViewState extends State<_CalendarView>
double viewHeaderHeight =
CalendarViewHelper.getViewHeaderHeight(calendar.viewHeaderHeight, view);
+ double allDayViewHeight = 0;
+
+ final bool isCurrentView =
+ _updateCalendarStateDetails.currentViewVisibleDates ==
+ widget.visibleDates;
if (isDayView) {
- allDayHeight = _kAllDayLayoutHeight;
+ if (isCurrentView) {
+ allDayViewHeight = _kAllDayLayoutHeight > viewHeaderHeight &&
+ _updateCalendarStateDetails.allDayPanelHeight > viewHeaderHeight
+ ? _updateCalendarStateDetails.allDayPanelHeight >
+ _kAllDayLayoutHeight
+ ? _kAllDayLayoutHeight
+ : _updateCalendarStateDetails.allDayPanelHeight
+ : viewHeaderHeight;
+ if (allDayViewHeight < _updateCalendarStateDetails.allDayPanelHeight) {
+ allDayViewHeight += kAllDayAppointmentHeight;
+ }
+ } else {
+ allDayViewHeight = viewHeaderHeight;
+ }
+
viewHeaderHeight = 0;
- } else {
- allDayHeight = allDayHeight > _kAllDayLayoutHeight
- ? _kAllDayLayoutHeight
- : allDayHeight;
+ } else if (isCurrentView) {
+ allDayViewHeight =
+ _updateCalendarStateDetails.allDayPanelHeight > _kAllDayLayoutHeight
+ ? _kAllDayLayoutHeight
+ : _updateCalendarStateDetails.allDayPanelHeight;
}
switch (view) {
case CalendarView.day:
case CalendarView.week:
case CalendarView.workWeek:
- timeIntervalHeight = (height - allDayHeight - viewHeaderHeight) /
+ timeIntervalHeight = (height - allDayViewHeight - viewHeaderHeight) /
CalendarViewHelper.getHorizontalLinesCount(
calendar.timeSlotViewSettings, view);
break;
diff --git a/packages/syncfusion_flutter_calendar/pubspec.yaml b/packages/syncfusion_flutter_calendar/pubspec.yaml
index 08505f522..6c50c0369 100644
--- a/packages/syncfusion_flutter_calendar/pubspec.yaml
+++ b/packages/syncfusion_flutter_calendar/pubspec.yaml
@@ -1,18 +1,18 @@
name: syncfusion_flutter_calendar
description: The Flutter Calendar widget has nine built-in configurable views that provide basic functionalities for scheduling and representing appointments/events efficiently.
-version: 20.3.47
+version: 20.4.38
homepage: https://github.com/syncfusion/flutter-examples
environment:
- sdk: '>=2.12.0 <3.0.0'
+ sdk: '>=2.17.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
timezone: 0.8.0
- syncfusion_flutter_core: ^20.3.47
+ syncfusion_flutter_core: ^20.4.38
- syncfusion_flutter_datepicker: ^20.3.47
+ syncfusion_flutter_datepicker: ^20.4.38
intl: ">=0.15.0 <0.20.0"
diff --git a/packages/syncfusion_flutter_charts/CHANGELOG.md b/packages/syncfusion_flutter_charts/CHANGELOG.md
index ee804f173..0ab9f8a3b 100644
--- a/packages/syncfusion_flutter_charts/CHANGELOG.md
+++ b/packages/syncfusion_flutter_charts/CHANGELOG.md
@@ -1,5 +1,53 @@
## Unreleased
+**Bugs**
+
+* #FB37705 - Now, the circular data label builder will render properly with connector lines.
+
+## [20.3.69] - 12/06/2022
+
+**Bugs**
+* #FB39502 - Now, the series is rendered with both the [primaryXAxis](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/SfCartesianChart/primaryXAxis.html) and [primaryYAxis](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/SfCartesianChart/primaryYAxis.html) as [LogarithmicAxis](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/LogarithmicAxis-class.html).
+* #FB39157 - Now, the [onPointTap](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/CartesianSeries/onPointTap.html) event returns the respective data point index while having the nearest x values.
+
+## [20.3.59] - 11/29/2022
+
+**Bugs**
+* #FB37704 - Now, the fast line series will render the line when the data points are outside of the range controller's.
+
+## [20.3.57] - 11/15/2022
+
+**Bugs**
+* #FB38884 - The null exception will no longer be thrown in the chart while dynamically enabling the [isVisibleInLegend](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/CartesianSeries/isVisibleInLegend.html) property for the series.
+
+## [20.3.56] - 11/08/2022
+
+**Bugs**
+* #FB37724 - Now, the Null check operator exception will no longer be thrown when refreshing the chart in the [onLegendTapped](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/SfCartesianChart/onLegendTapped.html) callback.
+* #FB38586 - Now, the plot band will render properly for the [LogarithmicAxis](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/LogarithmicAxis-class.html).
+
+## [20.3.52] - 10/26/2022
+
+**Bugs**
+* #FB38235 - The Null exception will no longer be thrown in trackball when using the RangeAreaSeries and AreaSeries with different data sources.
+
+## [20.3.50] - 10/18/2022
+
+**Bugs**
+* #FB37724 - Now, the series visibility gets toggled properly when setting the series visibility using the [onLegendTapped](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/SfCartesianChart/onLegendTapped.html) callback.
+* #FB37885 - Now, the candle series gets rendered properly when it starts updating data dynamically with a single data point.
+* #FB38196 - Now, there is no exception that occurs while calling the trackball public method [show](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/TrackballBehavior/show.html) when there is no visible series in the chart.
+* #FB38080 - Now, the trackball tooltip with builder will activate properly when using the [show](https://pub.dev/documentation/syncfusion_flutter_charts/latest/charts/TrackballBehavior/show.html) public method if the trackball is already moved in the chart using user interaction.
+* #FB38046 - Now, the doughnut series with stroke border renders properly with CornerStyle as both sided curve.
+* #FB37274 - Now, Infinity or NaN toInt exception will no longer be thrown when rendering Bollinger band with mapping more number identical close point values.
+
+## [20.3.49] - 10/11/2022
+
+**Bugs**
+* #FB36732 - Now, while performing zooming and panning, the hidden series won't become visible.
+
+## [20.3.47] - 09/29/2022
+
**Bugs**
* #FB37559 - Now, the `NoSuchMethodError` exception will not be thrown when a tooltip is activated using the `showByIndex` method in circular charts.
* #FB37311 - The FastLineSeries renders when all the y-values are the same.
diff --git a/packages/syncfusion_flutter_charts/README.md b/packages/syncfusion_flutter_charts/README.md
index 5e1745d98..824caf187 100644
--- a/packages/syncfusion_flutter_charts/README.md
+++ b/packages/syncfusion_flutter_charts/README.md
@@ -84,15 +84,12 @@ Explore the full capabilities of our Flutter widgets on your device by installin
-
-
+
+
-
-
-
@@ -320,7 +317,7 @@ Widget build(BuildContext context) {
## Support and Feedback
-* For any other queries, reach our [Syncfusion support team](https://www.syncfusion.com/support/directtrac/incidents/newincident?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) or post the queries through the [Community forums](https://www.syncfusion.com/forums?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev).
+* For any other queries, reach our [Syncfusion support team](https://support.syncfusion.com/support/tickets/create?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) or post the queries through the [Community forums](https://www.syncfusion.com/forums?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev).
* To renew the subscription, click [renew](https://www.syncfusion.com/sales/products?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) or contact our sales team at salessupport@syncfusion.com | Toll Free: 1-888-9 DOTNET.
## About Syncfusion Flutter Widgets
@@ -330,4 +327,4 @@ The Syncfusion's [Flutter library](https://www.syncfusion.com/flutter-widgets?ut
Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 20,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies.
-Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [JavaScript](https://www.syncfusion.com/javascript-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Angular](https://www.syncfusion.com/angular-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [React](https://www.syncfusion.com/react-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Vue](https://www.syncfusion.com/vue-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), and [Blazor](https://www.syncfusion.com/blazor-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Flutter](https://www.syncfusion.com/flutter-widgets?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [UWP](https://www.syncfusion.com/uwp-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev)), and desktop development ([WinForms](https://www.syncfusion.com/winforms-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [WPF](https://www.syncfusion.com/wpf-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [UWP](https://www.syncfusion.com/uwp-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev) and [WinUI](https://www.syncfusion.com/winui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
+Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [JavaScript](https://www.syncfusion.com/javascript-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Angular](https://www.syncfusion.com/angular-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [React](https://www.syncfusion.com/react-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Vue](https://www.syncfusion.com/vue-ui-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev)), mobile ([.NET MAUI](https://www.syncfusion.com/maui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Xamarin](https://www.syncfusion.com/xamarin-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Flutter](https://www.syncfusion.com/flutter-widgets?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [UWP](https://www.syncfusion.com/uwp-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev)), and desktop development ([.NET MAUI](https://www.syncfusion.com/maui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Flutter](https://www.syncfusion.com/flutter-widgets), [WinForms](https://www.syncfusion.com/winforms-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [WPF](https://www.syncfusion.com/wpf-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [UWP](https://www.syncfusion.com/uwp-ui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), and [WinUI](https://www.syncfusion.com/winui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
diff --git a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.cc
index e71a16d23..d38195aa0 100644
--- a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.h
index e0f0a47bc..9bf747894 100644
--- a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugins.cmake
index 2e1de87a7..51436ae8c 100644
--- a/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_charts/example/linux/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_charts/example/pubspec.yaml b/packages/syncfusion_flutter_charts/example/pubspec.yaml
index 3679c0b64..29cba666c 100644
--- a/packages/syncfusion_flutter_charts/example/pubspec.yaml
+++ b/packages/syncfusion_flutter_charts/example/pubspec.yaml
@@ -4,7 +4,7 @@ version: 1.0.0+1
publish_to: 'none'
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
@@ -13,6 +13,9 @@ dependencies:
path: ../
cupertino_icons: ^1.0.2
-flutter:
+dev_dependencies:
+ flutter_test:
+ sdk: flutter
+flutter:
uses-material-design: true
diff --git a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.cc
index 8b6d4680a..4bfa0f3a3 100644
--- a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.h
index dc139d85a..9846246b4 100644
--- a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugins.cmake
index b93c4c30c..4d10c2518 100644
--- a/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_charts/example/windows/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/annotation/annotation_settings.dart b/packages/syncfusion_flutter_charts/lib/src/chart/annotation/annotation_settings.dart
index 5652105b4..96dffafdb 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/annotation/annotation_settings.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/annotation/annotation_settings.dart
@@ -247,7 +247,7 @@ class CartesianChartAnnotation {
/// child: const Text('Annotation')),
/// x: 3,
/// y: 60,
- /// verticalAllignment: ChartAlignment.near
+ /// verticalAlignment: ChartAlignment.near
/// )
/// ],
/// )
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/axis/category_axis.dart b/packages/syncfusion_flutter_charts/lib/src/chart/axis/category_axis.dart
index 625a365c6..7f4188414 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/axis/category_axis.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/axis/category_axis.dart
@@ -488,7 +488,7 @@ class CategoryAxisRenderer extends ChartAxisRenderer {
for (;
tempInterval <= _axisDetails.visibleRange!.maximum;
tempInterval += _axisDetails.visibleRange!.interval) {
- if (withInRange(tempInterval, _axisDetails.visibleRange!)) {
+ if (withInRange(tempInterval, _axisDetails)) {
position = tempInterval.round();
if (position <= -1 ||
(_axisDetails.labels.isNotEmpty &&
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_axis.dart b/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_axis.dart
index df3c374dc..caff39cde 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_axis.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_axis.dart
@@ -510,7 +510,7 @@ class DateTimeAxisRenderer extends ChartAxisRenderer {
interval = _axisDetails._alignRangeStart(
this, interval, _axisDetails.visibleRange!.interval);
while (interval <= _axisDetails.visibleRange!.maximum) {
- if (withInRange(interval, _axisDetails.visibleRange!)) {
+ if (withInRange(interval, _axisDetails)) {
prevInterval = (label.isNotEmpty)
? _axisDetails
.visibleLabels[_axisDetails.visibleLabels.length - 1].value
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_category_axis.dart b/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_category_axis.dart
index 4bad8c450..858bf10f2 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_category_axis.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/axis/datetime_category_axis.dart
@@ -540,7 +540,7 @@ class DateTimeCategoryAxisRenderer extends ChartAxisRenderer {
for (;
tempInterval <= _axisDetails.visibleRange!.maximum;
tempInterval += interval) {
- if (withInRange(tempInterval, _axisDetails.visibleRange!)) {
+ if (withInRange(tempInterval, _axisDetails)) {
position = tempInterval.round();
if (position <= -1 ||
(_axisDetails.labels.isNotEmpty &&
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/axis/plotband.dart b/packages/syncfusion_flutter_charts/lib/src/chart/axis/plotband.dart
index 5db7a5f9c..2c1e60bfa 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/axis/plotband.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/axis/plotband.dart
@@ -1,3 +1,5 @@
+import 'dart:math';
+
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_core/core.dart';
@@ -887,28 +889,27 @@ class _PlotBandPainter extends CustomPainter {
axisDetails.orientation == AxisOrientation.vertical
? axis.plotOffset
: 0));
-
- startValue = axis is LogarithmicAxis
- ? calculateLogBaseValue(startValue, axis.logBase)
- : startValue;
- endValue = axis is LogarithmicAxis
- ? calculateLogBaseValue(endValue, axis.logBase)
- : endValue;
+ final num visibleMin = axis is LogarithmicAxis
+ ? pow(axis.logBase, axisDetails.visibleRange!.minimum)
+ : axisDetails.visibleRange!.minimum;
+ final num visibleMax = axis is LogarithmicAxis
+ ? pow(axis.logBase, axisDetails.visibleRange!.maximum)
+ : axisDetails.visibleRange!.maximum;
endValue < 0
- ? endValue <= axisDetails.visibleRange!.minimum
- ? endValue = axisDetails.visibleRange!.minimum
+ ? endValue <= visibleMin
+ ? endValue = visibleMin
: endValue = endValue
- : endValue >= axisDetails.visibleRange!.maximum
- ? endValue = axisDetails.visibleRange!.maximum
+ : endValue >= visibleMax
+ ? endValue = visibleMax
: endValue = endValue;
startValue < 0
- ? startValue <= axisDetails.visibleRange!.minimum
- ? startValue = axisDetails.visibleRange!.minimum
+ ? startValue <= visibleMin
+ ? startValue = visibleMin
: startValue = startValue
- : startValue >= axisDetails.visibleRange!.maximum
- ? startValue = axisDetails.visibleRange!.maximum
+ : startValue >= visibleMax
+ ? startValue = visibleMax
: startValue = startValue;
startPoint = calculatePoint(startValue, startValue, axisDetails,
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/base/chart_base.dart b/packages/syncfusion_flutter_charts/lib/src/chart/base/chart_base.dart
index 8b87c8ae7..8a61fbe9c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/base/chart_base.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/base/chart_base.dart
@@ -986,33 +986,6 @@ class SfCartesianChart extends StatefulWidget {
///```
final ImageProvider? plotAreaBackgroundImage;
- /// Data points or series can be selected while performing interaction on the chart.
- /// It can also be selected at the initial rendering using this property.
- ///
- ///
- ///```dart
- ///SelectionBehavior _selectionBehavior;
- ///
- ///@override
- ///void initState() {
- /// _selectionBehavior = SelectionBehavior( enable: true);
- /// super.initState();
- /// }
- ///
- ///Widget build(BuildContext context) {
- /// return Container(
- /// child: SfCartesianChart(
- /// series: >[
- /// BarSeries(
- /// initialSelectedDataIndexes: [2, 0],
- /// selectionBehavior: _selectionBehavior
- /// ),
- /// ],
- /// )
- /// );
- ///}
- ///```
-
/// By setting this, the orientation of x-axis is set to vertical and orientation of
/// y-axis is set to horizontal.
///
@@ -1950,7 +1923,8 @@ class SfCartesianChartState extends State
}
}
if (_stateProperties.renderingDetails.initialRender! ||
- (_stateProperties.renderingDetails.widgetNeedUpdate &&
+ ((_stateProperties.renderingDetails.widgetNeedUpdate ||
+ _stateProperties.isRedrawByZoomPan) &&
!_stateProperties.legendToggling &&
(_stateProperties.renderingDetails.oldDeviceOrientation ==
MediaQuery.of(context).orientation))) {
@@ -1963,10 +1937,6 @@ class SfCartesianChartState extends State
seriesRendererDetails.series.isVisible)) {
legendCheck = true;
} else {
- if (_stateProperties.renderingDetails.legendToggleStates.isNotEmpty) {
- _stateProperties.renderingDetails.legendToggleStates.clear();
- }
-
seriesRendererDetails.visible =
_stateProperties.renderingDetails.initialRender!
? seriesRendererDetails.series.isVisible
@@ -2040,7 +2010,7 @@ class SfCartesianChartState extends State
null &&
_stateProperties.renderingDetails.chartLegend
.legendCollections!.isNotEmpty
- ? _getLegendItemCollection(index)!.text
+ ? _getLegendItemCollection(index)?.text
: null;
final String? seriesName = visibleSeriesDetails.series.name;
@@ -2769,8 +2739,7 @@ class ContainerArea extends StatelessWidget {
point = dataPoints[j];
if (point.isVisible &&
!point.isGap &&
- withInRange(point.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!)) {
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!)) {
labelWidget = (series.dataLabelSettings.builder != null)
? series.dataLabelSettings.builder!(
series.dataSource[point.overallDataPointIndex!],
@@ -3282,6 +3251,13 @@ class ContainerArea extends StatelessWidget {
trackballRenderingDetails.isLongPressActivated = false;
}
+
+ if (chart.trackballBehavior.enable &&
+ chart.trackballBehavior.activationMode == ActivationMode.singleTap &&
+ chart.trackballBehavior.builder != null) {
+ trackballRenderingDetails.isMoving = false;
+ }
+
// ignore: unnecessary_null_comparison
if ((chart.crosshairBehavior != null &&
chart.crosshairBehavior.enable &&
@@ -3525,9 +3501,10 @@ class ContainerArea extends StatelessWidget {
// ignore: unnecessary_null_comparison
if ((chart.trackballBehavior != null &&
chart.trackballBehavior.enable == true &&
+ _findSeries(position!) != null &&
chart.trackballBehavior.activationMode ==
ActivationMode.longPress) &&
- SeriesHelper.getSeriesRendererDetails(_findSeries(position!)!).series
+ SeriesHelper.getSeriesRendererDetails(_findSeries(position)!).series
is! ErrorBarSeries &&
// ignore: unnecessary_null_comparison
position != null &&
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/base/series_base.dart b/packages/syncfusion_flutter_charts/lib/src/chart/base/series_base.dart
index 29b2b4525..0a44c85f9 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/base/series_base.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/base/series_base.dart
@@ -174,16 +174,27 @@ class ChartSeriesPanel {
series.sortFieldValueMapper != null;
// ignore: unnecessary_null_comparison
if (series.dataSource != null) {
- dynamic xVal;
+ dynamic previousX, currentX, nextX;
dynamic yVal;
num? low, high;
num maxYValue = 0;
seriesRendererDetails.overAllDataPoints =
?>[];
+ CartesianChartPoint? nextPoint;
+ CartesianChartPoint? prevPoint;
for (int pointIndex = 0; pointIndex < series.dataSource.length;) {
currentPoint = getChartPoint(
seriesRenderer, series.dataSource[pointIndex], pointIndex);
- xVal = currentPoint?.x;
+ if (pointIndex < series.dataSource.length - 1 &&
+ seriesRendererDetails.seriesType != 'histogram') {
+ nextPoint = getChartPoint(seriesRenderer,
+ series.dataSource[pointIndex + 1], pointIndex + 1);
+ } else {
+ nextPoint = currentPoint;
+ }
+ currentX = currentPoint?.x;
+ nextX = nextPoint?.x;
+ previousX = pointIndex == 0 ? currentPoint?.x : prevPoint?.x;
yVal = currentPoint?.y;
high = currentPoint?.high;
low = currentPoint?.low;
@@ -196,7 +207,7 @@ class ChartSeriesPanel {
currentPoint!.maxYValue = maxYValue;
}
- if (xVal != null) {
+ if (currentX != null) {
num bubbleSize;
final dynamic xAxis = seriesRendererDetails.xAxisDetails?.axis;
final dynamic yAxis = seriesRendererDetails.yAxisDetails?.axis;
@@ -204,19 +215,25 @@ class ChartSeriesPanel {
dynamic xMax = xAxis?.visibleMaximum;
final dynamic yMin = yAxis?.visibleMinimum;
final dynamic yMax = yAxis?.visibleMaximum;
- dynamic xPointValue = xVal;
+ dynamic xPointValue = currentX;
bool isXVisibleRange = true;
bool isYVisibleRange = true;
if (xAxis is DateTimeAxis) {
xMin = xMin != null ? xMin.millisecondsSinceEpoch : xMin;
xMax = xMax != null ? xMax.millisecondsSinceEpoch : xMax;
xPointValue = xPointValue?.millisecondsSinceEpoch;
+ nextX = nextX?.millisecondsSinceEpoch;
+ previousX = previousX?.millisecondsSinceEpoch;
} else if (xAxis is CategoryAxis) {
xPointValue = pointIndex;
+ nextX = pointIndex + 1;
+ previousX = pointIndex - 1;
} else if (xAxis is DateTimeCategoryAxis) {
xMin = xMin != null ? xMin.millisecondsSinceEpoch : xMin;
xMax = xMax != null ? xMax.millisecondsSinceEpoch : xMax;
xPointValue = xPointValue?.millisecondsSinceEpoch;
+ nextX = nextX?.millisecondsSinceEpoch;
+ previousX = previousX?.millisecondsSinceEpoch;
}
if (xMin != null || xMax != null) {
isXVisibleRange = false;
@@ -279,11 +296,24 @@ class ChartSeriesPanel {
: yMax != null
? (yVal ?? high) <= yMax
: false) ==
- true) {
+ true ||
+ // If the data points present between the range the following conditions are working.
+
+ // This condition will works when having a range between the data points and data points between the given range.
+ // Also works when having a visible minimum value alone and data point outside the range this is for left side point.
+ ((xMin != null && xPointValue <= xMin && nextX > xMin) ||
+ // This condition will work when having data points outside the given range and nearest to the given range and don't have a points between th range.
+ ((xMin != null && xMax != null) &&
+ ((xPointValue <= xMin && nextX >= xMax) ||
+ (previousX <= xMin && xPointValue >= xMax))) ||
+ // This condition will works when having a range between the data points and data points between the given range.
+ // Also works when having a visible maximum value and data point outside the range this is for right side point.
+ (xMax != null &&
+ (previousX < xMax && xPointValue >= xMax)))) {
isXVisibleRange = true;
isYVisibleRange = true;
seriesRendererDetails.dataPoints.add(currentPoint!);
- seriesRendererDetails.xValues!.add(xVal);
+ seriesRendererDetails.xValues!.add(currentX);
if (seriesRenderer is BubbleSeriesRenderer) {
bubbleSize = series.sizeValueMapper == null
? 4
@@ -401,6 +431,7 @@ class ChartSeriesPanel {
pointIndex = seriesRendererDetails.seriesType != 'histogram'
? pointIndex + 1
: pointIndex + yVal as int;
+ prevPoint = currentPoint;
}
if (seriesRendererDetails.xAxisDetails
is DateTimeCategoryAxisRenderer) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series.dart b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series.dart
index bb2695613..bfc62ccca 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series.dart
@@ -1402,13 +1402,16 @@ class ChartSeriesController {
if (needUpdate) {
if (seriesRendererDetails.dataPoints.length > index == true) {
seriesRendererDetails.dataPoints[index] = currentPoint;
+ seriesRendererDetails.overAllDataPoints[index] = currentPoint;
}
} else {
if (seriesRendererDetails.dataPoints.length == index) {
seriesRendererDetails.dataPoints.add(currentPoint);
+ seriesRendererDetails.overAllDataPoints.add(currentPoint);
} else if (seriesRendererDetails.dataPoints.length > index == true &&
index >= 0) {
seriesRendererDetails.dataPoints.insert(index, currentPoint);
+ seriesRendererDetails.overAllDataPoints.insert(index, currentPoint);
}
}
@@ -1654,6 +1657,7 @@ class ChartSeriesController {
_needXRecalculation = true;
}
seriesRendererDetails.dataPoints.removeAt(index);
+ seriesRendererDetails.overAllDataPoints.removeAt(index);
// ignore: unnecessary_null_comparison
if (currentPoint != null) {
if (!_needXRecalculation &&
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series_renderer_properties.dart b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series_renderer_properties.dart
index 2d02192ec..698f554d7 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series_renderer_properties.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/series_renderer_properties.dart
@@ -57,7 +57,7 @@ class SeriesRendererDetails {
bool hasSideBySideInfo = false;
/// Specifies whether the series has tooltip behavior
- bool hasTooltip = false;
+ bool isCalculateRegion = false;
/// Specifies whether to calculate region for the waterfall/ stacked bar/ stacked column
bool needsToCalculateRegion = false;
@@ -410,13 +410,12 @@ class SeriesRendererDetails {
seriesType.contains('box'));
// ignore: unnecessary_null_comparison
- hasTooltip = chart.tooltipBehavior != null &&
- seriesType != 'errorbar' &&
- (chart.tooltipBehavior.enable ||
- seriesRendererDetails.series.onPointTap != null ||
- seriesRendererDetails.series.onPointDoubleTap != null ||
- seriesRendererDetails.series.onPointLongPress != null) &&
- seriesType != 'boxandwhisker';
+ isCalculateRegion = seriesType != 'errorbar' &&
+ seriesType != 'boxandwhisker' &&
+ ((chart.tooltipBehavior.enable) ||
+ (seriesRendererDetails.series.onPointTap != null ||
+ seriesRendererDetails.series.onPointDoubleTap != null ||
+ seriesRendererDetails.series.onPointLongPress != null));
}
/// To find the region data of a series
@@ -431,7 +430,7 @@ class SeriesRendererDetails {
num? midX,
num? midY]) {
if (withInRange(seriesRendererDetails.dataPoints[pointIndex].xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!)) {
+ seriesRendererDetails.xAxisDetails!)) {
seriesRendererDetails.visibleDataPoints!
.add(seriesRendererDetails.dataPoints[pointIndex]);
seriesRendererDetails.dataPoints[pointIndex].visiblePointIndex =
@@ -483,7 +482,7 @@ class SeriesRendererDetails {
}
}
// ignore: unnecessary_null_comparison
- if (hasTooltip) {
+ if (isCalculateRegion) {
calculateTooltipRegion(
point, seriesIndex, seriesRendererDetails, stateProperties);
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/xy_data_series.dart b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/xy_data_series.dart
index aa7a6ce69..2ff869f7d 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/xy_data_series.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/chart_series/xy_data_series.dart
@@ -584,8 +584,8 @@ abstract class XyDataSeriesRenderer extends CartesianSeriesRenderer {
!seriesType.contains('stackedbar'))
? prevPoint.y ?? 0
: 0;
- currentPoint.open = 0;
- currentPoint.close = 0;
+ currentPoint.open = currentPoint.open ?? 0;
+ currentPoint.close = currentPoint.close ?? 0;
currentPoint.isVisible = false;
} else if (seriesType.contains('line') ||
seriesType == 'area' ||
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/common/data_label_renderer.dart b/packages/syncfusion_flutter_charts/lib/src/chart/common/data_label_renderer.dart
index ce84577e0..8a38f7359 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/common/data_label_renderer.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/common/data_label_renderer.dart
@@ -875,15 +875,40 @@ void triggerDataLabelEvent(SfCartesianChart chart,
SeriesHelper.getSeriesRendererDetails(seriesRenderer);
final List>? dataPoints =
seriesRendererDetails.visibleDataPoints;
+ late CartesianChartPoint currentPoint;
+ ChartLocation? dataLabelLocation;
+ final String seriesType = seriesRendererDetails.seriesType;
for (int pointIndex = 0; pointIndex < dataPoints!.length; pointIndex++) {
+ currentPoint = dataPoints[pointIndex];
+ dataLabelLocation = (currentPoint.dataLabelRegion != null &&
+ currentPoint.dataLabelRegion!.contains(position))
+ ? currentPoint.labelLocation
+ : (currentPoint.dataLabelRegion2 != null &&
+ currentPoint.dataLabelRegion2!.contains(position))
+ ? currentPoint.labelLocation2
+ : (seriesType == 'hiloopenclose' ||
+ seriesType == 'candle' ||
+ seriesType == 'boxandwhisker') &&
+ (currentPoint.dataLabelRegion3 != null &&
+ currentPoint.dataLabelRegion3!.contains(position))
+ ? currentPoint.labelLocation3
+ : (seriesType == 'hiloopenclose' ||
+ seriesType == 'candle' ||
+ seriesType == 'boxandwhisker') &&
+ (currentPoint.dataLabelRegion4 != null &&
+ currentPoint.dataLabelRegion4!.contains(position))
+ ? currentPoint.labelLocation4
+ : (seriesRendererDetails.seriesType == 'boxandwhisker' &&
+ currentPoint.dataLabelRegion5 != null &&
+ currentPoint.dataLabelRegion5!.contains(position))
+ ? currentPoint.labelLocation5
+ : null;
if (seriesRendererDetails.series.dataLabelSettings.isVisible == true &&
- dataPoints[pointIndex].dataLabelRegion != null &&
- dataPoints[pointIndex].dataLabelRegion!.contains(position)) {
- final CartesianChartPoint point = dataPoints[pointIndex];
+ dataLabelLocation != null) {
final Offset position =
- Offset(point.labelLocation!.x, point.labelLocation!.y);
+ Offset(dataLabelLocation.x, dataLabelLocation.y);
dataLabelTapEvent(chart, seriesRendererDetails.series.dataLabelSettings,
- pointIndex, point, position, seriesIndex);
+ pointIndex, currentPoint, position, seriesIndex);
break;
}
}
@@ -1076,7 +1101,7 @@ void _drawDataLabelRectAndText(
if (isRangeSeries || isBoxSeries) {
if (withInRange(isBoxSeries ? point.minimum : point.low,
- seriesRendererDetails.yAxisDetails!.visibleRange!)) {
+ seriesRendererDetails.yAxisDetails!)) {
seriesRendererDetails.renderer.drawDataLabel(
index,
canvas,
@@ -1565,35 +1590,33 @@ bool isLabelWithinRange(SeriesRendererDetails seriesRendererDetails,
seriesRendererDetails.seriesType.contains('boxandwhisker');
if (seriesRendererDetails.yAxisDetails is! LogarithmicAxisDetails) {
isWithInRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!) &&
+ point.xValue, seriesRendererDetails.xAxisDetails!) &&
(seriesRendererDetails.seriesType.contains('range') ||
seriesRendererDetails.seriesType == 'hilo'
? (isBoxSeries && point.minimum != null && point.maximum != null) ||
(!isBoxSeries && point.low != null && point.high != null) &&
- (withInRange(
- isBoxSeries ? point.minimum : point.low,
- seriesRendererDetails
- .yAxisDetails!.visibleRange!) ||
+ (withInRange(isBoxSeries ? point.minimum : point.low,
+ seriesRendererDetails.yAxisDetails!) ||
withInRange(isBoxSeries ? point.maximum : point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!))
+ seriesRendererDetails.yAxisDetails!))
: seriesRendererDetails.seriesType == 'hiloopenclose' ||
seriesRendererDetails.seriesType.contains('candle') ||
isBoxSeries
? (withInRange(isBoxSeries ? point.minimum : point.low,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
+ seriesRendererDetails.yAxisDetails!) &&
withInRange(isBoxSeries ? point.maximum : point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
+ seriesRendererDetails.yAxisDetails!) &&
withInRange(isBoxSeries ? point.lowerQuartile : point.open,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
+ seriesRendererDetails.yAxisDetails!) &&
withInRange(isBoxSeries ? point.upperQuartile : point.close,
- seriesRendererDetails.yAxisDetails!.visibleRange!))
+ seriesRendererDetails.yAxisDetails!))
: withInRange(
seriesRendererDetails.seriesType.contains('100')
? point.cumulativeValue
: seriesRendererDetails.seriesType == 'waterfall'
? point.endValue ?? 0
: point.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!));
+ seriesRendererDetails.yAxisDetails!));
}
return isWithInRange;
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bar_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bar_painter.dart
index 1bbae4ce3..76375cd95 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bar_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bar_painter.dart
@@ -255,13 +255,12 @@ class BarChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(point.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bubble_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bubble_painter.dart
index 6670808a3..bace34112 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bubble_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/bubble_painter.dart
@@ -223,13 +223,13 @@ class BubbleChartPainter extends CustomPainter {
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
final CartesianChartPoint currentPoint =
dataPoints[pointIndex];
- final bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange = withInRange(
+ currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(
stateProperties,
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/candle_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/candle_painter.dart
index 8461e1bec..e15f3d43c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/candle_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/candle_painter.dart
@@ -116,15 +116,29 @@ class CandleSeriesRenderer extends XyDataSeriesRenderer {
CandleSegment candleSegment, SegmentProperties segmentProperties) {
final SeriesRendererDetails candleSeriesDetails =
SeriesHelper.getSeriesRendererDetails(segmentProperties.seriesRenderer);
+ // While removing the data point the overallDataPointIndex value is not updated based on
+ // currently available overall data point, it stick with the old overallDataPointIndex value.
+ // So, when check the candle series overAllDataPoints by overallDataPointIndex value it through
+ // range error exception. So, currently we fixed this by checking the length of overAllDataPoints
+ // instead of overallDataPointIndex when the overallDataPointIndex value greater than overAllDataPoints length.
+
+ final int overallDataPointIndex =
+ segmentProperties.currentPoint!.overallDataPointIndex!;
+ final int overAllDataPointsCount =
+ candleSeriesDetails.overAllDataPoints.length;
if (_currentSeriesDetails.candleSeries.enableSolidCandles! &&
segmentProperties.isSolid) {
return (candleSeriesDetails
.overAllDataPoints[
- segmentProperties.currentPoint!.overallDataPointIndex!]!
+ (overAllDataPointsCount - 1 < overallDataPointIndex)
+ ? overAllDataPointsCount - 1
+ : overallDataPointIndex]!
.open <
candleSeriesDetails
.overAllDataPoints[
- segmentProperties.currentPoint!.overallDataPointIndex!]!
+ (overAllDataPointsCount - 1 < overallDataPointIndex)
+ ? overAllDataPointsCount - 1
+ : overallDataPointIndex]!
.close)
? _currentSeriesDetails.candleSeries.bullColor
: _currentSeriesDetails.candleSeries.bearColor;
@@ -132,13 +146,16 @@ class CandleSeriesRenderer extends XyDataSeriesRenderer {
final Color? color =
segmentProperties.currentPoint!.overallDataPointIndex! - 1 >= 0 &&
(candleSeriesDetails
- .overAllDataPoints[segmentProperties
- .currentPoint!.overallDataPointIndex! -
- 1]!
+ .overAllDataPoints[
+ (overAllDataPointsCount - 1 < overallDataPointIndex)
+ ? overAllDataPointsCount - 2
+ : overallDataPointIndex - 1]!
.close >
candleSeriesDetails
- .overAllDataPoints[segmentProperties
- .currentPoint!.overallDataPointIndex!]!
+ .overAllDataPoints[
+ (overAllDataPointsCount - 1 < overallDataPointIndex)
+ ? overAllDataPointsCount - 1
+ : overallDataPointIndex]!
.close)
? _currentSeriesDetails.candleSeries.bearColor
: _currentSeriesDetails.candleSeries.bullColor;
@@ -257,11 +274,13 @@ class CandlePainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
// ignore: unnecessary_null_comparison
final bool isTooltipEnabled = chart.tooltipBehavior != null;
- final bool hasTooltip = isTooltipEnabled &&
- (chart.tooltipBehavior.enable ||
- seriesRendererDetails.series.onPointTap != null ||
+ final bool isPointTapEnabled =
+ seriesRendererDetails.series.onPointTap != null ||
seriesRendererDetails.series.onPointDoubleTap != null ||
- seriesRendererDetails.series.onPointLongPress != null);
+ seriesRendererDetails.series.onPointLongPress != null;
+ final bool isCalculateRegion =
+ (isTooltipEnabled && chart.tooltipBehavior.enable) ||
+ isPointTapEnabled;
final bool hasSeriesElements = seriesRendererDetails.visible! &&
(series.markerSettings.isVisible ||
series.dataLabelSettings.isVisible ||
@@ -269,7 +288,8 @@ class CandlePainter extends CustomPainter {
chart.tooltipBehavior.enable &&
(isTooltipEnabled &&
chart.tooltipBehavior.enable &&
- series.enableTooltip)));
+ series.enableTooltip)) ||
+ isPointTapEnabled);
seriesRendererDetails.sideBySideInfo = calculateSideBySideInfo(
seriesRendererDetails.renderer, stateProperties);
final num? sideBySideMinimumVal =
@@ -287,16 +307,14 @@ class CandlePainter extends CustomPainter {
point.low != null &&
point.open != null &&
point.close != null) {
- withInHighLowRange = withInRange(point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
- withInRange(
- point.low, seriesRendererDetails.yAxisDetails!.visibleRange!);
- withInOpenCloseRange = withInRange(point.open,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
- withInRange(point.close,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInHighLowRange =
+ withInRange(point.high, seriesRendererDetails.yAxisDetails!) &&
+ withInRange(point.low, seriesRendererDetails.yAxisDetails!);
+ withInOpenCloseRange =
+ withInRange(point.open, seriesRendererDetails.yAxisDetails!) &&
+ withInRange(point.close, seriesRendererDetails.yAxisDetails!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
if (withInXRange || (withInHighLowRange && withInOpenCloseRange)) {
if (withInXRange) {
seriesRendererDetails.visibleDataPoints!
@@ -421,7 +439,7 @@ class CandlePainter extends CustomPainter {
(point.markerPoint!.x - point.markerPoint2!.x).abs(),
seriesRendererDetails.series.borderWidth);
}
- if (hasTooltip) {
+ if (isCalculateRegion) {
calculateTooltipRegion(
point, seriesIndex, seriesRendererDetails, stateProperties);
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/column_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/column_painter.dart
index 901a80555..fb437df98 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/column_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/column_painter.dart
@@ -266,13 +266,12 @@ class ColumnChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(point.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/error_bar_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/error_bar_painter.dart
index c9bab55cf..f4cf24df3 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/error_bar_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/error_bar_painter.dart
@@ -167,13 +167,12 @@ class ErrorBarChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(point.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/fastline_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/fastline_painter.dart
index 9dc0fbd6c..7c14a9f7c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/fastline_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/fastline_painter.dart
@@ -214,6 +214,10 @@ class FastLineChartPainter extends CustomPainter {
}
// ignore: unnecessary_null_comparison
final bool hasTooltipBehavior = chart.tooltipBehavior != null;
+ final bool isPointTapEnabled =
+ seriesRendererDetails.series.onPointTap != null ||
+ seriesRendererDetails.series.onPointDoubleTap != null ||
+ seriesRendererDetails.series.onPointLongPress != null;
final bool hasSeriesElements = seriesRendererDetails.visible! &&
(series.markerSettings.isVisible ||
series.dataLabelSettings.isVisible ||
@@ -221,12 +225,11 @@ class FastLineChartPainter extends CustomPainter {
chart.tooltipBehavior.enable &&
(hasTooltipBehavior &&
chart.tooltipBehavior.enable &&
- series.enableTooltip)));
- final bool hasTooltip = hasTooltipBehavior &&
- (chart.tooltipBehavior.enable ||
- seriesRendererDetails.series.onPointTap != null ||
- seriesRendererDetails.series.onPointDoubleTap != null ||
- seriesRendererDetails.series.onPointLongPress != null);
+ series.enableTooltip)) ||
+ isPointTapEnabled);
+ final bool isCalculateRegion =
+ (hasTooltipBehavior && chart.tooltipBehavior.enable) ||
+ isPointTapEnabled;
for (int pointIndex = 0;
pointIndex < seriesRendererDetails.dataPoints.length;
pointIndex++) {
@@ -237,36 +240,36 @@ class FastLineChartPainter extends CustomPainter {
(prevYValue - yVal).abs() >= yTolerance) {
point = currentPoint;
dataPoints.add(currentPoint);
- bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ bool withInXRange = withInRange(
+ currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
bool inRange = withInXRange || withInYRange;
if (!inRange &&
(pointIndex + 1 < seriesRendererDetails.dataPoints.length)) {
final CartesianChartPoint? nextPoint =
seriesRendererDetails.dataPoints[pointIndex + 1];
- withInXRange = withInRange(nextPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ nextPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = nextPoint != null &&
nextPoint.yValue != null &&
- withInRange(nextPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ nextPoint.yValue, seriesRendererDetails.yAxisDetails!);
inRange = withInXRange || withInYRange;
if (!inRange && pointIndex - 1 >= 0) {
final CartesianChartPoint? prevPoint =
seriesRendererDetails.dataPoints[pointIndex - 1];
- withInXRange = withInRange(prevPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ prevPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = prevPoint != null &&
prevPoint.yValue != null &&
- withInRange(prevPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ prevPoint.yValue, seriesRendererDetails.yAxisDetails!);
}
}
if (withInXRange || withInYRange) {
@@ -303,7 +306,7 @@ class FastLineChartPainter extends CustomPainter {
}
}
- if (hasTooltip) {
+ if (isCalculateRegion) {
calculateTooltipRegion(
point, seriesIndex, seriesRendererDetails, stateProperties);
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hilo_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hilo_painter.dart
index 144f3aadd..72c6d6d50 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hilo_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hilo_painter.dart
@@ -225,11 +225,13 @@ class HiloPainter extends CustomPainter {
}
// ignore: unnecessary_null_comparison
final bool isTooltipEnabled = chart.tooltipBehavior != null;
- final bool hasTooltip = isTooltipEnabled &&
- (chart.tooltipBehavior.enable ||
- seriesRendererDetails.series.onPointTap != null ||
+ final bool isPointTapEnabled =
+ seriesRendererDetails.series.onPointTap != null ||
seriesRendererDetails.series.onPointDoubleTap != null ||
- seriesRendererDetails.series.onPointLongPress != null);
+ seriesRendererDetails.series.onPointLongPress != null;
+ final bool isCalculateRegion =
+ (isTooltipEnabled && chart.tooltipBehavior.enable) ||
+ isPointTapEnabled;
final bool hasSeriesElements = seriesRendererDetails.visible! &&
(series.markerSettings.isVisible ||
series.dataLabelSettings.isVisible ||
@@ -237,7 +239,8 @@ class HiloPainter extends CustomPainter {
chart.tooltipBehavior.enable &&
(isTooltipEnabled &&
chart.tooltipBehavior.enable &&
- series.enableTooltip)));
+ series.enableTooltip)) ||
+ isPointTapEnabled);
seriesRendererDetails.sideBySideInfo = calculateSideBySideInfo(
seriesRendererDetails.renderer, stateProperties);
@@ -268,16 +271,14 @@ class HiloPainter extends CustomPainter {
}
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInHighLowRange = point != null &&
point.high != null &&
point.low != null &&
- (withInRange(point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!) ||
- withInRange(point.low,
- seriesRendererDetails.yAxisDetails!.visibleRange!));
+ (withInRange(point.high, seriesRendererDetails.yAxisDetails!) ||
+ withInRange(point.low, seriesRendererDetails.yAxisDetails!));
if (withInXRange || withInHighLowRange) {
if (withInXRange) {
seriesRendererDetails.visibleDataPoints!
@@ -332,7 +333,7 @@ class HiloPainter extends CustomPainter {
(point.markerPoint!.x - point.markerPoint2!.x).abs(),
seriesRendererDetails.series.borderWidth);
}
- if (hasTooltip) {
+ if (isCalculateRegion) {
calculateTooltipRegion(
point, seriesIndex, seriesRendererDetails, stateProperties);
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hiloopenclose_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hiloopenclose_painter.dart
index 98b26c711..b0b29723c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hiloopenclose_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/hiloopenclose_painter.dart
@@ -213,18 +213,21 @@ class HiloOpenClosePainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
// ignore: unnecessary_null_comparison
final bool isTooltipEnabled = chart.tooltipBehavior != null;
- final bool hasTooltip = isTooltipEnabled &&
- (chart.tooltipBehavior.enable ||
- seriesRendererDetails.series.onPointTap != null ||
+ final bool isPointTapEnabled =
+ seriesRendererDetails.series.onPointTap != null ||
seriesRendererDetails.series.onPointDoubleTap != null ||
- seriesRendererDetails.series.onPointLongPress != null);
+ seriesRendererDetails.series.onPointLongPress != null;
+ final bool isCalculateRegion =
+ (isTooltipEnabled && chart.tooltipBehavior.enable) ||
+ isPointTapEnabled;
final bool hasSeriesElements = seriesRendererDetails.visible! &&
(series.dataLabelSettings.isVisible ||
(isTooltipEnabled &&
chart.tooltipBehavior.enable &&
(isTooltipEnabled &&
chart.tooltipBehavior.enable &&
- series.enableTooltip)));
+ series.enableTooltip)) ||
+ isPointTapEnabled);
seriesRendererDetails.sideBySideInfo = calculateSideBySideInfo(
seriesRendererDetails.renderer, stateProperties);
final num? sideBySideMinimumVal =
@@ -234,8 +237,8 @@ class HiloOpenClosePainter extends CustomPainter {
seriesRendererDetails.sideBySideInfo?.maximum;
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
bool withInHighLowRange = false, withInOpenCloseRange = false;
// ignore: unnecessary_null_comparison
if (point != null &&
@@ -243,14 +246,12 @@ class HiloOpenClosePainter extends CustomPainter {
point.low != null &&
point.open != null &&
point.close != null) {
- withInHighLowRange = withInRange(point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
- withInRange(
- point.low, seriesRendererDetails.yAxisDetails!.visibleRange!);
- withInOpenCloseRange = withInRange(point.open,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
- withInRange(point.close,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInHighLowRange =
+ withInRange(point.high, seriesRendererDetails.yAxisDetails!) &&
+ withInRange(point.low, seriesRendererDetails.yAxisDetails!);
+ withInOpenCloseRange =
+ withInRange(point.open, seriesRendererDetails.yAxisDetails!) &&
+ withInRange(point.close, seriesRendererDetails.yAxisDetails!);
if (withInXRange || (withInHighLowRange && withInOpenCloseRange)) {
if (withInXRange) {
@@ -376,7 +377,7 @@ class HiloOpenClosePainter extends CustomPainter {
(point.markerPoint!.x - point.markerPoint2!.x).abs(),
seriesRendererDetails.series.borderWidth);
}
- if (hasTooltip) {
+ if (isCalculateRegion) {
calculateTooltipRegion(
point, seriesIndex, seriesRendererDetails, stateProperties);
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/histogram_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/histogram_painter.dart
index 67ee3c33f..dff55315c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/histogram_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/histogram_painter.dart
@@ -309,13 +309,12 @@ class HistogramChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(point.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(
stateProperties,
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/line_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/line_painter.dart
index a7b99da5e..a29aa58df 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/line_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/line_painter.dart
@@ -221,36 +221,36 @@ class LineChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
currentPoint = dataPoints[pointIndex];
- bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ bool withInXRange = withInRange(
+ currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
bool inRange = withInXRange || withInYRange;
if (!inRange && pointIndex + 1 < dataPoints.length) {
final CartesianChartPoint? nextPoint =
dataPoints[pointIndex + 1];
- withInXRange = withInRange(nextPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ nextPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = nextPoint != null &&
nextPoint.yValue != null &&
- withInRange(nextPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ nextPoint.yValue, seriesRendererDetails.yAxisDetails!);
inRange = withInXRange || withInYRange;
if (!inRange && pointIndex - 1 >= 0) {
final CartesianChartPoint? prevPoint =
dataPoints[pointIndex - 1];
- withInXRange = withInRange(prevPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ prevPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = prevPoint != null &&
prevPoint.yValue != null &&
- withInRange(prevPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ prevPoint.yValue, seriesRendererDetails.yAxisDetails!);
}
}
if (withInXRange || withInYRange) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/range_column_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/range_column_painter.dart
index b24dacc20..60a7ff571 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/range_column_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/range_column_painter.dart
@@ -274,16 +274,14 @@ class RangeColumnChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInHighLowRange = point != null &&
point.high != null &&
- withInRange(point.high,
- seriesRendererDetails.yAxisDetails!.visibleRange!) &&
+ withInRange(point.high, seriesRendererDetails.yAxisDetails!) &&
point.low != null &&
- withInRange(
- point.low, seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.low, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInHighLowRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/scatter_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/scatter_painter.dart
index 63fbc0340..6cbe3afcb 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/scatter_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/scatter_painter.dart
@@ -273,13 +273,13 @@ class ScatterChartPainter extends CustomPainter {
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
final CartesianChartPoint currentPoint =
dataPoints[pointIndex];
- final bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange = withInRange(
+ currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(
stateProperties,
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/spline_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/spline_painter.dart
index 4ca9037ca..a75d22289 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/spline_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/spline_painter.dart
@@ -235,11 +235,11 @@ class SplineChartPainter extends CustomPainter {
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
point = dataPoints[pointIndex];
if (withInRange(seriesRendererDetails.dataPoints[pointIndex].xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!) ||
+ seriesRendererDetails.xAxisDetails!) ||
(pointIndex < dataPoints.length - 1 &&
withInRange(
seriesRendererDetails.dataPoints[pointIndex + 1].xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!))) {
+ seriesRendererDetails.xAxisDetails!))) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
if ((point.isVisible && !point.isGap) && startPoint == null) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_area_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_area_painter.dart
index 12adf3db1..2ce40d7b7 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_area_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_area_painter.dart
@@ -278,7 +278,7 @@ class StackedAreaChartPainter extends CustomPainter {
seriesRendererDetails,
stateProperties,
seriesRendererDetails.seriesAnimation,
- seriesRendererDetails.seriesElementAnimation!,
+ seriesRendererDetails.seriesElementAnimation,
painterKey);
}
@@ -330,7 +330,7 @@ class StackedArea100ChartPainter extends CustomPainter {
seriesRendererDetails,
stateProperties,
seriesRendererDetails.seriesAnimation,
- seriesRendererDetails.seriesElementAnimation!,
+ seriesRendererDetails.seriesElementAnimation,
painterKey);
}
@@ -345,7 +345,7 @@ void stackedAreaPainter(
SeriesRendererDetails seriesRendererDetails,
CartesianStateProperties stateProperties,
Animation? seriesAnimation,
- Animation chartElementAnimation,
+ Animation? chartElementAnimation,
PainterKey painterKey) {
Rect clipRect, axisClipRect;
final int seriesIndex = painterKey.index;
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_bar_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_bar_painter.dart
index 50be2174b..2e26a00d2 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_bar_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_bar_painter.dart
@@ -370,13 +370,12 @@ void _stackedBarPainter(
pointIndex < seriesRendererDetails.dataPoints.length;
pointIndex++) {
point = seriesRendererDetails.dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(
- point.yValue, seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_column_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_column_painter.dart
index c364654a6..3efa87948 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_column_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_column_painter.dart
@@ -365,13 +365,12 @@ void _stackedRectPainter(
pointIndex < seriesRendererDetails.dataPoints.length;
pointIndex++) {
point = seriesRendererDetails.dataPoints[pointIndex];
- final bool withInXRange = withInRange(
- point.xValue, seriesRendererDetails.xAxisDetails!.visibleRange!);
+ final bool withInXRange =
+ withInRange(point.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
final bool withInYRange = point != null &&
point.yValue != null &&
- withInRange(
- point.yValue, seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(point.yValue, seriesRendererDetails.yAxisDetails!);
if (withInXRange || withInYRange) {
seriesRendererDetails.calculateRegionData(stateProperties,
seriesRendererDetails, painterKey.index, point, pointIndex);
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_line_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_line_painter.dart
index c3480aec3..d85ab12d8 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_line_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stacked_line_painter.dart
@@ -179,7 +179,7 @@ class StackedLineChartPainter extends CustomPainter {
seriesRendererDetails,
seriesRendererDetails.seriesAnimation,
stateProperties,
- seriesRendererDetails.seriesElementAnimation!,
+ seriesRendererDetails.seriesElementAnimation,
painterKey);
}
@@ -349,7 +349,7 @@ class StackedLine100ChartPainter extends CustomPainter {
seriesRendererDetails,
seriesRendererDetails.seriesAnimation,
stateProperties,
- seriesRendererDetails.seriesElementAnimation!,
+ seriesRendererDetails.seriesElementAnimation,
painterKey);
}
@@ -364,7 +364,7 @@ void _stackedLinePainter(
SeriesRendererDetails seriesRendererDetails,
Animation? seriesAnimation,
CartesianStateProperties stateProperties,
- Animation chartElementAnimation,
+ Animation? chartElementAnimation,
PainterKey painterKey) {
Rect clipRect;
double animationFactor;
@@ -419,37 +419,35 @@ void _stackedLinePainter(
pointIndex < seriesRendererDetails.dataPoints.length;
pointIndex++) {
currentPoint = seriesRendererDetails.dataPoints[pointIndex];
- bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ bool withInXRange =
+ withInRange(currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
bool inRange = withInXRange || withInYRange;
if (!inRange &&
pointIndex + 1 < seriesRendererDetails.dataPoints.length) {
final CartesianChartPoint? nextPoint =
seriesRendererDetails.dataPoints[pointIndex + 1];
- withInXRange = withInRange(nextPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange =
+ withInRange(nextPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = nextPoint != null &&
nextPoint.yValue != null &&
- withInRange(nextPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(nextPoint.yValue, seriesRendererDetails.yAxisDetails!);
inRange = withInXRange || withInYRange;
if (!inRange && pointIndex - 1 >= 0) {
final CartesianChartPoint? prevPoint =
seriesRendererDetails.dataPoints[pointIndex - 1];
- withInXRange = withInRange(prevPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ prevPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = prevPoint != null &&
prevPoint.yValue != null &&
- withInRange(prevPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ prevPoint.yValue, seriesRendererDetails.yAxisDetails!);
}
}
if (withInXRange || withInYRange) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stepline_painter.dart b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stepline_painter.dart
index d06403b7a..ce9241dac 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stepline_painter.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/series_painter/stepline_painter.dart
@@ -217,36 +217,36 @@ class StepLineChartPainter extends CustomPainter {
seriesRendererDetails.setSeriesProperties(seriesRendererDetails);
for (int pointIndex = 0; pointIndex < dataPoints.length; pointIndex++) {
currentPoint = dataPoints[pointIndex];
- bool withInXRange = withInRange(currentPoint.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ bool withInXRange = withInRange(
+ currentPoint.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
bool withInYRange = currentPoint != null &&
currentPoint.yValue != null &&
- withInRange(currentPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ currentPoint.yValue, seriesRendererDetails.yAxisDetails!);
bool inRange = withInXRange || withInYRange;
if (!inRange && pointIndex + 1 < dataPoints.length) {
final CartesianChartPoint? nextPoint =
dataPoints[pointIndex + 1];
- withInXRange = withInRange(nextPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ nextPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = nextPoint != null &&
nextPoint.yValue != null &&
- withInRange(nextPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ nextPoint.yValue, seriesRendererDetails.yAxisDetails!);
inRange = withInXRange || withInYRange;
if (!inRange && pointIndex - 1 >= 0) {
final CartesianChartPoint? prevPoint =
dataPoints[pointIndex - 1];
- withInXRange = withInRange(prevPoint!.xValue,
- seriesRendererDetails.xAxisDetails!.visibleRange!);
+ withInXRange = withInRange(
+ prevPoint!.xValue, seriesRendererDetails.xAxisDetails!);
// ignore: unnecessary_null_comparison
withInYRange = prevPoint != null &&
prevPoint.yValue != null &&
- withInRange(prevPoint.yValue,
- seriesRendererDetails.yAxisDetails!.visibleRange!);
+ withInRange(
+ prevPoint.yValue, seriesRendererDetails.yAxisDetails!);
}
}
if (withInXRange || withInYRange) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/technical_indicators/technical_indicator.dart b/packages/syncfusion_flutter_charts/lib/src/chart/technical_indicators/technical_indicator.dart
index 1532a8fb8..79da9d794 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/technical_indicators/technical_indicator.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/technical_indicators/technical_indicator.dart
@@ -1028,16 +1028,24 @@ class TechnicalIndicatorsRenderer {
bollingerPoints[j] = _BollingerData(
x: validData[j].xValue,
midBand: smaPoints[i],
- lowBand: lowerBand,
- upBand: upperBand,
+ lowBand: lowerBand.isNaN || lowerBand.isInfinite
+ ? smaPoints[i]
+ : lowerBand,
+ upBand: upperBand.isNaN || upperBand.isInfinite
+ ? smaPoints[i]
+ : upperBand,
visible: true);
}
}
bollingerPoints[i] = _BollingerData(
x: validData[i].xValue,
midBand: smaPoints[i],
- lowBand: lowerBand,
- upBand: upperBand,
+ lowBand: lowerBand.isNaN || lowerBand.isInfinite
+ ? smaPoints[i]
+ : lowerBand,
+ upBand: upperBand.isNaN || upperBand.isInfinite
+ ? smaPoints[i]
+ : upperBand,
visible: true);
} else {
if (i < indicator.period - 1) {
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/user_interaction/trackball.dart b/packages/syncfusion_flutter_charts/lib/src/chart/user_interaction/trackball.dart
index 0719f2ef6..984fffdd7 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/user_interaction/trackball.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/user_interaction/trackball.dart
@@ -427,6 +427,9 @@ class TrackballBehavior {
_stateProperties.trackballBehaviorRenderer);
final List visibleSeriesRenderer =
stateProperties.chartSeries.visibleSeriesRenderers;
+ if (visibleSeriesRenderer.isEmpty) {
+ return;
+ }
final SeriesRendererDetails seriesRendererDetails =
SeriesHelper.getSeriesRendererDetails(visibleSeriesRenderer.firstWhere(
(CartesianSeriesRenderer element) =>
@@ -1295,6 +1298,8 @@ class TrackballRenderingDetails {
for (final ChartPointInfo pointInfo in chartPointInfo) {
xValueList.add(pointInfo.chartDataPoint?.xValue);
}
+ String seriesType;
+ bool isRangeTypeSeries;
if (xValueList.isNotEmpty) {
for (int count = 0; count < xValueList.length; count++) {
if (xValueList[0] != xValueList[count]) {
@@ -1303,15 +1308,19 @@ class TrackballRenderingDetails {
if (pointInfo.xPosition == leastX) {
leastPointInfo.add(pointInfo);
visiblePoints.clear();
+ seriesType = pointInfo.seriesRendererDetails!.seriesType;
+ isRangeTypeSeries = seriesType.contains('range') ||
+ seriesType.contains('hilo') ||
+ seriesType == 'candle';
visiblePoints.add(ClosestPoints(
- closestPointX: !isRangeSeries
+ closestPointX: !isRangeTypeSeries
? pointInfo.xPosition!
- : isBoxSeries
+ : seriesType == 'boxandwhisker'
? pointInfo.maxXPosition!
: pointInfo.highXPosition!,
- closestPointY: isRangeSeries
+ closestPointY: isRangeTypeSeries
? pointInfo.highYPosition!
- : isBoxSeries
+ : seriesType == 'boxandwhisker'
? pointInfo.maxYPosition!
: pointInfo.yPosition!));
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/chart/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/chart/utils/helper.dart
index 3790e0eaf..aff4e977f 100644
--- a/packages/syncfusion_flutter_charts/lib/src/chart/utils/helper.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/chart/utils/helper.dart
@@ -115,9 +115,16 @@ num calculateLogBaseValue(num value, num base) =>
math.log(value) / math.log(base);
/// To check if value is within range.
-bool withInRange(num value, VisibleRange range) =>
-// ignore: unnecessary_null_comparison
- value != null && (value <= range.maximum) && (value >= range.minimum);
+bool withInRange(num value, ChartAxisRendererDetails axisDetails) {
+ final ChartAxis axis = axisDetails.axis;
+ final num visibleMinimum = axis is LogarithmicAxis
+ ? pow(axis.logBase, axisDetails.visibleRange!.minimum)
+ : axisDetails.visibleRange!.minimum;
+ final num visibleMaximum = axis is LogarithmicAxis
+ ? pow(axis.logBase, axisDetails.visibleRange!.maximum)
+ : axisDetails.visibleRange!.maximum;
+ return (value <= visibleMaximum) && (value >= visibleMinimum);
+}
/// To find the proper series color of each point in waterfall chart,
/// which includes intermediate sum, total sum and negative point.
diff --git a/packages/syncfusion_flutter_charts/lib/src/circular_chart/renderer/data_label_renderer.dart b/packages/syncfusion_flutter_charts/lib/src/circular_chart/renderer/data_label_renderer.dart
index 5152cb77f..809b2b0b1 100644
--- a/packages/syncfusion_flutter_charts/lib/src/circular_chart/renderer/data_label_renderer.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/circular_chart/renderer/data_label_renderer.dart
@@ -9,6 +9,7 @@ import '../../chart/common/data_label.dart';
import '../../chart/utils/enum.dart';
import '../../chart/utils/helper.dart';
import '../../common/event_args.dart';
+import '../../common/template/rendering.dart';
import '../../common/utils/helper.dart';
import '../../pyramid_chart/utils/helper.dart';
import '../base/circular_base.dart';
@@ -264,7 +265,10 @@ void _changeLabelAngle(ChartPoint currentPoint, num newAngle,
const String defaultConnectorLineLength = '10%';
final DataLabelSettings dataLabel =
seriesRenderer.dataLabelSettingsRenderer.dataLabelSettings;
- final Size textSize = measureText(currentPoint.text!, dataLabel.textStyle);
+ // Builder check for change the angle based on the template size.
+ final Size textSize = dataLabel.builder != null
+ ? currentPoint.dataLabelSize
+ : measureText(currentPoint.text!, dataLabel.textStyle);
final Path angleChangedConnectorPath = Path();
final num connectorLength = percentToValue(
dataLabel.connectorLineSettings.length ?? defaultConnectorLineLength,
@@ -414,99 +418,114 @@ void renderCircularDataLabel(
DataLabelRenderArgs dataLabelArgs;
TextStyle dataLabelStyle;
final List renderDataLabelRegions = [];
- Size textSize;
+ Size? textSize;
for (int pointIndex = 0;
pointIndex < seriesRenderer.renderPoints!.length;
pointIndex++) {
point = seriesRenderer.renderPoints![pointIndex];
- if (point.isVisible && (point.y != 0 || dataLabel.showZeroValue)) {
- label = point.text;
- label = seriesRenderer.renderer.getLabelContent(
- seriesRenderer, point, pointIndex, seriesIndex, label!);
- dataLabelStyle = dataLabel.textStyle;
- dataLabelSettingsRenderer.color =
- seriesRenderer.series.dataLabelSettings.color;
- if (chart.onDataLabelRender != null &&
- !seriesRenderer.renderPoints![pointIndex].labelRenderEvent) {
- dataLabelArgs = DataLabelRenderArgs(seriesRenderer,
- seriesRenderer.renderPoints, pointIndex, pointIndex);
- dataLabelArgs.text = label;
- dataLabelArgs.textStyle = dataLabelStyle;
- dataLabelArgs.color = dataLabelSettingsRenderer.color;
- chart.onDataLabelRender!(dataLabelArgs);
- label = point.text = dataLabelArgs.text;
- dataLabelStyle = dataLabelArgs.textStyle;
- pointIndex = dataLabelArgs.pointIndex!;
- dataLabelSettingsRenderer.color = dataLabelArgs.color;
- seriesRenderer.dataPoints[pointIndex].labelRenderEvent = true;
- }
- textSize = measureText(label, dataLabelStyle);
-
- /// condition check for labels after event.
- if (label != '') {
- if (seriesRenderer.seriesType == 'radialbar') {
- dataLabelStyle = chart.onDataLabelRender == null
- ? seriesRenderer.renderer.getDataLabelStyle(
- seriesRenderer,
- point,
- pointIndex,
- seriesIndex,
- dataLabelStyle,
- stateProperties.chartState)
- : dataLabelStyle;
- labelLocation = degreeToPoint(point.startAngle!,
- (point.innerRadius! + point.outerRadius!) / 2, point.center!);
- labelLocation = Offset(
- (labelLocation.dx - textSize.width - 5) +
- (angle == 0 ? 0 : textSize.width / 2),
- (labelLocation.dy - textSize.height / 2) +
- (angle == 0 ? 0 : textSize.height / 2));
- point.labelRect = Rect.fromLTWH(
- labelLocation.dx - labelPadding,
- labelLocation.dy - labelPadding,
- textSize.width + (2 * labelPadding),
- textSize.height + (2 * labelPadding));
- drawLabel(
- point.labelRect,
- labelLocation,
- label,
- null,
- canvas,
- seriesRenderer,
- point,
- pointIndex,
- seriesIndex,
- chart,
- dataLabelStyle,
- renderDataLabelRegions,
- animateOpacity);
+ if (dataLabel.builder == null ||
+ dataLabel.labelIntersectAction != LabelIntersectAction.shift) {
+ if (point.isVisible && (point.y != 0 || dataLabel.showZeroValue)) {
+ label = point.text;
+ label = seriesRenderer.renderer.getLabelContent(
+ seriesRenderer, point, pointIndex, seriesIndex, label!);
+ dataLabelStyle = dataLabel.textStyle;
+ dataLabelSettingsRenderer.color =
+ seriesRenderer.series.dataLabelSettings.color;
+ if (chart.onDataLabelRender != null &&
+ !seriesRenderer.renderPoints![pointIndex].labelRenderEvent) {
+ dataLabelArgs = DataLabelRenderArgs(seriesRenderer,
+ seriesRenderer.renderPoints, pointIndex, pointIndex);
+ dataLabelArgs.text = label;
+ dataLabelArgs.textStyle = dataLabelStyle;
+ dataLabelArgs.color = dataLabelSettingsRenderer.color;
+ chart.onDataLabelRender!(dataLabelArgs);
+ label = point.text = dataLabelArgs.text;
+ dataLabelStyle = dataLabelArgs.textStyle;
+ pointIndex = dataLabelArgs.pointIndex!;
+ dataLabelSettingsRenderer.color = dataLabelArgs.color;
+ seriesRenderer.dataPoints[pointIndex].labelRenderEvent = true;
+ }
+ if (seriesRenderer.series.dataLabelSettings.builder != null) {
+ final int pointIndex = seriesRenderer
+ .stateProperties.renderingDetails.templates
+ .indexWhere((ChartTemplateInfo templateInfo) =>
+ templateInfo.pointIndex == point.index);
+ // Checks template for avoid the hidden data point and calculate the label location based on template size.
+ if (pointIndex != -1) {
+ textSize = seriesRenderer.stateProperties.renderingDetails
+ .dataLabelTemplateRegions[pointIndex].size;
+ }
} else {
- setLabelPosition(
- dataLabel,
- point,
- textSize,
- stateProperties,
- canvas,
- renderDataLabelRegions,
- pointIndex,
- label,
- seriesRenderer,
- animateOpacity,
- dataLabelStyle,
- seriesIndex);
+ textSize = measureText(label, dataLabelStyle);
}
+
+ /// condition check for labels after event.
+ if (label != '') {
+ if (seriesRenderer.seriesType == 'radialbar') {
+ dataLabelStyle = chart.onDataLabelRender == null
+ ? seriesRenderer.renderer.getDataLabelStyle(
+ seriesRenderer,
+ point,
+ pointIndex,
+ seriesIndex,
+ dataLabelStyle,
+ stateProperties.chartState)
+ : dataLabelStyle;
+ labelLocation = degreeToPoint(point.startAngle!,
+ (point.innerRadius! + point.outerRadius!) / 2, point.center!);
+ labelLocation = Offset(
+ (labelLocation.dx - textSize!.width - 5) +
+ (angle == 0 ? 0 : textSize.width / 2),
+ (labelLocation.dy - textSize.height / 2) +
+ (angle == 0 ? 0 : textSize.height / 2));
+ point.labelRect = Rect.fromLTWH(
+ labelLocation.dx - labelPadding,
+ labelLocation.dy - labelPadding,
+ textSize.width + (2 * labelPadding),
+ textSize.height + (2 * labelPadding));
+ drawLabel(
+ point.labelRect,
+ labelLocation,
+ label,
+ null,
+ canvas,
+ seriesRenderer,
+ point,
+ pointIndex,
+ seriesIndex,
+ chart,
+ dataLabelStyle,
+ renderDataLabelRegions,
+ animateOpacity);
+ } else {
+ setLabelPosition(
+ dataLabel,
+ point,
+ textSize!,
+ stateProperties,
+ canvas,
+ renderDataLabelRegions,
+ pointIndex,
+ label,
+ seriesRenderer,
+ animateOpacity,
+ dataLabelStyle,
+ seriesIndex);
+ }
+ }
+ dataLabelStyle = chart.onDataLabelRender == null
+ ? seriesRenderer.renderer.getDataLabelStyle(
+ seriesRenderer,
+ point,
+ pointIndex,
+ seriesIndex,
+ dataLabelStyle,
+ stateProperties.chartState)
+ : dataLabelStyle;
+ } else {
+ point.labelRect = Rect.zero;
}
- dataLabelStyle = chart.onDataLabelRender == null
- ? seriesRenderer.renderer.getDataLabelStyle(
- seriesRenderer,
- point,
- pointIndex,
- seriesIndex,
- dataLabelStyle,
- stateProperties.chartState)
- : dataLabelStyle;
- } else {
- point.labelRect = Rect.zero;
}
}
if (seriesRenderer.dataLabelSettingsRenderer.dataLabelSettings
@@ -514,33 +533,35 @@ void renderCircularDataLabel(
LabelIntersectAction.shift &&
seriesRenderer.seriesType != 'radialbar') {
const int labelPadding = 2;
- leftPoints = >[];
- rightPoints = >[];
- for (int i = 0; i < seriesRenderer.renderPoints!.length; i++) {
- if (seriesRenderer.renderPoints![i].isVisible) {
- PointHelper.setNewAngle(seriesRenderer.renderPoints![i],
- seriesRenderer.renderPoints![i].midAngle);
- if (seriesRenderer.renderPoints![i].dataLabelPosition ==
- Position.left &&
- seriesRenderer.renderPoints![i].renderPosition ==
- ChartDataLabelPosition.outside) {
- leftPoints.add(seriesRenderer.renderPoints![i]);
- } else if (seriesRenderer.renderPoints![i].dataLabelPosition ==
- Position.right &&
- seriesRenderer.renderPoints![i].renderPosition ==
- ChartDataLabelPosition.outside) {
- rightPoints.add(seriesRenderer.renderPoints![i]);
+ if (dataLabel.builder == null) {
+ leftPoints = >[];
+ rightPoints = >[];
+ for (int i = 0; i < seriesRenderer.renderPoints!.length; i++) {
+ if (seriesRenderer.renderPoints![i].isVisible) {
+ PointHelper.setNewAngle(seriesRenderer.renderPoints![i],
+ seriesRenderer.renderPoints![i].midAngle);
+ if (seriesRenderer.renderPoints![i].dataLabelPosition ==
+ Position.left &&
+ seriesRenderer.renderPoints![i].renderPosition ==
+ ChartDataLabelPosition.outside) {
+ leftPoints.add(seriesRenderer.renderPoints![i]);
+ } else if (seriesRenderer.renderPoints![i].dataLabelPosition ==
+ Position.right &&
+ seriesRenderer.renderPoints![i].renderPosition ==
+ ChartDataLabelPosition.outside) {
+ rightPoints.add(seriesRenderer.renderPoints![i]);
+ }
}
}
- }
- leftPoints.sort((ChartPoint a, ChartPoint b) =>
- PointHelper.getNewAngle(a)!.compareTo(PointHelper.getNewAngle(b)!));
- if (leftPoints.isNotEmpty) {
- _arrangeLeftSidePoints(seriesRenderer);
- }
- isIncreaseAngle = false;
- if (rightPoints.isNotEmpty) {
- _arrangeRightSidePoints(seriesRenderer);
+ leftPoints.sort((ChartPoint a, ChartPoint b) =>
+ PointHelper.getNewAngle(a)!.compareTo(PointHelper.getNewAngle(b)!));
+ if (leftPoints.isNotEmpty) {
+ _arrangeLeftSidePoints(seriesRenderer);
+ }
+ isIncreaseAngle = false;
+ if (rightPoints.isNotEmpty) {
+ _arrangeRightSidePoints(seriesRenderer);
+ }
}
for (int pointIndex = 0;
pointIndex < seriesRenderer.renderPoints!.length;
@@ -552,49 +573,52 @@ void renderCircularDataLabel(
seriesRenderer.series.dataLabelSettings.margin;
final Rect rect = point.labelRect;
TextStyle dataLabelStyle = dataLabel.textStyle;
- dataLabelStyle = TextStyle(
- color: (chart.onDataLabelRender != null && dataLabelSettingsRenderer.color != null)
- ? getSaturationColor(
- dataLabelSettingsRenderer.color ?? point.fill)
- : ((dataLabelStyle.color ?? dataLabel.textStyle.color) ??
- getSaturationColor(
- point.renderPosition == ChartDataLabelPosition.outside
- ? findthemecolor(stateProperties, point, dataLabel)
- : dataLabelSettingsRenderer.color ?? point.fill)),
- fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
- fontFamily:
- dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
- fontStyle:
- dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
- fontWeight:
- dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
- inherit: dataLabelStyle.inherit,
- backgroundColor: dataLabelStyle.backgroundColor ??
- dataLabel.textStyle.backgroundColor,
- letterSpacing: dataLabelStyle.letterSpacing ??
- dataLabel.textStyle.letterSpacing,
- wordSpacing:
- dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
- textBaseline:
- dataLabelStyle.textBaseline ?? dataLabel.textStyle.textBaseline,
- height: dataLabelStyle.height ?? dataLabel.textStyle.height,
- locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
- foreground:
- dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
- background:
- dataLabelStyle.background ?? dataLabel.textStyle.background,
- shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
- fontFeatures:
- dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
- decoration:
- dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
- decorationColor: dataLabelStyle.decorationColor ??
- dataLabel.textStyle.decorationColor,
- decorationStyle: dataLabelStyle.decorationStyle ?? dataLabel.textStyle.decorationStyle,
- decorationThickness: dataLabelStyle.decorationThickness ?? dataLabel.textStyle.decorationThickness,
- debugLabel: dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
- fontFamilyFallback: dataLabelStyle.fontFamilyFallback ?? dataLabel.textStyle.fontFamilyFallback);
- textSize = measureText(label!, dataLabelStyle);
+ if (dataLabel.builder == null) {
+ dataLabelStyle = TextStyle(
+ color: (chart.onDataLabelRender != null &&
+ dataLabelSettingsRenderer.color != null)
+ ? getSaturationColor(
+ dataLabelSettingsRenderer.color ?? point.fill)
+ : ((dataLabelStyle.color ?? dataLabel.textStyle.color) ??
+ getSaturationColor(point.renderPosition ==
+ ChartDataLabelPosition.outside
+ ? findthemecolor(stateProperties, point, dataLabel)
+ : dataLabelSettingsRenderer.color ?? point.fill)),
+ fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
+ fontFamily:
+ dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
+ fontStyle:
+ dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
+ fontWeight:
+ dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
+ inherit: dataLabelStyle.inherit,
+ backgroundColor: dataLabelStyle.backgroundColor ??
+ dataLabel.textStyle.backgroundColor,
+ letterSpacing: dataLabelStyle.letterSpacing ??
+ dataLabel.textStyle.letterSpacing,
+ wordSpacing:
+ dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
+ textBaseline: dataLabelStyle.textBaseline ??
+ dataLabel.textStyle.textBaseline,
+ height: dataLabelStyle.height ?? dataLabel.textStyle.height,
+ locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
+ foreground:
+ dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
+ background:
+ dataLabelStyle.background ?? dataLabel.textStyle.background,
+ shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
+ fontFeatures:
+ dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
+ decoration: dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
+ decorationColor: dataLabelStyle.decorationColor ?? dataLabel.textStyle.decorationColor,
+ decorationStyle: dataLabelStyle.decorationStyle ?? dataLabel.textStyle.decorationStyle,
+ decorationThickness: dataLabelStyle.decorationThickness ?? dataLabel.textStyle.decorationThickness,
+ debugLabel: dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
+ fontFamilyFallback: dataLabelStyle.fontFamilyFallback ?? dataLabel.textStyle.fontFamilyFallback);
+ }
+ textSize = seriesRenderer.series.dataLabelSettings.builder != null
+ ? point.dataLabelSize
+ : measureText(label!, dataLabelStyle);
labelLocation = Offset(
rect.left +
(point.renderPosition == ChartDataLabelPosition.inside
@@ -847,50 +871,53 @@ void setLabelPosition(
(dataLabel.labelIntersectAction == LabelIntersectAction.none &&
dataLabel.overflowMode == OverflowMode.none)) {
point.renderPosition = ChartDataLabelPosition.inside;
- dataLabelStyle = TextStyle(
- color: (chart.onDataLabelRender != null &&
- dataLabelSettingsRenderer.color != null)
- ? getSaturationColor(
- dataLabelSettingsRenderer.color ?? point.fill)
- : ((dataLabelStyle.color ?? dataLabel.textStyle.color) ??
- getSaturationColor(
- dataLabelSettingsRenderer.color ?? point.fill)),
- fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
- fontFamily:
- dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
- fontStyle: dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
- fontWeight:
- dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
- inherit: dataLabelStyle.inherit,
- backgroundColor: dataLabelStyle.backgroundColor ??
- dataLabel.textStyle.backgroundColor,
- letterSpacing:
- dataLabelStyle.letterSpacing ?? dataLabel.textStyle.letterSpacing,
- wordSpacing:
- dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
- textBaseline:
- dataLabelStyle.textBaseline ?? dataLabel.textStyle.textBaseline,
- height: dataLabelStyle.height ?? dataLabel.textStyle.height,
- locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
- foreground:
- dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
- background:
- dataLabelStyle.background ?? dataLabel.textStyle.background,
- shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
- fontFeatures:
- dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
- decoration:
- dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
- decorationColor: dataLabelStyle.decorationColor ??
- dataLabel.textStyle.decorationColor,
- decorationStyle: dataLabelStyle.decorationStyle ??
- dataLabel.textStyle.decorationStyle,
- decorationThickness: dataLabelStyle.decorationThickness ??
- dataLabel.textStyle.decorationThickness,
- debugLabel:
- dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
- fontFamilyFallback: dataLabelStyle.fontFamilyFallback ??
- dataLabel.textStyle.fontFamilyFallback);
+ if (dataLabel.builder == null) {
+ dataLabelStyle = TextStyle(
+ color: (chart.onDataLabelRender != null &&
+ dataLabelSettingsRenderer.color != null)
+ ? getSaturationColor(
+ dataLabelSettingsRenderer.color ?? point.fill)
+ : ((dataLabelStyle.color ?? dataLabel.textStyle.color) ??
+ getSaturationColor(
+ dataLabelSettingsRenderer.color ?? point.fill)),
+ fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
+ fontFamily:
+ dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
+ fontStyle:
+ dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
+ fontWeight:
+ dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
+ inherit: dataLabelStyle.inherit,
+ backgroundColor: dataLabelStyle.backgroundColor ??
+ dataLabel.textStyle.backgroundColor,
+ letterSpacing: dataLabelStyle.letterSpacing ??
+ dataLabel.textStyle.letterSpacing,
+ wordSpacing:
+ dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
+ textBaseline:
+ dataLabelStyle.textBaseline ?? dataLabel.textStyle.textBaseline,
+ height: dataLabelStyle.height ?? dataLabel.textStyle.height,
+ locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
+ foreground:
+ dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
+ background:
+ dataLabelStyle.background ?? dataLabel.textStyle.background,
+ shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
+ fontFeatures:
+ dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
+ decoration:
+ dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
+ decorationColor: dataLabelStyle.decorationColor ??
+ dataLabel.textStyle.decorationColor,
+ decorationStyle: dataLabelStyle.decorationStyle ??
+ dataLabel.textStyle.decorationStyle,
+ decorationThickness: dataLabelStyle.decorationThickness ??
+ dataLabel.textStyle.decorationThickness,
+ debugLabel:
+ dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
+ fontFamilyFallback: dataLabelStyle.fontFamilyFallback ??
+ dataLabel.textStyle.fontFamilyFallback);
+ }
if (!isDataLabelCollide &&
(dataLabel.labelIntersectAction == LabelIntersectAction.shift &&
dataLabel.overflowMode != OverflowMode.hide)) {
@@ -943,40 +970,48 @@ void setLabelPosition(
}
} else {
point.renderPosition = ChartDataLabelPosition.outside;
- dataLabelStyle = TextStyle(
- color: (dataLabelStyle.color ?? dataLabel.textStyle.color) ??
- getSaturationColor(
- findthemecolor(stateProperties, point, dataLabel)),
- fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
- fontFamily: dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
- fontStyle: dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
- fontWeight: dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
- inherit: dataLabelStyle.inherit,
- backgroundColor: dataLabelStyle.backgroundColor ??
- dataLabel.textStyle.backgroundColor,
- letterSpacing:
- dataLabelStyle.letterSpacing ?? dataLabel.textStyle.letterSpacing,
- wordSpacing:
- dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
- textBaseline:
- dataLabelStyle.textBaseline ?? dataLabel.textStyle.textBaseline,
- height: dataLabelStyle.height ?? dataLabel.textStyle.height,
- locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
- foreground: dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
- background: dataLabelStyle.background ?? dataLabel.textStyle.background,
- shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
- fontFeatures:
- dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
- decoration: dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
- decorationColor: dataLabelStyle.decorationColor ??
- dataLabel.textStyle.decorationColor,
- decorationStyle: dataLabelStyle.decorationStyle ??
- dataLabel.textStyle.decorationStyle,
- decorationThickness: dataLabelStyle.decorationThickness ??
- dataLabel.textStyle.decorationThickness,
- debugLabel: dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
- fontFamilyFallback: dataLabelStyle.fontFamilyFallback ??
- dataLabel.textStyle.fontFamilyFallback);
+ if (dataLabel.builder == null) {
+ dataLabelStyle = TextStyle(
+ color: (dataLabelStyle.color ?? dataLabel.textStyle.color) ??
+ getSaturationColor(
+ findthemecolor(stateProperties, point, dataLabel)),
+ fontSize: dataLabelStyle.fontSize ?? dataLabel.textStyle.fontSize,
+ fontFamily:
+ dataLabelStyle.fontFamily ?? dataLabel.textStyle.fontFamily,
+ fontStyle: dataLabelStyle.fontStyle ?? dataLabel.textStyle.fontStyle,
+ fontWeight:
+ dataLabelStyle.fontWeight ?? dataLabel.textStyle.fontWeight,
+ inherit: dataLabelStyle.inherit,
+ backgroundColor: dataLabelStyle.backgroundColor ??
+ dataLabel.textStyle.backgroundColor,
+ letterSpacing:
+ dataLabelStyle.letterSpacing ?? dataLabel.textStyle.letterSpacing,
+ wordSpacing:
+ dataLabelStyle.wordSpacing ?? dataLabel.textStyle.wordSpacing,
+ textBaseline:
+ dataLabelStyle.textBaseline ?? dataLabel.textStyle.textBaseline,
+ height: dataLabelStyle.height ?? dataLabel.textStyle.height,
+ locale: dataLabelStyle.locale ?? dataLabel.textStyle.locale,
+ foreground:
+ dataLabelStyle.foreground ?? dataLabel.textStyle.foreground,
+ background:
+ dataLabelStyle.background ?? dataLabel.textStyle.background,
+ shadows: dataLabelStyle.shadows ?? dataLabel.textStyle.shadows,
+ fontFeatures:
+ dataLabelStyle.fontFeatures ?? dataLabel.textStyle.fontFeatures,
+ decoration:
+ dataLabelStyle.decoration ?? dataLabel.textStyle.decoration,
+ decorationColor: dataLabelStyle.decorationColor ??
+ dataLabel.textStyle.decorationColor,
+ decorationStyle: dataLabelStyle.decorationStyle ??
+ dataLabel.textStyle.decorationStyle,
+ decorationThickness: dataLabelStyle.decorationThickness ??
+ dataLabel.textStyle.decorationThickness,
+ debugLabel:
+ dataLabelStyle.debugLabel ?? dataLabel.textStyle.debugLabel,
+ fontFamilyFallback: dataLabelStyle.fontFamilyFallback ??
+ dataLabel.textStyle.fontFamilyFallback);
+ }
renderOutsideDataLabel(
canvas,
label,
@@ -1023,8 +1058,28 @@ void renderOutsideDataLabel(
if (connector.type == ConnectorType.line) {
connectorPath.lineTo(endPoint.dx, endPoint.dy);
}
- rect = getDataLabelRect(point.dataLabelPosition, connector.type, margin,
- connectorPath, endPoint, textSize);
+ if (seriesRenderer.series.dataLabelSettings.builder != null) {
+ final int pointIndex = seriesRenderer
+ .stateProperties.renderingDetails.templates
+ .indexWhere((ChartTemplateInfo templateInfo) =>
+ templateInfo.pointIndex == point.index);
+ // Checks template for avoid the hidden data point and calculate the label location based on template size.
+ if (pointIndex != -1) {
+ textSize = seriesRenderer.stateProperties.renderingDetails
+ .dataLabelTemplateRegions[pointIndex].size;
+ }
+ }
+ rect = getDataLabelRect(
+ point.dataLabelPosition,
+ connector.type,
+ margin,
+ connectorPath,
+ endPoint,
+ textSize,
+ // To avoid the extra padding added to the exact template size.
+ seriesRenderer.series.dataLabelSettings.builder != null
+ ? seriesRenderer.series.dataLabelSettings
+ : null);
point.labelRect = rect!;
labelLocation = Offset(rect.left + margin.left,
rect.top + rect.height / 2 - textSize.height / 2);
@@ -1075,8 +1130,10 @@ void renderOutsideDataLabel(
} else {
if (seriesRenderer.series.dataLabelSettings.labelIntersectAction !=
LabelIntersectAction.shift) {
- _drawConnectorLine(labelLocation, connectorPath, canvas, seriesRenderer,
- point, animateOpacity, seriesRenderer.series.dataLabelSettings);
+ if (textSize != Size.zero) {
+ _drawConnectorLine(labelLocation, connectorPath, canvas, seriesRenderer,
+ point, animateOpacity, seriesRenderer.series.dataLabelSettings);
+ }
}
}
}
@@ -1375,29 +1432,151 @@ void _drawConnectorLine(
if (dataLabel.builder != null) {
final List datalabelTemplate = seriesRenderer
.stateProperties.renderingDetails.dataLabelTemplateRegions;
- final Offset dataLabelLocation = seriesRenderer
- .stateProperties.renderingDetails.templates[point.index].location;
- for (int i = 0; i < datalabelTemplate.length; i++) {
- if (datalabelTemplate[i].contains(location) ||
- datalabelTemplate[i].contains(dataLabelLocation)) {
- canvas.drawPath(
- connectorPath,
- Paint()
- ..color = line.width <= 0
- ? Colors.transparent
- : line.color ?? point.fill.withOpacity(animateOpacity)
- ..strokeWidth = line.width
- ..style = PaintingStyle.stroke);
+ if (isTemplateWithinBounds(
+ seriesRenderer.stateProperties.renderingDetails.chartAreaRect,
+ point.labelRect) &&
+ // Decide to render or ignore the empty point label connected line.
+ (point.y != 0 || dataLabel.showZeroValue)) {
+ final List templates =
+ seriesRenderer.stateProperties.renderingDetails.templates;
+ if (seriesRenderer.dataLabelSettingsRenderer.dataLabelSettings
+ .labelIntersectAction ==
+ LabelIntersectAction.hide) {
+ for (int i = 0; i < templates.length; i++) {
+ // Here we have used the templates due to iterating the points leads to non initialized error.
+ // When the point get hidden by the legend toggle then the information of the point is not stored.
+ if (templates[i].pointIndex == point.index &&
+ datalabelTemplate[i] != Rect.zero) {
+ _drawConnectedPath(
+ canvas, connectorPath, line, point, animateOpacity);
+ }
+ }
+ } else {
+ // This is for the shift and none interaction type connected line.
+ _drawConnectedPath(canvas, connectorPath, line, point, animateOpacity);
}
}
} else {
- canvas.drawPath(
- connectorPath,
- Paint()
- ..color = line.width <= 0
- ? Colors.transparent
- : line.color ?? point.fill.withOpacity(animateOpacity)
- ..strokeWidth = line.width
- ..style = PaintingStyle.stroke);
+ _drawConnectedPath(canvas, connectorPath, line, point, animateOpacity);
}
}
+
+/// To shift the data label template in the circular chart.
+void shiftCircularDataLabelTemplate(
+ CircularSeriesRendererExtension seriesRenderer,
+ CircularStateProperties stateProperties,
+ List rectSize) {
+ leftPoints = >[];
+ rightPoints = >[];
+ final List renderDataLabelRegions = [];
+ const int labelPadding = 2;
+ final List templates =
+ seriesRenderer.stateProperties.renderingDetails.templates;
+ for (int i = 0; i < templates.length; i++) {
+ final ChartPoint point =
+ seriesRenderer.renderPoints![templates[i].pointIndex!];
+ if (PointHelper.getNewAngle(point) == null &&
+ point.isVisible &&
+ templates[i].templateType == 'DataLabel') {
+ // For the data label position is inside.
+ if (seriesRenderer.series.dataLabelSettings.labelPosition ==
+ ChartDataLabelPosition.inside) {
+ Offset labelLocation = degreeToPoint(point.midAngle!,
+ (point.innerRadius! + point.outerRadius!) / 2, point.center!);
+ labelLocation = Offset(labelLocation.dx - (rectSize[i].width / 2),
+ labelLocation.dy - (rectSize[i].height / 2));
+ final Rect rect = Rect.fromLTWH(
+ labelLocation.dx - labelPadding,
+ labelLocation.dy - labelPadding,
+ rectSize[i].width + (2 * labelPadding),
+ rectSize[i].height + (2 * labelPadding));
+ // If collide with label when the position is inside calculate the outside rect value of that perticular label.
+ if (findingCollision(rect, renderDataLabelRegions)) {
+ _renderOutsideDataLabelTemplate(
+ point, seriesRenderer, rectSize[i].size, renderDataLabelRegions);
+ } else {
+ point.renderPosition = ChartDataLabelPosition.inside;
+ point.labelRect = rect;
+ // Stored the region of template rect to compare with next label.
+ renderDataLabelRegions.add(rect);
+ }
+ } else if (seriesRenderer.series.dataLabelSettings.labelPosition ==
+ ChartDataLabelPosition.outside) {
+ _renderOutsideDataLabelTemplate(
+ point, seriesRenderer, rectSize[i].size, renderDataLabelRegions);
+ }
+ }
+ }
+ for (int i = 0; i < seriesRenderer.renderPoints!.length; i++) {
+ if (seriesRenderer.renderPoints![i].isVisible) {
+ PointHelper.setNewAngle(seriesRenderer.renderPoints![i],
+ seriesRenderer.renderPoints![i].midAngle);
+ if (seriesRenderer.renderPoints![i].dataLabelPosition == Position.left &&
+ seriesRenderer.renderPoints![i].renderPosition ==
+ ChartDataLabelPosition.outside) {
+ leftPoints.add(seriesRenderer.renderPoints![i]);
+ } else if (seriesRenderer.renderPoints![i].dataLabelPosition ==
+ Position.right &&
+ seriesRenderer.renderPoints![i].renderPosition ==
+ ChartDataLabelPosition.outside) {
+ rightPoints.add(seriesRenderer.renderPoints![i]);
+ }
+ }
+ }
+ leftPoints.sort((ChartPoint a, ChartPoint b) =>
+ PointHelper.getNewAngle(a)!.compareTo(PointHelper.getNewAngle(b)!));
+ isIncreaseAngle = false;
+ if (leftPoints.isNotEmpty) {
+ _arrangeLeftSidePoints(seriesRenderer);
+ }
+ isIncreaseAngle = false;
+ if (rightPoints.isNotEmpty) {
+ _arrangeRightSidePoints(seriesRenderer);
+ }
+}
+
+// Calculate the data label rectangle value when the data label template
+// position is outside and it consider the outer radius.
+void _renderOutsideDataLabelTemplate(
+ ChartPoint point,
+ CircularSeriesRendererExtension seriesRenderer,
+ Size templateSize,
+ List renderDataLabelRegion) {
+ point.renderPosition = ChartDataLabelPosition.outside;
+ const String defaultConnectorLineLength = '10%';
+ final EdgeInsets margin = seriesRenderer.series.dataLabelSettings.margin;
+ final ConnectorLineSettings connector =
+ seriesRenderer.series.dataLabelSettings.connectorLineSettings;
+ final Path connectorPath = Path();
+ final num connectorLength = percentToValue(
+ connector.length ?? defaultConnectorLineLength, point.outerRadius!)!;
+ final Offset startPoint =
+ degreeToPoint(point.midAngle!, point.outerRadius!, point.center!);
+ final Offset endPoint = degreeToPoint(
+ point.midAngle!, point.outerRadius! + connectorLength, point.center!);
+ connectorPath.moveTo(startPoint.dx, startPoint.dy);
+ if (connector.type == ConnectorType.line) {
+ connectorPath.lineTo(endPoint.dx, endPoint.dy);
+ }
+ point.dataLabelSize = templateSize;
+ final Rect rect = getDataLabelRect(point.dataLabelPosition, connector.type,
+ margin, connectorPath, endPoint, templateSize)!;
+ point.labelRect = rect;
+ renderDataLabelRegion.add(rect);
+}
+
+void _drawConnectedPath(
+ Canvas canvas,
+ Path connectorPath,
+ ConnectorLineSettings line,
+ ChartPoint point,
+ double animateOpacity) {
+ canvas.drawPath(
+ connectorPath,
+ Paint()
+ ..color = line.width <= 0
+ ? Colors.transparent
+ : line.color ?? point.fill.withOpacity(animateOpacity)
+ ..strokeWidth = line.width
+ ..style = PaintingStyle.stroke);
+}
diff --git a/packages/syncfusion_flutter_charts/lib/src/circular_chart/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/circular_chart/utils/helper.dart
index 7a2bd55a1..de2168fce 100644
--- a/packages/syncfusion_flutter_charts/lib/src/circular_chart/utils/helper.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/circular_chart/utils/helper.dart
@@ -100,22 +100,14 @@ Path getRoundedCornerArcPath(
ChartPoint point) {
final Path path = Path();
- Offset midPoint;
- num midStartAngle, midEndAngle;
if (cornerStyle == CornerStyle.startCurve ||
cornerStyle == CornerStyle.bothCurve) {
- midPoint =
- degreeToPoint(startAngle, (innerRadius + outerRadius) / 2, center!);
+ final Offset startPoint = degreeToPoint(startAngle, innerRadius, center!);
+ final Offset endPoint = degreeToPoint(startAngle, outerRadius, center);
- midStartAngle = degreesToRadians(180);
-
- midEndAngle = midStartAngle + degreesToRadians(180);
-
- path.addArc(
- Rect.fromCircle(
- center: midPoint, radius: (innerRadius - outerRadius).abs() / 2),
- midStartAngle.toDouble(),
- midEndAngle.toDouble());
+ path.moveTo(startPoint.dx, startPoint.dy);
+ path.arcToPoint(endPoint,
+ radius: Radius.circular((innerRadius - outerRadius).abs() / 2));
}
path.addArc(
@@ -125,18 +117,9 @@ Path getRoundedCornerArcPath(
if (cornerStyle == CornerStyle.endCurve ||
cornerStyle == CornerStyle.bothCurve) {
- midPoint = degreeToPoint(endAngle, (innerRadius + outerRadius) / 2, center);
-
- midStartAngle = degreesToRadians(endAngle / 2);
-
- midEndAngle = midStartAngle + degreesToRadians(180);
-
- path.arcTo(
- Rect.fromCircle(
- center: midPoint, radius: (innerRadius - outerRadius).abs() / 2),
- midStartAngle.toDouble(),
- midEndAngle.toDouble(),
- false);
+ final Offset endPoint = degreeToPoint(endAngle, innerRadius, center);
+ path.arcToPoint(endPoint,
+ radius: Radius.circular((innerRadius - outerRadius).abs() / 2));
}
path.arcTo(
@@ -146,6 +129,10 @@ Path getRoundedCornerArcPath(
degreesToRadians(endAngle.toDouble()))
.toDouble(),
false);
+ if (cornerStyle == CornerStyle.endCurve) {
+ path.close();
+ }
+
return path;
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/common/legend/legend.dart b/packages/syncfusion_flutter_charts/lib/src/common/legend/legend.dart
index ae376064c..24ac7d70d 100644
--- a/packages/syncfusion_flutter_charts/lib/src/common/legend/legend.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/common/legend/legend.dart
@@ -385,11 +385,27 @@ class ChartLegend {
(!series.isVisible &&
seriesRendererDetails.oldSeries!.isVisible == true))) {
legendRenderContext.isSelect = true;
- if (stateProperties.renderingDetails.legendToggleStates
- .contains(legendRenderContext) ==
- false) {
+ final List legendToggleStates =
+ stateProperties.renderingDetails.legendToggleStates;
+ if (legendToggleStates.isEmpty) {
stateProperties.renderingDetails.legendToggleStates
.add(legendRenderContext);
+ } else {
+ LegendRenderContext? legendContext;
+ bool isSame = false;
+ for (int i = 0; i < legendToggleStates.length; i++) {
+ if (legendToggleStates[i] == legendRenderContext ||
+ legendToggleStates[i].seriesIndex ==
+ legendRenderContext.seriesIndex) {
+ isSame = true;
+ } else if (!isSame) {
+ legendContext = legendRenderContext;
+ }
+ }
+ if (!isSame) {
+ stateProperties.renderingDetails.legendToggleStates
+ .add(legendContext!);
+ }
}
} else if (renderingDetails.widgetNeedUpdate &&
(seriesRendererDetails.oldSeries != null &&
diff --git a/packages/syncfusion_flutter_charts/lib/src/common/template/rendering.dart b/packages/syncfusion_flutter_charts/lib/src/common/template/rendering.dart
index 50731916e..086a1d925 100644
--- a/packages/syncfusion_flutter_charts/lib/src/common/template/rendering.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/common/template/rendering.dart
@@ -1,15 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
+import '../../../charts.dart';
import '../../chart/chart_series/series.dart';
import '../../chart/chart_series/series_renderer_properties.dart';
-import '../../chart/chart_series/xy_data_series.dart';
import '../../chart/common/cartesian_state_properties.dart';
import '../../chart/common/data_label.dart';
import '../../chart/common/data_label_renderer.dart';
import '../../chart/utils/helper.dart';
+import '../../circular_chart/base/circular_state_properties.dart';
+import '../../circular_chart/renderer/data_label_renderer.dart';
+import '../../circular_chart/renderer/renderer_extension.dart';
+import '../../circular_chart/utils/helper.dart';
+import '../rendering_details.dart';
import '../state_properties.dart';
-import '../utils/enum.dart';
import '../utils/helper.dart';
/// Represents the render template class.
@@ -186,7 +190,6 @@ class _ChartTemplateRenderBox extends RenderShiftedBox {
if (child != null) {
locationX = _templateInfo.location.dx;
locationY = _templateInfo.location.dy;
-
child!.layout(constraints, parentUsesSize: true);
size = constraints.constrain(Size(child!.size.width, child!.size.height));
if (child!.parentData is BoxParentData) {
@@ -267,8 +270,39 @@ class _ChartTemplateRenderBox extends RenderShiftedBox {
stateProperties.renderingDetails.dataLabelTemplateRegions;
final bool isCollide = (_templateInfo.templateType == 'DataLabel') &&
findingCollision(rect, dataLabelTemplateRegions);
- if (!isCollide &&
- _isTemplateWithinBounds(_templateInfo.clipRect, rect) &&
+ if (stateProperties is CircularStateProperties &&
+ _templateInfo.templateType == 'DataLabel' &&
+ stateProperties.chartSeries.visibleSeriesRenderers[0].seriesType !=
+ 'radialbar') {
+ final CircularSeriesRendererExtension seriesRenderer =
+ (stateProperties as CircularStateProperties)
+ .chartSeries
+ .visibleSeriesRenderers[0];
+ final DataLabelSettings dataLabelSettings =
+ seriesRenderer.dataLabelSettingsRenderer.dataLabelSettings;
+ if (dataLabelSettings.labelIntersectAction ==
+ LabelIntersectAction.shift) {
+ dataLabelTemplateRegions.add(rect);
+ } else {
+ final ChartPoint point =
+ seriesRenderer.renderPoints![_templateInfo.pointIndex!];
+ if ((isCollide &&
+ dataLabelSettings.labelIntersectAction ==
+ LabelIntersectAction.hide &&
+ child != null &&
+ child!.size != Size.zero) ||
+ (!isTemplateWithinBounds(_templateInfo.clipRect, rect) ||
+ (point.y == 0 && !dataLabelSettings.showZeroValue))) {
+ child!.layout(constraints.copyWith(maxWidth: 0, maxHeight: 0),
+ parentUsesSize: true);
+ dataLabelTemplateRegions.add(Rect.zero);
+ } else {
+ childParentData.offset = Offset(locationX, locationY);
+ dataLabelTemplateRegions.add(rect);
+ }
+ }
+ } else if (!isCollide &&
+ isTemplateWithinBounds(_templateInfo.clipRect, rect) &&
isLabelWithInRange) {
(_templateInfo.templateType == 'DataLabel')
? dataLabelTemplateRegions.add(rect)
@@ -285,13 +319,6 @@ class _ChartTemplateRenderBox extends RenderShiftedBox {
size = Size.zero;
}
}
-
- /// To check template is within bounds.
- bool _isTemplateWithinBounds(Rect bounds, Rect templateRect) =>
- templateRect.left >= bounds.left &&
- templateRect.left + templateRect.width <= bounds.left + bounds.width &&
- templateRect.top >= bounds.top &&
- templateRect.top + templateRect.height <= bounds.top + bounds.height;
}
/// Represents the chart template class.
@@ -321,6 +348,87 @@ class ChartTemplate extends StatefulWidget {
State createState() => _ChartTemplateState();
}
+/// Represent the render object for circular data label template.
+class DataLabelTemplateStack extends Stack {
+ /// Creating an argument constructor of DataLabelTemplateStack class.
+ DataLabelTemplateStack(
+ {required this.renderingDetails,
+ required this.stateProperties,
+ required List children})
+ : super(children: children);
+
+ /// Holds circular series rendering details.
+ final RenderingDetails renderingDetails;
+
+ /// Holds circular series state properties.
+ final CircularStateProperties stateProperties;
+
+ @override
+ RenderStack createRenderObject(BuildContext context) {
+ final RenderDataLabelTemplateStack dataLabelTemplateStack =
+ RenderDataLabelTemplateStack()
+ ..renderingDetails = renderingDetails
+ ..stateProperties = stateProperties
+ ..textDirection = Directionality.maybeOf(context);
+ return dataLabelTemplateStack;
+ }
+}
+
+/// Shifted the circular data label template based on the template size.
+class RenderDataLabelTemplateStack extends RenderStack {
+ /// Holds the Circular series rendering.
+ late RenderingDetails renderingDetails;
+
+ /// Holds the CircularStateProperties.
+ late CircularStateProperties stateProperties;
+
+ @override
+ void performLayout() {
+ super.performLayout();
+ final CircularSeriesRendererExtension seriesRenderer =
+ stateProperties.chartSeries.visibleSeriesRenderers[0];
+ final List regions = renderingDetails.dataLabelTemplateRegions;
+ shiftCircularDataLabelTemplate(seriesRenderer, stateProperties, regions);
+ RenderBox child = firstChild!;
+ const int labelPadding = 2;
+ final EdgeInsets margin = seriesRenderer.series.dataLabelSettings.margin;
+ int pointIndex = 0;
+ final List templates =
+ renderingDetails.chartTemplate!.templates;
+ // Iterate the template for avoid the hidden data points and get the visible points.
+ while (pointIndex < templates.length) {
+ final ChartPoint point =
+ seriesRenderer.renderPoints![templates[pointIndex].pointIndex!];
+ if (point.isVisible &&
+ templates[pointIndex].templateType == 'DataLabel') {
+ final Rect rect = point.labelRect;
+ final Offset labelLocation = Offset(
+ rect.left +
+ (point.renderPosition == ChartDataLabelPosition.inside
+ ? labelPadding
+ : margin.left),
+ rect.top + (rect.height / 2 - regions[pointIndex].height / 2));
+ final StackParentData parentData = child.parentData as StackParentData;
+ if (isTemplateWithinBounds(
+ stateProperties.renderingDetails.chartAreaRect, rect) &&
+ !isOverlapWithPrevious(
+ point, seriesRenderer.renderPoints!, point.index) &&
+ (point.y != 0 ||
+ seriesRenderer.series.dataLabelSettings.showZeroValue)) {
+ parentData.offset = labelLocation;
+ } else {
+ // made a child size to zero when it is goes outside the chart area or overlap with previous template.
+ child.layout(constraints.copyWith(maxHeight: 0, maxWidth: 0));
+ }
+ if (pointIndex < renderingDetails.chartTemplate!.templates.length - 1) {
+ child = (child.parentData! as StackParentData).nextSibling!;
+ }
+ }
+ pointIndex++;
+ }
+ }
+}
+
class _ChartTemplateState extends State {
@override
void initState() {
@@ -332,6 +440,19 @@ class _ChartTemplateState extends State {
Widget build(BuildContext context) {
widget.state = this;
Widget renderTemplate = Container();
+ CircularSeriesRendererExtension? seriesRenderer;
+ DataLabelSettings? dataLabelSettings;
+ if (widget.stateProperties is CircularStateProperties) {
+ seriesRenderer = (widget.stateProperties as CircularStateProperties)
+ .chartSeries
+ .visibleSeriesRenderers[0];
+ if (seriesRenderer.series.dataLabelSettings.isVisible) {
+ seriesRenderer.dataLabelSettingsRenderer =
+ DataLabelSettingsRenderer(seriesRenderer.series.dataLabelSettings);
+ dataLabelSettings =
+ seriesRenderer.dataLabelSettingsRenderer.dataLabelSettings;
+ }
+ }
final bool animationCompleted =
widget.stateProperties.renderingDetails.animateCompleted;
if (animationCompleted && widget.templates.isNotEmpty) {
@@ -344,7 +465,20 @@ class _ChartTemplateState extends State {
stateProperties: widget.stateProperties,
));
}
- renderTemplate = Stack(children: renderWidgets);
+ renderTemplate = ((widget.stateProperties is CircularStateProperties) &&
+ dataLabelSettings != null &&
+ seriesRenderer!.seriesType != 'radialbar' &&
+ dataLabelSettings.labelIntersectAction ==
+ LabelIntersectAction.shift &&
+ dataLabelSettings.builder != null)
+ ? DataLabelTemplateStack(
+ renderingDetails: widget.stateProperties.renderingDetails,
+ stateProperties:
+ widget.stateProperties as CircularStateProperties,
+ children: renderWidgets)
+ : Stack(
+ children: renderWidgets,
+ );
}
return renderTemplate;
}
diff --git a/packages/syncfusion_flutter_charts/lib/src/common/user_interaction/tooltip.dart b/packages/syncfusion_flutter_charts/lib/src/common/user_interaction/tooltip.dart
index de1443200..762f0921c 100644
--- a/packages/syncfusion_flutter_charts/lib/src/common/user_interaction/tooltip.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/common/user_interaction/tooltip.dart
@@ -692,8 +692,11 @@ class TooltipBehavior {
});
}
}
- if (renderingDetails.tooltipBehaviorRenderer._tooltipRenderingDetails
- .tooltipTemplate ==
+ if (chart.tooltipBehavior.builder != null && x != null) {
+ renderingDetails.tooltipBehaviorRenderer._tooltipRenderingDetails
+ .showTemplateTooltip(Offset(position.x, position.y));
+ } else if (renderingDetails.tooltipBehaviorRenderer
+ ._tooltipRenderingDetails.tooltipTemplate ==
null) {
final SfTooltipState? tooltipState =
tooltipBehaviorRenderer._tooltipRenderingDetails.chartTooltipState;
diff --git a/packages/syncfusion_flutter_charts/lib/src/common/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/common/utils/helper.dart
index 36e2af198..6468e53e4 100644
--- a/packages/syncfusion_flutter_charts/lib/src/common/utils/helper.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/common/utils/helper.dart
@@ -40,7 +40,17 @@ void dataLabelTapEvent(dynamic chart, DataLabelSettings dataLabelSettings,
datalabelArgs = DataLabelTapDetails(
seriesIndex,
pointIndex,
- chart is SfCartesianChart ? point.label : point.text,
+ chart is SfCartesianChart
+ ? point.dataLabelRegion.contains(position)
+ ? point.label
+ : point.dataLabelRegion2.contains(position)
+ ? point.label2
+ : point.dataLabelRegion3.contains(position)
+ ? point.label3
+ : point.dataLabelRegion4.contains(position)
+ ? point.label4
+ : point.label5
+ : point.text,
dataLabelSettings,
chart is SfCartesianChart ? point.overallDataPointIndex : pointIndex);
datalabelArgs.position = position;
@@ -1050,33 +1060,23 @@ void calculatePointSeriesIndex(
final SeriesRendererDetails seriesRendererDetails =
SeriesHelper.getSeriesRendererDetails(
stateProperties.chartSeries.visibleSeriesRenderers[i]);
- final String seriesType = seriesRendererDetails.seriesType;
int? pointIndex;
- final double padding = (seriesType == 'bubble') ||
- (seriesType == 'scatter') ||
- (seriesType == 'bar') ||
- (seriesType == 'column' ||
- seriesType == 'rangecolumn' ||
- seriesType.contains('stackedcolumn') ||
- seriesType.contains('stackedbar') ||
- seriesType == 'waterfall')
- ? 0
- : 15;
-
- /// Regional padding to detect smooth touch.
seriesRendererDetails.regionalData!
.forEach((dynamic regionRect, dynamic values) {
final Rect region = regionRect[0];
- final double left = region.left - padding;
- final double right = region.right + padding;
- final double top = region.top - padding;
- final double bottom = region.bottom + padding;
+ final double widthPadding =
+ region.width < 8 ? (8 - region.width) / 2 : 0;
+ final double heightPadding =
+ region.height < 8 ? (8 - region.height) / 2 : 0;
+ final double left = region.left - widthPadding;
+ final double right = region.right + widthPadding;
+ final double top = region.top - heightPadding;
+ final double bottom = region.bottom + heightPadding;
final Rect paddedRegion = Rect.fromLTRB(left, top, right, bottom);
if (paddedRegion.contains(position!)) {
pointIndex = regionRect[4].visiblePointIndex;
}
});
-
if (pointIndex != null && seriesRendererDetails.visible! == true) {
if ((seriesRendererDetails.series.onPointTap != null ||
seriesRendererDetails.series.onPointDoubleTap != null ||
@@ -1214,3 +1214,10 @@ String addEllipse(String text, int maxLength, String ellipse, {bool? isRtl}) {
return trimText + ellipse;
}
}
+
+/// To check template is within bounds.
+bool isTemplateWithinBounds(Rect bounds, Rect templateRect) =>
+ templateRect.left >= bounds.left &&
+ templateRect.left + templateRect.width <= bounds.left + bounds.width &&
+ templateRect.top >= bounds.top &&
+ templateRect.top + templateRect.height <= bounds.top + bounds.height;
diff --git a/packages/syncfusion_flutter_charts/lib/src/pyramid_chart/utils/helper.dart b/packages/syncfusion_flutter_charts/lib/src/pyramid_chart/utils/helper.dart
index acfd75de6..79fa1441d 100644
--- a/packages/syncfusion_flutter_charts/lib/src/pyramid_chart/utils/helper.dart
+++ b/packages/syncfusion_flutter_charts/lib/src/pyramid_chart/utils/helper.dart
@@ -213,7 +213,8 @@ bool isNeedExplode(int pointIndex, dynamic series, dynamic stateProperties) {
/// To return data label rect calculation method based on position.
Rect? getDataLabelRect(Position position, ConnectorType connectorType,
- EdgeInsets margin, Path connectorPath, Offset endPoint, Size textSize) {
+ EdgeInsets margin, Path connectorPath, Offset endPoint, Size textSize,
+ [DataLabelSettings? dataLabelSettings]) {
Rect? rect;
const int lineLength = 10;
switch (position) {
@@ -222,26 +223,32 @@ Rect? getDataLabelRect(Position position, ConnectorType connectorType,
? connectorPath.lineTo(endPoint.dx + lineLength, endPoint.dy)
: connectorPath.quadraticBezierTo(
endPoint.dx, endPoint.dy, endPoint.dx + lineLength, endPoint.dy);
- rect = Rect.fromLTWH(
- endPoint.dx + lineLength,
- endPoint.dy - (textSize.height / 2) - margin.top,
- textSize.width + margin.left + margin.right,
- textSize.height + margin.top + margin.bottom);
+ rect = dataLabelSettings != null && dataLabelSettings.builder != null
+ ? Rect.fromLTWH(
+ endPoint.dx, endPoint.dy, textSize.width, textSize.height)
+ : Rect.fromLTWH(
+ endPoint.dx + lineLength,
+ endPoint.dy - (textSize.height / 2) - margin.top,
+ textSize.width + margin.left + margin.right,
+ textSize.height + margin.top + margin.bottom);
break;
case Position.left:
connectorType == ConnectorType.line
? connectorPath.lineTo(endPoint.dx - lineLength, endPoint.dy)
: connectorPath.quadraticBezierTo(
endPoint.dx, endPoint.dy, endPoint.dx - lineLength, endPoint.dy);
- rect = Rect.fromLTWH(
- endPoint.dx -
- lineLength -
- margin.right -
- textSize.width -
- margin.left,
- endPoint.dy - (textSize.height / 2) - margin.top,
- textSize.width + margin.left + margin.right,
- textSize.height + margin.top + margin.bottom);
+ rect = dataLabelSettings != null && dataLabelSettings.builder != null
+ ? Rect.fromLTWH(
+ endPoint.dx, endPoint.dy, textSize.width, textSize.height)
+ : Rect.fromLTWH(
+ endPoint.dx -
+ lineLength -
+ margin.right -
+ textSize.width -
+ margin.left,
+ endPoint.dy - ((textSize.height / 2) + margin.top),
+ textSize.width + margin.left + margin.right,
+ textSize.height + margin.top + margin.bottom);
break;
}
return rect;
diff --git a/packages/syncfusion_flutter_charts/pubspec.yaml b/packages/syncfusion_flutter_charts/pubspec.yaml
index 680d9a62f..b7acb96c2 100644
--- a/packages/syncfusion_flutter_charts/pubspec.yaml
+++ b/packages/syncfusion_flutter_charts/pubspec.yaml
@@ -1,17 +1,17 @@
name: syncfusion_flutter_charts
description: A Flutter Charts library which includes data visualization widgets such as cartesian and circular charts, to create real-time, interactive, high-performance, animated charts.
-version: 20.3.47
+version: 20.4.38
homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_charts
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
intl: ^0.17.0
vector_math: ">=2.1.0 <=3.0.0"
- syncfusion_flutter_core: ^20.3.47
+ syncfusion_flutter_core: ^20.4.38
dev_dependencies:
flutter_test:
diff --git a/packages/syncfusion_flutter_core/README.md b/packages/syncfusion_flutter_core/README.md
index 07cafb6a9..b5d173851 100644
--- a/packages/syncfusion_flutter_core/README.md
+++ b/packages/syncfusion_flutter_core/README.md
@@ -33,15 +33,12 @@ Explore the full capabilities of our Flutter widgets on your device by installin
-
-
+
+
-
-
-
@@ -55,11 +52,11 @@ Take a look at the following to learn more about Syncfusion Flutter widgets:
## Support and Feedback
-* For any other queries, reach our [Syncfusion support team](https://www.syncfusion.com/support/directtrac/incidents/newincident) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
+* For any other queries, reach our [Syncfusion support team](https://support.syncfusion.com/support/tickets/create) or post the queries through the [Community forums](https://www.syncfusion.com/forums) and submit a feature request or a bug through our [Feedback portal](https://www.syncfusion.com/feedback/flutter).
* To renew the subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at salessupport@syncfusion.com | Toll Free: 1-888-9 DOTNET.
## About Syncfusion
Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 20,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies.
-Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), and [Blazor](https://www.syncfusion.com/blazor-components), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls) and [.NET MAUI](https://www.syncfusion.com/maui-controls)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
+Today we provide 1,000+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([Flutter](https://www.syncfusion.com/flutter-widgets), [WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [.NET MAUI](https://www.syncfusion.com/maui-controls)). We provide ready-to deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
diff --git a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.cc
index e71a16d23..d38195aa0 100644
--- a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.h
index e0f0a47bc..9bf747894 100644
--- a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugins.cmake
index 2e1de87a7..51436ae8c 100644
--- a/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_core/example/linux/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_core/example/pubspec.yaml b/packages/syncfusion_flutter_core/example/pubspec.yaml
index fdabf4577..2219d1655 100644
--- a/packages/syncfusion_flutter_core/example/pubspec.yaml
+++ b/packages/syncfusion_flutter_core/example/pubspec.yaml
@@ -3,7 +3,7 @@ description: This project holds information about registering a license key with
version: 1.0.0+1
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
diff --git a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.cc
index 8b6d4680a..4bfa0f3a3 100644
--- a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.h
index dc139d85a..9846246b4 100644
--- a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugins.cmake
index b93c4c30c..4d10c2518 100644
--- a/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_core/example/windows/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart b/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart
index 8eb11e3d5..1c2958e8d 100644
--- a/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart
+++ b/packages/syncfusion_flutter_core/lib/src/localizations/global_localizations.dart
@@ -241,79 +241,83 @@ abstract class SfLocalizations {
String get greaterThanOrEqualDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort Smallest to Largest` option in drop down widget.
+ /// `Sort Smallest to Largest` option in the popup menu.
String get sortSmallestToLargestDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// ` Sort Largest to Smallest ` option in drop down widget.
+ /// ` Sort Largest to Smallest ` option in the popup menu.
String get sortLargestToSmallestDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort A to Z` option in drop down widget.
+ /// `Sort A to Z` option in the popup menu.
String get sortAToZDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort Z to A` option in drop down widget.
+ /// `Sort Z to A` option in the popup menu.
String get sortZToADataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort Oldest to Newest` option in drop down widget.
+ /// `Sort Oldest to Newest` option in the popup menu..
String get sortOldestToNewestDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort Newest to Oldest` option in drop down widget.
+ /// `Sort Newest to Oldest` option in the popup menu.
String get sortNewestToOldestDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Clear Filter From` option in drop down widget.
- String get clearFilterFromDataGridFilteringLabel;
+ /// `Clear Filter` text in `Clear Filter From` option in the popup menu.
+ String get clearFilterDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Text Filters` option in drop down widget.
+ /// `From` text in `Clear Filter From` option in the popup menu.
+ String get fromDataGridFilteringLabel;
+
+ /// The label that is displayed in the filter view in SfDataGrid for
+ /// `Text Filters` option in the popup menu.
String get textFiltersDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Number Filters` option in drop down widget.
+ /// `Number Filters` option in the popup menu.
String get numberFiltersDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Date Filters` option in drop down widget.
+ /// `Date Filters` option in the popup menu.
String get dateFiltersDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Search` option in drop down widget.
+ /// `Search` option in the popup menu.
String get searchDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `No matches` option in drop down widget.
+ /// `No matches` option in the popup menu.
String get noMatchesDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `OK ` option in drop down widget.
+ /// `OK ` option in the popup menu.
String get okDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Cancel` option in drop down widget.
+ /// `Cancel` option in the popup menu.
String get cancelDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Show rows where` option in drop down widget.
+ /// `Show rows where` option in the popup menu.
String get showRowsWhereDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `And` option in drop down widget.
+ /// `And` option in the popup menu.
String get andDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Or` option in drop down widget.
+ /// `Or` option in the popup menu.
String get orDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Select All` option in drop down widget.
+ /// `Select All` option in the popup menu.
String get selectAllDataGridFilteringLabel;
/// The label that is displayed in the filter view in SfDataGrid for
- /// `Sort and Filter` option in drop down widget.
+ /// `Sort and Filter` option in the popup menu.
String get sortAndFilterDataGridFilteringLabel;
/// Label that is displayed in the bookmark view header of PdfViewer.
@@ -659,7 +663,10 @@ class _DefaultLocalizations implements SfLocalizations {
'Sort Newest to Oldest';
@override
- String get clearFilterFromDataGridFilteringLabel => 'Clear Filter From';
+ String get clearFilterDataGridFilteringLabel => 'Clear Filter';
+
+ @override
+ String get fromDataGridFilteringLabel => 'From';
@override
String get textFiltersDataGridFilteringLabel => 'Text Filters';
diff --git a/packages/syncfusion_flutter_core/lib/src/theme/datagrid_theme.dart b/packages/syncfusion_flutter_core/lib/src/theme/datagrid_theme.dart
index 78f73cf74..e29c712b9 100644
--- a/packages/syncfusion_flutter_core/lib/src/theme/datagrid_theme.dart
+++ b/packages/syncfusion_flutter_core/lib/src/theme/datagrid_theme.dart
@@ -124,6 +124,11 @@ class SfDataGridThemeData with Diagnosticable {
double? columnResizeIndicatorStrokeWidth,
TextStyle? rowHoverTextStyle,
Widget? sortIcon,
+ Widget? filterIcon,
+ Color? filterIconColor,
+ Color? filterIconHoverColor,
+ Color? sortOrderNumberColor,
+ Color? sortOrderNumberBackgroundColor,
}) {
return SfDataGridThemeData.raw(
brightness: brightness,
@@ -141,7 +146,12 @@ class SfDataGridThemeData with Diagnosticable {
columnResizeIndicatorColor: columnResizeIndicatorColor,
columnResizeIndicatorStrokeWidth: columnResizeIndicatorStrokeWidth,
rowHoverTextStyle: rowHoverTextStyle,
- sortIcon: sortIcon);
+ sortIcon: sortIcon,
+ filterIcon: filterIcon,
+ filterIconColor: filterIconColor,
+ filterIconHoverColor: filterIconHoverColor,
+ sortOrderNumberColor: sortOrderNumberColor,
+ sortOrderNumberBackgroundColor: sortOrderNumberBackgroundColor);
}
/// Create a [SfDataGridThemeData] given a set of exact values.
@@ -167,7 +177,12 @@ class SfDataGridThemeData with Diagnosticable {
required this.columnResizeIndicatorStrokeWidth,
required this.rowHoverColor,
required this.rowHoverTextStyle,
- required this.sortIcon});
+ required this.sortIcon,
+ required this.filterIcon,
+ required this.filterIconColor,
+ required this.filterIconHoverColor,
+ required this.sortOrderNumberColor,
+ required this.sortOrderNumberBackgroundColor});
/// The brightness of the overall theme of the
/// application for the [SfDataGrid] widgets.
@@ -389,6 +404,84 @@ class SfDataGridThemeData with Diagnosticable {
/// ```
final Widget? sortIcon;
+ /// The icon to indicate the filtering applied in column.
+ ///
+ /// If you want to change the icon filter or filtered state, you can use the
+ /// [Builder](https://api.flutter.dev/flutter/widgets/Builder-class.html)
+ /// widget and return the respective icon for the state. You have to return
+ /// the icons for both the states even if you want to change the icon
+ /// for specific state.
+ ///
+ /// ```dart
+ /// @override
+ /// Widget build(BuildContext context) {
+ /// return Scaffold(
+ /// appBar: AppBar(
+ /// title: const Text('Syncfusion Flutter DataGrid',
+ /// overflow: TextOverflow.ellipsis),
+ /// ),
+ /// body: SfDataGridTheme(
+ /// data: SfDataGridThemeData(filterIcon: Builder(
+ /// builder: (context) {
+ /// Widget? icon;
+ /// String columnName = '';
+ /// context.visitAncestorElements((element) {
+ /// if (element is GridHeaderCellElement) {
+ /// columnName = element.column.columnName;
+ /// }
+ /// return true;
+ /// });
+ /// var column = _employeeDataSource.filterConditions.keys
+ /// .where((element) => element == columnName)
+ /// .firstOrNull;
+
+ /// if (column != null) {
+ /// icon = const Icon(
+ /// Icons.filter_alt_outlined,
+ /// size: 20,
+ /// color: Colors.purple,
+ /// );
+ /// }
+ /// return icon ??
+ /// const Icon(
+ /// Icons.filter_alt_off_outlined,
+ /// size: 20,
+ /// color: Colors.deepOrange,
+ /// );
+ /// },
+ /// )),
+ /// child: SfDataGrid(
+ /// source: _employeeDataSource,
+ /// allowFiltering: true,
+ /// allowSorting: true,
+ /// columns: getColumns(),
+ /// ),
+ /// ),
+ /// );
+ /// }
+ /// ```
+ final Widget? filterIcon;
+
+ /// The color of the filter icon which indicates whether
+ /// the column is filtered or not.
+ ///
+ /// This is not applicable when `filterIcon` property is set.
+ /// This applies the color to default filter icon only.
+ final Color? filterIconColor;
+
+ /// The color for the filter icon when a pointer is hovering over it.
+ ///
+ /// This is not applicable when `filterIcon` property is set.
+ /// This applies the color to default filter icon only.
+ final Color? filterIconHoverColor;
+
+ /// The color of the number displayed when the order of the sorting is shown.
+ final Color? sortOrderNumberColor;
+
+ /// The color of the rounded background displayed
+ /// when the order of the sorting is shown.
+ final Color? sortOrderNumberBackgroundColor;
+
/// Creates a copy of this theme but with the given
/// fields replaced with the new values.
SfDataGridThemeData copyWith({
@@ -408,6 +501,11 @@ class SfDataGridThemeData with Diagnosticable {
Color? rowHoverColor,
TextStyle? rowHoverTextStyle,
Widget? sortIcon,
+ Widget? filterIcon,
+ Color? filterIconColor,
+ Color? filterIconHoverColor,
+ Color? sortOrderNumberColor,
+ Color? sortOrderNumberBackgroundColor,
}) {
return SfDataGridThemeData.raw(
brightness: brightness ?? this.brightness,
@@ -428,6 +526,12 @@ class SfDataGridThemeData with Diagnosticable {
rowHoverColor: rowHoverColor ?? this.rowHoverColor,
rowHoverTextStyle: rowHoverTextStyle ?? this.rowHoverTextStyle,
sortIcon: sortIcon ?? this.sortIcon,
+ filterIcon: filterIcon ?? this.filterIcon,
+ filterIconColor: filterIconColor ?? this.filterIconColor,
+ filterIconHoverColor: filterIconHoverColor ?? this.filterIconHoverColor,
+ sortOrderNumberColor: sortOrderNumberColor ?? this.sortOrderNumberColor,
+ sortOrderNumberBackgroundColor:
+ sortOrderNumberBackgroundColor ?? this.sortOrderNumberBackgroundColor,
);
}
@@ -462,6 +566,15 @@ class SfDataGridThemeData with Diagnosticable {
t),
rowHoverTextStyle:
TextStyle.lerp(a.rowHoverTextStyle, b.rowHoverTextStyle, t),
+ filterIconColor: Color.lerp(a.filterIconColor, b.filterIconColor, t),
+ filterIconHoverColor:
+ Color.lerp(a.filterIconHoverColor, b.filterIconHoverColor, t),
+ sortOrderNumberColor:
+ Color.lerp(a.sortOrderNumberColor, b.sortOrderNumberColor, t),
+ sortOrderNumberBackgroundColor: Color.lerp(
+ a.sortOrderNumberBackgroundColor,
+ b.sortOrderNumberBackgroundColor,
+ t),
);
}
@@ -491,7 +604,12 @@ class SfDataGridThemeData with Diagnosticable {
other.columnResizeIndicatorStrokeWidth ==
columnResizeIndicatorStrokeWidth &&
other.rowHoverTextStyle == rowHoverTextStyle &&
- other.sortIcon == sortIcon;
+ other.sortIcon == sortIcon &&
+ other.filterIcon == filterIcon &&
+ other.filterIconColor == filterIconColor &&
+ other.filterIconHoverColor == filterIconHoverColor &&
+ other.sortOrderNumberColor == sortOrderNumberColor &&
+ other.sortOrderNumberBackgroundColor == sortOrderNumberBackgroundColor;
}
@override
@@ -511,7 +629,12 @@ class SfDataGridThemeData with Diagnosticable {
columnResizeIndicatorColor,
columnResizeIndicatorStrokeWidth,
rowHoverTextStyle,
- sortIcon
+ sortIcon,
+ filterIcon,
+ filterIconColor,
+ filterIconHoverColor,
+ sortOrderNumberColor,
+ sortOrderNumberBackgroundColor
];
return Object.hashAll(values);
}
@@ -554,6 +677,19 @@ class SfDataGridThemeData with Diagnosticable {
properties.add(DiagnosticsProperty(
'rowHoverTextStyle', rowHoverTextStyle,
defaultValue: defaultData.rowHoverTextStyle));
+ properties.add(DiagnosticsProperty('sortIcon', sortIcon,
+ defaultValue: defaultData.sortIcon));
+ properties.add(DiagnosticsProperty('filterIcon', filterIcon,
+ defaultValue: defaultData.filterIcon));
+ properties.add(ColorProperty('filterIconColor', filterIconColor,
+ defaultValue: defaultData.filterIconColor));
+ properties.add(ColorProperty('filterIconHoverColor', filterIconHoverColor,
+ defaultValue: defaultData.filterIconHoverColor));
+ properties.add(ColorProperty('sortOrderNumberColor', sortOrderNumberColor,
+ defaultValue: defaultData.sortOrderNumberColor));
+ properties.add(ColorProperty(
+ 'sortOrderNumberBackgroundColor', sortOrderNumberBackgroundColor,
+ defaultValue: defaultData.sortOrderNumberBackgroundColor));
}
}
diff --git a/packages/syncfusion_flutter_core/lib/tooltip_internal.dart b/packages/syncfusion_flutter_core/lib/tooltip_internal.dart
index 7cbbed140..9faa99398 100644
--- a/packages/syncfusion_flutter_core/lib/tooltip_internal.dart
+++ b/packages/syncfusion_flutter_core/lib/tooltip_internal.dart
@@ -8,3 +8,4 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'core.dart';
part 'src/tooltip/tooltip.dart';
+part 'src/test/tooltip_tests.dart';
diff --git a/packages/syncfusion_flutter_core/pubspec.yaml b/packages/syncfusion_flutter_core/pubspec.yaml
index 5ee49343b..bd8e2ae89 100644
--- a/packages/syncfusion_flutter_core/pubspec.yaml
+++ b/packages/syncfusion_flutter_core/pubspec.yaml
@@ -1,10 +1,10 @@
name: syncfusion_flutter_core
description: Syncfusion Flutter Core is a dependent package for all the Syncfusion Flutter widgets.
-version: 20.3.47
+version: 20.4.38
homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_core
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
vector_math: ">=2.1.0 <=3.0.0"
diff --git a/packages/syncfusion_flutter_datagrid/CHANGELOG.md b/packages/syncfusion_flutter_datagrid/CHANGELOG.md
index 64628a1c8..0fefdc892 100644
--- a/packages/syncfusion_flutter_datagrid/CHANGELOG.md
+++ b/packages/syncfusion_flutter_datagrid/CHANGELOG.md
@@ -1,5 +1,51 @@
## Unreleased
+**Features**
+
+* Provided the support to change the shape of the built-in checkbox column.
+* Provided the support to change the filter icon and its color. The padding around the filter icon can also be customized.
+* Provided the support to customize the filter options in the filter popup. Users can hide the sorting and “Clear Filter” options and show only the checked listbox view or advanced filter popup view to apply filtering.
+* Provided the support to customize the color of the sort order number and its rounded background.
+* Provided the support to change the elevation effect when setting the `frozenPaneLineColor` property.
+
+**Bugs**
+
+* The filtering is now properly applied when programmatically adding the filter conditions and filter popup menu is now opened with proper items in checked listbox.
+
+## [20.3.60] - 12/06/2022
+
+**Bugs**
+
+* The `onFilterChanging` and `onFilterChanged` callbacks will be called now when tapping `Select All` option to select all the rows in the checked listbox filtering.
+* The current cell is now properly removed when setting the `selectedIndex` property as -1 programmatically.
+
+## [20.3.59] - 11/29/2022
+
+**Bugs**
+
+* The focus is now moved to widgets that are outside the DataGrid when the canSubmitCell method returns true.
+
+## [20.3.57] - 11/15/2022
+
+**Bugs**
+
+* The listeners in `SelectionController` class are properly disposed
+
+## [20.3.49] - 10/11/2022
+
+**Bugs**
+
+* The current cell is now updating properly while adding a row at runtime through the `RowSelectionManager`.
+* SfDataPager is now working properly when changing the `pageCount` property at run time.
+
+## [20.3.48] - 10/05/2022
+
+**Bugs**
+
+* Filtering is now working properly when page count is set for paging to apply whole data sorting.
+
+## [20.3.47] - 09/29/2022
+
**Breaking changes**
* The left and border is now drawn by default in DataGrid. Hence, there is no need to add `Container` widget as parent for DataGrid to set left and top borders.
diff --git a/packages/syncfusion_flutter_datagrid/README.md b/packages/syncfusion_flutter_datagrid/README.md
index 01e55f8ab..a53600ba2 100644
--- a/packages/syncfusion_flutter_datagrid/README.md
+++ b/packages/syncfusion_flutter_datagrid/README.md
@@ -100,15 +100,12 @@ Explore the full capabilities of our Flutter widgets on your device by installin
-
-
+
+
-
-
-
@@ -290,11 +287,11 @@ The following screenshot illustrates the result of the above code sample.
## Support and Feedback
-* If you have any questions, you can reach the [Syncfusion support team](https://www.syncfusion.com/support/directtrac/incidents/newincident) or post queries to the [community forums](https://www.syncfusion.com/forums). You can also submit a feature request or a bug report through our [feedback portal](https://www.syncfusion.com/feedback/flutter).
+* If you have any questions, you can reach the [Syncfusion support team](https://support.syncfusion.com/support/tickets/create) or post queries to the [community forums](https://www.syncfusion.com/forums). You can also submit a feature request or a bug report through our [feedback portal](https://www.syncfusion.com/feedback/flutter).
* To renew your subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at sales@syncfusion.com | Toll Free: 1-888-9 DOTNET.
## About Syncfusion
Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 20,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies.
-Today we provide 1,600+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), and [Blazor](https://www.syncfusion.com/blazor-components)) , mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls) and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to- deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
+Today we provide 1,600+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([.NET MAUI](https://www.syncfusion.com/maui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([Flutter](https://www.syncfusion.com/flutter-widgets), [.NET MAUI](https://www.syncfusion.com/maui-controls?utm_source=pubdev&utm_medium=listing&utm_campaign=flutter-charts-pubdev), [WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to- deploy enterprise software for dashboards, reports, data integration, and big data processing. Many customers have saved millions in licensing fees by deploying our software.
\ No newline at end of file
diff --git a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.cc
index e71a16d23..d38195aa0 100644
--- a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.h
index e0f0a47bc..9bf747894 100644
--- a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugins.cmake
index 2e1de87a7..51436ae8c 100644
--- a/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_datagrid/example/linux/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_datagrid/example/pubspec.yaml b/packages/syncfusion_flutter_datagrid/example/pubspec.yaml
index 1a9eb6866..79b413564 100644
--- a/packages/syncfusion_flutter_datagrid/example/pubspec.yaml
+++ b/packages/syncfusion_flutter_datagrid/example/pubspec.yaml
@@ -3,7 +3,7 @@ description: This project demonstrates how to use Syncfusion Flutter DataGrid wi
version: 1.0.0+1
environment:
- sdk: ">=2.12.0 <3.0.0"
+ sdk: ">=2.17.0 <3.0.0"
dependencies:
flutter:
diff --git a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.cc b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.cc
index 8b6d4680a..4bfa0f3a3 100644
--- a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.cc
+++ b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.cc
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#include "generated_plugin_registrant.h"
diff --git a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.h b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.h
index dc139d85a..9846246b4 100644
--- a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.h
+++ b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugin_registrant.h
@@ -2,8 +2,6 @@
// Generated file. Do not edit.
//
-// clang-format off
-
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
diff --git a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugins.cmake b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugins.cmake
index b93c4c30c..4d10c2518 100644
--- a/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugins.cmake
+++ b/packages/syncfusion_flutter_datagrid/example/windows/flutter/generated_plugins.cmake
@@ -5,9 +5,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
)
-list(APPEND FLUTTER_FFI_PLUGIN_LIST
-)
-
set(PLUGIN_BUNDLED_LIBRARIES)
foreach(plugin ${FLUTTER_PLUGIN_LIST})
@@ -16,8 +13,3 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST})
list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
endforeach(plugin)
-
-foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
- add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
- list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
-endforeach(ffi_plugin)
diff --git a/packages/syncfusion_flutter_datagrid/lib/datagrid.dart b/packages/syncfusion_flutter_datagrid/lib/datagrid.dart
index 603de756b..24975b337 100644
--- a/packages/syncfusion_flutter_datagrid/lib/datagrid.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/datagrid.dart
@@ -31,6 +31,8 @@ export './src/datagrid_widget/sfdatagrid.dart'
addFilterConditions,
removeFilterConditions,
refreshEffectiveRows,
+ performSorting,
+ updateDataPager,
DataGridThemeHelper;
export './src/datapager/sfdatapager.dart'
hide SfDataPagerState, DataPagerThemeHelper;
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_configuration.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_configuration.dart
index ba4e66c9f..f7a6bda83 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_configuration.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_configuration.dart
@@ -60,7 +60,7 @@ class DataGridConfiguration {
late ColumnResizeController columnResizeController;
/// Provides the base functionalities to process the filtering in [SfDataGrid].
- late DataGridFilterHelper dataGridFilterHelper;
+ DataGridFilterHelper? dataGridFilterHelper;
/// The width of the current datagrid view.
late double viewWidth;
@@ -366,4 +366,7 @@ class DataGridConfiguration {
/// Decides whether the Horizontal ScrollController can be disposed of in the source itself.
/// Default to true.
bool disposeHorizontalScrollController = true;
+
+ /// Defines the OutlinedBorder for the shape of the checkbox.
+ OutlinedBorder? checkboxShape;
}
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_helper.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_helper.dart
index 7155a4d12..7eb483d3f 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_helper.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/datagrid_helper.dart
@@ -833,9 +833,11 @@ Future scrollVertical(
return;
}
- verticalOffset = verticalOffset > verticalController.position.maxScrollExtent
- ? verticalController.position.maxScrollExtent
- : verticalOffset;
+ final double maxScrollExtent = max(
+ dataGridConfiguration.container.rowHeights.totalExtent -
+ dataGridConfiguration.viewHeight,
+ 0.0);
+ verticalOffset = min(verticalOffset, maxScrollExtent);
verticalOffset = verticalOffset.isNegative || verticalOffset == 0.0
? verticalController.position.minScrollExtent
: verticalOffset;
@@ -863,10 +865,11 @@ Future scrollHorizontal(
return;
}
- horizontalOffset =
- horizontalOffset > horizontalController.position.maxScrollExtent
- ? horizontalController.position.maxScrollExtent
- : horizontalOffset;
+ final double maxScrollExtent = max(
+ dataGridConfiguration.container.columnWidths.totalExtent -
+ dataGridConfiguration.viewWidth,
+ 0.0);
+ horizontalOffset = min(horizontalOffset, maxScrollExtent);
horizontalOffset = horizontalOffset.isNegative || horizontalOffset == 0.0
? horizontalController.position.minScrollExtent
: horizontalOffset;
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/enums.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/enums.dart
index dc9b5b393..9297764e3 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/enums.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/helper/enums.dart
@@ -341,3 +341,15 @@ enum AdvancedFilterType {
/// values.
date,
}
+
+/// Decides how the checked listbox and advanced filter options should be shown in filter popup
+enum FilterMode {
+ /// Specifies whether the checked listbox only should be shown along with other options.
+ checkboxFilter,
+
+ /// Specifies whether the advanced filter dropdown only should be shown along with other options.
+ advancedFilter,
+
+ /// Specifies whether both the checked listbox and advanced filter dropdown options should be shown.
+ both,
+}
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/cell_renderers.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/cell_renderers.dart
index 55ecad466..c95e9dc09 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/cell_renderers.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/cell_renderers.dart
@@ -166,6 +166,7 @@ class GridHeaderCellRenderer
visible: dataGridConfiguration
.checkboxColumnSettings.showCheckboxOnHeader,
child: Checkbox(
+ shape: dataGridConfiguration.checkboxShape,
tristate: true,
value: dataGridConfiguration.headerCheckboxState,
onChanged: (bool? newValue) {
@@ -258,6 +259,7 @@ class GridCheckboxRenderer
dataCell.dataRow!.isDirty,
dataGridStateDetails: _dataGridStateDetails,
child: Checkbox(
+ shape: dataGridConfiguration.checkboxShape,
value: selectionState,
onChanged: (bool? newValue) {
selection_manager.handleSelectionFromCheckbox(
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart
index a65df6728..24fed70a0 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/runtime/column.dart
@@ -31,7 +31,9 @@ class GridColumn {
this.maximumWidth = double.nan,
this.width = double.nan,
this.allowEditing = true,
- this.allowFiltering = true}) {
+ this.allowFiltering = true,
+ this.filterPopupMenuOptions,
+ this.filterIconPadding = const EdgeInsets.symmetric(horizontal: 8.0)}) {
_actualWidth = double.nan;
_autoWidth = double.nan;
}
@@ -157,6 +159,12 @@ class GridColumn {
/// * [DataGridSource.filterConditions] – This property holds the collection
/// of the filter conditions which are applied for various columns.
final bool allowFiltering;
+
+ /// Decides how the checked listbox and advanced filter options should be shown in filter popup.
+ final FilterPopupMenuOptions? filterPopupMenuOptions;
+
+ /// The amount of space which should be added with the filter icon
+ final EdgeInsetsGeometry filterIconPadding;
}
/// A column which displays the values of the string in its cells.
@@ -318,7 +326,12 @@ class ColumnSizer {
static const double _sortIconWidth = 20.0;
static const double _sortNumberWidth = 18.0;
- static const double _filterIconWidth = 34.0;
+ static const double _filterIconWidth = 18.0;
+
+ /// Defines the outer padding of the sort and filter icon's container. We need
+ /// to consider this padding to measure the auto-width and height calculation.
+ EdgeInsetsGeometry iconsOuterPadding =
+ const EdgeInsets.symmetric(horizontal: 4.0);
void _initialRefresh(double availableWidth) {
final LineSizeCollection lineSizeCollection =
@@ -610,9 +623,13 @@ class ColumnSizer {
double _calculateColumnHeaderWidth(GridColumn column,
{bool setWidth = true}) {
- final double width = _getHeaderCellWidth(column) +
- _getSortIconWidth(column) +
- _getFilterIconWidth(column);
+ double iconsWidth = _getSortIconWidth(column) + _getFilterIconWidth(column);
+
+ if (iconsWidth > 0) {
+ iconsWidth += iconsOuterPadding.horizontal;
+ }
+
+ final double width = _getHeaderCellWidth(column) + iconsWidth;
_updateSetWidth(setWidth, column, width);
return width;
}
@@ -818,7 +835,7 @@ class ColumnSizer {
double _getFilterIconWidth(GridColumn column) {
if (_dataGridStateDetails!().allowFiltering && column.allowFiltering) {
- return _filterIconWidth;
+ return _filterIconWidth + column.filterIconPadding.horizontal;
}
return 0.0;
}
@@ -1065,17 +1082,22 @@ class ColumnSizer {
: dataGridConfiguration.container.columnWidths[columnIndex];
final double strokeWidth = _getGridLineStrokeWidth(
- rowIndex: rowIndex, dataGridConfiguration: dataGridConfiguration)
+ rowIndex: rowIndex,
+ dataGridConfiguration: dataGridConfiguration,
+ column: column)
.width;
final double horizontalPadding = column.autoFitPadding.horizontal;
// Removed the padding and gridline stroke width from the column width to
// measure the accurate height for the cell content.
- columnWidth -= _getSortIconWidth(column) +
- _getFilterIconWidth(column) +
- horizontalPadding +
- strokeWidth;
+ double iconsWidth = _getSortIconWidth(column) + _getFilterIconWidth(column);
+
+ if (iconsWidth > 0) {
+ iconsWidth += iconsOuterPadding.horizontal;
+ }
+
+ columnWidth -= iconsWidth + horizontalPadding + strokeWidth;
return _calculateTextSize(
column: column,
@@ -1107,7 +1129,8 @@ class ColumnSizer {
Size _getGridLineStrokeWidth(
{required int rowIndex,
- required DataGridConfiguration dataGridConfiguration}) {
+ required DataGridConfiguration dataGridConfiguration,
+ required GridColumn column}) {
final double strokeWidth =
dataGridConfiguration.dataGridThemeHelper!.gridLineStrokeWidth;
@@ -1116,15 +1139,24 @@ class ColumnSizer {
? dataGridConfiguration.headerGridLinesVisibility
: dataGridConfiguration.gridLinesVisibility;
+ final GridColumn firstVisibleColumn = dataGridConfiguration.columns
+ .firstWhere(
+ (GridColumn column) => column.visible && column.width != 0.0);
+ final bool isFirstColumn =
+ firstVisibleColumn.columnName == column.columnName;
+
switch (gridLinesVisibility) {
case GridLinesVisibility.none:
return Size.zero;
case GridLinesVisibility.both:
- return Size(strokeWidth, strokeWidth);
+ return Size(strokeWidth,
+ rowIndex == 0 ? (strokeWidth + strokeWidth) : strokeWidth);
case GridLinesVisibility.vertical:
- return Size(strokeWidth, 0);
+ return Size(isFirstColumn ? (strokeWidth + strokeWidth) : strokeWidth,
+ rowIndex == 0 ? strokeWidth : 0);
case GridLinesVisibility.horizontal:
- return Size(0, strokeWidth);
+ return Size(isFirstColumn ? strokeWidth : 0,
+ rowIndex == 0 ? (strokeWidth + strokeWidth) : strokeWidth);
}
}
@@ -1145,7 +1177,9 @@ class ColumnSizer {
_dataGridStateDetails!();
final Size strokeWidthSize = _getGridLineStrokeWidth(
- rowIndex: rowIndex, dataGridConfiguration: dataGridConfiguration);
+ rowIndex: rowIndex,
+ dataGridConfiguration: dataGridConfiguration,
+ column: column);
final TextPainter textPainter = TextPainter(
text: TextSpan(text: value?.toString() ?? '', style: textStyle),
@@ -1841,12 +1875,10 @@ class DataGridFilterHelper {
advancedFilterHelper = DataGridAdvancedFilterHelper(_dataGridStateDetails);
}
- /// Checks whether the column is already filtered and needs to use the
- /// previous source without current filter conditions or not.
- bool canUsePreviousSource = false;
-
- /// Checks whether the UI view filtering is applied or not.
- bool isViewFilterAppiled = false;
+ /// Holds the data rows that before apply filtering to the current column.
+ /// Sets the rows when generating the checkbox list view items and use it to
+ /// apply filtering to optimize the filtering instead of filter whole rows again.
+ List _previousDataRows = [];
/// This flag is used to check whether the filtering popup menu is currently
/// showing or not in the view.
@@ -1908,11 +1940,7 @@ class DataGridFilterHelper {
/// Apply filter to the effective rows based on `filterConditions`.
void applyFilter() {
if (_dataGridStateDetails().source.filterConditions.isNotEmpty) {
- if (isViewFilterAppiled) {
- _refreshViewFilter();
- } else {
- _refreshFilter();
- }
+ _refreshFilter();
}
}
@@ -1932,60 +1960,52 @@ class DataGridFilterHelper {
}
}
- /// Applies filtering based on the filter conditions in orders.
- void _refreshViewFilter() {
- final DataGridConfiguration dataGridConfiguration = _dataGridStateDetails();
- final Map> filterConditions =
- dataGridConfiguration.source.filterConditions;
-
- if (filterConditions.isNotEmpty) {
- for (final String columnName in filterConditions.keys) {
- final Map> currentFilterCondition =
- >{
- columnName: filterConditions[columnName]!
- };
-
- final List filteredRows = _getFilterRows(
- dataGridConfiguration.source.effectiveRows, currentFilterCondition);
-
- refreshEffectiveRows(dataGridConfiguration.source, filteredRows);
- }
- }
- }
-
void _createCheckboxFilterConditions(GridColumn column) {
final DataGridSource source = _dataGridStateDetails().source;
if (_unCheckedItemsCount == 0 &&
checkboxFilterHelper._searchedItems.isEmpty) {
- if (source.filterConditions.isNotEmpty) {
- removeFilterConditions(source, column.columnName);
+ // Need to invoke `onFilterChanging` and `onFilterChanged` callback to notify
+ // the filtering changes when tapping `SelectAll` button to select all the
+ // rows in the Checkbox UI filtering.
+ if (source.filterConditions.containsKey(column.columnName)) {
+ if (_invokeFilterChangingCallback(column, [])) {
+ removeFilterConditions(source, column.columnName);
+ } else {
+ return;
+ }
}
} else {
final bool useSelected = !(_checkedItemsCount > _unCheckedItemsCount &&
_unCheckedItemsCount > 0);
- final List conditions = checkboxFilterHelper.items
- .where((FilterElement element) => element.isSelected == useSelected)
- .map((FilterElement value) {
- final FilterType filterType =
- useSelected ? FilterType.equals : FilterType.notEqual;
- final FilterOperator filterOperator =
- useSelected ? FilterOperator.or : FilterOperator.and;
- final String? filterValue =
- value.value == '(Blanks)' ? null : value.value.toString();
-
- return FilterCondition(
- type: filterType,
- isCaseSensitive: true,
- value: filterValue,
- filterBehavior: FilterBehavior.stringDataType,
- filterOperator: filterOperator);
- }).toList();
+ final List conditions = [];
+ for (final FilterElement value in checkboxFilterHelper.items) {
+ if (value.isSelected == useSelected) {
+ final FilterType filterType =
+ useSelected ? FilterType.equals : FilterType.notEqual;
+ FilterOperator filterOperator =
+ useSelected ? FilterOperator.or : FilterOperator.and;
+ final String? filterValue =
+ value.value == '(Blanks)' ? null : value.value.toString();
+
+ // Sets the first filter condition's filter operator as 'AND' to
+ // perform multi-column filtering.
+ if (conditions.isEmpty) {
+ filterOperator = FilterOperator.and;
+ }
+
+ conditions.add(FilterCondition(
+ type: filterType,
+ isCaseSensitive: true,
+ value: filterValue,
+ filterBehavior: FilterBehavior.stringDataType,
+ filterOperator: filterOperator));
+ }
+ }
addFilterConditions(source, column.columnName, conditions);
}
if (source.filterConditions.isEmpty) {
- isViewFilterAppiled = false;
setFilterFrom(column, FilteredFrom.none);
} else {
setFilterFrom(column, FilteredFrom.checkboxFilter);
@@ -2011,6 +2031,11 @@ class DataGridFilterHelper {
/// Format the given cell value to the string data type to display.
String getDisplayValue(Object? value) {
if (value != null) {
+ // Should return if the value defines the blank filter.
+ if (value == '(Blanks)') {
+ return '(Blanks)';
+ }
+
switch (advancedFilterHelper.advancedFilterType) {
case AdvancedFilterType.text:
case AdvancedFilterType.numeric:
@@ -2069,7 +2094,8 @@ class DataGridFilterHelper {
}
final DataGridSource source = dataGridConfiguration.source;
- if (source.filterConditions.isNotEmpty) {
+ // Should avoid the type checking if the `effectiveRows` contains an empty list.
+ if (source.effectiveRows.isNotEmpty && source.filterConditions.isNotEmpty) {
for (final String columnName in source.filterConditions.keys) {
final GridColumn? column = dataGridConfiguration.columns
.firstWhereOrNull(
@@ -2131,10 +2157,10 @@ class DataGridFilterHelper {
_debugCheckDataType(dataGridConfiguration);
if (dataGridConfiguration.source.filterConditions.isNotEmpty) {
- final List rows = dataGridConfiguration.source.effectiveRows;
+ final DataGridSource source = dataGridConfiguration.source;
final List filteredRows =
- _getFilterRows(rows, dataGridConfiguration.source.filterConditions);
- refreshEffectiveRows(dataGridConfiguration.source, filteredRows);
+ _getFilterRows(source.rows, source.filterConditions);
+ refreshEffectiveRows(source, filteredRows);
}
}
@@ -2142,39 +2168,37 @@ class DataGridFilterHelper {
final DataGridSource source = _dataGridStateDetails().source;
if (source.filterConditions.containsKey(column.columnName)) {
- if (!_invokeFilterChangingCallback(
- column, source.filterConditions[column.columnName]!)) {
+ final List? filterConditions =
+ source.filterConditions[column.columnName];
+ if (!_invokeFilterChangingCallback(column, filterConditions!)) {
removeFilterConditions(source, column.columnName);
- if (source.filterConditions.isEmpty) {
- isViewFilterAppiled = false;
- }
return;
}
- final Map> currentFilterCondition =
- >{
- column.columnName: source.filterConditions[column.columnName]!
- };
-
- final List dataGridRows = canUsePreviousSource
- ? _getPreviousFilteredRows(column.columnName)
- : source.effectiveRows;
-
- final List filteredRows =
- _getFilterRows(dataGridRows, currentFilterCondition);
+ List filteredRows = [];
+ if (_previousDataRows.isNotEmpty) {
+ filteredRows = _getFilterRows(
+ _previousDataRows, >{
+ column.columnName: filterConditions
+ });
+ } else {
+ filteredRows = _getFilterRows(source.rows, source.filterConditions);
+ }
- if (canUsePreviousSource) {
- canUsePreviousSource = false;
+ if (_previousDataRows.isNotEmpty) {
+ _previousDataRows.clear();
}
- isViewFilterAppiled = true;
+ // Need to apply sorting to the filtered rows.
+ performSorting(source, filteredRows);
refreshEffectiveRows(source, filteredRows);
+ updateDataPager(source);
notifyDataGridPropertyChangeListeners(source, propertyName: 'Filtering');
- _invokeFilterChangedCallback(
- column, source.filterConditions[column.columnName]!);
+ _invokeFilterChangedCallback(column, filterConditions);
} else {
updateDataSource(source);
notifyDataGridPropertyChangeListeners(source, propertyName: 'Filtering');
+ _invokeFilterChangedCallback(column, []);
}
}
@@ -2186,14 +2210,14 @@ class DataGridFilterHelper {
source.filterConditions[columnName];
if (conditions != null && conditions.isNotEmpty) {
- if (conditions == source.filterConditions.values.last) {
- removeFilterConditions(source, columnName);
- items = source.filterConditions.isEmpty
- ? source.rows
- : _getFilterRows(source.rows, source.filterConditions);
- canUsePreviousSource = true;
- addFilterConditions(source, columnName, conditions);
- }
+ removeFilterConditions(source, columnName);
+ items = source.filterConditions.isEmpty
+ ? source.rows
+ : _getFilterRows(source.rows, source.filterConditions);
+ _previousDataRows = items.toList();
+ addFilterConditions(source, columnName, conditions);
+ } else {
+ _previousDataRows.clear();
}
return items ?? source.effectiveRows;
@@ -2202,15 +2226,23 @@ class DataGridFilterHelper {
List _getCellValues(
GridColumn column, List items) {
bool hasBlankValues = false;
+ final DataGridSource source = _dataGridStateDetails().source;
+ final List conditions =
+ source.filterConditions[column.columnName] ?? [];
+
bool isSelected(Object? value) {
- final List? currentConditions =
- _dataGridStateDetails().source.filterConditions[column.columnName];
- if (currentConditions != null && currentConditions.isNotEmpty) {
- final bool isEquals = currentConditions.first.type == FilterType.equals;
- final FilterCondition? condition = currentConditions.firstWhereOrNull(
- (FilterCondition element) =>
- element.value?.toString() == value?.toString());
- return isEquals ? condition != null : condition == null;
+ if (conditions.isNotEmpty) {
+ // Checkes the previous filtered data rows with current effecive rows to
+ // find selected and unselected items in the checkbox list view.
+ for (final DataGridRow row in source.effectiveRows) {
+ final DataGridCell? cell = row.getCells().firstWhereOrNull(
+ (DataGridCell element) =>
+ element.columnName == column.columnName);
+ if (cell?.value?.toString() == value?.toString()) {
+ return true;
+ }
+ }
+ return false;
}
return true;
}
@@ -2332,13 +2364,10 @@ class DataGridFilterHelper {
setFilterFrom(column, FilteredFrom.none);
removeFilterConditions(dataGridConfiguration.source, column.columnName);
- if (dataGridConfiguration.source.filterConditions.isEmpty) {
- isViewFilterAppiled = false;
- }
-
updateDataSource(dataGridConfiguration.source);
notifyDataGridPropertyChangeListeners(dataGridConfiguration.source,
propertyName: 'Filtering');
+ _invokeFilterChangedCallback(column, []);
}
bool _invokeFilterChangingCallback(
@@ -2382,10 +2411,20 @@ class DataGridFilterHelper {
bool _filterRow(
DataGridRow row, Map> filterConditions) {
bool? isEqual;
+ // Holds the previous column's comparer value of the current row to help to
+ // perform multi-column filtering.
+ bool previousComparer = true;
for (final String columnName in filterConditions.keys) {
for (final FilterCondition condition in filterConditions[columnName]!) {
final Object? cellValue = _getCellValue(row, columnName);
+ // Resets the previous column's comparer value if a column is not
+ // applicable to the multi-column filtering.
+ if (condition == filterConditions[columnName]!.first &&
+ condition.filterOperator == FilterOperator.or) {
+ previousComparer = true;
+ }
+
/// Holds the current filter type result.
bool comparerValue = false;
switch (condition.type) {
@@ -2430,9 +2469,12 @@ class DataGridFilterHelper {
grid_helper.compareLessThan(condition, cellValue, true);
break;
}
- isEqual = grid_helper.compare(
- isEqual, comparerValue, condition.filterOperator);
+
+ isEqual = previousComparer &&
+ grid_helper.compare(
+ isEqual, comparerValue, condition.filterOperator);
}
+ previousComparer = isEqual != null && isEqual;
}
return isEqual != null && isEqual;
}
@@ -2490,6 +2532,11 @@ class DataGridFilterHelper {
return false;
}
+ // Sets the first filter condition's filter operator as 'AND' to perform
+ // multi-column filtering.
+ FilterOperator getFilterOperator() =>
+ filterConditions.isEmpty ? FilterOperator.and : filterOperator;
+
switch (advancedFilterHelper.advancedFilterType) {
case AdvancedFilterType.text:
{
@@ -2497,7 +2544,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue1, filterType1, true)) {
final FilterCondition condition = FilterCondition(
type: type1,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue1,
filterBehavior: FilterBehavior.stringDataType,
isCaseSensitive: advancedFilterHelper.isCaseSensitive1);
@@ -2508,7 +2555,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue2, filterType2, false)) {
final FilterCondition condition = FilterCondition(
type: type2,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue2,
filterBehavior: FilterBehavior.stringDataType,
isCaseSensitive: advancedFilterHelper.isCaseSensitive2);
@@ -2522,7 +2569,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue1, filterType1, true)) {
final FilterCondition condition = FilterCondition(
type: type1,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue1);
filterConditions.add(condition);
}
@@ -2531,7 +2578,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue2, filterType2, false)) {
final FilterCondition condition = FilterCondition(
type: type2,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue2);
filterConditions.add(condition);
}
@@ -2543,7 +2590,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue1, filterType1, true)) {
final FilterCondition condition = FilterCondition(
type: type1,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue1);
filterConditions.add(condition);
}
@@ -2552,7 +2599,7 @@ class DataGridFilterHelper {
if (canCreateFilterCondition(filterValue2, filterType2, false)) {
final FilterCondition condition = FilterCondition(
type: type2,
- filterOperator: filterOperator,
+ filterOperator: getFilterOperator(),
value: advancedFilterHelper.filterValue2);
filterConditions.add(condition);
}
@@ -2837,9 +2884,9 @@ class DataGridAdvancedFilterHelper {
isOrPredicate = condition.filterOperator == FilterOperator.or;
}
- firstValueTextController.text = dataGridConfiguration.dataGridFilterHelper
+ firstValueTextController.text = dataGridConfiguration.dataGridFilterHelper!
.getDisplayValue(filterValue1);
- secondValueTextController.text = dataGridConfiguration.dataGridFilterHelper
+ secondValueTextController.text = dataGridConfiguration.dataGridFilterHelper!
.getDisplayValue(filterValue2);
}
@@ -2867,3 +2914,26 @@ class FilterElement {
/// Defines the check box state of the cell.
bool isSelected;
}
+
+/// Controls how the filtering menu options can be customized.
+@immutable
+class FilterPopupMenuOptions {
+ ///
+ const FilterPopupMenuOptions(
+ {this.filterMode = FilterMode.both,
+ this.canShowClearFilterOption = true,
+ this.canShowSortingOptions = true,
+ this.showColumnName = true});
+
+ /// Decides how the checked listbox and advanced filter options should be shown in filter popup.
+ final FilterMode filterMode;
+
+ /// Decides whether the `Clear Filter From {Column Name}` option should be displayed in filtering popup.
+ final bool canShowClearFilterOption;
+
+ /// Decides whether the ascending and descending sorting options should be displayed in filtering popup.
+ final bool canShowSortingOptions;
+
+ /// Decides whether the column name should be displayed along with the content of `Clear Filter` option .
+ final bool showColumnName;
+}
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/selection/selection_manager.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/selection/selection_manager.dart
index 3a5175662..675167621 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/selection/selection_manager.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/selection/selection_manager.dart
@@ -156,6 +156,9 @@ class RowSelectionManager extends SelectionManagerBase {
_addSelection(record, dataGridConfiguration);
} else {
_clearSelectedRow(dataGridConfiguration);
+ if (dataGridConfiguration.navigationMode == GridNavigationMode.cell) {
+ _clearCurrentCell(dataGridConfiguration);
+ }
}
notifyListeners();
@@ -618,10 +621,16 @@ class RowSelectionManager extends SelectionManagerBase {
dataGridConfiguration.selectionMode != SelectionMode.multiple;
//If newValue is negative we have clear the whole selection data.
- //In multiple case we shouldn't to clear the collection as well
- // source properties.
- if (newValue == null && canClearSelections()) {
- _clearSelectedRow(dataGridConfiguration);
+ if (newValue == null && _selectedRows.isNotEmpty) {
+ // If selection mode is multiple we need to clear all the selected rows.
+ if (dataGridConfiguration.selectionMode == SelectionMode.multiple) {
+ _clearSelectedRows(dataGridConfiguration);
+ } else {
+ _clearSelectedRow(dataGridConfiguration);
+ }
+ if (dataGridConfiguration.navigationMode == GridNavigationMode.cell) {
+ _clearCurrentCell(dataGridConfiguration);
+ }
notifyListeners();
return;
}
@@ -679,10 +688,21 @@ class RowSelectionManager extends SelectionManagerBase {
dataGridConfiguration.selectionMode != SelectionMode.multiple;
//If newValue is negative we have to clear the whole selection data.
- //In multiple case we shouldn't to clear the collection as
- // well source properties.
- if (newValue == -1 && canClearSelections()) {
- _clearSelectedRow(dataGridConfiguration);
+ if (newValue == -1 && _selectedRows.isNotEmpty) {
+ // If selection mode is multiple we need to clear all the selected rows.
+ if (dataGridConfiguration.selectionMode == SelectionMode.multiple) {
+ _clearSelectedRows(dataGridConfiguration);
+ } else {
+ _clearSelectedRow(dataGridConfiguration);
+ }
+
+ // Issue:
+ // FLUT-7123-The current cell is not removed when setting the selected index as -1 through the SelectionController
+ // We removed the selected rows only when setting the selected index as -1 from the controller
+ // We have resolved the issue by removing the current cell too.
+ if (dataGridConfiguration.navigationMode == GridNavigationMode.cell) {
+ _clearCurrentCell(dataGridConfiguration);
+ }
notifyListeners();
return;
}
@@ -1481,8 +1501,11 @@ class CurrentCellManager {
return null;
}
- return dataRows
- .firstWhereOrNull((DataRowBase row) => row.rowIndex == rowIndex);
+ // If attempt to obtain a current row after calling the `refreshView` method,
+ // all the row indexes will be -1 in the `items` collection. So, need to
+ // consider the `isCurrentRow` property additionally to get the current row.
+ return dataRows.firstWhereOrNull(
+ (DataRowBase row) => row.rowIndex == rowIndex || row.isCurrentRow);
}
DataCellBase? _getDataCell(DataRowBase dataRow, int columnIndex) {
@@ -1710,21 +1733,39 @@ class CurrentCellManager {
return;
}
+ // In programmatic begin edit, need to update current cell when the
+ // dataCell doesn't contain the proper current cell index. So, we commonly
+ // update the current cell here for programmatic and F2 key to begin edit
+ // the cell.
+ void setCurrentCell() {
+ final DataRowBase? dataRow =
+ _getDataRow(dataGridConfiguration, editingRowColumnIndex!.rowIndex);
+ if (dataRow != null) {
+ dataCell = _getDataCell(dataRow, editingRowColumnIndex.columnIndex);
+ } else {
+ return;
+ }
+ }
+
// If the editing is initiate from f2 key, need not to process the
// handleTap.
if (needToResolveIndex) {
dataGridConfiguration.rowSelectionManager
.handleTap(editingRowColumnIndex);
+
+ // In programmatic begin edit, if the `editingRowColumnIndex` has valid
+ // row and column index and the current cell has a previous current cell
+ // value, need to update the current cell based on the
+ // `editingRowColumnIndex` property.
+ if (dataCell != null &&
+ !editingRowColumnIndex.equals(
+ RowColumnIndex(dataCell!.rowIndex, dataCell!.columnIndex))) {
+ setCurrentCell();
+ }
} else {
// Need to skip the editing when current cell is not in view and we
// process initiate the editing from f2 key.
- final DataRowBase? dataRow =
- _getDataRow(dataGridConfiguration, editingRowColumnIndex.rowIndex);
- if (dataRow != null) {
- dataCell = _getDataCell(dataRow, editingRowColumnIndex.columnIndex);
- } else {
- return;
- }
+ setCurrentCell();
}
editingDataCell = dataCell;
@@ -1772,9 +1813,14 @@ class CurrentCellManager {
/// So, we need to request the focus here.
/// Also, if we return false from the canSubmitCell method and tap other cells
/// We need to retain the focus on the text field instead of losing focus.
+ ///
+ // Issue:
+ // FLUT-7120-The focus did not go to the other widgets when DataGrid's current cell is in edit mode.
+ // We have checked whether the current cell is editing or not based on the `isCurrentCellInEditing` property.
+ // In this case, it is true. So we fixed it by checking the value of the `canCellSumbit` method.
if (!_focusScopeNode.hasFocus &&
!dataGridConfiguration.dataGridFocusNode!.hasFocus &&
- dataGridConfiguration.controller.isCurrentCellInEditing) {
+ !canSubmitCell(dataGridConfiguration)) {
_focusScopeNode.requestFocus();
}
},
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart
index e34497e9f..185af41dc 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/sfdatagrid.dart
@@ -460,6 +460,7 @@ class SfDataGrid extends StatefulWidget {
this.allowFiltering = false,
this.onFilterChanging,
this.onFilterChanged,
+ this.checkboxShape,
}) : assert(frozenColumnsCount >= 0),
assert(footerFrozenColumnsCount >= 0),
assert(frozenRowsCount >= 0),
@@ -1582,6 +1583,15 @@ class SfDataGrid extends StatefulWidget {
/// programmatically.
final DataGridFilterChangedCallback? onFilterChanged;
+ /// The shape of the checkbox.
+ ///
+ /// This is applicable for checkbox which is shown when enable the [showCheckboxColumn] property.
+ ///
+ /// See also,
+ ///
+ /// [Checkbox.shape]
+ final OutlinedBorder? checkboxShape;
+
@override
State createState() => SfDataGridState();
}
@@ -1630,6 +1640,9 @@ class SfDataGridState extends State
duration: const Duration(milliseconds: 200), vsync: this);
_setUp();
_updateDataGridStateDetails();
+
+ // To perform sort and filter operations based on the `DataGridSource`.
+ updateDataSource(_dataGridConfiguration.source);
super.initState();
}
@@ -1715,7 +1728,7 @@ class SfDataGridState extends State
_localizations = newLocalizations;
_dataGridConfiguration
..localizations = newLocalizations
- ..dataGridFilterHelper.advancedFilterHelper.initProperties();
+ ..dataGridFilterHelper!.advancedFilterHelper.initProperties();
}
}
@@ -1734,7 +1747,10 @@ class SfDataGridState extends State
}
void _setUp() {
- _initializeDataGridDataSource();
+ // Initializes the source
+ _source = widget.source.._dataGridStateDetails = _dataGridStateDetails;
+ _addDataGridSourceListeners();
+
_initializeCellRendererCollection();
//DataGrid Controller
@@ -1780,11 +1796,6 @@ class SfDataGridState extends State
ColumnResizeController(dataGridStateDetails: _dataGridStateDetails!);
_initializeProperties();
-
- // Apply filter on initial loading.
- if (_dataGridConfiguration.source._filterConditions.isNotEmpty) {
- _dataGridConfiguration.dataGridFilterHelper.applyFilter();
- }
}
@protected
@@ -1979,10 +1990,6 @@ class SfDataGridState extends State
_resetColumn();
}
- if (_dataGridConfiguration.source._filterConditions.isNotEmpty) {
- _dataGridConfiguration.dataGridFilterHelper.applyFilter();
- }
-
if (widget.selectionMode != SelectionMode.none)
selection_manager.removeUnWantedDataGridRows(_dataGridConfiguration);
if (widget.selectionMode != SelectionMode.none &&
@@ -2321,7 +2328,8 @@ class SfDataGridState extends State
..dataGridThemeHelper = _dataGridThemeHelper
..allowFiltering = widget.allowFiltering
..onFilterChanging = widget.onFilterChanging
- ..onFilterChanged = widget.onFilterChanged;
+ ..onFilterChanged = widget.onFilterChanged
+ ..checkboxShape = widget.checkboxShape;
if (widget.allowPullToRefresh) {
_dataGridConfiguration.refreshIndicatorKey ??=
@@ -2390,6 +2398,8 @@ class SfDataGridState extends State
// To apply filtering to the runtime changes of columns.
final bool canApplyFiltering =
isColumnsChanged && _columns!.length != widget.columns.length;
+ final bool isFilteringChanged =
+ oldWidget.allowFiltering != widget.allowFiltering;
if (oldWidget.verticalScrollController != widget.verticalScrollController) {
if (widget.verticalScrollController != null) {
@@ -2506,11 +2516,13 @@ class SfDataGridState extends State
isSwipingChanged ||
isFooterRowChanged ||
isTableSummaryRowsChanged ||
+ isFilteringChanged ||
oldWidget.rowHeight != widget.rowHeight ||
oldWidget.headerRowHeight != widget.headerRowHeight ||
oldWidget.defaultColumnWidth != widget.defaultColumnWidth ||
oldWidget.navigationMode != widget.navigationMode ||
oldWidget.showCheckboxColumn != widget.showCheckboxColumn ||
+ oldWidget.checkboxShape != widget.checkboxShape ||
oldWidget.rowsCacheExtent != widget.rowsCacheExtent ||
isRowsPerPageChanged) {
// Need to endEdit before refreshing
@@ -2519,7 +2531,7 @@ class SfDataGridState extends State
// Need to initialize the data source when the `isColumnsCollectionChanged`
// property is true to adapt the `DataGridRow.cells` changes that made by
// the user based on the `columns` collection changes.
- if (isSourceChanged || isColumnsCollectionChanged) {
+ if (isSourceChanged || isColumnsCollectionChanged || canApplyFiltering) {
_initializeDataGridDataSource();
}
if (isSortingChanged || isMultiColumnSortingChanged) {
@@ -2556,10 +2568,6 @@ class SfDataGridState extends State
_initializeProperties();
- if (canApplyFiltering) {
- _dataGridConfiguration.dataGridFilterHelper.applyFilter();
- }
-
if (isStackedHeaderRowsChanged || isColumnsChanged) {
_onStackedHeaderRowsPropertyChanged(oldWidget, widget);
}
@@ -2586,16 +2594,37 @@ class SfDataGridState extends State
isColumnsChanged ||
isColumnSizerChanged ||
isFrozenColumnPaneChanged ||
- isSortingChanged ||
isStackedHeaderRowsChanged ||
oldWidget.showCheckboxColumn != widget.showCheckboxColumn ||
+ oldWidget.checkboxShape != widget.checkboxShape) {
+ _resetColumn(clearEditing: false);
+ if (isColumnSizerChanged) {
+ resetAutoCalculation(_dataGridConfiguration.columnSizer);
+ }
+ }
+
+ // Need to reset the auto calculation when sorting, filtering or show
+ // sort number properties are changed at runtime. then only, the auto-width
+ // calculation will be calculated for all the columns again. Otherwise,
+ // all the columns will retain the previously calculated width.
+ if (isSortingChanged ||
+ isFilteringChanged ||
widget.allowSorting && isMultiColumnSortingChanged ||
widget.allowSorting &&
widget.allowMultiColumnSorting &&
isShowSortNumbersChanged) {
- _resetColumn(clearEditing: false);
- if (isColumnSizerChanged) {
- resetAutoCalculation(_dataGridConfiguration.columnSizer);
+ // To reset the auto width calculation.
+ resetAutoCalculation(_dataGridConfiguration.columnSizer);
+
+ final DataRowBase? dataRow = _rowGenerator.items.firstWhereOrNull(
+ (DataRowBase element) => element.rowType == RowType.headerRow);
+ // To refresh the header row to update the sort and filter icon changes
+ // in the header cells.
+ if (dataRow != null) {
+ for (final DataCellBase dataCell in dataRow.visibleColumns) {
+ dataCell.columnIndex = -1;
+ }
+ _container.needToRefreshColumn = true;
}
}
@@ -2852,9 +2881,9 @@ class SfDataGridState extends State
_screenSize ??= currentScreenSize;
if (_screenSize != currentScreenSize &&
_dataGridConfiguration
- .dataGridFilterHelper.isFilterPopupMenuShowing) {
+ .dataGridFilterHelper!.isFilterPopupMenuShowing) {
Navigator.pop(context);
- _dataGridConfiguration.dataGridFilterHelper.isFilterPopupMenuShowing =
+ _dataGridConfiguration.dataGridFilterHelper!.isFilterPopupMenuShowing =
false;
}
_screenSize = currentScreenSize;
@@ -2909,7 +2938,20 @@ class SfDataGridState extends State
@override
void dispose() {
_removeDataGridSourceListeners();
- _controller?.removeListener(_handleDataGridPropertyChangeListeners);
+
+ // Issue:
+ // FLUT-7056 - The dataGridPropertyChanged listener is not removed properly
+ // when DataGrid is disposed
+ //
+ // Fix:
+ // The issue occurred due to we didn't remove the listener properly.
+ // It's added to `_dataGridPropertyChangeListeners` but we didn't remove it from the _dataGridPropertyChangeListeners.
+ // We have fixed the issue by removing the respective listener from the_dataGridPropertyChangeListeners
+ // through the _removeDataGridPropertyChangeListener method.
+ _controller?._removeDataGridPropertyChangeListener(
+ _handleDataGridPropertyChangeListeners);
+ _controller?._removeDataGridPropertyChangeListener(
+ _handleSelectionPropertyChanged);
_dataGridConfiguration
..gridPaint = null
..boxPainter = null
@@ -2919,10 +2961,10 @@ class SfDataGridState extends State
_swipingAnimationController!.dispose();
_swipingAnimationController = null;
}
- _dataGridConfiguration.dataGridFilterHelper.checkboxFilterHelper
+ _dataGridConfiguration.dataGridFilterHelper!.checkboxFilterHelper
..textController.dispose()
..searchboxFocusNode.dispose();
- _dataGridConfiguration.dataGridFilterHelper.advancedFilterHelper
+ _dataGridConfiguration.dataGridFilterHelper!.advancedFilterHelper
..firstValueTextController.dispose()
..secondValueTextController.dispose();
super.dispose();
@@ -3152,10 +3194,10 @@ abstract class DataGridSource extends DataGridSourceChangeNotifier
});
}
- /// To update the sorted collection in _paginatedRows, notifyListener should be
+ /// To update the sorted or filtered collection in _paginatedRows, notifyListener should be
/// called instead notifyDataGridPropertyChangeListener. Because, notifyListener is common for
/// in DataPagerDelegate and DataGridSource will get notified.
- void _updateDataPagerOnSorting() {
+ void _updateDataPager() {
if (_pageCount > 0 &&
_paginatedRows.isNotEmpty &&
!_suspendDataPagerUpdate) {
@@ -3291,17 +3333,20 @@ abstract class DataGridSource extends DataGridSourceChangeNotifier
} else {
_effectiveRows = rows;
}
- // Should refresh sorting when the data grid source is updated.
- performSorting(_effectiveRows);
// Should refresh filtering when the filterConditions is not empty.
- if (_filterConditions.isNotEmpty) {
- _dataGridStateDetails!().dataGridFilterHelper.applyFilter();
+ if (_dataGridStateDetails != null &&
+ _dataGridStateDetails!().dataGridFilterHelper != null &&
+ _filterConditions.isNotEmpty) {
+ _dataGridStateDetails!().dataGridFilterHelper!.applyFilter();
}
- /// Helps to update the sorted collection in _paginatedRows
- /// by call the DataPagerDelegate.handlePageChange after sorting.
- _updateDataPagerOnSorting();
+ // Should refresh sorting when the data grid source is updated.
+ performSorting(_effectiveRows);
+
+ /// Helps to update the sorted or filtered collection in _paginatedRows
+ /// by call the DataPagerDelegate.handlePageChange after sorting or filtering.
+ _updateDataPager();
}
/// Call this method when you are adding the [SortColumnDetails]
@@ -3406,7 +3451,9 @@ abstract class DataGridSource extends DataGridSourceChangeNotifier
_filterConditions[columnName] = conditions;
- _refreshFilter(_dataGridStateDetails!());
+ if (_dataGridStateDetails != null) {
+ _refreshFilter(_dataGridStateDetails!());
+ }
}
/// Remove the [FilterCondition] from the given column.
@@ -3449,7 +3496,9 @@ abstract class DataGridSource extends DataGridSourceChangeNotifier
_filterConditions[columnName] = conditions;
}
- _refreshFilter(_dataGridStateDetails!());
+ if (_dataGridStateDetails != null) {
+ _refreshFilter(_dataGridStateDetails!());
+ }
}
/// Clear the [FilterCondition] from a given column or clear all the filter
@@ -3484,10 +3533,14 @@ abstract class DataGridSource extends DataGridSourceChangeNotifier
if (_filterConditions.isNotEmpty) {
if (columnName != null && _filterConditions.containsKey(columnName)) {
_filterConditions.remove(columnName);
- _refreshFilter(_dataGridStateDetails!());
+ if (_dataGridStateDetails != null) {
+ _refreshFilter(_dataGridStateDetails!());
+ }
} else if (columnName == null) {
_filterConditions.clear();
- _refreshFilter(_dataGridStateDetails!());
+ if (_dataGridStateDetails != null) {
+ _refreshFilter(_dataGridStateDetails!());
+ }
}
}
}
@@ -3734,6 +3787,17 @@ void refreshEffectiveRows(DataGridSource source, List filterRows) {
source._effectiveRows = filterRows;
}
+/// Apply sorting to the given rows. It is used to invoke the
+/// `DataGridSource.performSorting` method internally.
+void performSorting(DataGridSource source, List rows) {
+ source.performSorting(rows);
+}
+
+/// Helps to refresh the data pager.
+void updateDataPager(DataGridSource source) {
+ source._updateDataPager();
+}
+
/// Controls a [SfDataGrid] widget.
///
/// This can be used to control the selection and current-cell operations such
@@ -4282,6 +4346,12 @@ class DataGridThemeHelper {
fontSize: 14,
color: colorScheme!.onSurface.withOpacity(0.87));
sortIcon = dataGridThemeData.sortIcon;
+ filterIcon = dataGridThemeData.filterIcon;
+ filterIconColor = dataGridThemeData.filterIconColor;
+ filterIconHoverColor = dataGridThemeData.filterIconHoverColor;
+ sortOrderNumberColor = dataGridThemeData.sortOrderNumberColor;
+ sortOrderNumberBackgroundColor =
+ dataGridThemeData.sortOrderNumberBackgroundColor;
}
///ToDo
@@ -4344,4 +4414,79 @@ class DataGridThemeHelper {
/// To do
late Widget? sortIcon;
+
+ /// The icon to indicate the filtering applied in column.
+ ///
+ /// If you want to change the icon filter or filtered state, you can use the [Builder]
+ /// widget and return the respective icon for the state. You have to return
+ /// the icons for both the states even if you want to change the icon
+ /// for specific state.
+ ///
+ /// ```dart
+ /// @override
+ /// Widget build(BuildContext context) {
+ /// return Scaffold(
+ /// appBar: AppBar(
+ /// title: const Text('Syncfusion Flutter DataGrid',
+ /// overflow: TextOverflow.ellipsis),
+ /// ),
+ /// body: SfDataGridTheme(
+ /// data: SfDataGridThemeData(filterIcon: Builder(
+ /// builder: (context) {
+ /// Widget? icon;
+ /// String columnName = '';
+ /// context.visitAncestorElements((element) {
+ /// if (element is GridHeaderCellElement) {
+ /// columnName = element.column.columnName;
+ /// }
+ /// return true;
+ /// });
+ /// var column = _employeeDataSource.filterConditions.keys
+ /// .where((element) => element == columnName)
+ /// .firstOrNull;
+
+ /// if (column != null) {
+ /// icon = const Icon(
+ /// Icons.filter_alt_outlined,
+ /// size: 20,
+ /// color: Colors.purple,
+ /// );
+ /// }
+ /// return icon ??
+ /// const Icon(
+ /// Icons.filter_alt_off_outlined,
+ /// size: 20,
+ /// color: Colors.deepOrange,
+ /// );
+ /// },
+ /// )),
+ /// child: SfDataGrid(
+ /// source: _employeeDataSource,
+ /// allowFiltering: true,
+ /// allowSorting: true,
+ /// columns: getColumns(),
+ /// ),
+ /// ),
+ /// );
+ /// }
+ /// ```
+ late Widget? filterIcon;
+
+ /// The color of the filter icon which indicates whether the column is filtered or not.
+ ///
+ /// This is not applicable when `filterIcon` property is set.
+ /// This applies the color to default filter icon only.
+ late Color? filterIconColor;
+
+ /// The color for the filter icon when a pointer is hovering over it.
+ ///
+ /// This is not applicable when `filterIcon` property is set.
+ /// This applies the color to default filter icon only.
+ late Color? filterIconHoverColor;
+
+ /// The color of the number displayed when the order of the sorting is shown.
+ late Color? sortOrderNumberColor;
+
+ /// Creates a copy of this theme but with the given fields replaced with the new values.
+ late Color? sortOrderNumberBackgroundColor;
}
diff --git a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart
index 92a632669..0ba269bce 100644
--- a/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart
+++ b/packages/syncfusion_flutter_datagrid/lib/src/datagrid_widget/widgets/cell_widget.dart
@@ -386,10 +386,12 @@ class _GridHeaderCellState extends State {
final int sortNumber =
dataGridConfiguration.source.sortedColumns.indexOf(sortColumn) + 1;
_sortDirection = sortColumn.sortDirection;
- _sortNumberBackgroundColor =
+ _sortNumberBackgroundColor = dataGridConfiguration
+ .dataGridThemeHelper!.sortOrderNumberBackgroundColor ??
dataGridConfiguration.colorScheme!.onSurface.withOpacity(0.12);
_sortNumberTextColor =
- dataGridConfiguration.colorScheme!.onSurface.withOpacity(0.87);
+ dataGridConfiguration.dataGridThemeHelper!.sortOrderNumberColor ??
+ dataGridConfiguration.colorScheme!.onSurface.withOpacity(0.87);
if (dataGridConfiguration.source.sortedColumns.length > 1 &&
dataGridConfiguration.showSortNumbers) {
_sortNumber = sortNumber;
@@ -466,7 +468,7 @@ class _GridHeaderCellState extends State {
child: Container(child: child),
),
Container(
- padding: const EdgeInsets.only(left: 4.0, right: 4.0),
+ padding: dataGridConfiguration.columnSizer.iconsOuterPadding,
child: Center(child: Row(children: children)),
)
]);
@@ -726,34 +728,49 @@ class _FilterIcon extends StatelessWidget {
return GestureDetector(
onTapUp: (TapUpDetails details) => onHandleTap(details, context),
child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
+ padding: column.filterIconPadding,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return MouseRegion(
- onEnter: (PointerEnterEvent details) {
+ onEnter: (_) {
setState(() {
isHovered = true;
});
},
- onExit: (PointerExitEvent details) {
+ onExit: (_) {
setState(() {
isHovered = false;
});
},
- child: Icon(
- isFiltered
- ? const IconData(0xe704,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid')
- : const IconData(0xe702,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid'),
- size: 18.0,
- color: isHovered
- ? dataGridConfiguration.colorScheme!.onSurface
- .withOpacity(0.87)
- : dataGridConfiguration.dataGridFilterHelper.iconColor,
- ),
+ child: isFiltered
+ ? _FilteredIcon(
+ iconColor: isHovered
+ ? (dataGridConfiguration
+ .dataGridThemeHelper!.filterIconHoverColor ??
+ dataGridConfiguration.colorScheme!.onSurface
+ .withOpacity(0.87))
+ : (dataGridConfiguration
+ .dataGridThemeHelper!.filterIconColor ??
+ dataGridConfiguration
+ .dataGridFilterHelper!.iconColor),
+ filterIcon:
+ dataGridConfiguration.dataGridThemeHelper!.filterIcon,
+ gridColumnName: column.columnName,
+ )
+ : _UnfilteredIcon(
+ iconColor: isHovered
+ ? (dataGridConfiguration
+ .dataGridThemeHelper!.filterIconHoverColor ??
+ dataGridConfiguration.colorScheme!.onSurface
+ .withOpacity(0.87))
+ : (dataGridConfiguration
+ .dataGridThemeHelper!.filterIconColor ??
+ dataGridConfiguration
+ .dataGridFilterHelper!.iconColor),
+ filterIcon:
+ dataGridConfiguration.dataGridThemeHelper!.filterIcon,
+ gridColumnName: column.columnName,
+ ),
);
}),
),
@@ -761,6 +778,60 @@ class _FilterIcon extends StatelessWidget {
}
}
+class _UnfilteredIcon extends StatelessWidget {
+ const _UnfilteredIcon(
+ {Key? key,
+ required this.iconColor,
+ required this.filterIcon,
+ required this.gridColumnName})
+ : super(key: key);
+
+ final Color iconColor;
+ final Widget? filterIcon;
+ final String? gridColumnName;
+
+ @override
+ Widget build(BuildContext context) {
+ return filterIcon ??
+ Icon(
+ const IconData(0xe702,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid'),
+ size: 18.0,
+ color: iconColor,
+ key: ValueKey(
+ 'datagrid_filtering_${gridColumnName}_filterIcon'),
+ );
+ }
+}
+
+class _FilteredIcon extends StatelessWidget {
+ const _FilteredIcon(
+ {Key? key,
+ required this.iconColor,
+ required this.filterIcon,
+ required this.gridColumnName})
+ : super(key: key);
+
+ final Color iconColor;
+ final Widget? filterIcon;
+ final String? gridColumnName;
+
+ @override
+ Widget build(BuildContext context) {
+ return filterIcon ??
+ Icon(
+ const IconData(0xe704,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid'),
+ size: 18.0,
+ color: iconColor,
+ key: ValueKey(
+ 'datagrid_filtering_${gridColumnName}_filterIcon'),
+ );
+ }
+}
+
class _FilterPopupMenuItem extends PopupMenuItem {
const _FilterPopupMenuItem(
{required this.column, required this.dataGridConfiguration})
@@ -845,7 +916,7 @@ class _FilterPopupState extends State<_FilterPopup> {
void _initializeFilterProperties() {
isMobile = !widget.dataGridConfiguration.isDesktop;
- filterHelper = widget.dataGridConfiguration.dataGridFilterHelper;
+ filterHelper = widget.dataGridConfiguration.dataGridFilterHelper!;
filterHelper.filterFrom = filterHelper.getFilterForm(widget.column);
isAdvancedFilter = filterHelper.filterFrom == FilteredFrom.advancedFilter;
filterHelper.checkboxFilterHelper.textController.clear();
@@ -891,6 +962,7 @@ class _FilterPopupState extends State<_FilterPopup> {
child: Container(height: 1.0, color: filterHelper.borderColor)),
backgroundColor: filterHelper.backgroundColor,
leading: IconButton(
+ key: const ValueKey('datagrid_filtering_cancelFilter_icon'),
onPressed: closePage,
icon: Icon(Icons.close, size: 22.0, color: filterHelper.iconColor)),
centerTitle: false,
@@ -901,6 +973,7 @@ class _FilterPopupState extends State<_FilterPopup> {
style: filterHelper.textStyle),
actions: [
IconButton(
+ key: const ValueKey('datagrid_filtering_applyFilter_icon'),
onPressed: canDisableOkButton() ? null : onHandleOkButtonTap,
icon: Icon(Icons.check,
size: 22.0,
@@ -925,106 +998,152 @@ class _FilterPopupState extends State<_FilterPopup> {
final bool isSortDescendingEnabled =
canEnableSortButton(DataGridSortDirection.descending);
final bool isClearFilterEnabled = hasFilterConditions();
+ const FilterPopupMenuOptions filterPopupMenuOptions =
+ FilterPopupMenuOptions();
+ bool isCheckboxFilterEnabled =
+ filterPopupMenuOptions.filterMode == FilterMode.checkboxFilter;
+ bool isAdvancedFilterEnabled =
+ filterPopupMenuOptions.filterMode == FilterMode.advancedFilter;
+ bool isBothFilterEnabled =
+ filterPopupMenuOptions.filterMode == FilterMode.both;
+ bool canShowSortingOptions = filterPopupMenuOptions.canShowSortingOptions;
+ bool canShowClearFilterOption =
+ filterPopupMenuOptions.canShowClearFilterOption;
+ bool showColumnName = filterPopupMenuOptions.showColumnName;
+ double advanceFilterTopPadding = 12;
+
+ if (widget.column.filterPopupMenuOptions != null) {
+ isCheckboxFilterEnabled =
+ widget.column.filterPopupMenuOptions!.filterMode ==
+ FilterMode.checkboxFilter;
+ isAdvancedFilterEnabled =
+ widget.column.filterPopupMenuOptions!.filterMode ==
+ FilterMode.advancedFilter;
+ isBothFilterEnabled =
+ widget.column.filterPopupMenuOptions!.filterMode == FilterMode.both;
+ canShowSortingOptions =
+ widget.column.filterPopupMenuOptions!.canShowSortingOptions;
+ canShowClearFilterOption =
+ widget.column.filterPopupMenuOptions!.canShowClearFilterOption;
+ showColumnName = widget.column.filterPopupMenuOptions!.showColumnName;
+ }
Widget buildPopup({Size? viewSize}) {
return SingleChildScrollView(
+ key: const ValueKey('datagrid_filtering_scrollView'),
child: Container(
width: isMobile ? null : 274.0,
color: filterHelper.backgroundColor,
child: Column(
children: [
- _FilterPopupMenuTile(
- style: isSortAscendingEnabled
+ if (canShowSortingOptions)
+ _FilterPopupMenuTile(
+ style: isSortAscendingEnabled
+ ? filterHelper.textStyle
+ : filterHelper.disableTextStyle,
+ height: filterHelper.tileHeight,
+ prefix: Icon(
+ const IconData(0xe700,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid'),
+ color: isSortAscendingEnabled
+ ? iconColor
+ : filterHelper.disableIconColor),
+ prefixPadding:
+ const EdgeInsets.only(left: 4.0, right: 14.0),
+ onTap: isSortAscendingEnabled
+ ? onHandleSortAscendingTap
+ : null,
+ child: Text(grid_helper.getSortButtonText(
+ localizations, true, filterType))),
+ if (canShowSortingOptions)
+ _FilterPopupMenuTile(
+ style: isSortDescendingEnabled
? filterHelper.textStyle
: filterHelper.disableTextStyle,
height: filterHelper.tileHeight,
prefix: Icon(
- const IconData(0xe700,
+ const IconData(0xe701,
fontFamily: 'FilterIcon',
fontPackage: 'syncfusion_flutter_datagrid'),
- color: isSortAscendingEnabled
+ color: isSortDescendingEnabled
? iconColor
: filterHelper.disableIconColor),
prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
- onTap:
- isSortAscendingEnabled ? onHandleSortAscendingTap : null,
+ onTap: isSortDescendingEnabled
+ ? onHandleSortDescendingTap
+ : null,
child: Text(grid_helper.getSortButtonText(
- localizations, true, filterType))),
- _FilterPopupMenuTile(
- style: isSortDescendingEnabled
- ? filterHelper.textStyle
- : filterHelper.disableTextStyle,
- height: filterHelper.tileHeight,
- prefix: Icon(
- const IconData(0xe701,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid'),
- color: isSortDescendingEnabled
- ? iconColor
- : filterHelper.disableIconColor),
- prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
- onTap:
- isSortDescendingEnabled ? onHandleSortDescendingTap : null,
- child: Text(grid_helper.getSortButtonText(
- localizations, false, filterType)),
- ),
- const Divider(indent: 8.0, endIndent: 8.0),
- _FilterPopupMenuTile(
- style: isClearFilterEnabled
- ? filterHelper.textStyle
- : filterHelper.disableTextStyle,
- height: filterHelper.tileHeight,
- prefix: Icon(
- const IconData(0xe703,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid'),
- size: 22.0,
- color: isClearFilterEnabled
- ? iconColor
- : filterHelper.disableIconColor),
- prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
- onTap: isClearFilterEnabled ? onHandleClearFilterTap : null,
- child: Text(getClearFilterText(localizations),
- overflow: TextOverflow.ellipsis),
- ),
- _FilterPopupMenuTile(
- style: filterHelper.textStyle,
- height: filterHelper.tileHeight,
- onTap: onHandleExpansionTileTap,
- prefix: Icon(
- filterHelper.getFilterForm(widget.column) ==
- FilteredFrom.advancedFilter
- ? const IconData(0xe704,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid')
- : const IconData(0xe702,
- fontFamily: 'FilterIcon',
- fontPackage: 'syncfusion_flutter_datagrid'),
- size: 20.0,
- color: iconColor),
- suffix: Icon(
- isAdvancedFilter
- ? Icons.keyboard_arrow_down
- : Icons.keyboard_arrow_right,
- size: 20.0,
- color: iconColor),
- prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
- child: Text(
- grid_helper.getFilterTileText(localizations, filterType)),
- ),
- Visibility(
- visible: isAdvancedFilter,
- replacement: _CheckboxFilterMenu(
- column: widget.column,
- setState: setState,
- viewSize: viewSize,
- dataGridConfiguration: widget.dataGridConfiguration,
+ localizations, false, filterType)),
),
- child: _AdvancedFilterPopupMenu(
+ if (canShowSortingOptions)
+ const Divider(indent: 8.0, endIndent: 8.0),
+ if (canShowClearFilterOption)
+ _FilterPopupMenuTile(
+ style: isClearFilterEnabled
+ ? filterHelper.textStyle
+ : filterHelper.disableTextStyle,
+ height: filterHelper.tileHeight,
+ prefix: Icon(
+ const IconData(0xe703,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid'),
+ size: 22.0,
+ color: isClearFilterEnabled
+ ? iconColor
+ : filterHelper.disableIconColor),
+ prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
+ onTap: isClearFilterEnabled ? onHandleClearFilterTap : null,
+ child: Text(getClearFilterText(localizations, showColumnName),
+ overflow: TextOverflow.ellipsis),
+ ),
+ if (isAdvancedFilterEnabled)
+ _AdvancedFilterPopupMenu(
setState: setState,
dataGridConfiguration: widget.dataGridConfiguration,
+ advanceFilterTopPadding: advanceFilterTopPadding,
+ ),
+ if (isBothFilterEnabled)
+ _FilterPopupMenuTile(
+ style: filterHelper.textStyle,
+ height: filterHelper.tileHeight,
+ onTap: onHandleExpansionTileTap,
+ prefix: Icon(
+ filterHelper.getFilterForm(widget.column) ==
+ FilteredFrom.advancedFilter
+ ? const IconData(0xe704,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid')
+ : const IconData(0xe702,
+ fontFamily: 'FilterIcon',
+ fontPackage: 'syncfusion_flutter_datagrid'),
+ size: 20.0,
+ color: iconColor),
+ suffix: Icon(
+ isAdvancedFilter
+ ? Icons.keyboard_arrow_down
+ : Icons.keyboard_arrow_right,
+ size: 20.0,
+ color: iconColor),
+ prefixPadding: const EdgeInsets.only(left: 4.0, right: 14.0),
+ child: Text(
+ grid_helper.getFilterTileText(localizations, filterType)),
+ ),
+ if (isCheckboxFilterEnabled || isBothFilterEnabled)
+ Visibility(
+ visible: isAdvancedFilter,
+ replacement: _CheckboxFilterMenu(
+ column: widget.column,
+ setState: setState,
+ viewSize: viewSize,
+ dataGridConfiguration: widget.dataGridConfiguration,
+ ),
+ child: _AdvancedFilterPopupMenu(
+ setState: setState,
+ dataGridConfiguration: widget.dataGridConfiguration,
+ advanceFilterTopPadding: advanceFilterTopPadding,
+ ),
),
- ),
if (!isMobile) const Divider(height: 10),
if (!isMobile)
Padding(
@@ -1063,6 +1182,15 @@ class _FilterPopupState extends State<_FilterPopup> {
);
}
+ if (isAdvancedFilterEnabled) {
+ isAdvancedFilter = true;
+ }
+ if (isAdvancedFilterEnabled &&
+ !canShowClearFilterOption &&
+ !canShowSortingOptions) {
+ advanceFilterTopPadding = 6;
+ }
+
if (isMobile) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constrainsts) =>
@@ -1139,8 +1267,12 @@ class _FilterPopupState extends State<_FilterPopup> {
return false;
}
- String getClearFilterText(SfLocalizations localization) {
- return '${localization.clearFilterFromDataGridFilteringLabel} "${widget.column.columnName}"';
+ String getClearFilterText(SfLocalizations localization, bool showColumnName) {
+ if (showColumnName) {
+ return '${localization.clearFilterDataGridFilteringLabel} ${localization.fromDataGridFilteringLabel} "${widget.column.columnName}"';
+ } else {
+ return localization.clearFilterDataGridFilteringLabel;
+ }
}
}
@@ -1261,7 +1393,7 @@ class _CheckboxFilterMenu extends StatelessWidget {
}
DataGridCheckboxFilterHelper get filterHelper {
- return dataGridConfiguration.dataGridFilterHelper.checkboxFilterHelper;
+ return dataGridConfiguration.dataGridFilterHelper!.checkboxFilterHelper;
}
@override
@@ -1278,12 +1410,31 @@ class _CheckboxFilterMenu extends StatelessWidget {
Widget _buildCheckboxListView(BuildContext context) {
final DataGridFilterHelper helper =
- dataGridConfiguration.dataGridFilterHelper;
+ dataGridConfiguration.dataGridFilterHelper!;
+
+ // 340.0 it's a occupied height in the current view by the other widgets.
+ double occupiedHeight = 340.0;
+
+ // Need to set the Checkbox Filter height in the mobile platform
+ // based on the options enabled in the Filter popup menu
+ if (column.filterPopupMenuOptions != null && isMobile) {
+ if (!column.filterPopupMenuOptions!.canShowSortingOptions) {
+ // 16.0 is the height of the divider shown below the sorting options
+ occupiedHeight -= (helper.tileHeight * 2) + 16.0;
+ }
+ if (!column.filterPopupMenuOptions!.canShowClearFilterOption) {
+ occupiedHeight -= helper.tileHeight;
+ }
+ if (column.filterPopupMenuOptions!.filterMode ==
+ FilterMode.checkboxFilter) {
+ occupiedHeight -= helper.tileHeight;
+ }
+ }
+
// Gets the remaining height of the current view to fill the checkbox
- // listview in the mobile platform. 340.0 it's a occupied height in the
- // current view by the other widgets.
+ // listview in the mobile platform.
final double checkboxHeight =
- isMobile ? max(viewSize!.height - 340.0, 120.0) : 200.0;
+ isMobile ? max(viewSize!.height - occupiedHeight, 120.0) : 200.0;
final double selectAllButtonHeight = isMobile ? 48.0 : 40.0;
return Padding(
@@ -1323,6 +1474,8 @@ class _CheckboxFilterMenu extends StatelessWidget {
SizedBox(
height: checkboxHeight,
child: ListView.builder(
+ key: const ValueKey(
+ 'datagrid_filtering_checkbox_listView'),
prototypeItem: buildCheckboxTile(
filterHelper.items.length - 1, helper.textStyle),
itemCount: filterHelper.items.length,
@@ -1338,12 +1491,11 @@ class _CheckboxFilterMenu extends StatelessWidget {
Widget _buildSearchBox(Color onSurface, BuildContext context) {
final DataGridFilterHelper helper =
- dataGridConfiguration.dataGridFilterHelper;
+ dataGridConfiguration.dataGridFilterHelper!;
void onSearchboxSubmitted(String value) {
if (filterHelper.items.isNotEmpty) {
- dataGridConfiguration.dataGridFilterHelper
- .createFilterConditions(true, column);
+ helper.createFilterConditions(true, column);
Navigator.pop(context);
} else {
filterHelper.searchboxFocusNode.requestFocus();
@@ -1355,6 +1507,7 @@ class _CheckboxFilterMenu extends StatelessWidget {
child: SizedBox(
height: isMobile ? 52.0 : 36.0,
child: TextField(
+ key: const ValueKey('datagrid_filtering_search_textfield'),
focusNode: filterHelper.searchboxFocusNode,
controller: filterHelper.textController,
onChanged: onHandleSearchTextFieldChanged,
@@ -1365,6 +1518,8 @@ class _CheckboxFilterMenu extends StatelessWidget {
suffixIcon: Visibility(
visible: filterHelper.textController.text.isEmpty,
replacement: IconButton(
+ key: const ValueKey(
+ 'datagrid_filtering_clearSearch_icon'),
iconSize: 22.0,
padding: EdgeInsets.zero,
constraints: const BoxConstraints.tightFor(
@@ -1391,7 +1546,7 @@ class _CheckboxFilterMenu extends StatelessWidget {
Widget? buildCheckboxTile(int index, TextStyle style) {
if (filterHelper.items.isNotEmpty) {
final FilterElement element = filterHelper.items[index];
- final String displayText = dataGridConfiguration.dataGridFilterHelper
+ final String displayText = dataGridConfiguration.dataGridFilterHelper!
.getDisplayValue(element.value);
return _FilterPopupMenuTile(
style: style,
@@ -1433,25 +1588,30 @@ class _CheckboxFilterMenu extends StatelessWidget {
class _AdvancedFilterPopupMenu extends StatelessWidget {
const _AdvancedFilterPopupMenu(
- {Key? key, required this.setState, required this.dataGridConfiguration})
+ {Key? key,
+ required this.setState,
+ required this.dataGridConfiguration,
+ required this.advanceFilterTopPadding})
: super(key: key);
final StateSetter setState;
final DataGridConfiguration dataGridConfiguration;
+ final double advanceFilterTopPadding;
+
bool get isMobile {
return !dataGridConfiguration.isDesktop;
}
DataGridAdvancedFilterHelper get filterHelper {
- return dataGridConfiguration.dataGridFilterHelper.advancedFilterHelper;
+ return dataGridConfiguration.dataGridFilterHelper!.advancedFilterHelper;
}
@override
Widget build(BuildContext context) {
final DataGridFilterHelper helper =
- dataGridConfiguration.dataGridFilterHelper;
+ dataGridConfiguration.dataGridFilterHelper!;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
@@ -1459,7 +1619,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
children: [
_FilterMenuDropdown(
height: 16.0,
- padding: const EdgeInsets.only(top: 12.0, bottom: 8.0),
+ padding: EdgeInsets.only(top: advanceFilterTopPadding, bottom: 8.0),
child: Text(
'${dataGridConfiguration.localizations.showRowsWhereDataGridFilteringLabel}:',
style: TextStyle(
@@ -1495,7 +1655,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
Widget _buildRadioButtons() {
final DataGridFilterHelper helper =
- dataGridConfiguration.dataGridFilterHelper;
+ dataGridConfiguration.dataGridFilterHelper!;
final SfLocalizations localizations = dataGridConfiguration.localizations;
void handleChanged(bool? value) {
@@ -1510,6 +1670,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
SizedBox.fromSize(
size: const Size(24.0, 24.0),
child: Radio(
+ key: const ValueKey('datagrid_filtering_and_button'),
value: false,
activeColor: helper.primaryColor,
onChanged: handleChanged,
@@ -1523,6 +1684,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
SizedBox.fromSize(
size: const Size(24.0, 24.0),
child: Radio(
+ key: const ValueKey('datagrid_filtering_or_button'),
value: true,
activeColor: helper.primaryColor,
onChanged: handleChanged,
@@ -1537,7 +1699,7 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
Widget _buildFilterValueDropdown({required bool isTopButton}) {
final DataGridFilterHelper helper =
- dataGridConfiguration.dataGridFilterHelper;
+ dataGridConfiguration.dataGridFilterHelper!;
void setValue(Object? value) {
if (isTopButton) {
@@ -1572,6 +1734,11 @@ class _AdvancedFilterPopupMenu extends StatelessWidget {
Widget buildDropdownFormField() {
return DropdownButtonHideUnderline(
child: DropdownButtonFormField