├── .github └── workflows │ └── flutter-test.yml ├── .gitignore ├── .metadata ├── .run ├── charts_web.run.xml └── example.run.xml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── assets ├── bar_chart_animating.gif ├── chart_image.png ├── fixed_axis_scroll_chart.gif ├── line_chart_animating.gif ├── scrollable_chart.gif └── showcase.gif ├── charts_web ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── charts_web │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ ├── font │ │ ├── InterTight-Light.ttf │ │ ├── InterTight-Medium.ttf │ │ ├── InterTight-Regular.ttf │ │ └── InterTight-SemiBold.ttf │ ├── png │ │ ├── futurama1.jpeg │ │ ├── futurama2.jpeg │ │ ├── futurama4.jpeg │ │ ├── futurama5.jpeg │ │ ├── futurama_small.png │ │ ├── general_grid_decoration_golden.png │ │ ├── general_horizontal_decoration_golden.png │ │ ├── general_sparkline_decoration_golden.png │ │ └── general_vertical_decoration_golden.png │ └── svg │ │ ├── bar_chart_icon.svg │ │ ├── bubble_chart_icon.svg │ │ ├── deco_background.svg │ │ ├── deco_foreground.svg │ │ ├── line_no.svg │ │ ├── line_yes.svg │ │ ├── showcase.svg │ │ ├── smoothed_no.svg │ │ ├── smoothed_yes.svg │ │ ├── strategy default.svg │ │ └── strategy stack.svg ├── lib │ ├── assets.gen.dart │ ├── fonts.gen.dart │ ├── main.dart │ └── ui │ │ ├── common │ │ ├── dialog │ │ │ ├── border_dialog.dart │ │ │ ├── border_radius_dialog.dart │ │ │ ├── color_picker_dialog.dart │ │ │ └── gradient_dialog.dart │ │ ├── respo │ │ │ ├── respo.dart │ │ │ └── respo.freezed.dart │ │ └── widget │ │ │ ├── double_option_input.dart │ │ │ └── switch_with_image.dart │ │ └── home │ │ ├── chart_options │ │ ├── chart_options.dart │ │ └── widget │ │ │ ├── futurama_bar_widget.dart │ │ │ ├── options_component_header.dart │ │ │ ├── options_data_component.dart │ │ │ ├── options_decoration_component.dart │ │ │ └── options_items_component.dart │ │ ├── decorations │ │ ├── common_decoration_box.dart │ │ ├── decorations_horizontal_axis.dart │ │ ├── decorations_sparkline.dart │ │ ├── decorations_vertical_axis.dart │ │ ├── decorations_widget.dart │ │ └── presenters │ │ │ ├── decorations_horizontal_axis_presenter.dart │ │ │ ├── decorations_sparkline_presenter.dart │ │ │ ├── decorations_vertical_axis_presenter.dart │ │ │ └── decorations_widget_presenter.dart │ │ ├── home_screen.dart │ │ └── presenter │ │ ├── chart_decorations_presenter.dart │ │ └── chart_state_presenter.dart ├── pubspec.yaml ├── test │ └── widget_test.dart └── web │ ├── .nojekyll │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ ├── Icon-maskable-512.png │ └── chart_image.png │ ├── index.html │ ├── manifest.json │ └── style.css ├── dart_test.yaml ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── png │ │ ├── futurama1.jpeg │ │ ├── futurama2.jpeg │ │ ├── futurama4.jpeg │ │ ├── futurama5.jpeg │ │ └── futurama_small.png ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── Runner-Bridging-Header.h ├── lib │ ├── chart_types.dart │ ├── charts │ │ ├── bar_chart_screen.dart │ │ ├── bar_target_chart_screen.dart │ │ ├── bubble_chart_screen.dart │ │ ├── candle_chart_screen.dart │ │ ├── ios_charts_screen.dart │ │ ├── line_chart_screen.dart │ │ ├── migration_chart_screen.dart │ │ ├── multi_bar_chart_screen.dart │ │ ├── multi_bar_widget_chart_screen.dart │ │ ├── scrollable_chart_screen.dart │ │ ├── scrollable_visible_items_chart_screen.dart │ │ └── showcase_chart_screen.dart │ ├── click_test.dart │ ├── complex │ │ └── complex_charts.dart │ ├── issue_repro.dart │ ├── main.dart │ ├── showcase │ │ ├── ios_charts.dart │ │ └── showcase_charts.dart │ └── widgets │ │ ├── bar_chart.dart │ │ ├── bubble_chart.dart │ │ ├── candle_chart.dart │ │ ├── chart_options.dart │ │ ├── counter_item.dart │ │ ├── line_chart.dart │ │ └── toggle_item.dart ├── pubspec.yaml └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json ├── lib ├── chart.dart └── chart │ ├── model │ ├── chart_state.dart │ ├── data │ │ └── chart_data.dart │ ├── data_strategy │ │ ├── data_strategy.dart │ │ ├── default_data_strategy.dart │ │ └── stack_data_strategy.dart │ ├── geometry │ │ ├── bar_value_item.dart │ │ ├── bubble_value_item.dart │ │ ├── candle_value_item.dart │ │ └── chart_item.dart │ └── theme │ │ ├── chart_behaviour.dart │ │ ├── item_theme │ │ ├── bar │ │ │ ├── bar_item.dart │ │ │ └── bar_item_options.dart │ │ ├── bubble │ │ │ ├── bubble_item.dart │ │ │ └── bubble_item_options.dart │ │ ├── draw_data_item.dart │ │ ├── item_builder_data.dart │ │ ├── item_options.dart │ │ └── widget │ │ │ └── widget_item_options.dart │ │ └── scroll_settings.dart │ ├── render │ ├── chart_renderer.dart │ ├── data_renderer │ │ ├── chart_data_renderer.dart │ │ └── chart_linear_data_renderer.dart │ ├── decorations │ │ ├── border_decoration.dart │ │ ├── decoration_painter.dart │ │ ├── grid_decoration.dart │ │ ├── horizontal_axis_decoration.dart │ │ ├── renderer │ │ │ ├── chart_decoration_child_renderer.dart │ │ │ ├── chart_decoration_renderer.dart │ │ │ └── decorations_renderer.dart │ │ ├── selected_item_decoration.dart │ │ ├── spark_line_decoration.dart │ │ ├── target_decoration.dart │ │ ├── target_legends_decoration.dart │ │ ├── value_decoration.dart │ │ ├── vertical_axis_decoration.dart │ │ └── widget_decoration.dart │ ├── geometry │ │ ├── child_item_renderer.dart │ │ ├── leaf_item_renderer.dart │ │ └── painters │ │ │ ├── bar_geometry_painter.dart │ │ │ ├── bubble_geometry_painter.dart │ │ │ ├── empty_geometry_painter.dart │ │ │ └── geometry_painter.dart │ └── util │ │ └── dashed_path_util.dart │ └── widgets │ ├── animated_chart.dart │ ├── chart.dart │ └── chart_widget.dart ├── pubspec.yaml └── test ├── flutter_test_config.dart ├── golden ├── GOLDENS.md ├── complex │ ├── goldens │ │ ├── ci │ │ │ ├── complex_multi_charts.png │ │ │ └── showcase_charts.png │ │ └── macos │ │ │ ├── complex_multi_charts.png │ │ │ └── showcase_charts.png │ ├── multi_value_test.dart │ └── showcase_test.dart ├── decoration │ ├── border_decoration_test.dart │ ├── general_golden_test.dart │ ├── goldens │ │ ├── ci │ │ │ ├── border_decoration_golden.png │ │ │ ├── general_border_decoration_golden.png │ │ │ ├── general_grid_decoration_golden.png │ │ │ ├── general_horizontal_decoration_golden.png │ │ │ ├── general_selected_item_decoration_golden.png │ │ │ ├── general_sparkline_decoration_golden.png │ │ │ ├── general_target_area_decoration_golden.png │ │ │ ├── general_target_line_decoration_golden.png │ │ │ ├── general_target_line_text_decoration_golden.png │ │ │ ├── general_vertical_decoration_golden.png │ │ │ ├── grid_decoration_golden.png │ │ │ ├── horizontal_decoration_golden.png │ │ │ ├── sparkline_decoration_golden.png │ │ │ ├── vertical_decoration_golden.png │ │ │ └── widget_decoration_golden.png │ │ └── macos │ │ │ ├── border_decoration_golden.png │ │ │ ├── general_border_decoration_golden.png │ │ │ ├── general_grid_decoration_golden.png │ │ │ ├── general_horizontal_decoration_golden.png │ │ │ ├── general_selected_item_decoration_golden.png │ │ │ ├── general_sparkline_decoration_golden.png │ │ │ ├── general_target_area_decoration_golden.png │ │ │ ├── general_target_line_decoration_golden.png │ │ │ ├── general_target_line_text_decoration_golden.png │ │ │ ├── general_vertical_decoration_golden.png │ │ │ ├── grid_decoration_golden.png │ │ │ ├── horizontal_decoration_golden.png │ │ │ ├── sparkline_decoration_golden.png │ │ │ ├── vertical_decoration_golden.png │ │ │ └── widget_decoration_golden.png │ ├── grid_decoration_test.dart │ ├── horizontal_decoration_test.dart │ ├── sparkline_decoration_test.dart │ ├── vertical_decoration_test.dart │ └── widget_decoration_test.dart ├── examples │ ├── example_golden_test.dart │ └── goldens │ │ ├── ci │ │ ├── bar_chart.png │ │ ├── line_chart.png │ │ ├── multi_line_chart.png │ │ ├── simple_bar_chart.png │ │ └── simple_line_chart.png │ │ └── macos │ │ ├── bar_chart.png │ │ ├── line_chart.png │ │ ├── multi_line_chart.png │ │ ├── simple_bar_chart.png │ │ └── simple_line_chart.png ├── geometry │ ├── geometry_golden_test.dart │ └── goldens │ │ ├── ci │ │ ├── bar_geometry_golden.png │ │ ├── bubble_geometry_golden.png │ │ ├── candle_geometry_golden.png │ │ └── widget_geometry_golden.png │ │ └── macos │ │ ├── bar_geometry_golden.png │ │ ├── bubble_geometry_golden.png │ │ ├── candle_geometry_golden.png │ │ └── widget_geometry_golden.png └── util.dart └── unit ├── chart_animation_test.dart ├── chart_data_test.dart └── chart_state_test.dart /.github/workflows/flutter-test.yml: -------------------------------------------------------------------------------- 1 | name: flutter-test 2 | 3 | on: 4 | push: 5 | branches: [ "*" ] 6 | pull_request: 7 | branches: [ "*" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: subosito/flutter-action@v1 16 | - run: flutter doctor 17 | - run: flutter analyze lib/ 18 | - run: flutter test --dart-define=CI=true 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # VSCode related 19 | .vscode/ 20 | 21 | ### Flutter ### 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .flutter-plugins-dependencies 27 | .fvm/ 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | coverage/ 33 | lib/generated_plugin_registrant.dart 34 | # For library packages, don’t commit the pubspec.lock file. 35 | # Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. 36 | # See https://dart.dev/guides/libraries/private-files#pubspeclock 37 | pubspec.lock 38 | 39 | # don't check in golden failure output 40 | **/failures/*.png 41 | 42 | # Android related 43 | **/android/**/gradle-wrapper.jar 44 | **/android/.gradle 45 | **/android/captures/ 46 | **/android/gradlew 47 | **/android/gradlew.bat 48 | **/android/local.properties 49 | **/android/**/GeneratedPluginRegistrant.java 50 | 51 | # iOS/XCode related 52 | **/ios/**/*.mode1v3 53 | **/ios/**/*.mode2v3 54 | **/ios/**/*.moved-aside 55 | **/ios/**/*.pbxuser 56 | **/ios/**/*.perspectivev3 57 | **/ios/**/*sync/ 58 | **/ios/**/.sconsign.dblite 59 | **/ios/**/.tags* 60 | **/ios/**/.vagrant/ 61 | **/ios/**/DerivedData/ 62 | **/ios/**/Icon? 63 | **/ios/**/Pods/ 64 | **/ios/**/.symlinks/ 65 | **/ios/**/profile 66 | **/ios/**/xcuserdata 67 | **/ios/.generated/ 68 | **/ios/Flutter/App.framework 69 | **/ios/Flutter/Flutter.framework 70 | **/ios/Flutter/Flutter.podspec 71 | **/ios/Flutter/Generated.xcconfig 72 | **/ios/Flutter/app.flx 73 | **/ios/Flutter/app.zip 74 | **/ios/Flutter/flutter_assets/ 75 | **/ios/Flutter/flutter_export_environment.sh 76 | **/ios/ServiceDefinitions.json 77 | **/ios/Runner/GeneratedPluginRegistrant.* 78 | 79 | # Exceptions to above rules. 80 | !**/ios/**/default.mode1v3 81 | !**/ios/**/default.mode2v3 82 | !**/ios/**/default.pbxuser 83 | !**/ios/**/default.perspectivev3 84 | 85 | example/*.skp 86 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /.run/charts_web.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.run/example.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [3.1.0] - 15.02.2023 2 | * Added a screenshot 3 | * Fixed VerticalAxisDecoration padding 4 | * Fixed item width for WidgetItemOptions 5 | * Add onHover states to ChartBehavior 6 | * Add ScrollSettings to ChartBehavior to control number of visible items when in scroll mode 7 | 8 | 9 | 10 | ## [3.0.0] - 02.11.2022 11 | * Introduction of WidgetItemOptions and WidgetDecoration 12 | * ChartState: data and itemOptions are now required named parameters 13 | * New item options builder parameter 14 | * Deprecated: BarValue, BubbleValue,TargetLineDecoration, TargetLineTextDecoration, 15 | TargetAreaDecoration, BorderDecoration, SelectedItemDecoration, ValueDecoration 16 | * multiItemStack moved to DefaultDataStrategy stackMultipleValues 17 | * Fix: Add alignment to chart items when max item size is set 18 | * Migration guide: https://github.com/infinum/flutter-charts/wiki/Migration-guide-to-3.0 19 | 20 | ## [2.0.0+2] - 05.04.2022. 21 | * Reduce final .apk app size when using this lib 22 | * Fixed `ValueDecoration` when all items were 0 23 | * Add value label generator in `ValueDecoration` 24 | * Add show the line for value to `HorizontalDecoration` for more precise control of when to show horizontal line 25 | * Fix gradient color on `SparkLineDecoration` 26 | * Fix fixed horizontal decoration values getting clipped 27 | 28 | ## [2.0.0+1] - 01.03.2022. 29 | * Updated packages 30 | * Removed flutter_path_drawing dependency 31 | * Selected item can be shown on value 32 | 33 | ## [2.0.0] - 30.11.2021. 34 | **This release has some breaking changes. You might have to update existing charts code!** 35 | 36 | * Migrate the lib to use custom render objects instead of CustomPainters 37 | * Extend DataStrategy from enum to abstract class, extending it to manipulate data further 38 | * Removed options from Charts, they are now part of ChartData or ItemOptions 39 | * Update README with more examples and possibilities 40 | 41 | ## [1.1.0] - 12.05.2021. 42 | 43 | * Migrate to null safety 44 | 45 | ## [1.0.0+1] - 26.02.2021. 46 | 47 | * Formatting fixes 48 | 49 | ## [1.0.0] - 25.02.2021. 50 | 51 | * Initial release 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Infinum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:lints/recommended.yaml 2 | 3 | # Specify analysis options. 4 | # 5 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 6 | # See: https://github.com/dart-lang/linter/issues/288 7 | # 8 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 9 | # See the configuration guide for more 10 | # https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer 11 | # 12 | # There are other similar analysis options files in the flutter repos, 13 | # which should be kept in sync with this file: 14 | # 15 | # - analysis_options.yaml (this file) 16 | # - packages/flutter/lib/analysis_options_user.yaml 17 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 18 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 19 | # 20 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 21 | # Android Studio, and the `flutter analyze` command. 22 | 23 | analyzer: 24 | strong-mode: 25 | implicit-casts: false 26 | implicit-dynamic: false 27 | errors: 28 | avoid_function_literals_in_foreach_calls: ignore 29 | no_leading_underscores_for_local_identifiers: ignore 30 | library_private_types_in_public_api: ignore 31 | # treat missing required parameters as a warning (not a hint) 32 | missing_required_param: warning 33 | # treat missing returns as a warning (not a hint) 34 | missing_return: warning 35 | # allow having TODOs in the code 36 | todo: ignore 37 | # Ignore analyzer hints for updating pubspecs when using Future or 38 | # Stream and not importing dart:async 39 | # Please see https://github.com/flutter/flutter/pull/24528 for details. 40 | sdk_version_async_exported_from_core: ignore 41 | exclude: 42 | - "bin/cache/**" 43 | - "lib/assets.dart" 44 | # - "example/**" 45 | # - "charts_web/**" 46 | -------------------------------------------------------------------------------- /assets/bar_chart_animating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/bar_chart_animating.gif -------------------------------------------------------------------------------- /assets/chart_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/chart_image.png -------------------------------------------------------------------------------- /assets/fixed_axis_scroll_chart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/fixed_axis_scroll_chart.gif -------------------------------------------------------------------------------- /assets/line_chart_animating.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/line_chart_animating.gif -------------------------------------------------------------------------------- /assets/scrollable_chart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/scrollable_chart.gif -------------------------------------------------------------------------------- /assets/showcase.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/assets/showcase.gif -------------------------------------------------------------------------------- /charts_web/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Android Studio will place build artifacts here 43 | /android/app/debug 44 | /android/app/profile 45 | /android/app/release 46 | 47 | # FVM related 48 | .fvm/* 49 | !.fvm/fvm_config.json 50 | -------------------------------------------------------------------------------- /charts_web/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7c9d327e5eac69b1ddb10902f0cc5bb5b7911d4e 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /charts_web/README.md: -------------------------------------------------------------------------------- 1 | # charts_web 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /charts_web/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /charts_web/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /charts_web/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion flutter.compileSdkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.example.charts_web" 47 | minSdkVersion flutter.minSdkVersion 48 | targetSdkVersion flutter.targetSdkVersion 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /charts_web/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/kotlin/com/example/charts_web/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.charts_web 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /charts_web/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /charts_web/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /charts_web/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /charts_web/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /charts_web/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /charts_web/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /charts_web/assets/font/InterTight-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/font/InterTight-Light.ttf -------------------------------------------------------------------------------- /charts_web/assets/font/InterTight-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/font/InterTight-Medium.ttf -------------------------------------------------------------------------------- /charts_web/assets/font/InterTight-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/font/InterTight-Regular.ttf -------------------------------------------------------------------------------- /charts_web/assets/font/InterTight-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/font/InterTight-SemiBold.ttf -------------------------------------------------------------------------------- /charts_web/assets/png/futurama1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/futurama1.jpeg -------------------------------------------------------------------------------- /charts_web/assets/png/futurama2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/futurama2.jpeg -------------------------------------------------------------------------------- /charts_web/assets/png/futurama4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/futurama4.jpeg -------------------------------------------------------------------------------- /charts_web/assets/png/futurama5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/futurama5.jpeg -------------------------------------------------------------------------------- /charts_web/assets/png/futurama_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/futurama_small.png -------------------------------------------------------------------------------- /charts_web/assets/png/general_grid_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/general_grid_decoration_golden.png -------------------------------------------------------------------------------- /charts_web/assets/png/general_horizontal_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/general_horizontal_decoration_golden.png -------------------------------------------------------------------------------- /charts_web/assets/png/general_sparkline_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/general_sparkline_decoration_golden.png -------------------------------------------------------------------------------- /charts_web/assets/png/general_vertical_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/assets/png/general_vertical_decoration_golden.png -------------------------------------------------------------------------------- /charts_web/assets/svg/bar_chart_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /charts_web/assets/svg/bubble_chart_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /charts_web/assets/svg/deco_background.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /charts_web/assets/svg/deco_foreground.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /charts_web/assets/svg/line_no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /charts_web/assets/svg/line_yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /charts_web/assets/svg/showcase.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /charts_web/assets/svg/smoothed_no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /charts_web/assets/svg/smoothed_yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /charts_web/assets/svg/strategy default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /charts_web/assets/svg/strategy stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /charts_web/lib/fonts.gen.dart: -------------------------------------------------------------------------------- 1 | /// GENERATED CODE - DO NOT MODIFY BY HAND 2 | /// ***************************************************** 3 | /// FlutterGen 4 | /// ***************************************************** 5 | 6 | // coverage:ignore-file 7 | // ignore_for_file: type=lint 8 | // ignore_for_file: directives_ordering,unnecessary_import 9 | 10 | class FontFamily { 11 | FontFamily._(); 12 | 13 | /// Font family: InterTight 14 | static const String interTight = 'InterTight'; 15 | } 16 | -------------------------------------------------------------------------------- /charts_web/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_web/ui/common/respo/respo.dart'; 2 | import 'package:charts_web/ui/home/home_screen.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | void main() { 7 | runApp(const ProviderScope(child: MyApp())); 8 | } 9 | 10 | class MyApp extends StatelessWidget { 11 | const MyApp({Key? key}) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return MaterialApp( 16 | title: 'Flutter Demo', 17 | theme: ThemeData( 18 | fontFamily: 'InterTight', 19 | primarySwatch: Colors.red, 20 | ), 21 | builder: _builder, 22 | home: HomeScreen(), 23 | ); 24 | } 25 | } 26 | 27 | Widget _builder(BuildContext context, Widget? child) { 28 | return Respo(child: child ?? const SizedBox.shrink()); 29 | } 30 | -------------------------------------------------------------------------------- /charts_web/lib/ui/common/dialog/color_picker_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flex_color_picker/flex_color_picker.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class ColorPickerDialog extends StatelessWidget { 5 | const ColorPickerDialog( 6 | {Key? key, required this.startColor, this.additionalText}) 7 | : super(key: key); 8 | 9 | static Future show(BuildContext context, Color startColor, 10 | {String? additionalText}) { 11 | return showDialog( 12 | context: context, 13 | builder: (_) { 14 | return AlertDialog( 15 | content: ColorPickerDialog( 16 | startColor: startColor, additionalText: additionalText), 17 | ); 18 | }); 19 | } 20 | 21 | final Color startColor; 22 | final String? additionalText; 23 | 24 | @override 25 | Widget build(BuildContext context) { 26 | return SizedBox( 27 | width: double.infinity, 28 | child: Padding( 29 | padding: const EdgeInsets.all(6), 30 | child: Column( 31 | mainAxisSize: MainAxisSize.min, 32 | children: [ 33 | Text( 34 | 'In this editor you can select only colors from given pallete. Any color can be given in code.\n$additionalText'), 35 | const SizedBox(height: 16), 36 | ColorPicker( 37 | color: startColor, 38 | // Update the screenPickerColor using the callback. 39 | onColorChanged: (Color color) { 40 | Navigator.of(context).pop(color); 41 | }, 42 | width: 44, 43 | height: 44, 44 | enableShadesSelection: false, 45 | pickersEnabled: const { 46 | ColorPickerType.primary: true, 47 | ColorPickerType.accent: false 48 | }, 49 | borderRadius: 22, 50 | heading: Text( 51 | 'Select color', 52 | style: Theme.of(context).textTheme.headlineSmall, 53 | ), 54 | subheading: Text( 55 | 'Select color shade', 56 | style: Theme.of(context).textTheme.titleSmall, 57 | ), 58 | ), 59 | ], 60 | ), 61 | ), 62 | ); 63 | } 64 | } 65 | 66 | String colorToCode(Color color) { 67 | return 'Color.fromARGB(${color.alpha}, ${color.red}, ${color.green}, ${color.blue})'; 68 | } 69 | -------------------------------------------------------------------------------- /charts_web/lib/ui/common/widget/switch_with_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_svg/svg.dart'; 3 | 4 | class SwitchWithImage extends StatelessWidget { 5 | const SwitchWithImage({ 6 | Key? key, 7 | required this.value, 8 | required this.onChanged, 9 | required this.title1, 10 | required this.title2, 11 | this.subtitle, 12 | required this.image1, 13 | required this.image2, 14 | }) : super(key: key); 15 | 16 | final bool value; 17 | final ValueChanged? onChanged; 18 | 19 | final String title1; 20 | final String title2; 21 | final String? subtitle; 22 | 23 | final String image1; 24 | final String image2; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | return Stack( 29 | children: [ 30 | SwitchListTile( 31 | value: value, 32 | title: Text(value ? title1 : title2), 33 | subtitle: subtitle != null ? Text(subtitle!) : null, 34 | onChanged: onChanged, 35 | ), 36 | Positioned( 37 | right: 8, 38 | top: 2, 39 | child: IgnorePointer( 40 | child: Container( 41 | decoration: BoxDecoration( 42 | borderRadius: BorderRadius.circular(8), 43 | color: const Color(0xffdedede), 44 | ), 45 | height: subtitle != null ? 60 : 45, 46 | width: subtitle != null ? 60 : 45, 47 | margin: EdgeInsets.only(right: subtitle != null ? 4 : 14), 48 | padding: const EdgeInsets.only(bottom: 4), 49 | alignment: Alignment.center, 50 | child: SvgPicture.asset( 51 | value ? image1 : image2, 52 | height: 40, 53 | ), 54 | ), 55 | ), 56 | ) 57 | ], 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/chart_options/chart_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_web/assets.gen.dart'; 2 | import 'package:charts_web/ui/home/chart_options/widget/options_data_component.dart'; 3 | import 'package:charts_web/ui/home/chart_options/widget/options_decoration_component.dart'; 4 | import 'package:charts_web/ui/home/chart_options/widget/options_items_component.dart'; 5 | import 'package:example/main.dart'; 6 | import 'package:flutter/cupertino.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_svg/flutter_svg.dart'; 9 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 10 | 11 | class ChartOptions extends HookConsumerWidget { 12 | @override 13 | Widget build(BuildContext context, WidgetRef ref) { 14 | return Container( 15 | margin: const EdgeInsets.all(24.0), 16 | child: Column( 17 | mainAxisSize: MainAxisSize.min, 18 | crossAxisAlignment: CrossAxisAlignment.start, 19 | children: [ 20 | Text( 21 | 'Welcome to charts_painter playground. Here we exposed some options to see what kind of charts you can build. Make sure to check showcase for more examples.', 22 | style: Theme.of(context).textTheme.bodyText1, 23 | ), 24 | const SizedBox(height: 16), 25 | CupertinoButton.filled( 26 | child: Row( 27 | children: [ 28 | Opacity( 29 | opacity: 0.8, 30 | child: SvgPicture.asset(Assets.svg.showcase, width: 50)), 31 | const SizedBox(width: 16), 32 | const Text('Showcase'), 33 | ], 34 | ), 35 | padding: const EdgeInsets.all(24), 36 | onPressed: () { 37 | Navigator.of(context) 38 | .push(MaterialPageRoute(builder: (_) => ChartDemo())); 39 | }, 40 | ), 41 | const SizedBox(height: 24), 42 | const OptionsDataComponent(), 43 | const SizedBox(height: 16), 44 | const OptionsItemsComponent(), 45 | const SizedBox(height: 16), 46 | const DecorationsComponent(), 47 | ], 48 | ), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/chart_options/widget/futurama_bar_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:charts_web/assets.gen.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class FuturamaBarWidget extends StatelessWidget { 6 | FuturamaBarWidget( 7 | {Key? key, 8 | required this.stackItems, 9 | required this.listKey, 10 | required this.item}) 11 | : super(key: key); 12 | 13 | final bool stackItems; 14 | final int listKey; 15 | final ChartItem item; 16 | 17 | final _images = [ 18 | Assets.png.futurama1.path, 19 | Assets.png.futurama2.path, 20 | Assets.png.futurama5.path, 21 | Assets.png.futurama4.path, 22 | Assets.png.futurama1.path, 23 | ]; 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | return Container( 28 | margin: const EdgeInsets.symmetric(horizontal: 3.0), 29 | decoration: BoxDecoration( 30 | borderRadius: BorderRadius.vertical( 31 | top: Radius.circular((!stackItems || listKey == 0) ? 12 : 0)), 32 | ), 33 | foregroundDecoration: BoxDecoration( 34 | borderRadius: BorderRadius.vertical( 35 | top: Radius.circular((!stackItems || listKey == 0) ? 12 : 0)), 36 | color: Colors.accents[listKey].withOpacity(0.2), 37 | border: Border.all( 38 | width: 2, 39 | color: Colors.accents[listKey], 40 | ), 41 | ), 42 | child: ClipRRect( 43 | borderRadius: BorderRadius.vertical( 44 | top: Radius.circular((!stackItems || listKey == 0) ? 12 : 0)), 45 | child: Stack( 46 | children: [ 47 | Positioned.fill( 48 | child: Image.asset( 49 | _images[listKey], 50 | fit: BoxFit.cover, 51 | ), 52 | ), 53 | Positioned( 54 | top: 8.0, 55 | left: 0.0, 56 | right: 0.0, 57 | child: Text( 58 | '${item.max?.toStringAsFixed(2)}', 59 | textAlign: TextAlign.center, 60 | style: Theme.of(context).textTheme.subtitle1!.copyWith( 61 | color: Colors.black87, 62 | fontWeight: FontWeight.w700, 63 | ), 64 | ), 65 | ), 66 | ], 67 | ), 68 | ), 69 | ); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/chart_options/widget/options_component_header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class OptionsComponentHeader extends StatelessWidget { 4 | const OptionsComponentHeader( 5 | {Key? key, required this.title, required this.subtitle}) 6 | : super(key: key); 7 | 8 | final String title; 9 | final String subtitle; 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return Column( 14 | mainAxisSize: MainAxisSize.min, 15 | children: [ 16 | SizedBox( 17 | width: double.infinity, 18 | child: Text( 19 | title, 20 | style: Theme.of(context) 21 | .textTheme 22 | .headline4! 23 | .copyWith(fontWeight: FontWeight.bold, color: Colors.black87), 24 | ), 25 | ), 26 | SizedBox( 27 | width: double.infinity, 28 | child: Text( 29 | subtitle, 30 | style: Theme.of(context).textTheme.bodyText1, 31 | ), 32 | ), 33 | const SizedBox(height: 16), 34 | ], 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/decorations/decorations_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_web/ui/home/decorations/common_decoration_box.dart'; 2 | import 'package:charts_web/ui/home/decorations/presenters/decorations_widget_presenter.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:hooks_riverpod/hooks_riverpod.dart'; 5 | 6 | class DecorationsWidget extends HookConsumerWidget { 7 | const DecorationsWidget({Key? key, required this.decorationIndex}) 8 | : super(key: key); 9 | 10 | final int decorationIndex; 11 | 12 | @override 13 | Widget build(BuildContext context, WidgetRef ref) { 14 | final _presenter = ref.watch(decorationWidgetPresenter(decorationIndex)); 15 | 16 | return CommonDecorationBox( 17 | name: 'Widget decoration', 18 | decorationIndex: decorationIndex, 19 | child: Column( 20 | children: [ 21 | const Text( 22 | 'With widget decoration you provide your own widget and you can do a lot of customization this way. Here are some examples:'), 23 | Wrap( 24 | spacing: 16, 25 | runSpacing: 16, 26 | children: [ 27 | TextButton( 28 | onPressed: () => _presenter.updateType(0), 29 | child: const Text('Target line'), 30 | ), 31 | TextButton( 32 | onPressed: () => _presenter.updateType(1), 33 | child: const Text('Target line with text'), 34 | ), 35 | TextButton( 36 | onPressed: () => _presenter.updateType(2), 37 | child: const Text('Target area'), 38 | ), 39 | TextButton( 40 | onPressed: () => _presenter.updateType(3), 41 | child: const Text('Border'), 42 | ), 43 | TextButton( 44 | onPressed: () => _presenter.updateType(4), 45 | child: const Text('Clickable widget'), 46 | ), 47 | ], 48 | ), 49 | ], 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/decorations/presenters/decorations_horizontal_axis_presenter.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:charts_web/ui/common/dialog/color_picker_dialog.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | import '../../presenter/chart_decorations_presenter.dart'; 7 | 8 | final decorationHorizontalAxisPresenter = 9 | ChangeNotifierProvider.family( 10 | (ref, a) => DecorationHorizontalAxisPresenter(a, ref)); 11 | 12 | class DecorationHorizontalAxisPresenter extends ChangeNotifier 13 | implements DecorationBuilder { 14 | DecorationHorizontalAxisPresenter(this.index, Ref ref); 15 | 16 | int lineId = 0; 17 | 18 | final int index; 19 | 20 | bool showLines = true; 21 | bool showValues = false; 22 | bool endWithChart = false; 23 | double lineWidth = 1.0; 24 | double axisStep = 1.0; 25 | Color lineColor = Colors.grey; 26 | 27 | void updateShowLines(bool value) { 28 | showLines = value; 29 | notifyListeners(); 30 | } 31 | 32 | void updateShowValues(bool value) { 33 | showValues = value; 34 | notifyListeners(); 35 | } 36 | 37 | void updateColor(Color newColor) { 38 | lineColor = newColor; 39 | notifyListeners(); 40 | } 41 | 42 | void updateAxisStep(double newAxisStep) { 43 | axisStep = newAxisStep; 44 | notifyListeners(); 45 | } 46 | 47 | void updateLineWidth(double newLineWidth) { 48 | lineWidth = newLineWidth; 49 | notifyListeners(); 50 | } 51 | 52 | void updateEndWithChart(bool value) { 53 | endWithChart = value; 54 | notifyListeners(); 55 | } 56 | 57 | @override 58 | HorizontalAxisDecoration buildDecoration() { 59 | return HorizontalAxisDecoration( 60 | showLines: showLines, 61 | textScale: 1.2, 62 | showValues: showValues, 63 | endWithChart: endWithChart, 64 | lineWidth: lineWidth, 65 | axisStep: axisStep, 66 | lineColor: lineColor, 67 | ); 68 | } 69 | 70 | @override 71 | String buildDecorationCode() { 72 | return ''' HorizontalAxisDecoration( 73 | showLines: $showLines, 74 | textScale: 1.2, 75 | showValues: $showValues, 76 | endWithChart: $endWithChart, 77 | lineWidth: $lineWidth, 78 | axisStep: $axisStep, 79 | lineColor: ${colorToCode(lineColor)}, 80 | ), 81 | '''; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/decorations/presenters/decorations_sparkline_presenter.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:charts_web/ui/common/dialog/color_picker_dialog.dart'; 3 | import 'package:charts_web/ui/home/presenter/chart_decorations_presenter.dart'; 4 | import 'package:charts_web/ui/home/presenter/chart_state_presenter.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 7 | 8 | final decorationSparkLinePresenter = 9 | ChangeNotifierProvider.family( 10 | (ref, a) => DecorationSparkLinePresenter(a, ref)); 11 | 12 | class DecorationSparkLinePresenter extends ChangeNotifier 13 | implements DecorationBuilder { 14 | DecorationSparkLinePresenter(this.index, Ref ref) { 15 | color = ref.read(chartStatePresenter).listColors.first; 16 | } 17 | 18 | int lineId = 0; 19 | 20 | final int index; 21 | 22 | bool filled = false; 23 | bool smoothPoints = false; 24 | double lineWidth = 1.0; 25 | double startPosition = 0.5; 26 | 27 | late Color color; 28 | LinearGradient? gradient; 29 | 30 | // bool stretchLine = false; 31 | 32 | void updateFilled(bool value) { 33 | filled = value; 34 | notifyListeners(); 35 | } 36 | 37 | void updateSmoothPoints(bool value) { 38 | smoothPoints = value; 39 | notifyListeners(); 40 | } 41 | 42 | void updateColor(Color newColor) { 43 | color = newColor; 44 | notifyListeners(); 45 | } 46 | 47 | void updateGradient(LinearGradient? newGradient) { 48 | gradient = newGradient; 49 | notifyListeners(); 50 | } 51 | 52 | void updateId(int newLineId) { 53 | lineId = newLineId; 54 | notifyListeners(); 55 | } 56 | 57 | void updateLineWidth(double newLineWidth) { 58 | lineWidth = newLineWidth; 59 | notifyListeners(); 60 | } 61 | 62 | void updateStartPosition(double startPosition) { 63 | this.startPosition = startPosition; 64 | notifyListeners(); 65 | } 66 | 67 | @override 68 | SparkLineDecoration buildDecoration() { 69 | return SparkLineDecoration( 70 | listIndex: lineId, 71 | fill: filled, 72 | smoothPoints: smoothPoints, 73 | lineColor: color, 74 | lineWidth: lineWidth, 75 | gradient: gradient, 76 | startPosition: startPosition, 77 | ); 78 | } 79 | 80 | @override 81 | String buildDecorationCode() { 82 | return ''' SparkLineDecoration( 83 | lineKey: $lineId, 84 | fill: $filled, 85 | smoothPoints: $smoothPoints, 86 | lineColor: ${colorToCode(color)}, 87 | lineWidth: $lineWidth, 88 | gradient: null, 89 | startPosition: $startPosition, 90 | ), 91 | '''; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/decorations/presenters/decorations_vertical_axis_presenter.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:charts_web/ui/common/dialog/color_picker_dialog.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 5 | 6 | import '../../presenter/chart_decorations_presenter.dart'; 7 | 8 | final decorationVerticalAxisPresenter = 9 | ChangeNotifierProvider.family( 10 | (ref, a) => DecorationVerticalAxisPresenter(a, ref)); 11 | 12 | class DecorationVerticalAxisPresenter extends ChangeNotifier 13 | implements DecorationBuilder { 14 | DecorationVerticalAxisPresenter(this.index, Ref ref); 15 | 16 | int lineId = 0; 17 | 18 | final int index; 19 | 20 | bool showLines = true; 21 | bool showValues = false; 22 | bool endWithChart = false; 23 | double lineWidth = 1.0; 24 | double axisStep = 1.0; 25 | Color lineColor = Colors.grey; 26 | 27 | void updateShowLines(bool value) { 28 | showLines = value; 29 | notifyListeners(); 30 | } 31 | 32 | void updateShowValues(bool value) { 33 | showValues = value; 34 | notifyListeners(); 35 | } 36 | 37 | void updateColor(Color newColor) { 38 | lineColor = newColor; 39 | notifyListeners(); 40 | } 41 | 42 | void updateAxisStep(double newAxisStep) { 43 | axisStep = newAxisStep; 44 | notifyListeners(); 45 | } 46 | 47 | void updateLineWidth(double newLineWidth) { 48 | lineWidth = newLineWidth; 49 | notifyListeners(); 50 | } 51 | 52 | void updateEndWithChart(bool value) { 53 | endWithChart = value; 54 | notifyListeners(); 55 | } 56 | 57 | @override 58 | VerticalAxisDecoration buildDecoration() { 59 | return VerticalAxisDecoration( 60 | showLines: showLines, 61 | textScale: 1.2, 62 | showValues: showValues, 63 | endWithChart: endWithChart, 64 | lineWidth: lineWidth, 65 | axisStep: axisStep, 66 | lineColor: lineColor, 67 | ); 68 | } 69 | 70 | @override 71 | String buildDecorationCode() { 72 | return ''' VerticalAxisDecoration( 73 | showLines: $showLines, 74 | textScale: 1.2, 75 | showValues: $showValues, 76 | endWithChart: $endWithChart, 77 | lineWidth: $lineWidth, 78 | axisStep: $axisStep, 79 | lineColor: ${colorToCode(lineColor)}, 80 | ), 81 | '''; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /charts_web/lib/ui/home/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:charts_web/ui/common/respo/respo.dart'; 3 | import 'package:charts_web/ui/home/chart_options/chart_options.dart'; 4 | import 'package:charts_web/ui/home/presenter/chart_state_presenter.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_riverpod/flutter_riverpod.dart'; 7 | 8 | class HomeScreen extends ConsumerStatefulWidget { 9 | @override 10 | _HomeScreenState createState() => _HomeScreenState(); 11 | } 12 | 13 | class _HomeScreenState extends ConsumerState { 14 | @override 15 | Widget build(BuildContext context) { 16 | final _provider = ref.watch(chartStatePresenter); 17 | 18 | return Scaffold( 19 | backgroundColor: const Color(0xffefefef), 20 | body: Respo.of(context).size.maybeMap(small: (_) { 21 | return ListView( 22 | shrinkWrap: true, 23 | children: [ 24 | ChartOptions(), 25 | const SizedBox(height: 500, child: _Chart()), 26 | ], 27 | ); 28 | }, orElse: () { 29 | return Row( 30 | crossAxisAlignment: CrossAxisAlignment.start, 31 | children: [ 32 | SizedBox( 33 | width: 600.0, 34 | child: SingleChildScrollView(child: ChartOptions())), 35 | const Expanded(child: _Chart()), 36 | ], 37 | ); 38 | }), 39 | ); 40 | } 41 | } 42 | 43 | class _Chart extends ConsumerWidget { 44 | const _Chart({Key? key}) : super(key: key); 45 | 46 | @override 47 | Widget build(BuildContext context, WidgetRef ref) { 48 | final _provider = ref.watch(chartStatePresenter); 49 | 50 | return Container( 51 | margin: const EdgeInsets.all(20), 52 | decoration: BoxDecoration( 53 | color: Colors.white, 54 | borderRadius: BorderRadius.circular(24), 55 | ), 56 | padding: const EdgeInsets.all(20), 57 | child: AnimatedChart( 58 | duration: const Duration(milliseconds: 450), 59 | state: _provider.state, 60 | ), 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /charts_web/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: charts_web 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.16.0-126.0.dev <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | charts_painter: 28 | path: ../../flutter-charts 29 | example: 30 | path: ../example 31 | 32 | flutter_riverpod: ^1.0.3 33 | riverpod: ^1.0.3 34 | flutter_hooks: ^0.18.2+1 35 | hooks_riverpod: ^1.0.2 36 | cupertino_icons: ^1.0.4 37 | freezed_annotation: ^2.1.0 38 | flex_color_picker: ^2.6.1 39 | flutter_svg: ^1.1.5 40 | 41 | dev_dependencies: 42 | flutter_test: 43 | sdk: flutter 44 | build_runner: ^2.1.8 45 | freezed: ^2.1.0+1 46 | flutter_lints: ^1.0.4 47 | flutter_gen_runner: ^4.1.6 48 | 49 | flutter_gen: 50 | output: lib/ 51 | line_length: 120 52 | 53 | # The following section is specific to Flutter. 54 | flutter: 55 | uses-material-design: true 56 | 57 | assets: 58 | - assets/svg/ 59 | - assets/png/ 60 | 61 | fonts: 62 | - family: InterTight 63 | fonts: 64 | - asset: assets/font/InterTight-Regular.ttf 65 | - asset: assets/font/InterTight-Light.ttf 66 | weight: 400 67 | - asset: assets/font/InterTight-Medium.ttf 68 | weight: 600 69 | - asset: assets/font/InterTight-SemiBold.ttf 70 | weight: 700 71 | 72 | -------------------------------------------------------------------------------- /charts_web/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:charts_web/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /charts_web/web/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/.nojekyll -------------------------------------------------------------------------------- /charts_web/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/favicon.png -------------------------------------------------------------------------------- /charts_web/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/icons/Icon-192.png -------------------------------------------------------------------------------- /charts_web/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/icons/Icon-512.png -------------------------------------------------------------------------------- /charts_web/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /charts_web/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /charts_web/web/icons/chart_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/charts_web/web/icons/chart_image.png -------------------------------------------------------------------------------- /charts_web/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "charts_web", 3 | "short_name": "charts_web", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /charts_web/web/style.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .loading { 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | margin: 0; 8 | position: absolute; 9 | top: 50%; 10 | left: 50%; 11 | -ms-transform: translate(-50%, -50%); 12 | transform: translate(-50%, -50%); 13 | } 14 | -------------------------------------------------------------------------------- /dart_test.yaml: -------------------------------------------------------------------------------- 1 | tags: 2 | golden: 3 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1aafb3a8b9b0c36241c5f5b34ee914770f015818 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Flutter charts example -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:pedantic/analysis_options.yaml 2 | 3 | # Specify analysis options. 4 | # 5 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 6 | # See: https://github.com/dart-lang/linter/issues/288 7 | # 8 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 9 | # See the configuration guide for more 10 | # https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer 11 | # 12 | # There are other similar analysis options files in the flutter repos, 13 | # which should be kept in sync with this file: 14 | # 15 | # - analysis_options.yaml (this file) 16 | # - packages/flutter/lib/analysis_options_user.yaml 17 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 18 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 19 | # 20 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 21 | # Android Studio, and the `flutter analyze` command. 22 | 23 | analyzer: 24 | strong-mode: 25 | implicit-casts: false 26 | implicit-dynamic: false 27 | errors: 28 | # treat missing required parameters as a warning (not a hint) 29 | missing_required_param: warning 30 | # treat missing returns as a warning (not a hint) 31 | missing_return: warning 32 | # allow having TODOs in the code 33 | todo: ignore 34 | # Ignore analyzer hints for updating pubspecs when using Future or 35 | # Stream and not importing dart:async 36 | # Please see https://github.com/flutter/flutter/pull/24528 for details. 37 | sdk_version_async_exported_from_core: ignore 38 | exclude: 39 | - "bin/cache/**" 40 | - "lib/assets.dart" 41 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion flutter.compileSdkVersion 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.example.example" 47 | minSdkVersion flutter.minSdkVersion 48 | targetSdkVersion flutter.targetSdkVersion 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/assets/png/futurama1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/assets/png/futurama1.jpeg -------------------------------------------------------------------------------- /example/assets/png/futurama2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/assets/png/futurama2.jpeg -------------------------------------------------------------------------------- /example/assets/png/futurama4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/assets/png/futurama4.jpeg -------------------------------------------------------------------------------- /example/assets/png/futurama5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/assets/png/futurama5.jpeg -------------------------------------------------------------------------------- /example/assets/png/futurama_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/assets/png/futurama_small.png -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/click_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp(MaterialApp(home: ChartApp())); 6 | } 7 | 8 | class ChartApp extends StatefulWidget { 9 | ChartApp({Key? key}) : super(key: key); 10 | 11 | @override 12 | _ChartAppState createState() => _ChartAppState(); 13 | } 14 | 15 | class _ChartAppState extends State { 16 | int? _selectedIndex = null; 17 | 18 | @override 19 | Widget build(BuildContext context) { 20 | return Container( 21 | padding: const EdgeInsets.all(24.0), 22 | color: Colors.grey.shade600, 23 | child: Chart( 24 | state: ChartState( 25 | data: ChartData( 26 | [ 27 | [2, 4, 6, 3, 2, 5, 4, 3, 2] 28 | .map((e) => ChartItem(e.toDouble())) 29 | .toList(), 30 | ], 31 | valueAxisMaxOver: 2, 32 | ), 33 | itemOptions: BarItemOptions( 34 | barItemBuilder: (_) => BarItem(), 35 | padding: const EdgeInsets.symmetric(horizontal: 8.0), 36 | ), 37 | behaviour: ChartBehaviour( 38 | onItemClicked: (index) { 39 | setState(() { 40 | _selectedIndex = index.itemIndex; 41 | }); 42 | }, 43 | ), 44 | backgroundDecorations: [ 45 | GridDecoration(), 46 | ], 47 | foregroundDecorations: [ 48 | SelectedItemDecoration(_selectedIndex), 49 | ]), 50 | ), 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/lib/issue_repro.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp(MaterialApp( 6 | home: Scaffold( 7 | backgroundColor: Colors.white, 8 | body: ChartTest(), 9 | ), 10 | )); 11 | } 12 | 13 | class ChartTest extends StatelessWidget { 14 | ChartTest({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | final byCount = [5, 6, 4, 8, 6, 4, 1, 2, 3, 7, 9, 4, 2]; 19 | 20 | return Padding( 21 | padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 128.0), 22 | child: Chart( 23 | state: ChartState( 24 | data: ChartData( 25 | [ 26 | byCount.map((e) => ChartItem(e.toDouble())).toList(), 27 | // byCount.map((e) => BarValue(e.toDouble())).toList() 28 | ], 29 | ), 30 | itemOptions: BarItemOptions(), 31 | // itemOptions: BarItemOptions( 32 | // padding: const EdgeInsets.symmetric(horizontal: 2), 33 | // color: Colors.blue, 34 | // ), 35 | backgroundDecorations: [ 36 | GridDecoration( 37 | showHorizontalGrid: false, 38 | showVerticalGrid: false, 39 | showVerticalValues: true, 40 | verticalLegendPosition: VerticalLegendPosition.top, 41 | verticalAxisValueFromIndex: (idx) => '${idx + 1}', 42 | gridWidth: 2, 43 | textStyle: Theme.of(context).textTheme.subtitle2!.copyWith(fontSize: 8, fontWeight: FontWeight.bold), 44 | gridColor: Theme.of(context).dividerColor, 45 | ), 46 | ], 47 | // foregroundDecorations: [ 48 | // HorizontalAxisDecoration(lineColor: Colors.brown), 49 | // ], 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/lib/showcase/ios_charts.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:example/charts/ios_charts_screen.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class IosCharts extends StatelessWidget { 6 | const IosCharts({Key? key}) : super(key: key); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Column( 11 | children: [ 12 | ListTile( 13 | title: Text('Apple battery chart'), 14 | trailing: Padding( 15 | padding: const EdgeInsets.symmetric(vertical: 8), 16 | child: Container( 17 | width: 100.0, 18 | child: Chart( 19 | state: ChartState( 20 | data: ChartData.fromList( 21 | [1, 3, 4, 2, 7, 7, 7, 7, 4, 5, 7, 8, 9, 4] 22 | .map((e) => ChartItem(e.toDouble())) 23 | .toList(), 24 | axisMax: 9, 25 | ), 26 | itemOptions: BarItemOptions( 27 | barItemBuilder: (_) => BarItem( 28 | radius: BorderRadius.vertical(top: Radius.circular(12.0)), 29 | color: Colors.green, 30 | ), 31 | padding: const EdgeInsets.symmetric(horizontal: 1.0), 32 | maxBarWidth: 8.0, 33 | ), 34 | backgroundDecorations: [ 35 | GridDecoration( 36 | verticalAxisStep: 1, 37 | horizontalAxisStep: 1.5, 38 | gridColor: Theme.of(context).dividerColor, 39 | ), 40 | ], 41 | ), 42 | ), 43 | ), 44 | ), 45 | onTap: () { 46 | Navigator.of(context).push( 47 | MaterialPageRoute(builder: (_) => IosChartScreen())); 48 | }, 49 | ), 50 | Divider(), 51 | ], 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/lib/widgets/bar_chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | typedef DataToValue = double Function(T item); 5 | typedef DataToAxis = String Function(int item); 6 | 7 | /// Short-hand to easier create several bar charts 8 | class BarChart extends StatelessWidget { 9 | BarChart({ 10 | required List data, 11 | required DataToValue dataToValue, 12 | this.height = 240.0, 13 | this.backgroundDecorations = const [], 14 | this.foregroundDecorations = const [], 15 | this.chartBehaviour = const ChartBehaviour(), 16 | this.itemOptions = const BarItemOptions(), 17 | this.stack = false, 18 | Key? key, 19 | }) : _mappedValues = [data.map((e) => BarValue(dataToValue(e))).toList()], 20 | super(key: key); 21 | 22 | const BarChart.map( 23 | this._mappedValues, { 24 | this.height = 240.0, 25 | this.backgroundDecorations = const [], 26 | this.foregroundDecorations = const [], 27 | this.chartBehaviour = const ChartBehaviour(), 28 | this.itemOptions = const BarItemOptions(), 29 | this.stack = false, 30 | Key? key, 31 | }) : super(key: key); 32 | 33 | final List>> _mappedValues; 34 | final double height; 35 | 36 | final bool stack; 37 | final ItemOptions itemOptions; 38 | final ChartBehaviour chartBehaviour; 39 | final List backgroundDecorations; 40 | final List foregroundDecorations; 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | final _data = ChartData( 45 | _mappedValues, 46 | valueAxisMaxOver: 1, 47 | dataStrategy: stack 48 | ? StackDataStrategy() 49 | : DefaultDataStrategy(stackMultipleValues: false), 50 | ); 51 | 52 | return AnimatedChart( 53 | height: height, 54 | width: MediaQuery.of(context).size.width - 24.0, 55 | duration: const Duration(milliseconds: 450), 56 | state: ChartState( 57 | data: _data, 58 | itemOptions: itemOptions, 59 | behaviour: chartBehaviour, 60 | foregroundDecorations: foregroundDecorations, 61 | backgroundDecorations: [ 62 | ...backgroundDecorations, 63 | ], 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/lib/widgets/bubble_chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | typedef DataToValue = double Function(T item); 6 | typedef DataToAxis = String Function(int item); 7 | 8 | /// Short-hand to easier create several bubble charts 9 | class BubbleChart extends StatelessWidget { 10 | BubbleChart({ 11 | required this.data, 12 | required this.dataToValue, 13 | this.height = 240.0, 14 | this.itemOptions = const BarItemOptions(), 15 | this.backgroundDecorations = const [], 16 | this.foregroundDecorations = const [], 17 | Key? key, 18 | }) : _mappedValues = [ 19 | data.map((e) => BubbleValue(dataToValue(e))).toList() 20 | ], 21 | super(key: key); 22 | 23 | final List data; 24 | final DataToValue dataToValue; 25 | final List>> _mappedValues; 26 | 27 | final double height; 28 | final ItemOptions itemOptions; 29 | 30 | final List backgroundDecorations; 31 | final List foregroundDecorations; 32 | 33 | @override 34 | Widget build(BuildContext context) { 35 | return AnimatedChart( 36 | height: height, 37 | duration: const Duration(milliseconds: 450), 38 | state: ChartState( 39 | data: ChartData(_mappedValues, valueAxisMaxOver: 5.0), 40 | itemOptions: itemOptions, 41 | foregroundDecorations: foregroundDecorations, 42 | backgroundDecorations: [ 43 | ...backgroundDecorations, 44 | ], 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/widgets/candle_chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | typedef DataToValue = CandleValue Function(T item); 6 | typedef DataToAxis = String Function(int item); 7 | 8 | /// Short-hand to easier create several candle charts 9 | class CandleChart extends StatelessWidget { 10 | CandleChart({ 11 | required this.data, 12 | required this.dataToValue, 13 | this.height = 240.0, 14 | this.width, 15 | this.backgroundDecorations = const [], 16 | this.chartBehaviour = const ChartBehaviour(), 17 | this.chartItemOptions = const BarItemOptions(), 18 | this.foregroundDecorations = const [], 19 | this.geometryPainter = barPainter, 20 | Key? key, 21 | }) : _mappedValues = [data.map(dataToValue).toList()], 22 | super(key: key); 23 | 24 | final List data; 25 | final DataToValue dataToValue; 26 | 27 | final double height; 28 | final double? width; 29 | final List backgroundDecorations; 30 | final List foregroundDecorations; 31 | final ChartBehaviour chartBehaviour; 32 | final ItemOptions chartItemOptions; 33 | final ChartGeometryPainter geometryPainter; 34 | 35 | final List>> _mappedValues; 36 | 37 | @override 38 | Widget build(BuildContext context) { 39 | return AnimatedChart( 40 | height: height, 41 | width: width, 42 | duration: const Duration(milliseconds: 450), 43 | state: ChartState( 44 | data: ChartData(_mappedValues), 45 | itemOptions: chartItemOptions, 46 | behaviour: chartBehaviour, 47 | foregroundDecorations: foregroundDecorations, 48 | backgroundDecorations: backgroundDecorations, 49 | ), 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /example/lib/widgets/counter_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CounterItem extends StatelessWidget { 4 | CounterItem( 5 | {required this.title, 6 | required this.value, 7 | required this.onMinus, 8 | required this.onPlus, 9 | Key? key}) 10 | : super(key: key); 11 | 12 | final int value; 13 | final String title; 14 | final VoidCallback onMinus; 15 | final VoidCallback onPlus; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Container( 20 | child: ListTile( 21 | title: Text(title), 22 | trailing: Row( 23 | mainAxisSize: MainAxisSize.min, 24 | children: [ 25 | InkWell( 26 | onTap: onMinus, 27 | child: AspectRatio( 28 | aspectRatio: 1, 29 | child: Icon(Icons.remove), 30 | ), 31 | ), 32 | InkWell( 33 | onTap: onPlus, 34 | child: AspectRatio( 35 | aspectRatio: 1, 36 | child: Icon(Icons.add), 37 | ), 38 | ), 39 | AspectRatio( 40 | aspectRatio: 1, 41 | child: Center(child: Text('$value')), 42 | ), 43 | ], 44 | ), 45 | )); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /example/lib/widgets/line_chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | typedef DataToValue = double Function(T item); 5 | typedef DataToAxis = String Function(int item); 6 | 7 | class LineChart extends StatelessWidget { 8 | LineChart({ 9 | required List data, 10 | required DataToValue dataToValue, 11 | this.height = 240.0, 12 | this.lineWidth = 2.0, 13 | this.itemColor = Colors.red, 14 | this.backgroundDecorations = const [], 15 | this.foregroundDecorations = const [], 16 | this.chartItemOptions, 17 | this.chartBehaviour = const ChartBehaviour(), 18 | this.smoothCurves = false, 19 | this.gradient, 20 | this.stack = false, 21 | Key? key, 22 | }) : _mappedValues = [ 23 | data.map((e) => BubbleValue(dataToValue(e))).toList() 24 | ], 25 | super(key: key); 26 | 27 | LineChart.multiple( 28 | this._mappedValues, { 29 | this.height = 240.0, 30 | this.lineWidth = 2.0, 31 | this.itemColor = Colors.red, 32 | this.backgroundDecorations = const [], 33 | this.foregroundDecorations = const [], 34 | this.chartItemOptions, 35 | this.chartBehaviour = const ChartBehaviour(), 36 | this.smoothCurves = false, 37 | this.gradient, 38 | this.stack = false, 39 | Key? key, 40 | }) : super(key: key); 41 | 42 | final double height; 43 | 44 | final bool smoothCurves; 45 | final Color itemColor; 46 | final Gradient? gradient; 47 | final double lineWidth; 48 | final bool stack; 49 | 50 | final List backgroundDecorations; 51 | final List foregroundDecorations; 52 | final ChartBehaviour chartBehaviour; 53 | final ItemOptions? chartItemOptions; 54 | 55 | final List>> _mappedValues; 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | return AnimatedChart( 60 | height: height, 61 | duration: const Duration(milliseconds: 450), 62 | state: ChartState( 63 | data: ChartData( 64 | _mappedValues, 65 | dataStrategy: stack 66 | ? StackDataStrategy() 67 | : DefaultDataStrategy(stackMultipleValues: true), 68 | ), 69 | itemOptions: chartItemOptions ?? 70 | BarItemOptions(barItemBuilder: (_) => BarItem()), 71 | foregroundDecorations: [ 72 | SparkLineDecoration( 73 | id: 'chart_decoration', 74 | lineWidth: lineWidth, 75 | lineColor: itemColor, 76 | gradient: gradient, 77 | smoothPoints: smoothCurves, 78 | ), 79 | ...foregroundDecorations, 80 | ], 81 | backgroundDecorations: [ 82 | ...backgroundDecorations, 83 | ], 84 | ), 85 | ); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example/lib/widgets/toggle_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ToggleItem extends StatelessWidget { 4 | ToggleItem( 5 | {required this.title, 6 | required this.value, 7 | required this.onChanged, 8 | Key? key}) 9 | : super(key: key); 10 | 11 | final bool value; 12 | final String title; 13 | final ValueChanged onChanged; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Container( 18 | child: SwitchListTile( 19 | value: value, 20 | title: Text(title), 21 | onChanged: onChanged, 22 | ), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | 27 | 28 | # The following adds the Cupertino Icons font to your application. 29 | # Use with the CupertinoIcons class for iOS style icons. 30 | cupertino_icons: ^1.0.0 31 | charts_painter: 32 | path: ../ 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | 38 | # For information on the generic Dart part of this file, see the 39 | # following page: https://dart.dev/tools/pub/pubspec 40 | 41 | # The following section is specific to Flutter. 42 | flutter: 43 | 44 | # The following line ensures that the Material Icons font is 45 | # included with your application, so that you can use the icons in 46 | # the material Icons class. 47 | uses-material-design: true 48 | 49 | assets: 50 | - assets/png/ 51 | 52 | # To add assets to your application, add an assets section, like this: 53 | # assets: 54 | # - images/a_dot_burr.jpeg 55 | # - images/a_dot_ham.jpeg 56 | 57 | # An image asset can refer to one or more resolution-specific "variants", see 58 | # https://flutter.dev/assets-and-images/#resolution-aware. 59 | 60 | # For details regarding adding assets from package dependencies, see 61 | # https://flutter.dev/assets-and-images/#from-packages 62 | 63 | # To add custom fonts to your application, add a fonts section here, 64 | # in this "flutter" section. Each entry in this list should have a 65 | # "family" key with the font family name, and a "fonts" key with a 66 | # list giving the asset and other descriptors for the font. For 67 | # example: 68 | # fonts: 69 | # - family: Schyler 70 | # fonts: 71 | # - asset: fonts/Schyler-Regular.ttf 72 | # - asset: fonts/Schyler-Italic.ttf 73 | # style: italic 74 | # - family: Trajan Pro 75 | # fonts: 76 | # - asset: fonts/TrajanPro.ttf 77 | # - asset: fonts/TrajanPro_Bold.ttf 78 | # weight: 700 79 | # 80 | # For details regarding fonts from package dependencies, 81 | # see https://flutter.dev/custom-fonts/#from-packages 82 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/chart/model/data_strategy/data_strategy.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Data strategy will process the data one final time before being passed to painters 4 | /// 5 | /// Data strategy is part of [ChartData] and it can be changed there. 6 | abstract class DataStrategy { 7 | const DataStrategy({required this.stackMultipleValues}) 8 | : _stackMultipleValuesProgress = stackMultipleValues ? 1.0 : 0.0; 9 | const DataStrategy._lerp(this._stackMultipleValuesProgress) 10 | : stackMultipleValues = _stackMultipleValuesProgress > 0.5; 11 | 12 | final double _stackMultipleValuesProgress; 13 | 14 | /// Return true if multi item drawing is set to stack 15 | final bool stackMultipleValues; 16 | 17 | List>> formatDataStrategy( 18 | List>> items); 19 | 20 | DataStrategy animateTo(DataStrategy dataStrategy, double t); 21 | } 22 | -------------------------------------------------------------------------------- /lib/chart/model/data_strategy/default_data_strategy.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Used by default and it won't do anything to the data just pass it along 4 | class DefaultDataStrategy extends DataStrategy { 5 | const DefaultDataStrategy({required bool stackMultipleValues}) 6 | : super(stackMultipleValues: stackMultipleValues); 7 | const DefaultDataStrategy._lerp(double stackMultipleValuesProgress) 8 | : super._lerp(stackMultipleValuesProgress); 9 | 10 | @override 11 | List>> formatDataStrategy( 12 | List>> items) => 13 | items; 14 | 15 | @override 16 | DataStrategy animateTo(DataStrategy dataStrategy, double t) { 17 | if (dataStrategy is DefaultDataStrategy) { 18 | return DefaultDataStrategy._lerp(lerpDouble(_stackMultipleValuesProgress, 19 | dataStrategy._stackMultipleValuesProgress, t) ?? 20 | dataStrategy._stackMultipleValuesProgress); 21 | } 22 | 23 | return dataStrategy; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/chart/model/data_strategy/stack_data_strategy.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Stacks multiple lists one on top of another. 4 | /// 5 | /// ex. 6 | /// List with: 7 | /// [ 8 | /// [1, 3, 2], 9 | /// [3, 2, 1] 10 | /// ] 11 | /// 12 | /// will become: 13 | /// [ 14 | /// [1, 3, 2], 15 | /// [4, 5, 3] 16 | /// ] 17 | class StackDataStrategy extends DataStrategy { 18 | const StackDataStrategy() : super(stackMultipleValues: true); 19 | 20 | @override 21 | List>> formatDataStrategy( 22 | List>> items) { 23 | final _incrementList = >[]; 24 | return items.reversed 25 | .map((entry) { 26 | return entry.asMap().entries.map((e) { 27 | if (_incrementList.length > e.key) { 28 | final _newValue = e.value + _incrementList[e.key]; 29 | _incrementList[e.key] = (_incrementList[e.key] + e.value); 30 | return _newValue; 31 | } else { 32 | _incrementList.add(e.value); 33 | } 34 | 35 | return e.value; 36 | }).toList(); 37 | }) 38 | .toList() 39 | .reversed 40 | .toList(); 41 | } 42 | 43 | @override 44 | DataStrategy animateTo(DataStrategy dataStrategy, double t) { 45 | return dataStrategy; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/chart/model/geometry/bar_value_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Bar value items have min locked to 0.0 (or [ChartData.axisMin] if defined) 4 | /// Value for bar item can be negative 5 | @Deprecated('Use ChartItem(x)') 6 | class BarValue extends ChartItem { 7 | /// Simple [BarValue] item just with max value. 8 | BarValue(double max) : super(max); 9 | 10 | /// Bar value, with item `T` and max value 11 | BarValue.withValue(T value, double max) : super(max, value: value); 12 | } 13 | -------------------------------------------------------------------------------- /lib/chart/model/geometry/bubble_value_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Bubble value items max values that are just shown as a point 4 | /// Values can go negative 5 | @Deprecated('Use ChartItem(x, min: x)') 6 | class BubbleValue extends ChartItem { 7 | /// Simple bubble value with max value 8 | BubbleValue(double max) : super(max, min: max); 9 | 10 | /// Bubble value with item `T` and max value 11 | BubbleValue.withValue(T value, double max) 12 | : super(max, value: value, min: max); 13 | } 14 | -------------------------------------------------------------------------------- /lib/chart/model/geometry/candle_value_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Candle value items have min and max set up 4 | /// Values can go negative 5 | @Deprecated('Use ChartItem(x, min: y)') 6 | class CandleValue extends ChartItem { 7 | /// Simple candle value with min and max values 8 | CandleValue(double min, double max) : super(max, min: min, value: null); 9 | 10 | /// Candle value with item `T`, min and max value 11 | CandleValue.withValue(T value, double min, double max) 12 | : super(max, value: value, min: min); 13 | } 14 | -------------------------------------------------------------------------------- /lib/chart/model/geometry/chart_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Default `ChartItem` 4 | class ChartItem { 5 | /// Constructor for regular items 6 | ChartItem(this.max, {this.min, this.value}); 7 | 8 | /// Minimum chart item value 9 | final double? min; 10 | 11 | /// Maximum item value 12 | final double? max; 13 | 14 | /// Items can have value attached to them `T` 15 | final T? value; 16 | 17 | /// Check if current item is empty 18 | bool get isEmpty => (max ?? 0) == 0 && (min ?? 0) == 0; 19 | 20 | /// Animate to [endValue] with factor `t` 21 | ChartItem animateTo(ChartItem endValue, double t) { 22 | return ChartItem( 23 | lerpDouble(max, endValue.max, t), 24 | value: endValue.value, 25 | min: lerpDouble(min, endValue.min, t), 26 | ); 27 | } 28 | 29 | /// Animate from [startValue] to this with factor `t` 30 | ChartItem animateFrom(ChartItem startValue, double t) { 31 | return animateTo(startValue, 1 - t); 32 | } 33 | 34 | @override 35 | int get hashCode => Object.hash(min, max) ^ value.hashCode; 36 | 37 | @override 38 | bool operator ==(Object other) { 39 | if (other is ChartItem) { 40 | return other.hashCode == hashCode; 41 | } 42 | 43 | return false; 44 | } 45 | 46 | /// Add two [ChartItem]'s together 47 | /// `T` value is taken from [other] 48 | ChartItem operator +(Object other) { 49 | if (other is ChartItem) { 50 | return ChartItem( 51 | (other.max ?? 0.0) + (max ?? 0.0), 52 | value: other.value, 53 | min: (other.min ?? 0.0) + (min ?? 0.0), 54 | ); 55 | } 56 | 57 | return this; 58 | } 59 | 60 | /// Multiply [ChartItem] with another [ChartItem] of number 61 | ChartItem operator *(Object? other) { 62 | if (other is ChartItem) { 63 | return ChartItem( 64 | (other.max ?? 0.0) * (max ?? 0.0), 65 | value: other.value, 66 | min: (other.min ?? 0.0) * (min ?? 0.0), 67 | ); 68 | } else if (other is num) { 69 | return ChartItem( 70 | other.toDouble() * (max ?? 0.0), 71 | value: value, 72 | min: other.toDouble() * (min ?? 0.0), 73 | ); 74 | } 75 | 76 | return this; 77 | } 78 | 79 | @override 80 | String toString() { 81 | return 'ChartItem(min: $min, max: $max, value: $value)'; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/chart/model/theme/chart_behaviour.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Behaviour of the chart 4 | /// [isScrollable] - If chart is scrollable then width of canvas is ignored and 5 | /// chart will take any size it needs. Chart has to be wrapped with [SingleChildScrollView] 6 | /// or similar scrollable widget. 7 | /// [onItemClicked] - Returns index of clicked item. 8 | class ChartBehaviour { 9 | /// Default constructor for ChartBehaviour 10 | /// If chart is scrollable then it will ignore width limit and it should be wrapped in [SingleChildScrollView] 11 | const ChartBehaviour({ 12 | this.scrollSettings = const ScrollSettings.none(), 13 | this.onItemClicked, 14 | this.onItemHoverEnter, 15 | this.onItemHoverExit, 16 | }); 17 | 18 | ChartBehaviour._lerp( 19 | this.scrollSettings, 20 | this.onItemClicked, 21 | this.onItemHoverEnter, 22 | this.onItemHoverExit, 23 | ); 24 | 25 | final ScrollSettings scrollSettings; 26 | 27 | /// Return index of item clicked. Since graph can be multi value, user 28 | /// will have to handle clicked index to show data they want to show 29 | final ValueChanged? onItemClicked; 30 | 31 | /// Return true if chart is currently scrollable 32 | bool get isScrollable => scrollSettings._isScrollable > 0.5; 33 | 34 | /// Return index of item clicked. Since graph can be multi value, user 35 | /// will have to handle clicked index to show data they want to show 36 | final ValueChanged? onItemHoverEnter; 37 | 38 | /// Return index of item clicked. Since graph can be multi value, user 39 | /// will have to handle clicked index to show data they want to show 40 | final ValueChanged? onItemHoverExit; 41 | 42 | /// Animate Behaviour from one state to other 43 | static ChartBehaviour lerp(ChartBehaviour a, ChartBehaviour b, double t) { 44 | return ChartBehaviour._lerp( 45 | ScrollSettings.lerp(a.scrollSettings, b.scrollSettings, t), 46 | t > 0.5 ? b.onItemClicked : a.onItemClicked, 47 | t > 0.5 ? b.onItemHoverEnter : a.onItemHoverEnter, 48 | t > 0.5 ? b.onItemHoverExit : a.onItemHoverExit, 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/bar/bar_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | class BarItem extends DrawDataItem { 4 | const BarItem({ 5 | this.radius, 6 | Gradient? gradient, 7 | BorderSide? border, 8 | Color? color, 9 | }) : super(color: color, gradient: gradient, border: border); 10 | 11 | /// Set border radius for each item 12 | /// Radius will automatically flip when showing values in negative space 13 | final BorderRadius? radius; 14 | 15 | BarItem lerp(BarItem endValue, double t) { 16 | return BarItem( 17 | radius: BorderRadius.lerp( 18 | radius, endValue is BarItemOptions ? endValue.radius : null, t), 19 | gradient: Gradient.lerp( 20 | gradient, endValue is BarItemOptions ? endValue.gradient : null, t), 21 | border: BorderSide.lerp(border, 22 | endValue is BarItemOptions ? (endValue.border) : BorderSide.none, t), 23 | color: Color.lerp(color, endValue.color, t), 24 | ); 25 | } 26 | 27 | @override 28 | List get props => [radius, gradient, border, color]; 29 | } 30 | 31 | class BarItemBuilderLerp { 32 | static BarItemBuilder lerp(BarItemOptions a, BarItemOptions b, double t) { 33 | return (ItemBuilderData data) { 34 | final _aItem = a.barItemBuilder(data); 35 | final _bItem = b.barItemBuilder(data); 36 | return _aItem.lerp(_bItem, t); 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/bar/bar_item_options.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Bar painter 4 | GeometryPainter barPainter(ChartItem item, ChartData data, 5 | ItemOptions itemOptions, DrawDataItem drawDataItem) => 6 | BarGeometryPainter(item, data, itemOptions, drawDataItem as BarItem); 7 | 8 | typedef BarItemBuilder = BarItem Function(ItemBuilderData data); 9 | 10 | /// Extension options for bar items 11 | /// [geometryPainter] is set to [BarGeometryPainter] 12 | /// 13 | /// Extra options included in [BarGeometryPainter] are: 14 | /// [radius] Define corner radius for each bar item 15 | /// [border] Define border width and color 16 | /// [gradient] Item can have gradient color 17 | class BarItemOptions extends ItemOptions { 18 | /// Constructor for bar item options, has some extra options just for [BarGeometryPainter] 19 | const BarItemOptions({ 20 | EdgeInsets padding = EdgeInsets.zero, 21 | EdgeInsets multiValuePadding = EdgeInsets.zero, 22 | double? maxBarWidth, 23 | double? minBarWidth, 24 | double startPosition = 0.5, 25 | this.barItemBuilder = _defaultBarItem, 26 | }) : super( 27 | padding: padding, 28 | multiValuePadding: multiValuePadding, 29 | maxBarWidth: maxBarWidth, 30 | minBarWidth: minBarWidth, 31 | startPosition: startPosition, 32 | geometryPainter: barPainter, 33 | itemBuilder: barItemBuilder); 34 | 35 | BarItemOptions._lerp( 36 | {EdgeInsets padding = EdgeInsets.zero, 37 | EdgeInsets multiValuePadding = EdgeInsets.zero, 38 | double? maxBarWidth, 39 | double? minBarWidth, 40 | double startPosition = 0.5, 41 | required this.barItemBuilder}) 42 | : super._lerp( 43 | padding: padding, 44 | multiValuePadding: multiValuePadding, 45 | maxBarWidth: maxBarWidth, 46 | minBarWidth: minBarWidth, 47 | startPosition: startPosition, 48 | geometryPainter: barPainter, 49 | itemBuilder: barItemBuilder); 50 | 51 | final BarItemBuilder barItemBuilder; 52 | 53 | @override 54 | ItemOptions animateTo(ItemOptions endValue, double t) { 55 | if (endValue is BarItemOptions) { 56 | return BarItemOptions._lerp( 57 | barItemBuilder: BarItemBuilderLerp.lerp(this, endValue, t), 58 | padding: 59 | EdgeInsets.lerp(padding, endValue.padding, t) ?? EdgeInsets.zero, 60 | multiValuePadding: 61 | EdgeInsets.lerp(multiValuePadding, endValue.multiValuePadding, t) ?? 62 | EdgeInsets.zero, 63 | maxBarWidth: lerpDouble(maxBarWidth, endValue.maxBarWidth, t), 64 | minBarWidth: lerpDouble(minBarWidth, endValue.minBarWidth, t), 65 | startPosition: 66 | lerpDouble(startPosition, endValue.startPosition, t) ?? 0.5, 67 | ); 68 | } else { 69 | return endValue; 70 | } 71 | } 72 | } 73 | 74 | BarItem _defaultBarItem(ItemBuilderData _) { 75 | return BarItem(); 76 | } 77 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/bubble/bubble_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | class BubbleItem extends DrawDataItem { 4 | const BubbleItem({ 5 | Gradient? gradient, 6 | BorderSide? border, 7 | Color? color, 8 | }) : super(color: color, gradient: gradient, border: border); 9 | 10 | BubbleItem lerp(BubbleItem endValue, double t) { 11 | return BubbleItem( 12 | gradient: Gradient.lerp(gradient, 13 | endValue is BubbleItemOptions ? endValue.gradient : null, t), 14 | border: BorderSide.lerp( 15 | border, 16 | endValue is BubbleItemOptions ? (endValue.border) : BorderSide.none, 17 | t), 18 | color: Color.lerp(color, endValue.color, t), 19 | ); 20 | } 21 | 22 | @override 23 | List get props => [gradient, border, color]; 24 | } 25 | 26 | class BubbleItemBuilderLerp { 27 | static BubbleItemBuilder lerp( 28 | BubbleItemOptions a, BubbleItemOptions b, double t) { 29 | return (ItemBuilderData data) { 30 | final _aItem = a.bubbleItemBuilder(data); 31 | final _bItem = b.bubbleItemBuilder(data); 32 | return _aItem.lerp(_bItem, t); 33 | }; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/bubble/bubble_item_options.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Bubble painter 4 | GeometryPainter bubblePainter(ChartItem item, ChartData data, 5 | ItemOptions itemOptions, DrawDataItem drawDataItem) => 6 | BubbleGeometryPainter( 7 | item, data, itemOptions, drawDataItem as BubbleItem); 8 | 9 | typedef BubbleItemBuilder = BubbleItem Function(ItemBuilderData); 10 | 11 | /// Extension options for bar items 12 | /// [geometryPainter] is set to [BubbleGeometryPainter] 13 | /// 14 | /// Extra options included in [BubbleGeometryPainter] are: 15 | /// [border] Define border width and color 16 | /// [gradient] Item can have gradient color 17 | class BubbleItemOptions extends ItemOptions { 18 | /// Constructor for bubble item options, has some options just for [BubbleGeometryPainter] 19 | BubbleItemOptions({ 20 | EdgeInsets padding = EdgeInsets.zero, 21 | EdgeInsets multiValuePadding = EdgeInsets.zero, 22 | double? maxBarWidth, 23 | double? minBarWidth, 24 | this.bubbleItemBuilder = _defaultBubbleItem, 25 | }) : super( 26 | padding: padding, 27 | multiValuePadding: multiValuePadding, 28 | minBarWidth: minBarWidth, 29 | maxBarWidth: maxBarWidth, 30 | geometryPainter: bubblePainter, 31 | itemBuilder: bubbleItemBuilder); 32 | 33 | BubbleItemOptions._lerp({ 34 | EdgeInsets padding = EdgeInsets.zero, 35 | EdgeInsets multiValuePadding = EdgeInsets.zero, 36 | double? maxBarWidth, 37 | double? minBarWidth, 38 | required this.bubbleItemBuilder, 39 | }) : super._lerp( 40 | padding: padding, 41 | multiValuePadding: multiValuePadding, 42 | minBarWidth: minBarWidth, 43 | maxBarWidth: maxBarWidth, 44 | geometryPainter: bubblePainter, 45 | itemBuilder: bubbleItemBuilder, 46 | ); 47 | 48 | final BubbleItemBuilder bubbleItemBuilder; 49 | 50 | @override 51 | ItemOptions animateTo(ItemOptions endValue, double t) { 52 | if (endValue is BubbleItemOptions) { 53 | return BubbleItemOptions._lerp( 54 | bubbleItemBuilder: BubbleItemBuilderLerp.lerp(this, endValue, t), 55 | padding: 56 | EdgeInsets.lerp(padding, endValue.padding, t) ?? EdgeInsets.zero, 57 | multiValuePadding: 58 | EdgeInsets.lerp(multiValuePadding, endValue.multiValuePadding, t) ?? 59 | EdgeInsets.zero, 60 | maxBarWidth: lerpDouble(maxBarWidth, endValue.maxBarWidth, t), 61 | minBarWidth: lerpDouble(minBarWidth, endValue.minBarWidth, t), 62 | ); 63 | } else { 64 | return endValue; 65 | } 66 | } 67 | } 68 | 69 | BubbleItem _defaultBubbleItem(ItemBuilderData _) { 70 | return BubbleItem(); 71 | } 72 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/draw_data_item.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Data needed for drawing on the canvas 4 | /// 5 | /// Use subclasses [BarItem], [BubbleItem] 6 | abstract class DrawDataItem extends Equatable { 7 | const DrawDataItem({Color? color, this.gradient, BorderSide? border}) 8 | : color = color ?? Colors.black, 9 | border = border ?? BorderSide.none; 10 | 11 | /// Set solid color to chart items 12 | final Color color; 13 | 14 | /// Set gradient color to chart items 15 | final Gradient? gradient; 16 | 17 | /// Set border to chart items 18 | final BorderSide border; 19 | 20 | Paint getPaint(Size size) { 21 | var _paint = Paint(); 22 | _paint.color = color; 23 | 24 | if (gradient != null) { 25 | // Compiler complains that gradient could be null. But unless if fails us that will never be null. 26 | _paint.shader = gradient!.createShader( 27 | Rect.fromPoints(Offset.zero, Offset(size.width, size.height))); 28 | } 29 | 30 | return _paint; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/item_builder_data.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | typedef ItemBuilder = dynamic Function(ItemBuilderData); 4 | 5 | /// Data that can be used when building items to make each item appear different. 6 | class ItemBuilderData { 7 | ItemBuilderData(this.item, this.itemIndex, this.listIndex); 8 | 9 | /// ChartItem contains value of an item and min/max heights. 10 | /// This is useful when you want to have different design/color based on item value or height. 11 | final ChartItem item; 12 | 13 | /// Item index represents index of an item in the list. This is useful when you want to have different design/colors 14 | /// for each item. 15 | /// 16 | /// E.g. if your chart data is : 17 | /// 18 | /// [ 19 | /// [4, 6, 3, 6, 7, 9].map((e) => ChartValue(e.toDouble())).toList(), 20 | /// ] 21 | /// 22 | /// This will return 0 for first item (4), 1 for second item (6) and so on. 23 | final int itemIndex; 24 | 25 | /// List index represents index of an list in the data. This is useful if you have multiple lists and want to have 26 | /// different design/colors for them. 27 | /// 28 | /// E.g. if your chart data is : 29 | /// 30 | /// [ 31 | /// [4, 6, 3, 6, 7, 9].map((e) => ChartValue(e.toDouble())).toList(), 32 | /// [1, 5, 2, 3, 6, 4].map((e) => ChartValue(e.toDouble())).toList(), 33 | /// ] 34 | /// 35 | /// This will return 0 for first list ([4, 6, 3, 6, 7, 9]) and 1 for second list ([1, 5, 2, 3, 6, 4]) and so on. 36 | final int listIndex; 37 | 38 | @override 39 | String toString() { 40 | return 'ItemBuilderData{item: $item, itemIndex: $itemIndex, listIndex: $listIndex}'; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/item_options.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Item painter, use [barPainter] or [bubblePainter]. 4 | /// Custom painter can also be added by extending [GeometryPainter] 5 | typedef ChartGeometryPainter = GeometryPainter Function( 6 | ChartItem item, 7 | ChartData data, 8 | ItemOptions itemOptions, 9 | DrawDataItem drawDataItem); 10 | 11 | /// Options for chart items. You can use this subclasses: [BarItemOptions], [BubbleItemOptions], [WidgetItemOptions] 12 | /// 13 | /// Required [itemBuilder] parameter is used to provide a data for each item on the chart. 14 | /// 15 | /// Required [geometryPainter] specifies how to draw these items on the chart. 16 | /// 17 | /// Extend this to make your custom options or painters if needed. 18 | /// 19 | /// [WidgetItemOptions] is only [ItemOptions] that is not using [geometryPainter] and 20 | /// instead is passing [_EmptyGeometryPainter] as the painter, and defaulting all other values to 0.0. 21 | abstract class ItemOptions { 22 | /// Default constructor for ItemOptions 23 | /// It's recommended to make/use custom item options for custom painters. 24 | const ItemOptions({ 25 | required this.geometryPainter, 26 | this.padding = EdgeInsets.zero, 27 | this.multiValuePadding = EdgeInsets.zero, 28 | this.maxBarWidth, 29 | this.minBarWidth, 30 | this.startPosition = 0.5, 31 | required this.itemBuilder, 32 | }) : assert(maxBarWidth == null || 33 | minBarWidth == null || 34 | maxBarWidth >= minBarWidth); 35 | 36 | const ItemOptions._lerp({ 37 | required this.geometryPainter, 38 | this.padding = EdgeInsets.zero, 39 | this.multiValuePadding = EdgeInsets.zero, 40 | this.maxBarWidth, 41 | this.minBarWidth, 42 | this.startPosition = 0.5, 43 | double multiItemStack = 1.0, 44 | required this.itemBuilder, 45 | }); 46 | 47 | /// Item padding, if [minBarWidth] and [padding] are more then available space 48 | /// [padding] will get ignored 49 | final EdgeInsets padding; 50 | 51 | /// Multi value chart padding, this will `group` values with same index from different lists 52 | /// use to make space between index changes in multi value charts 53 | /// Only used for multiple data lists when they are not stacked 54 | final EdgeInsets multiValuePadding; 55 | 56 | final ItemBuilder itemBuilder; 57 | 58 | /// Max width of item in the chart 59 | final double? maxBarWidth; 60 | 61 | /// Min width of item in the chart 62 | final double? minBarWidth; 63 | 64 | /// Set start position. 65 | /// This value ranges from 0.0 - 1.0. 66 | /// 67 | /// 0.0 means that start position is left most point of the item, 68 | /// 1.0 means right most point. 69 | /// 70 | /// By default this is set to 0.5, so items are located in center 71 | final double startPosition; 72 | 73 | /// Geometry 74 | final ChartGeometryPainter geometryPainter; 75 | 76 | /// Animate to next [ItemOptions] state 77 | /// When making custom [ItemOptions] make sure to override this return custom painter 78 | /// with all available options, otherwise changes in options won't be animated 79 | ItemOptions animateTo(ItemOptions endValue, double t); 80 | } 81 | -------------------------------------------------------------------------------- /lib/chart/model/theme/item_theme/widget/widget_item_options.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | // Hidden because it's only used if chart item is a widget. 4 | GeometryPainter _emptyPainter( 5 | ChartItem item, ChartData data, ItemOptions itemOptions, DrawDataItem drawDataItem) => 6 | _EmptyGeometryPainter(item, data, itemOptions); 7 | 8 | typedef WidgetItemBuilder = Widget Function(ItemBuilderData); 9 | 10 | /// Options for widget items. 11 | /// 12 | /// [widgetItemBuilder] returns a [Widget] that will be shown as [ChartItem]. 13 | /// 14 | /// [multiStackItem] This has effect only if you have multiple lists. 15 | /// Should the items stack one on top of the other. If false items will be shown side by side in single [itemWidth] 16 | /// 17 | /// To show basic chart you can just use: 18 | /// ```dart 19 | /// itemOptions: WidgetItemOptions( 20 | /// chartItemBuilder: (data) => Container(color: Colors.red), 21 | /// ), 22 | /// ``` 23 | /// 24 | /// You can replace your ValueDecoration with [WidgetItemOptions] like this: 25 | /// ```dart 26 | /// itemOptions: WidgetItemOptions( 27 | /// chartItemBuilder: (data) => Container( 28 | /// color: Colors.red, 29 | /// child: Center( 30 | /// child: Text( 31 | /// '${item.max?.toString()}', 32 | /// style: TextStyle(color: Colors.white), 33 | /// ), 34 | /// ), 35 | /// ), 36 | /// ), 37 | /// ``` 38 | /// 39 | /// Other options are reverted to 0 since you can set everything in the builder. 40 | /// 41 | class WidgetItemOptions extends ItemOptions { 42 | /// Constructor for bar item options, has some extra options just for [BarGeometryPainter] 43 | const WidgetItemOptions({ 44 | required this.widgetItemBuilder, 45 | EdgeInsets multiValuePadding = EdgeInsets.zero, 46 | double? maxBarWidth, 47 | double? minBarWidth, 48 | }) : super( 49 | padding: EdgeInsets.zero, 50 | multiValuePadding: multiValuePadding, 51 | geometryPainter: _emptyPainter, 52 | itemBuilder: widgetItemBuilder, 53 | maxBarWidth: maxBarWidth, 54 | minBarWidth: minBarWidth, 55 | ); 56 | 57 | const WidgetItemOptions._lerp({ 58 | required this.widgetItemBuilder, 59 | EdgeInsets multiValuePadding = EdgeInsets.zero, 60 | }) : super._lerp( 61 | multiValuePadding: multiValuePadding, 62 | geometryPainter: _emptyPainter, 63 | itemBuilder: widgetItemBuilder, 64 | ); 65 | 66 | final WidgetItemBuilder widgetItemBuilder; 67 | 68 | @override 69 | ItemOptions animateTo(ItemOptions endValue, double t) { 70 | return WidgetItemOptions._lerp( 71 | widgetItemBuilder: endValue is WidgetItemOptions ? endValue.widgetItemBuilder : widgetItemBuilder, 72 | multiValuePadding: EdgeInsets.lerp(multiValuePadding, endValue.multiValuePadding, t) ?? EdgeInsets.zero, 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /lib/chart/model/theme/scroll_settings.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | class ScrollSettings { 4 | const ScrollSettings({ 5 | this.visibleItems, 6 | }) : assert(visibleItems == null || visibleItems > 0, 7 | 'visibleItems must be greater than 0'), 8 | _isScrollable = 1.0; 9 | 10 | const ScrollSettings.none() 11 | : _isScrollable = 0.0, 12 | visibleItems = null; 13 | 14 | ScrollSettings._lerp(this._isScrollable, this.visibleItems); 15 | 16 | final double _isScrollable; 17 | 18 | /// Number of visible items on the screen. 19 | final double? visibleItems; 20 | 21 | static ScrollSettings lerp(ScrollSettings a, ScrollSettings b, double t) { 22 | // This values should never return null, this is for null-safety 23 | // But if it somehow does occur, then revert to default values 24 | final scrollableLerp = 25 | lerpDouble(a._isScrollable, b._isScrollable, t) ?? 0.0; 26 | final visibleLerp = lerpDouble(a.visibleItems, b.visibleItems, t); 27 | 28 | return ScrollSettings._lerp(scrollableLerp, visibleLerp); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/chart/render/data_renderer/chart_data_renderer.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | typedef ChartDataRendererFactory = ChartDataRenderer Function( 4 | ChartState state); 5 | 6 | /// Renderer for whole chart data 7 | /// 8 | /// It should go through all data in chart state and assign [ChartItemRenderer] to each item in data. 9 | abstract class ChartDataRenderer extends MultiChildRenderObjectWidget { 10 | ChartDataRenderer({Key? key, List children = const []}) 11 | : super(key: key, children: children); 12 | } 13 | 14 | abstract class ChartItemRenderer extends RenderBox { 15 | ChartItemRenderer(this._chartState) : super(); 16 | 17 | ChartState _chartState; 18 | ChartState get chartState => _chartState; 19 | set chartState(ChartState data) { 20 | if (_chartState != data) { 21 | _chartState = data; 22 | markNeedsPaint(); 23 | markNeedsSemanticsUpdate(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/chart/render/decorations/decoration_painter.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Abstract class for decorations 4 | /// Decorations are placed under and/or above items in the charts 5 | abstract class DecorationPainter { 6 | /// Draw decoration. 7 | /// Decoration can be foreground or background decoration that will be drawn on the chart 8 | /// decorations can ignore padding and can use whole available canvas to draw. 9 | void draw(Canvas canvas, Size size, ChartState state); 10 | 11 | /// Get extra margin (not definable by the user). This makes sure that any decoration 12 | /// that leaves original drawing window is not drawing outside of that window (This is not 13 | /// enforced right now but it's unwanted behaviour) 14 | /// 15 | /// Any decoration that needs space on side of the chart (any side) has to override this 16 | /// method and return how much space it needs and where as [EdgeInsets]. 17 | EdgeInsets marginNeeded() { 18 | return EdgeInsets.zero; 19 | } 20 | 21 | /// Get extra padding (not definable by user, calculated by decoration if needed). This makes sure 22 | /// that decoration will fit with the chart in wanted area. 23 | /// 24 | /// Any decoration that needs padding can override this method and return [EdgeInsets] how much space it needs. 25 | EdgeInsets paddingNeeded() { 26 | return EdgeInsets.zero; 27 | } 28 | 29 | Size layoutSize(BoxConstraints constraints, ChartState state) { 30 | return constraints.biggest; 31 | } 32 | 33 | Offset applyPaintTransform(ChartState state, Size size) { 34 | return Offset.zero; 35 | } 36 | 37 | /// Init decoration is first thing called on decorations, it will pass current [ChartState] 38 | /// so decoration can easily calculate needed stuff for their layout. 39 | void initDecoration(ChartState state) { 40 | return; 41 | } 42 | 43 | Widget getRenderer(ChartState state) { 44 | return ChartDecorationRenderer(state, this, key: ValueKey(hashCode)); 45 | } 46 | 47 | /// Animate to next decoration state, each decoration should implement this. 48 | /// This is just regular lerp function, but instead of static function where you pass start and 49 | /// end state, here we start with current state and animate to [endValue]. 50 | DecorationPainter animateTo(DecorationPainter endValue, double t); 51 | 52 | /// Used for animating, we just need to find matching type, don't actually check for equality since we want to animate 53 | /// from one state to other. Some decorations may consider overriding this in case multiples are used 54 | bool isSameType(DecorationPainter other) { 55 | return runtimeType == other.runtimeType; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/chart/render/decorations/renderer/chart_decoration_renderer.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | class ChartDecorationRenderer extends LeafRenderObjectWidget { 4 | ChartDecorationRenderer(this.chartState, this.decorationPainter, {Key? key}) 5 | : super(key: key); 6 | 7 | final ChartState chartState; 8 | final DecorationPainter decorationPainter; 9 | 10 | @override 11 | RenderObject createRenderObject(BuildContext context) { 12 | return _RenderChartDecoration(chartState, decorationPainter); 13 | } 14 | 15 | @override 16 | void updateRenderObject( 17 | BuildContext context, _RenderChartDecoration renderObject) { 18 | renderObject 19 | ..chartState = chartState 20 | ..item = decorationPainter; 21 | 22 | renderObject.markNeedsLayout(); 23 | } 24 | } 25 | 26 | class _RenderChartDecoration extends RenderBox { 27 | _RenderChartDecoration(this._chartState, this._decoration); 28 | 29 | DecorationPainter _decoration; 30 | set item(DecorationPainter decoration) { 31 | if (decoration != _decoration) { 32 | _decoration = decoration; 33 | markNeedsPaint(); 34 | } 35 | } 36 | 37 | DecorationPainter get item => _decoration; 38 | 39 | ChartState _chartState; 40 | set chartState(ChartState chartState) { 41 | if (chartState != _chartState) { 42 | _chartState = chartState; 43 | markNeedsPaint(); 44 | } 45 | } 46 | 47 | ChartState get chartState => _chartState; 48 | 49 | double get _defaultSize => 0; 50 | 51 | @override 52 | double computeMinIntrinsicWidth(double height) => _defaultSize; 53 | 54 | @override 55 | double computeMaxIntrinsicWidth(double height) => _defaultSize; 56 | 57 | @override 58 | double computeMinIntrinsicHeight(double width) => _defaultSize; 59 | 60 | @override 61 | double computeMaxIntrinsicHeight(double width) => _defaultSize; 62 | 63 | @override 64 | bool get sizedByParent => false; 65 | 66 | @override 67 | Size computeDryLayout(BoxConstraints constraints) { 68 | final _size = constraints.biggest; 69 | final childParentData = parentData! as BoxParentData; 70 | final offset = _decoration.applyPaintTransform(_chartState, _size); 71 | childParentData.offset = offset; 72 | 73 | return _decoration.layoutSize(constraints, _chartState); 74 | } 75 | 76 | @override 77 | void performLayout() { 78 | size = computeDryLayout(constraints); 79 | } 80 | 81 | @override 82 | void paint(PaintingContext context, Offset offset) { 83 | final canvas = context.canvas; 84 | canvas.save(); 85 | canvas.translate(offset.dx, offset.dy); 86 | 87 | _decoration.draw(canvas, size, _chartState); 88 | 89 | canvas.restore(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lib/chart/render/decorations/renderer/decorations_renderer.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | class DecorationsRenderer extends MultiChildRenderObjectWidget { 4 | DecorationsRenderer(List fixedDecoration, this.chartState, 5 | {Key? key}) 6 | : super( 7 | key: key, 8 | children: 9 | fixedDecoration.map((e) => e.getRenderer(chartState)).toList()); 10 | 11 | final ChartState chartState; 12 | 13 | @override 14 | RenderObject createRenderObject(BuildContext context) { 15 | return _FixedDecorationRenderObject(chartState); 16 | } 17 | 18 | @override 19 | void updateRenderObject( 20 | BuildContext context, _FixedDecorationRenderObject renderObject) { 21 | renderObject.chartState = chartState; 22 | renderObject.markNeedsLayout(); 23 | } 24 | } 25 | 26 | class _FixedDecorationRenderObject extends RenderBox 27 | with 28 | ContainerRenderObjectMixin, 29 | RenderBoxContainerDefaultsMixin { 30 | _FixedDecorationRenderObject(this._chartState); 31 | 32 | ChartState _chartState; 33 | set chartState(ChartState state) { 34 | if (_chartState != state) { 35 | _chartState = state; 36 | markNeedsPaint(); 37 | } 38 | } 39 | 40 | @override 41 | void setupParentData(RenderBox child) { 42 | if (child.parentData is! BoxPaneParentData) { 43 | child.parentData = BoxPaneParentData(); 44 | } 45 | } 46 | 47 | @override 48 | void performLayout() { 49 | var child = firstChild; 50 | 51 | while (child != null) { 52 | final childParentData = child.parentData! as BoxPaneParentData; 53 | 54 | child.layout(constraints.loosen()); 55 | assert(child.parentData == childParentData); 56 | child = childParentData.nextSibling; 57 | } 58 | 59 | size = constraints.biggest; 60 | } 61 | 62 | @override 63 | bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { 64 | return defaultHitTestChildren(result, position: position); 65 | } 66 | 67 | @override 68 | void paint(PaintingContext context, Offset offset) { 69 | var child = firstChild; 70 | while (child != null) { 71 | final childParentData = child.parentData! as BoxPaneParentData; 72 | context.paintChild(child, childParentData.offset + offset); 73 | child = childParentData.nextSibling; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/chart/render/decorations/target_legends_decoration.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Show text on the left side of the chart, this text will be at 4 | /// [TargetLineDecoration] or at max value of [TargetAreaDecoration]. 5 | /// 6 | /// Text will be rotated 90 CCW 7 | @Deprecated( 8 | 'You can make this decoration and much more using WidgetDecoration. Check migration guide for more info') 9 | class TargetLineLegendDecoration extends DecorationPainter { 10 | /// Target line legend constructor 11 | /// 12 | /// [legendDescription] and [legendStyle] are required 13 | TargetLineLegendDecoration({ 14 | required this.legendDescription, 15 | required this.legendStyle, 16 | this.legendTarget = 0, 17 | this.padding = EdgeInsets.zero, 18 | }) : assert(legendStyle.fontSize != null, 19 | 'You must specify fontSize when using TargetLineLegendDecoration'); 20 | 21 | /// Label to show at [legendTarget] 22 | final String legendDescription; 23 | 24 | /// Legend text style 25 | final TextStyle legendStyle; 26 | 27 | /// Label padding 28 | final EdgeInsets padding; 29 | 30 | /// Target value where to show the label 31 | final double legendTarget; 32 | 33 | @override 34 | void draw(Canvas canvas, Size size, ChartState state) { 35 | final _maxValue = state.data.maxValue - state.data.minValue; 36 | final scale = size.height / _maxValue; 37 | final _minValue = state.data.minValue * scale; 38 | 39 | canvas.save(); 40 | canvas.translate( 41 | state.defaultMargin.left, size.height + state.defaultMargin.top); 42 | 43 | size = state.defaultPadding.deflateSize(size); 44 | 45 | final _textPainter = TextPainter( 46 | text: TextSpan( 47 | text: legendDescription, 48 | style: legendStyle, 49 | ), 50 | textAlign: TextAlign.start, 51 | maxLines: 1, 52 | textDirection: TextDirection.ltr, 53 | )..layout( 54 | maxWidth: size.width, 55 | ); 56 | 57 | canvas.translate(-(legendStyle.fontSize ?? 0) * 1.5, 58 | -scale * legendTarget + _minValue + _textPainter.width + padding.top); 59 | canvas.rotate(pi * 1.5); 60 | 61 | _textPainter.paint( 62 | canvas, 63 | Offset.zero, 64 | ); 65 | 66 | canvas.restore(); 67 | } 68 | 69 | @override 70 | EdgeInsets marginNeeded() { 71 | return EdgeInsets.only(left: (legendStyle.fontSize ?? 0) * 2); 72 | } 73 | 74 | @override 75 | DecorationPainter animateTo(DecorationPainter endValue, double t) { 76 | if (endValue is TargetLineLegendDecoration) { 77 | return TargetLineLegendDecoration( 78 | legendStyle: TextStyle.lerp(legendStyle, endValue.legendStyle, t) ?? 79 | endValue.legendStyle, 80 | legendDescription: endValue.legendDescription, 81 | padding: 82 | EdgeInsets.lerp(padding, endValue.padding, t) ?? endValue.padding, 83 | legendTarget: lerpDouble(legendTarget, endValue.legendTarget, t) ?? 84 | endValue.legendTarget, 85 | ); 86 | } 87 | 88 | return this; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/chart/render/geometry/painters/bubble_geometry_painter.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Paint bubble value item. 4 | /// 5 | /// ┌───────────┐ --> Max value in set or [ChartData.axisMax] 6 | /// │ │ 7 | /// │ │ 8 | /// │ /⎺⎺\ │ --> ChartItem max value 9 | /// │ \__/ │ 10 | /// │ │ 11 | /// │ │ 12 | /// └───────────┘ --> 0 or [ChartData.axisMin] 13 | /// 14 | class BubbleGeometryPainter extends GeometryPainter { 15 | /// Constructor for bubble painter 16 | BubbleGeometryPainter(ChartItem item, ChartData data, 17 | ItemOptions itemOptions, this.drawDataItem) 18 | : super(item, data, itemOptions); 19 | 20 | final BubbleItem drawDataItem; 21 | 22 | @override 23 | void draw(Canvas canvas, Size size, Paint paint) { 24 | final _maxValue = data.maxValue - data.minValue; 25 | final _verticalMultiplier = size.height / max(1, _maxValue); 26 | final _minValue = data.minValue * _verticalMultiplier; 27 | 28 | final _itemWidth = max( 29 | itemOptions.minBarWidth ?? 0.0, 30 | min( 31 | itemOptions.maxBarWidth ?? double.infinity, 32 | size.width - 33 | (itemOptions.padding.horizontal.isNegative 34 | ? 0.0 35 | : itemOptions.padding.horizontal))); 36 | 37 | final _itemMaxValue = item.max ?? 0.0; 38 | // If item is empty, or it's max value is below chart's minValue then don't draw it. 39 | // minValue can be below 0, this will just ensure that animation is drawn correctly. 40 | if (item.isEmpty || _itemMaxValue < data.minValue) { 41 | return; 42 | } 43 | 44 | /// Bubble value, we need to draw a circle for this one 45 | final _circleSize = _itemWidth / 2; 46 | 47 | canvas.drawCircle( 48 | Offset(size.width * 0.5, 49 | size.height - _itemMaxValue * _verticalMultiplier - _minValue), 50 | _circleSize, 51 | paint, 52 | ); 53 | 54 | if (itemOptions is BubbleItemOptions) { 55 | final _border = drawDataItem.border; 56 | 57 | if (_border.style == BorderStyle.solid) { 58 | final _borderPaint = Paint(); 59 | _borderPaint.style = PaintingStyle.stroke; 60 | 61 | _borderPaint.color = _border.color; 62 | _borderPaint.strokeWidth = _border.width; 63 | 64 | canvas.drawCircle( 65 | Offset(size.width * 0.5, 66 | size.height - _itemMaxValue * _verticalMultiplier - _minValue), 67 | _circleSize, 68 | _borderPaint, 69 | ); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/chart/render/geometry/painters/empty_geometry_painter.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Empty geometry painter. Used if you don't want to use [DecorationPainter] to paint the items. 4 | class _EmptyGeometryPainter extends GeometryPainter { 5 | _EmptyGeometryPainter( 6 | ChartItem item, ChartData data, ItemOptions itemOptions) 7 | : super(item, data, itemOptions); 8 | 9 | @override 10 | void draw(Canvas canvas, Size size, Paint paint) { 11 | // NOOP 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/chart/render/geometry/painters/geometry_painter.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Item painter for charts 4 | /// Chart will slice the canvas and each item is painted has constraints (width / [itemWidth]) * height 5 | abstract class GeometryPainter { 6 | /// Default constructor for [GeometryPainter] 7 | @mustCallSuper 8 | GeometryPainter(this.item, this.data, this.itemOptions); 9 | 10 | /// Current data of the chart 11 | final ChartData data; 12 | final ItemOptions itemOptions; 13 | 14 | /// Current item being painted 15 | final ChartItem item; 16 | 17 | /// Draw [ChartItem] on the canvas. 18 | /// Canvas with item size is passed, item's padding and margin need to be calculated 19 | /// This is to allow more flexibility for more custom items if needed 20 | /// 21 | /// Use [paint] for drawing item to canvas, this allows us to change colors of the item 22 | /// from [_ChartPainter] 23 | void draw(Canvas canvas, Size size, Paint paint); 24 | 25 | /// Calculate item width based on current [Size] and [ChartState] 26 | double itemWidth(Size size) { 27 | return max(itemOptions.minBarWidth ?? 0.0, 28 | min(itemOptions.maxBarWidth ?? double.infinity, size.width)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/chart/render/util/dashed_path_util.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Creates a new path that is drawn from the segments of `source`. 4 | /// Passing a `source` that is an empty path will return an empty path. 5 | Path dashPath( 6 | Path source, { 7 | required List dashArray, 8 | }) { 9 | final dest = Path(); 10 | 11 | // Get dashed path for this [PathMetric] 12 | Path _pathFromMetrics(PathMetric metric) { 13 | final _path = Path(); 14 | var distance = 0.0; 15 | var _index = 0; 16 | 17 | while (distance < metric.length) { 18 | final len = dashArray[_index % dashArray.length]; 19 | if (_index % 2 == 0) { 20 | _path.addPath( 21 | metric.extractPath(distance, distance + len), Offset.zero); 22 | } 23 | distance += len; 24 | _index++; 25 | } 26 | 27 | return _path; 28 | } 29 | 30 | source.computeMetrics().forEach((metric) { 31 | dest.addPath(_pathFromMetrics(metric), Offset.zero); 32 | }); 33 | 34 | return dest; 35 | } 36 | -------------------------------------------------------------------------------- /lib/chart/widgets/chart.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Draw [_ChartWidget] with set [state], [width] and [height] for the chart 4 | class Chart extends StatelessWidget { 5 | /// Make chart widget 6 | const Chart({ 7 | required this.state, 8 | this.height = 240.0, 9 | this.width, 10 | Key? key, 11 | }) : super(key: key); 12 | 13 | /// Chart height 14 | final double height; 15 | 16 | /// Chart width 17 | final double? width; 18 | 19 | /// Chart state 20 | final ChartState state; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return _ChartWidget( 25 | height: height, 26 | width: width, 27 | state: state, 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/chart/widgets/chart_widget.dart: -------------------------------------------------------------------------------- 1 | part of charts_painter; 2 | 3 | /// Chart widget will initiate [_ChartPainter] with passed state 4 | /// chart size and [GestureDetector] are added here as well 5 | /// 6 | // TODO(lukaknezic): Add ScrollView here as well? We already have access to [ChartState.behaviour.isScrollable] 7 | class _ChartWidget extends StatelessWidget { 8 | const _ChartWidget({ 9 | this.height = 240.0, 10 | this.width, 11 | required this.state, 12 | Key? key, 13 | }) : super(key: key); 14 | 15 | final double? height; 16 | final double? width; 17 | final ChartState state; 18 | 19 | double get _horizontalItemPadding => state.itemOptions.padding.horizontal; 20 | 21 | double _clampItemWidth(double width) { 22 | final minBarWidth = state.itemOptions.minBarWidth; 23 | final maxBarWidth = state.itemOptions.maxBarWidth; 24 | 25 | if (minBarWidth != null) { 26 | return max(minBarWidth, width); 27 | } 28 | 29 | if (maxBarWidth != null) { 30 | return min(maxBarWidth, width); 31 | } 32 | 33 | return width; 34 | } 35 | 36 | double _calcItemWidthNonScrollable() { 37 | return max( 38 | state.itemOptions.minBarWidth ?? 0.0, 39 | state.itemOptions.maxBarWidth ?? 0.0, 40 | ); 41 | } 42 | 43 | double _calcItemWidthForScrollable(double frameWidth) { 44 | final visibleItems = state.behaviour.scrollSettings.visibleItems; 45 | if (visibleItems == null) { 46 | return _calcItemWidthNonScrollable(); 47 | } 48 | 49 | final availableWidth = frameWidth - state.defaultPadding.horizontal; 50 | final width = availableWidth / visibleItems - _horizontalItemPadding; 51 | 52 | return _clampItemWidth(max(0, width)); 53 | } 54 | 55 | double _calcItemWidth(double frameWidth) { 56 | // Used for smooth transition between scrollable and non-scrollable chart 57 | final sizeTween = Tween( 58 | begin: _calcItemWidthNonScrollable(), 59 | end: _calcItemWidthForScrollable(frameWidth), 60 | ); 61 | 62 | return sizeTween.transform(state.behaviour.scrollSettings._isScrollable); 63 | } 64 | 65 | Size _calcChartSize(double itemWidth, double frameWidth, double frameHeight) { 66 | final listSize = state.data.listSize; 67 | final totalItemWidth = itemWidth + _horizontalItemPadding; 68 | final listWidth = totalItemWidth * listSize; 69 | 70 | final chartWidth = frameWidth + 71 | (listWidth - frameWidth) * state.behaviour.scrollSettings._isScrollable; 72 | final finalWidth = chartWidth + state.defaultPadding.horizontal; 73 | 74 | return Size(finalWidth, frameHeight); 75 | } 76 | 77 | @override 78 | Widget build(BuildContext context) { 79 | return LayoutBuilder( 80 | builder: (context, constraints) { 81 | final frameWidth = 82 | constraints.maxWidth.isFinite ? constraints.maxWidth : width!; 83 | final frameHeight = 84 | constraints.maxHeight.isFinite ? constraints.maxHeight : height!; 85 | 86 | final itemWidth = _calcItemWidth(frameWidth); 87 | final size = _calcChartSize(itemWidth, frameWidth, frameHeight); 88 | 89 | return Container( 90 | constraints: BoxConstraints.tight(size), 91 | child: ChartRenderer(state), 92 | ); 93 | }, 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: charts_painter 2 | description: Highly customizable and extendable charts library for flutter made with custom painters 3 | version: 3.1.0 4 | homepage: https://github.com/infinum/flutter-charts 5 | repository: https://github.com/infinum/flutter-charts 6 | 7 | environment: 8 | sdk: '>=2.12.0 <3.0.0' 9 | flutter: ">=1.17.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | equatable: ^2.0.5 15 | collection: ^1.16.0 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | pedantic: ^1.11.1 21 | golden_toolkit: ^0.13.0 22 | lints: ^2.0.1 23 | alchemist: 24 | git: 25 | url: https://github.com/Betterment/alchemist 26 | ref: d57c359ceadeae7ebde51639bcf9fbf37bb5f100 27 | 28 | # For information on the generic Dart part of this file, see the 29 | # following page: https://dart.dev/tools/pub/pubspec 30 | 31 | # The following section is specific to Flutter. 32 | flutter: 33 | uses-material-design: true 34 | 35 | screenshots: 36 | - description: 'Showcase of possible charts with charts_painter' 37 | path: assets/showcase.gif 38 | -------------------------------------------------------------------------------- /test/flutter_test_config.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:alchemist/alchemist.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:golden_toolkit/golden_toolkit.dart'; 6 | 7 | Future testExecutable(FutureOr Function() testMain) async { 8 | const isRunningInCi = bool.fromEnvironment('CI', defaultValue: false); 9 | 10 | await loadAppFonts(); 11 | 12 | return AlchemistConfig.runWithConfig( 13 | config: AlchemistConfig( 14 | theme: ThemeData( 15 | colorScheme: ColorScheme.fromSeed( 16 | seedColor: Colors.red, 17 | brightness: Brightness.light, 18 | background: Colors.white, 19 | ), 20 | backgroundColor: Colors.white, 21 | brightness: Brightness.light, 22 | ), 23 | ciGoldensConfig: const CiGoldensConfig( 24 | enabled: isRunningInCi, 25 | tolerance: 0.05, 26 | ), 27 | platformGoldensConfig: const PlatformGoldensConfig( 28 | enabled: !isRunningInCi, 29 | ), 30 | ), 31 | run: testMain, 32 | ); 33 | 34 | // return GoldenToolkit.runWithConfiguration( 35 | // () async { 36 | // await loadAppFonts(); 37 | // return testMain(); 38 | // }, 39 | // config: GoldenToolkitConfiguration( 40 | // enableRealShadows: false, 41 | // // Mac has fon smoothing that will sometimes trigger false positives based on system settings. 42 | // // Skip assertion on Mac until fix is deployed: https://github.com/flutter/flutter/issues/56383 43 | // // skipGoldenAssertion: () => Platform.isMacOS, 44 | // ), 45 | // ); 46 | } 47 | -------------------------------------------------------------------------------- /test/golden/GOLDENS.md: -------------------------------------------------------------------------------- 1 | ## Golden files 2 | These are generated images that are tested against new code. 3 | Any changes will be visible here as well. 4 | 5 | ## Table of Contents 6 | * [Decorations](#decorations) 7 | * [Horizontal decoration golden](#horizontal-decoration-golden) 8 | * [Vertical decoration golden](#vertical-decoration-golden) 9 | * [Grid decoration golden](#grid-decoration-golden) 10 | * [Border decoration golden](#border-decoration-golden) 11 | * [Value decoration golden](#value-decoration-golden) 12 | * [Target line decoration golden](#target-line-decoration-golden) 13 | * [Target line text decoration golden](#target-line-text-decoration-golden) 14 | * [Target area decoration golden](#target-area-decoration-golden) 15 | * [Sparkline decoration golden](#sparkline-decoration-golden) 16 | * [Selected decoration golden](#selected-item-decoration-golden) 17 | * [Complex](#complex) 18 | * [Multi value charts](#multi-value-charts) 19 | * [Showcase charts](#showcase-charts) 20 | 21 | ## Decorations 22 | 23 | ##### Horizontal decoration golden 24 | ![horizontal_decorations] 25 | 26 | ##### Vertical decoration golden 27 | ![vertical_decorations] 28 | 29 | ##### Grid decoration golden 30 | ![grid_decorations] 31 | 32 | ##### Border decoration golden 33 | Deprecated 34 | 35 | ##### Value decoration golden 36 | Deprecated 37 | 38 | ##### Target line decoration golden 39 | Deprecated 40 | 41 | ##### Target line text decoration golden 42 | Deprecated 43 | 44 | ##### Target area decoration golden 45 | Deprecated 46 | 47 | ##### Sparkline decoration golden 48 | ![sparkline_decorations] 49 | 50 | ##### Selected item decoration golden 51 | Deprecated 52 | 53 | ## Complex 54 | 55 | ##### Multi value charts 56 | ![complex_multi_value] 57 | 58 | ##### Showcase charts 59 | ![showcase] 60 | 61 | [vertical_decorations]: decoration/goldens/macos/vertical_decoration_golden.png 62 | [horizontal_decorations]: decoration/goldens/macos/horizontal_decoration_golden.png 63 | [grid_decorations]: decoration/goldens/macos/grid_decoration_golden.png 64 | [border_decorations]: decoration/goldens/macos/border_decoration_golden.png 65 | [value_decorations]: decoration/goldens/macos/value_decoration_golden.png 66 | [target_line_decorations]: decoration/goldens/macos/target_line_decoration_golden.png 67 | [target_line_text_decorations]: decoration/goldens/macos/target_line_text_decoration_golden.png 68 | [target_area_decorations]: decoration/goldens/macos/target_area_decoration_golden.png 69 | [sparkline_decorations]: decoration/goldens/macos/sparkline_decoration_golden.png 70 | [selected_item_decorations]: decoration/goldens/macos/selected_item_decoration_golden.png 71 | [complex_multi_value]: complex/goldens/macos/complex_multi_charts.png 72 | [showcase]: complex/goldens/macos/showcase_charts.png -------------------------------------------------------------------------------- /test/golden/complex/goldens/ci/complex_multi_charts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/complex/goldens/ci/complex_multi_charts.png -------------------------------------------------------------------------------- /test/golden/complex/goldens/ci/showcase_charts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/complex/goldens/ci/showcase_charts.png -------------------------------------------------------------------------------- /test/golden/complex/goldens/macos/complex_multi_charts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/complex/goldens/macos/complex_multi_charts.png -------------------------------------------------------------------------------- /test/golden/complex/goldens/macos/showcase_charts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/complex/goldens/macos/showcase_charts.png -------------------------------------------------------------------------------- /test/golden/decoration/border_decoration_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alchemist/alchemist.dart'; 2 | import 'package:charts_painter/chart.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:golden_toolkit/golden_toolkit.dart'; 6 | 7 | import '../util.dart'; 8 | 9 | void main() { 10 | setUpAll(() async { 11 | await loadAppFonts(); 12 | }); 13 | 14 | goldenTest('Border decoration', fileName: 'border_decoration_golden', 15 | builder: () { 16 | return GoldenTestGroup( 17 | children: [ 18 | GoldenTestScenario( 19 | name: 'Default', 20 | child: getDefaultChart(backgroundDecorations: [ 21 | BorderDecoration(), 22 | ]), 23 | ), 24 | GoldenTestScenario( 25 | name: 'Increase width', 26 | child: getDefaultChart(backgroundDecorations: [ 27 | BorderDecoration( 28 | borderWidth: 6.0, 29 | ), 30 | ]), 31 | ), 32 | GoldenTestScenario( 33 | name: 'End with cahrt', 34 | child: getDefaultChart(backgroundDecorations: [ 35 | BorderDecoration( 36 | sidesWidth: Border.symmetric( 37 | vertical: BorderSide(width: 1.0, color: Colors.black))), 38 | ]), 39 | ), 40 | GoldenTestScenario( 41 | name: 'Just vertical', 42 | child: getDefaultChart(backgroundDecorations: [ 43 | BorderDecoration( 44 | sidesWidth: Border.symmetric( 45 | vertical: BorderSide(width: 1.0, color: Colors.black))), 46 | ]), 47 | ), 48 | GoldenTestScenario( 49 | name: 'Just horizontal', 50 | child: getDefaultChart(backgroundDecorations: [ 51 | BorderDecoration( 52 | sidesWidth: Border.symmetric( 53 | horizontal: BorderSide(width: 1.0, color: Colors.black))), 54 | ]), 55 | ), 56 | GoldenTestScenario( 57 | name: 'All different', 58 | child: getDefaultChart(backgroundDecorations: [ 59 | BorderDecoration( 60 | sidesWidth: Border( 61 | top: BorderSide(width: 2.0, color: Colors.red), 62 | bottom: BorderSide(width: 4.0, color: Colors.yellow), 63 | left: BorderSide(width: 2.0, color: Colors.green), 64 | right: BorderSide(width: 4.0, color: Colors.black), 65 | )), 66 | ]), 67 | ), 68 | ], 69 | ); 70 | }); 71 | } 72 | -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/border_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/border_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_border_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_border_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_grid_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_grid_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_horizontal_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_horizontal_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_selected_item_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_selected_item_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_sparkline_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_sparkline_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_target_area_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_target_area_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_target_line_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_target_line_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_target_line_text_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_target_line_text_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/general_vertical_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/general_vertical_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/grid_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/grid_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/horizontal_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/horizontal_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/sparkline_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/sparkline_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/vertical_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/vertical_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/ci/widget_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/ci/widget_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/border_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/border_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_border_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_border_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_grid_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_grid_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_horizontal_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_horizontal_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_selected_item_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_selected_item_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_sparkline_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_sparkline_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_target_area_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_target_area_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_target_line_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_target_line_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_target_line_text_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_target_line_text_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/general_vertical_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/general_vertical_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/grid_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/grid_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/horizontal_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/horizontal_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/sparkline_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/sparkline_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/vertical_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/vertical_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/goldens/macos/widget_decoration_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/decoration/goldens/macos/widget_decoration_golden.png -------------------------------------------------------------------------------- /test/golden/decoration/vertical_decoration_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:alchemist/alchemist.dart'; 2 | import 'package:charts_painter/chart.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:golden_toolkit/golden_toolkit.dart'; 6 | 7 | import '../util.dart'; 8 | 9 | void main() { 10 | setUpAll(() async { 11 | await loadAppFonts(); 12 | }); 13 | 14 | goldenTest('Vertical decoration', fileName: 'vertical_decoration_golden', 15 | builder: () { 16 | return GoldenTestGroup(children: [ 17 | GoldenTestScenario( 18 | name: 'Default', 19 | child: getDefaultChart(backgroundDecorations: [ 20 | VerticalAxisDecoration(), 21 | ]), 22 | ), 23 | GoldenTestScenario( 24 | name: 'Show values on bottom', 25 | child: getDefaultChart(backgroundDecorations: [ 26 | VerticalAxisDecoration( 27 | showValues: true, 28 | legendFontStyle: defaultTextStyle, 29 | valuesPadding: const EdgeInsets.only(top: 8.0, bottom: 4.0)), 30 | ]), 31 | ), 32 | GoldenTestScenario( 33 | name: 'Show values on top', 34 | child: getDefaultChart(backgroundDecorations: [ 35 | VerticalAxisDecoration( 36 | showValues: true, 37 | legendPosition: VerticalLegendPosition.top, 38 | legendFontStyle: defaultTextStyle, 39 | valuesPadding: const EdgeInsets.only(top: 8.0, bottom: 4.0)), 40 | ]), 41 | ), 42 | GoldenTestScenario( 43 | name: 'Increase steps', 44 | child: getDefaultChart(backgroundDecorations: [ 45 | VerticalAxisDecoration( 46 | showValues: true, 47 | axisStep: 2.0, 48 | valuesAlign: TextAlign.start, 49 | legendFontStyle: defaultTextStyle, 50 | valuesPadding: const EdgeInsets.only(top: 8.0, bottom: 4.0)), 51 | ]), 52 | ), 53 | GoldenTestScenario( 54 | name: 'Show dashed lines', 55 | child: getDefaultChart(backgroundDecorations: [ 56 | VerticalAxisDecoration( 57 | showValues: true, 58 | dashArray: [10, 10], 59 | legendFontStyle: defaultTextStyle, 60 | valuesPadding: const EdgeInsets.only(top: 8.0, bottom: 4.0)), 61 | ]), 62 | ), 63 | GoldenTestScenario( 64 | name: 'End lines with chart', 65 | child: getDefaultChart(backgroundDecorations: [ 66 | VerticalAxisDecoration( 67 | showValues: true, 68 | endWithChart: true, 69 | legendFontStyle: defaultTextStyle, 70 | valuesPadding: const EdgeInsets.only(top: 8.0, bottom: 4.0)), 71 | ]), 72 | ) 73 | ]); 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /test/golden/examples/goldens/ci/bar_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/ci/bar_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/ci/line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/ci/line_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/ci/multi_line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/ci/multi_line_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/ci/simple_bar_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/ci/simple_bar_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/ci/simple_line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/ci/simple_line_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/macos/bar_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/macos/bar_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/macos/line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/macos/line_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/macos/multi_line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/macos/multi_line_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/macos/simple_bar_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/macos/simple_bar_chart.png -------------------------------------------------------------------------------- /test/golden/examples/goldens/macos/simple_line_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/examples/goldens/macos/simple_line_chart.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/ci/bar_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/ci/bar_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/ci/bubble_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/ci/bubble_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/ci/candle_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/ci/candle_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/ci/widget_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/ci/widget_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/macos/bar_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/macos/bar_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/macos/bubble_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/macos/bubble_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/macos/candle_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/macos/candle_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/geometry/goldens/macos/widget_geometry_golden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/infinum/flutter-charts/0a7ac5cefbd5a564e315262d0d340b1282263d20/test/golden/geometry/goldens/macos/widget_geometry_golden.png -------------------------------------------------------------------------------- /test/golden/util.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:charts_painter/chart.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | TextStyle get defaultTextStyle => 7 | TextStyle(fontFamily: 'Roboto', color: Colors.black54, fontSize: 12.0); 8 | 9 | Widget getDefaultChart({ 10 | List? foregroundDecorations, 11 | List? backgroundDecorations, 12 | }) { 13 | return Container( 14 | height: 300, 15 | width: 450, 16 | padding: EdgeInsets.zero, 17 | child: Chart( 18 | state: ChartState( 19 | data: ChartData.fromList( 20 | [5, 6, 8, 4, 3, 5, 2, 6, 7] 21 | .map((e) => BarValue(e.toDouble())) 22 | .toList(), 23 | valueAxisMaxOver: 2, 24 | ), 25 | itemOptions: BarItemOptions( 26 | padding: const EdgeInsets.symmetric(horizontal: 4.0), 27 | barItemBuilder: (_) => BarItem(color: Colors.red.withOpacity(0.1)), 28 | ), 29 | backgroundDecorations: backgroundDecorations ?? [], 30 | foregroundDecorations: foregroundDecorations ?? [], 31 | ), 32 | ), 33 | ); 34 | } 35 | 36 | Widget getMultiValueChart({ 37 | int size = 2, 38 | List? foregroundDecorations, 39 | List? backgroundDecorations, 40 | ItemOptions? options, 41 | ChartBehaviour? behaviour, 42 | DataStrategy strategy = const DefaultDataStrategy(stackMultipleValues: true), 43 | }) { 44 | return SizedBox( 45 | height: 300, 46 | width: 400, 47 | child: Padding( 48 | padding: EdgeInsets.zero, 49 | child: Chart( 50 | state: ChartState( 51 | data: ChartData( 52 | List.generate( 53 | size, 54 | (index) => List.generate( 55 | 8, 56 | (i) => BarValue( 57 | (Random(((index + 1) * (i + 1))).nextDouble() * 15) + 58 | 5))), 59 | valueAxisMaxOver: 2, 60 | dataStrategy: strategy, 61 | ), 62 | itemOptions: options ?? BarItemOptions(), 63 | behaviour: behaviour ?? ChartBehaviour(), 64 | backgroundDecorations: backgroundDecorations ?? [], 65 | foregroundDecorations: foregroundDecorations ?? [], 66 | ), 67 | ), 68 | ), 69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /test/unit/chart_data_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:charts_painter/chart.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | 4 | void main() { 5 | test('Max is extracted from data', () { 6 | final _data = ChartData.fromList( 7 | [2, 4, 6].map((e) => BarValue(e.toDouble())).toList()); 8 | expect(_data.maxValue, 6); 9 | // Min should be 0 10 | expect(_data.minValue, 0); 11 | }); 12 | 13 | test('Data can contain just 0', () { 14 | final _data = ChartData.fromList( 15 | [0, 0, 0, 0].map((e) => BarValue(e.toDouble())).toList()); 16 | 17 | expect(_data.isEmpty, false); 18 | expect(_data.maxValue, 0); 19 | expect(_data.minValue, 0); 20 | }); 21 | 22 | test('Negative data is new min', () { 23 | final _data = ChartData.fromList( 24 | [-2, 4, 6].map((e) => BarValue(e.toDouble())).toList()); 25 | 26 | expect(_data.minValue, -2); 27 | }); 28 | 29 | test('Value over axis adds to max value', () { 30 | final _data = ChartData.fromList( 31 | [2, 4, 6].map((e) => BarValue(e.toDouble())).toList(), 32 | valueAxisMaxOver: 2, 33 | ); 34 | 35 | expect(_data.maxValue, 8); 36 | }); 37 | 38 | test('Max value is extracted even if there are multiple lists', () { 39 | final _data = ChartData( 40 | [ 41 | [2, 4, 6].map((e) => BarValue(e.toDouble())).toList(), 42 | [8, 10, 12].map((e) => BarValue(e.toDouble())).toList() 43 | ], 44 | dataStrategy: DefaultDataStrategy(stackMultipleValues: true), 45 | ); 46 | 47 | expect(_data.maxValue, 12); 48 | }); 49 | 50 | test('Data can stack on top of each other', () { 51 | final _data = ChartData( 52 | [ 53 | [2, 4, 6].map((e) => BarValue(e.toDouble())).toList(), 54 | [8, 10, 12].map((e) => BarValue(e.toDouble())).toList() 55 | ], 56 | dataStrategy: StackDataStrategy(), 57 | ); 58 | 59 | // 6 + 12, last column should have height of 18 60 | expect(_data.maxValue, 18); 61 | }); 62 | } 63 | --------------------------------------------------------------------------------