├── .gitignore ├── .idea ├── .gitignore ├── kotlinc.xml ├── libraries │ ├── Dart_Packages.xml │ ├── Dart_SDK.xml │ ├── Flutter_Plugins.xml │ └── KotlinJavaRuntime.xml ├── misc.xml ├── modules.xml ├── runConfigurations │ └── main_dart.xml ├── vcs.xml └── workspace.xml ├── .metadata ├── AUTHORS ├── CHANGELOG.md ├── LICENSE ├── README-source-for-md.org ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── flutter_charts │ │ │ │ └── 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 ├── flutter_charts_android.iml ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── doc ├── notes │ └── design-and-deploy │ │ └── design-and-pub-publish-notes.org └── readme_images │ ├── README.org_20171102_154245_27063qmN.png │ ├── README.org_20171102_154329_270633wT.png │ ├── README.org_20171102_172324_27063E7Z.png │ ├── README.org_20171102_173422_27063ePm.png │ ├── README.org_20171102_180657_27063rZs.png │ ├── README.org_20171102_180915_270634jy.png │ ├── README.org_20171102_191037_27063qtB.png │ ├── README.org_20171102_191138_2706333H.png │ ├── README.org_20171102_195745_27063ECO.png │ ├── README.org_iterative-layout-step-1.png │ ├── README.org_iterative-layout-step-2.png │ ├── README.org_iterative-layout-step-3.png │ ├── README.org_iterative-layout-step-4.png │ ├── README.org_iterative-layout-step-5.png │ ├── ex10RandomData_lineChart.png │ ├── ex10RandomData_lineChart_w150.png │ ├── ex10RandomData_verticalBarChart.png │ ├── ex10RandomData_verticalBarChart_w150.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_w150.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart_w150.png │ ├── ex31SomeNegativeValues_lineChart.png │ ├── ex31SomeNegativeValues_lineChart_w150.png │ ├── ex31SomeNegativeValues_verticalBarChart.png │ ├── ex31SomeNegativeValues_verticalBarChart_w150.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_lineChart.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_lineChart_w150.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart_w150.png │ ├── ex33AllNegativeYsYAxisEndsBelow0_lineChart.png │ ├── ex33AllNegativeYsYAxisEndsBelow0_lineChart_w150.png │ ├── ex34OptionsDefiningUserTextStyleOnLabels_lineChart.png │ ├── ex34OptionsDefiningUserTextStyleOnLabels_lineChart_w150.png │ ├── ex35AnimalsBySeasonNoLabelsShown_lineChart.png │ ├── ex35AnimalsBySeasonNoLabelsShown_lineChart_w150.png │ ├── ex35AnimalsBySeasonNoLabelsShown_verticalBarChart.png │ ├── ex35AnimalsBySeasonNoLabelsShown_verticalBarChart_w150.png │ ├── ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart.png │ ├── ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_w150.png │ ├── ex50StocksWithNegativesWithUserColors_verticalBarChart.png │ ├── ex50StocksWithNegativesWithUserColors_verticalBarChart_w150.png │ ├── ex51AnimalsBySeasonManualLogarithmicScale_lineChart.png │ ├── ex51AnimalsBySeasonManualLogarithmicScale_lineChart_w150.png │ ├── ex52AnimalsBySeasonLogarithmicScale_lineChart.png │ ├── ex52AnimalsBySeasonLogarithmicScale_lineChart_w150.png │ ├── ex52AnimalsBySeasonLogarithmicScale_verticalBarChart.png │ ├── ex52AnimalsBySeasonLogarithmicScale_verticalBarChart_w150.png │ ├── ex60LabelsIteration1_verticalBarChart.png │ ├── ex60LabelsIteration1_verticalBarChart_w150.png │ ├── ex60LabelsIteration2_verticalBarChart.png │ ├── ex60LabelsIteration2_verticalBarChart_w150.png │ ├── ex60LabelsIteration3_verticalBarChart.png │ ├── ex60LabelsIteration3_verticalBarChart_w150.png │ ├── ex60LabelsIteration4_verticalBarChart.png │ ├── ex60LabelsIteration4_verticalBarChart_w150.png │ ├── ex900ErrorFixUserDataAllZero_lineChart.png │ └── ex900ErrorFixUserDataAllZero_lineChart_w150.png ├── example └── main_run_doc_example.dart ├── flutter_charts.iml ├── google_fonts ├── Comforter-Regular.ttf └── OFL.txt ├── integration_test ├── README.org ├── deprecated_v1 │ └── screenshot_create_deprecated_v1_test.dart ├── screenshot_create_test.dart └── screenshots_expected │ ├── ex10RandomData_barChart_column_stacked_oldManualLayouter.png │ ├── ex10RandomData_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_barChart_column_stacked_oldManualLayouter.png │ ├── ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex31SomeNegativeValues_barChart_column_nonStacked_newAutoLayouter.png │ ├── ex31SomeNegativeValues_barChart_column_stacked_newAutoLayouter.png │ ├── ex31SomeNegativeValues_barChart_column_stacked_oldManualLayouter.png │ ├── ex31SomeNegativeValues_barChart_row_nonStacked_newAutoLayouter.png │ ├── ex31SomeNegativeValues_barChart_row_stacked_newAutoLayouter.png │ ├── ex31SomeNegativeValues_lineChart_column_nonStacked_newAutoLayouter.png │ ├── ex31SomeNegativeValues_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex31SomeNegativeValues_lineChart_row_nonStacked_newAutoLayouter.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_barChart_column_stacked_oldManualLayouter.png │ ├── ex32AllPositiveYsYAxisStartsAbove0_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex33AllNegativeYsYAxisEndsBelow0_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex34OptionsDefiningUserTextStyleOnLabels_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex35AnimalsBySeasonNoLabelsShown_barChart_column_stacked_oldManualLayouter.png │ ├── ex35AnimalsBySeasonNoLabelsShown_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex50StocksWithNegativesWithUserColors_barChart_column_stacked_oldManualLayouter.png │ ├── ex52AnimalsBySeasonLogarithmicScale_barChart_column_stacked_oldManualLayouter.png │ ├── ex52AnimalsBySeasonLogarithmicScale_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex60LabelsIteration1_barChart_column_stacked_oldManualLayouter.png │ ├── ex60LabelsIteration2_barChart_column_stacked_oldManualLayouter.png │ ├── ex60LabelsIteration3_barChart_column_stacked_oldManualLayouter.png │ ├── ex60LabelsIteration4_barChart_column_stacked_oldManualLayouter.png │ ├── ex70AnimalsBySeasonLegendIsColumnStartLooseItemIsRowStartLoose_barChart_column_stacked_oldManualLayouter.png │ ├── ex71AnimalsBySeasonLegendIsColumnStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png │ ├── ex72AnimalsBySeasonLegendIsRowCenterLooseItemIsRowEndLoose_barChart_column_stacked_oldManualLayouter.png │ ├── ex73AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png │ ├── ex74AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightSecondGreedy_barChart_column_stacked_oldManualLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_nonStacked_newAutoLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_newAutoLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_oldManualLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_nonStacked_newAutoLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_stacked_newAutoLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_newAutoLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_oldManualLayouter.png │ ├── ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_row_nonStacked_newAutoLayouter.png │ ├── ex76AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenAligned_barChart_column_stacked_oldManualLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_barChart_column_nonStacked_newAutoLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_barChart_column_stacked_newAutoLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_barChart_row_nonStacked_newAutoLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_barChart_row_stacked_newAutoLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_lineChart_column_nonStacked_newAutoLayouter.png │ ├── ex800EU12CountriesHistoricalPopulation_lineChart_row_nonStacked_newAutoLayouter.png │ └── ex900ErrorFixUserDataAllZero_lineChart_column_nonStacked_oldManualLayouter.png ├── lib ├── flutter_charts.dart ├── src │ ├── chart │ │ ├── cartesian │ │ │ ├── chart_type │ │ │ │ ├── bar │ │ │ │ │ ├── chart.dart │ │ │ │ │ ├── container │ │ │ │ │ │ ├── data_container.dart │ │ │ │ │ │ └── root_container.dart │ │ │ │ │ └── options.dart │ │ │ │ └── line │ │ │ │ │ ├── chart.dart │ │ │ │ │ ├── container │ │ │ │ │ ├── data_container.dart │ │ │ │ │ └── root_container.dart │ │ │ │ │ └── options.dart │ │ │ └── container │ │ │ │ ├── axis_corner_container.dart │ │ │ │ ├── axislabels_axislines_gridlines_container.dart │ │ │ │ ├── container_common.dart │ │ │ │ ├── data_container.dart │ │ │ │ ├── legend_container.dart │ │ │ │ ├── line_segment_container.dart │ │ │ │ └── root_container.dart │ │ ├── chart.dart │ │ ├── chart_label_container.dart │ │ ├── future │ │ │ └── container_future_additions_and_changes.dart │ │ ├── iterative_layout_strategy.dart │ │ ├── model │ │ │ ├── data_model.dart │ │ │ └── random_chart_data.dart │ │ ├── options.dart │ │ ├── painter.dart │ │ ├── util │ │ │ └── example_descriptor.dart │ │ └── view_model │ │ │ ├── label_model.dart │ │ │ └── view_model.dart │ ├── coded_layout │ │ └── chart │ │ │ ├── axis_container.dart │ │ │ ├── chart_type │ │ │ ├── bar │ │ │ │ ├── presenter.dart │ │ │ │ └── root_container.dart │ │ │ └── line │ │ │ │ ├── presenter.dart │ │ │ │ └── root_container.dart │ │ │ ├── container.dart │ │ │ ├── data_container.dart │ │ │ ├── label_container.dart │ │ │ ├── line_container.dart │ │ │ └── presenter.dart │ ├── morphic │ │ ├── container │ │ │ ├── chart_support │ │ │ │ └── chart_style.dart │ │ │ ├── constraints.dart │ │ │ ├── container_alignment.dart │ │ │ ├── container_edge_padding.dart │ │ │ ├── container_key.dart │ │ │ ├── container_layouter_base.dart │ │ │ ├── label_container.dart │ │ │ ├── layouter_one_dimensional.dart │ │ │ ├── morphic_dart_enums.dart │ │ │ └── unused.dart │ │ ├── ui2d │ │ │ └── point.dart │ │ └── util │ │ │ └── extensible_enum.dart │ ├── switch_view_model │ │ ├── auto_layout │ │ │ ├── bar │ │ │ │ └── view_model.dart │ │ │ └── line │ │ │ │ └── view_model.dart │ │ ├── coded_layout │ │ │ ├── bar │ │ │ │ └── view_model.dart │ │ │ └── line │ │ │ │ └── view_model.dart │ │ ├── view_model.dart │ │ └── view_model_cl.dart │ └── util │ │ ├── collection.dart │ │ ├── extensions_dart.dart │ │ ├── extensions_flutter.dart │ │ ├── geometry.dart │ │ ├── util_dart.dart │ │ ├── util_flutter.dart │ │ └── vector │ │ ├── function_matrix_2d.dart │ │ ├── matrix_2d.dart │ │ └── vector_2d.dart └── test │ └── src │ ├── README.org │ ├── chart │ ├── cartesian │ │ └── container │ │ │ └── legend_container.dart │ └── options.dart │ ├── switch_view_model │ └── coded_layout │ │ ├── bar │ │ └── view_model.dart │ │ └── line │ │ └── view_model.dart │ ├── test_main.dart │ └── util │ └── test_util.dart ├── pubspec.yaml ├── test ├── chart │ ├── layouter_one_dimensional_test.dart │ └── util │ │ └── example_descriptor_test.dart ├── deprecated_v1 │ └── screenshot_validate_deprecated_v1_test.dart ├── screenshot_validate_test.dart ├── tmp │ └── .gitignore ├── util │ ├── extensions_dart_test.dart │ ├── function_test.dart │ ├── util_dart_test.dart │ ├── util_flutter_test.dart │ ├── util_labels_test.dart │ └── vector │ │ └── vector_test.dart └── widget_test.dart ├── test_driver └── integration_test.dart └── tool ├── README-tool.org ├── demo └── run_example.sh ├── frequent_commands.org ├── generate_chart_plantuml.sh ├── make_new_chart_type_structure.sh └── test ├── deprecated_v1 ├── deprecated_frequent_commands.org ├── deprecated_integration_test_create_then_validate_screenshots.sh ├── deprecated_run_all_tests.sh ├── deprecated_run_core_integration_tests.sh ├── deprecated_run_representative_tests.sh └── deprecated_start_emulator_and_generate_example_descriptor.sh ├── run_all_tests.sh ├── run_core_dart_and_flutter_widget_tests.sh ├── run_screenshots_compare_integration_test.sh └── start_emulator.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # mz vvv 2 | # Ignore misc local ides, also .gnupg which is secret. 3 | .emacs.d/ 4 | .emacs.d-psession/ 5 | .emacs.d-desktop/ 6 | .emacs.desktop 7 | .emacs.desktop.lock 8 | .project.el 9 | .projectile 10 | .gnupg/ 11 | 12 | # Note: contents of the following folders is ignored via the special .gitignore in the folders. 13 | # - integration_test/screenshots_tested/ 14 | # - test/tmp 15 | 16 | # Ignore Emacs, maybe other editors lock files, they are named starting with #. 17 | .\#* 18 | 19 | # Private notes, todos, readme 20 | INTERNAL-GITIGNORE/ 21 | 22 | # Ignore my backup files of no interest. 23 | *mzchanged* 24 | *mzdel* 25 | 26 | 27 | # Most of android and ios dirs are needed to run the example/main_run_doc_example.dart sample app (on android, not sure about Ios) 28 | # android 29 | # ios 30 | 31 | # Ignore screenshots_tested/ directory, as screenshots are volatile and change often. Also ignore screenshots_expected_server/ and screenshots_expected_laptop/. Those maintain specific versions. 32 | integration_test/screenshots_tested/ 33 | integration_test/screenshots_expected_laptop/ 34 | integration_test/screenshots_expected_server/ 35 | # mz ^^^ 36 | 37 | 38 | # Miscellaneous 39 | *.class 40 | *.log 41 | *.pyc 42 | *.swp 43 | .DS_Store 44 | .atom/ 45 | .buildlog/ 46 | .history 47 | .svn/ 48 | 49 | # 2022-10-17 : Keeping IntelliJ related 50 | # *.iml 51 | # *.ipr 52 | # *.iws 53 | # .idea/workspace.xml contains Edit->Run Configurations settings, so keeping the whole .idea directory. 54 | # Also, there is a .idea/.gitignore, so check that file if workspace.xml is not excluded. 55 | # .idea/ 56 | 57 | # 2023-09-15 : IntelliJ : consider ignoring 58 | # .idea/libraries/Dart_Packages.xml 59 | # .idea/misc.xml 60 | # .idea/workspace.xml 61 | 62 | # gitignore-added-2025-01-01: Caches that idea keeps. 63 | .idea/caches/ 64 | android/.idea/caches/ 65 | 66 | # The .vscode folder contains launch configuration and tasks you configure in 67 | # VS Code which you may wish to be included in version control, so this line 68 | # is commented out by default. 69 | #.vscode/ 70 | 71 | # Flutter/Dart/Pub related 72 | **/doc/api/ 73 | **/ios/Flutter/.last_build_id 74 | # .dart_tool directory and .packages files are created after you’ve run pub get. 75 | # Don’t check them into source control. 76 | .dart_tool/ 77 | .flutter-plugins 78 | .flutter-plugins-dependencies 79 | .packages 80 | .pub-cache/ 81 | .pub/ 82 | /build/ 83 | # pubspec.lock file id created after you’ve run pub get. Leave it out of source control 84 | # because this package is a library package (not an application package, then we would commit it). 85 | pubspec.lock 86 | 87 | # Web related 88 | lib/generated_plugin_registrant.dart 89 | 90 | # Symbolication related 91 | app.*.symbols 92 | 93 | # Obfuscation related 94 | app.*.map.json 95 | 96 | # Android Studio will place build artifacts here 97 | /android/app/debug 98 | /android/app/profile 99 | /android/app/release 100 | 101 | 102 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | # workspace.xml contains Edit->Run Configurations, so keep it 4 | # /workspace.xml 5 | # Datasource local storage ignored files 6 | /dataSources/ 7 | /dataSources.local.xml 8 | # Editor-based HTTP Client requests 9 | /httpRequests/ 10 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/libraries/KotlinJavaRuntime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.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: "17025dd88227cd9532c33fa78f5250d548d87e9a" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 17 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 18 | - platform: android 19 | create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 20 | base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a 21 | 22 | # User provided section 23 | 24 | # List of Local paths (relative to this file) that should be 25 | # ignored by the migrate tool. 26 | # 27 | # Files that are not part of the templates will be ignored by default. 28 | unmanaged_files: 29 | - 'lib/main.dart' 30 | - 'ios/Runner.xcodeproj/project.pbxproj' 31 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Milan Zimmermann (milan.zimmermann@gmail.com) 2 | 3 | see also: LICENSE 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, 2018, 2019, 2020, 2021, 2022 Milan Zimmermann (milan.zimmermann@gmail.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /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 | avoid_relative_lib_imports: false # todo-01 : remove this later. Need for example prevents this 28 | non_constant_identifier_names: false # todo-01 : remove this, but figure out better naming for long names 29 | hash_and_equals: true # todo-00-last : added this, probably included by default 30 | 31 | # Additional information about this file can be found at 32 | # https://dart.dev/guides/language/analysis-options 33 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. 5 | id "dev.flutter.flutter-gradle-plugin" 6 | } 7 | 8 | android { 9 | namespace = "com.example.flutter_charts" 10 | compileSdk = flutter.compileSdkVersion 11 | // todo-00-done-mzchanged-2025-01-01: Build warning suggests to hardcode the ndkVersion. 12 | // ndkVersion = flutter.ndkVersion 13 | ndkVersion = "27.0.12077973" 14 | // ndkVersion = "28.0.12674087" 15 | // 16 | 17 | compileOptions { 18 | sourceCompatibility = JavaVersion.VERSION_17 19 | targetCompatibility = JavaVersion.VERSION_17 20 | } 21 | 22 | kotlinOptions { 23 | jvmTarget = JavaVersion.VERSION_17 24 | } 25 | 26 | defaultConfig { 27 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 28 | applicationId = "com.example.flutter_charts" 29 | // You can update the following values to match your application needs. 30 | // For more information, see: https://flutter.dev/to/review-gradle-config. 31 | minSdk = flutter.minSdkVersion 32 | targetSdk = flutter.targetSdkVersion 33 | versionCode = flutter.versionCode 34 | versionName = flutter.versionName 35 | } 36 | 37 | buildTypes { 38 | release { 39 | // TODO: Add your own signing config for the release build. 40 | // Signing with the debug keys for now, so `flutter run --release` works. 41 | signingConfig = signingConfigs.debug 42 | } 43 | } 44 | } 45 | 46 | flutter { 47 | source = "../.." 48 | } 49 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/flutter_charts/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.flutter_charts 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = "../build" 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(":app") 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /android/flutter_charts_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-all.zip 6 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | }() 9 | 10 | includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | /* todo-00-done-mzchanged-2025-01-01: To fix error during build 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "8.2.1" apply false 23 | id "org.jetbrains.kotlin.android" version "1.8.22" apply false 24 | } 25 | */ 26 | 27 | plugins { 28 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 29 | id 'com.android.application' version '8.7.3' apply false 30 | // id 'com.android.library' version '8.7.3' apply false 31 | id 'org.jetbrains.kotlin.android' version '2.0.20' apply false 32 | } 33 | 34 | include ":app" 35 | -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_154245_27063qmN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_154245_27063qmN.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_154329_270633wT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_154329_270633wT.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_172324_27063E7Z.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_172324_27063E7Z.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_173422_27063ePm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_173422_27063ePm.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_180657_27063rZs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_180657_27063rZs.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_180915_270634jy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_180915_270634jy.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_191037_27063qtB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_191037_27063qtB.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_191138_2706333H.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_191138_2706333H.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_20171102_195745_27063ECO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_20171102_195745_27063ECO.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_iterative-layout-step-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_iterative-layout-step-1.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_iterative-layout-step-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_iterative-layout-step-2.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_iterative-layout-step-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_iterative-layout-step-3.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_iterative-layout-step-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_iterative-layout-step-4.png -------------------------------------------------------------------------------- /doc/readme_images/README.org_iterative-layout-step-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/README.org_iterative-layout-step-5.png -------------------------------------------------------------------------------- /doc/readme_images/ex10RandomData_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex10RandomData_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex10RandomData_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex10RandomData_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex10RandomData_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex10RandomData_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex10RandomData_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex10RandomData_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex30AnimalsBySeasonWithLabelLayoutStrategy_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex31SomeNegativeValues_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex31SomeNegativeValues_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex31SomeNegativeValues_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex31SomeNegativeValues_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex31SomeNegativeValues_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex31SomeNegativeValues_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex31SomeNegativeValues_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex31SomeNegativeValues_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex32AllPositiveYsYAxisStartsAbove0_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex33AllNegativeYsYAxisEndsBelow0_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex33AllNegativeYsYAxisEndsBelow0_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex33AllNegativeYsYAxisEndsBelow0_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex33AllNegativeYsYAxisEndsBelow0_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex34OptionsDefiningUserTextStyleOnLabels_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex34OptionsDefiningUserTextStyleOnLabels_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex34OptionsDefiningUserTextStyleOnLabels_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex34OptionsDefiningUserTextStyleOnLabels_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex35AnimalsBySeasonNoLabelsShown_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex50StocksWithNegativesWithUserColors_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex50StocksWithNegativesWithUserColors_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex50StocksWithNegativesWithUserColors_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex50StocksWithNegativesWithUserColors_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex51AnimalsBySeasonManualLogarithmicScale_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex51AnimalsBySeasonManualLogarithmicScale_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex51AnimalsBySeasonManualLogarithmicScale_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex51AnimalsBySeasonManualLogarithmicScale_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_lineChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex52AnimalsBySeasonLogarithmicScale_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration1_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration1_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration1_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration1_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration2_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration2_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration2_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration2_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration3_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration3_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration3_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration3_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration4_verticalBarChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration4_verticalBarChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex60LabelsIteration4_verticalBarChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex60LabelsIteration4_verticalBarChart_w150.png -------------------------------------------------------------------------------- /doc/readme_images/ex900ErrorFixUserDataAllZero_lineChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex900ErrorFixUserDataAllZero_lineChart.png -------------------------------------------------------------------------------- /doc/readme_images/ex900ErrorFixUserDataAllZero_lineChart_w150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/doc/readme_images/ex900ErrorFixUserDataAllZero_lineChart_w150.png -------------------------------------------------------------------------------- /flutter_charts.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /google_fonts/Comforter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/google_fonts/Comforter-Regular.ttf -------------------------------------------------------------------------------- /google_fonts/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2015 The Comforter Project Authors (https://github.com/googlefonts/comforter) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /integration_test/README.org: -------------------------------------------------------------------------------- 1 | * Integration test in Flutter 2 | 3 | Flutter *integration test* is performed by the command ~flutter drive~; the test file 4 | is the file in the ~--target=path_to_test.dart~. The test files are executed ON THE DEVICE, 5 | AND COULD BE CALLED ON-DEVICE-TESTS. 6 | 7 | Files in this directory which end with '_test.dart' are such *integration tests*, performed 8 | in a command such as 9 | 10 | #+begin_src: sh 11 | # Note: "$examplesDescriptors" may be "allSupported" or similar single test or named group of tests, 12 | # or a list of single test names 13 | flutter drive \ 14 | --dart-define=EXAMPLES_DESCRIPTORS="$examplesDescriptors" \ 15 | --driver=test_driver/integration_test.dart \ 16 | --target=integration_test/screenshot_create_test.dart 17 | #+end_src 18 | 19 | Optionally, the *integration test* can be controlled, from the computer, by another program, which could be described as 20 | 'on-computer driver for the on-device integration test'. Such 'on-computer driver' is the program 21 | ~--driver=test_driver/integration_test.dart~ program above; it runs on the computer, 22 | and controls the program in the ~--target=integration_test/screenshot_create_test.dart~ running on the device (drive). 23 | 24 | Note: The naming of the on-device integration test TARGET and it's on-computer controlling program DRIVER 25 | seems backwards, but Flutter seems to insist on it, by making the name 'integration_test.dart' for the DRIVER 26 | the default required name. 27 | 28 | See the "Testing in Flutter" heading in https://github.com/mzimmerm/flutter_experiments/blob/master/doc/flutter-notes.org 29 | for details of Dart unit test, Flutter widget test and Flutter integration test. 30 | 31 | See https://docs.flutter.dev/cookbook/testing/integration/introduction 32 | for integration testing in Flutter. 33 | 34 | See https://dev.to/mjablecnik/take-screenshot-during-flutter-integration-tests-435k 35 | for how to take a screenshot from your Flutter app inside flutter test integration_test/app_test.dart; 36 | but the same should work from an actual flutter run --device_id app.dart 37 | 38 | -------------------------------------------------------------------------------- /integration_test/deprecated_v1/screenshot_create_deprecated_v1_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:integration_test/integration_test.dart' show IntegrationTestWidgetsFlutterBinding; 3 | 4 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart' show ExampleDescriptor; 5 | import 'package:flutter_charts/test/src/util/test_util.dart'; 6 | import 'package:flutter_charts/test/src/test_main.dart' as app; 7 | 8 | /// @Deprecated, see 'integration_test/screenshot_create_test_new.dart'. 9 | /// 10 | /// Integration testing by taking a screenshot from the example app, 11 | /// and comparing the produced screenshot with a known correct screenshot. 12 | /// 13 | void main() { 14 | final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 15 | 16 | testWidgets('screenshot', (WidgetTester tester) async { 17 | var screenshotPaths = ScreenshotPaths(exampleDescriptor: ExampleDescriptor.requestedExampleToRun()); 18 | String screenshotPath = screenshotPaths.actualScreenshotPath; 19 | 20 | // Build the app and run it on device. 21 | app.main(); 22 | 23 | // This is required prior to taking the screenshot (Android only). 24 | await binding.convertFlutterSurfaceToImage(); 25 | 26 | // Trigger a frame. 27 | await tester.pumpAndSettle(); 28 | 29 | // Take screenshot. 30 | await binding.takeScreenshot(screenshotPath); 31 | 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex10RandomData_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex10RandomData_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex10RandomData_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex10RandomData_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex30AnimalsBySeasonWithLabelLayoutStrategy_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex30AnimalsBySeasonWithLabelLayoutStrategy_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex30AnimalsBySeasonWithLabelLayoutStrategy_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_row_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_barChart_row_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex31SomeNegativeValues_lineChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex32AllPositiveYsYAxisStartsAbove0_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex32AllPositiveYsYAxisStartsAbove0_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex32AllPositiveYsYAxisStartsAbove0_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex32AllPositiveYsYAxisStartsAbove0_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex33AllNegativeYsYAxisEndsBelow0_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex33AllNegativeYsYAxisEndsBelow0_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex34OptionsDefiningUserTextStyleOnLabels_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex34OptionsDefiningUserTextStyleOnLabels_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex35AnimalsBySeasonNoLabelsShown_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex35AnimalsBySeasonNoLabelsShown_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex35AnimalsBySeasonNoLabelsShown_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex35AnimalsBySeasonNoLabelsShown_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex40LanguagesWithYOrdinalUserLabelsAndUserColors_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex50StocksWithNegativesWithUserColors_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex50StocksWithNegativesWithUserColors_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex52AnimalsBySeasonLogarithmicScale_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex52AnimalsBySeasonLogarithmicScale_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex52AnimalsBySeasonLogarithmicScale_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex52AnimalsBySeasonLogarithmicScale_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex60LabelsIteration1_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex60LabelsIteration1_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex60LabelsIteration2_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex60LabelsIteration2_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex60LabelsIteration3_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex60LabelsIteration3_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex60LabelsIteration4_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex60LabelsIteration4_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex70AnimalsBySeasonLegendIsColumnStartLooseItemIsRowStartLoose_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex70AnimalsBySeasonLegendIsColumnStartLooseItemIsRowStartLoose_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex71AnimalsBySeasonLegendIsColumnStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex71AnimalsBySeasonLegendIsColumnStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex72AnimalsBySeasonLegendIsRowCenterLooseItemIsRowEndLoose_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex72AnimalsBySeasonLegendIsRowCenterLooseItemIsRowEndLoose_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex73AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex73AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTight_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex74AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightSecondGreedy_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex74AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightSecondGreedy_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_barChart_row_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded_lineChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex76AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenAligned_barChart_column_stacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex76AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenAligned_barChart_column_stacked_oldManualLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_column_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_column_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_row_stacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_barChart_row_stacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_lineChart_column_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_lineChart_column_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_lineChart_row_nonStacked_newAutoLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex800EU12CountriesHistoricalPopulation_lineChart_row_nonStacked_newAutoLayouter.png -------------------------------------------------------------------------------- /integration_test/screenshots_expected/ex900ErrorFixUserDataAllZero_lineChart_column_nonStacked_oldManualLayouter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mzimmerm/flutter_charts/57b404cab0cb764e21167fa897fe3f2acdb0be85/integration_test/screenshots_expected/ex900ErrorFixUserDataAllZero_lineChart_column_nonStacked_oldManualLayouter.png -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/bar/chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart' as widgets; 2 | 3 | // base libraries 4 | import 'package:flutter_charts/src/chart/chart.dart'; 5 | import 'package:flutter_charts/src/chart/painter.dart' show FlutterChartPainter; 6 | import 'package:flutter_charts/src/chart/view_model/view_model.dart' show ChartViewModel; 7 | 8 | /// Provides paint for the vertical bar chart. 9 | /// 10 | /// It extends [CustomPaint] which is the flutter widget 11 | /// that provides a canvas on which to draw during the paint phase. 12 | /// The core override is to set the concrete [ChartContainer], and 13 | /// it's [ChartContainer.isStacked] setting. 14 | class BarChart extends FlutterChart { 15 | /// Default constructor accepts size 16 | BarChart({ 17 | widgets.Key? key, 18 | required FlutterChartPainter flutterChartPainter, 19 | required ChartViewModel chartViewModel, 20 | widgets.CustomPainter? foregroundPainter, 21 | widgets.Size size = widgets.Size.zero, 22 | widgets.Widget? child, 23 | }) : super( 24 | key: key, 25 | flutterChartPainter: flutterChartPainter, 26 | chartViewModel: chartViewModel, 27 | foregroundPainter: foregroundPainter, 28 | size: size, 29 | child: child, 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/bar/container/root_container.dart: -------------------------------------------------------------------------------- 1 | // base libraries 2 | import 'package:flutter_charts/src/chart/cartesian/container/root_container.dart'; 3 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 4 | import 'package:flutter_charts/src/chart/cartesian/container/data_container.dart'; 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 7 | 8 | /// The container-hierarchy root container of the vertical bar chart. 9 | class BarChartRootContainer extends ChartRootContainer { 10 | 11 | BarChartRootContainer({ 12 | required LegendContainer legendContainer, 13 | required TransposingAxisLabels horizontalAxisContainer, 14 | required TransposingAxisLabels verticalAxisContainerFirst, 15 | required TransposingAxisLabels verticalAxisContainer, 16 | required DataContainer dataContainer, 17 | required ChartViewModel chartViewModel, 18 | }) : super( 19 | legendContainer: legendContainer, 20 | horizontalAxisContainer: horizontalAxisContainer, 21 | verticalAxisContainerFirst: verticalAxisContainerFirst, 22 | verticalAxisContainer: verticalAxisContainer, 23 | dataContainer: dataContainer, 24 | chartViewModel: chartViewModel, 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/bar/options.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart' show immutable; 2 | 3 | /// The options specific for the [BarChart]. 4 | @immutable 5 | class BarChartOptions { 6 | /// Constructor of [BarChartOptions]. No options specific for vertical bar chart. 7 | const BarChartOptions(); 8 | } 9 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/line/chart.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart' as widgets; 2 | 3 | // base libraries 4 | import 'package:flutter_charts/src/chart/chart.dart'; 5 | import 'package:flutter_charts/src/chart/painter.dart' show FlutterChartPainter; 6 | import 'package:flutter_charts/src/chart/view_model/view_model.dart' show ChartViewModel; 7 | 8 | /// Provides paint for the line chart. 9 | /// 10 | /// It extends [CustomPaint] which is the flutter widget 11 | /// that provides a canvas on which to draw during the paint phase. 12 | /// The core override is to set the concrete [ChartContainer], and 13 | /// it's [ChartContainer.isStacked] setting. 14 | /// 15 | /// Note: The [LineChart] constructor shows how to call a super 16 | /// with named parameters. The super's [CustomPaint] single constructor is 17 | /// `const CustomPaint({ Key key, this.painter, this.foregroundPainter, 18 | /// this.size: Size.zero, Widget child })` 19 | /// and syntax of a constructor with named parameters 20 | /// can be seen in the [LineChart] constructor. 21 | class LineChart extends FlutterChart { 22 | /// Default constructor accepts size 23 | LineChart({ 24 | widgets.Key? key, 25 | required FlutterChartPainter flutterChartPainter, 26 | required ChartViewModel chartViewModel, 27 | widgets.CustomPainter? foregroundPainter, 28 | widgets.Size size = widgets.Size.zero, 29 | widgets.Widget? child, 30 | }) : super( 31 | key: key, 32 | flutterChartPainter: flutterChartPainter, 33 | chartViewModel: chartViewModel, 34 | foregroundPainter: foregroundPainter, 35 | size: size, 36 | child: child, 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/line/container/root_container.dart: -------------------------------------------------------------------------------- 1 | // base libraries 2 | import 'package:flutter_charts/src/chart/cartesian/container/root_container.dart'; 3 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 4 | import 'package:flutter_charts/src/chart/cartesian/container/data_container.dart'; 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 7 | 8 | /// The container-hierarchy root container of the line chart. 9 | class LineChartRootContainer extends ChartRootContainer { 10 | LineChartRootContainer({ 11 | required LegendContainer legendContainer, 12 | required TransposingAxisLabels horizontalAxisContainer, 13 | required TransposingAxisLabels verticalAxisContainerFirst, 14 | required TransposingAxisLabels verticalAxisContainer, 15 | required DataContainer dataContainer, 16 | required ChartViewModel chartViewModel, 17 | }) : super( 18 | legendContainer: legendContainer, 19 | horizontalAxisContainer: horizontalAxisContainer, 20 | verticalAxisContainerFirst: verticalAxisContainerFirst, 21 | verticalAxisContainer: verticalAxisContainer, 22 | dataContainer: dataContainer, 23 | chartViewModel: chartViewModel, 24 | ); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/chart_type/line/options.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Color; 2 | import 'package:flutter/material.dart' as material show Colors; // any color we can use is from here, more descriptive 3 | import 'package:flutter/foundation.dart' show immutable; 4 | 5 | @immutable 6 | class LineChartOptions { 7 | /// Control the look of the circle on line chart 8 | final double hotspotInnerRadius; 9 | final double hotspotOuterRadius; 10 | 11 | /// Paint for the inner circle on line chart. 12 | /// Using common paint object for all circles, we 13 | /// force all circles to look the same. 14 | /// todo 3 - consider per valuesRow control. 15 | final ui.Color hotspotInnerPaintColor; 16 | 17 | final ui.Color hotspotOuterPaintColor; 18 | 19 | /// Width of the line connecting the circles on line chart. 20 | /// Paint for one series. Using one option for all series, we 21 | /// force all series width the same. 22 | /// todo 3 - consider per valuesRow width instances. 23 | final double lineStrokeWidth; 24 | 25 | /// Constructor with default values. 26 | const LineChartOptions({ 27 | this.hotspotInnerRadius = 3.0, 28 | this.hotspotOuterRadius = 6.0, 29 | this.hotspotInnerPaintColor = material.Colors.yellow, 30 | this.hotspotOuterPaintColor = material.Colors.black, 31 | this.lineStrokeWidth = 3.0, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/container/axis_corner_container.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Rect, Canvas, Paint; 2 | import 'package:flutter/material.dart' as material show Colors; 3 | 4 | // this level 5 | import 'package:flutter_charts/src/chart/cartesian/container/container_common.dart' as container_common; 6 | 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart' as view_model; 8 | 9 | // base libraries 10 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart'; 11 | 12 | 13 | 14 | class AxisCornerContainer extends container_common.ChartAreaContainer { 15 | AxisCornerContainer({ 16 | required view_model.ChartViewModel chartViewModel, 17 | List? children, 18 | }) : super( 19 | chartViewModel: chartViewModel, 20 | children: children, 21 | ); 22 | 23 | /// This default implementation has no children, it is leaf, so override the only method 24 | /// needed to override for leafs 25 | @override 26 | layout_Post_Leaf_SetSize_FromInternals() { 27 | /// Set some small layoutSize 28 | ui.Rect rect = const ui.Rect.fromLTWH(0.0, 0.0, 20.0, 20.0); 29 | 30 | layoutSize = rect.size; 31 | } 32 | 33 | @override 34 | paint(ui.Canvas canvas) { 35 | ui.Paint paint = (ui.Paint()..color = material.Colors.red); 36 | canvas.drawRect(offset & layoutSize, paint); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/container/container_common.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' show LabelLayoutStrategy; 2 | import 'package:flutter_charts/src/chart/view_model/view_model.dart' show ChartViewModel; 3 | 4 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart'; 5 | import 'package:flutter_charts/src/morphic/container/container_key.dart'; 6 | 7 | // documentation 8 | import 'package:flutter_charts/src/chart/cartesian/container/root_container.dart'; 9 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 10 | import 'package:flutter_charts/src/chart/cartesian/container/data_container.dart'; 11 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 12 | 13 | /// Base class which manages, lays out, offsets, and paints 14 | /// all [BoxContainer] derived classes used on charts. 15 | /// 16 | /// In addition to the [BoxContainer] responsibilities, 17 | /// this class has access to [chartViewModel], instance of [ChartViewModel], 18 | /// which builds the whole [ChartRootContainer] container hierarchy. 19 | /// 20 | /// The basic top level chart blocks are: 21 | /// - [ChartRootContainer] - the whole chart 22 | /// - [LegendContainer] - manages the legend 23 | /// - [TransposingOutputAxisLabels] - manages the output labels layout, which defines: 24 | /// - Y axis label sizes 25 | /// - Y positions of Y axis labels, defined as yTickY. 26 | /// yTicksY s are the Y points of extrapolated data values 27 | /// and also Y points on which the Y labels are centered. 28 | /// - [TransposingInputAxisLabels] - Equivalent to [TransposingOutputAxisLabels], but manages the input labels. 29 | /// - [DataContainer] and extensions - manages the area which displays: 30 | /// - Data as bar chart, line chart, or other chart type. 31 | /// - Grid (this includes the X and Y axis). 32 | /// 33 | /// See [BoxContainer] for discussion of roles of this class. 34 | /// This extension of [BoxContainer] has the added ability 35 | /// to access the container's parent, which is handled by 36 | /// [chartViewModel]. 37 | abstract class ChartAreaContainer extends PositioningBoxContainer { 38 | /// Constructs instance, by providing (this derived class required) [chartViewModel]. 39 | /// 40 | /// The instance of [ChartViewModel] is needed on all instances of [ChartAreaContainer]s 41 | /// tha 42 | ChartAreaContainer({ 43 | required this.chartViewModel, 44 | List? children, 45 | ContainerKey? key, 46 | ConstraintsWeight constraintsWeight = ConstraintsWeight.defaultWeight, 47 | }) : super( 48 | children: children, 49 | key: key, 50 | constraintsWeight: constraintsWeight, 51 | ); 52 | 53 | /// The instance of [ChartViewModel] which makes (produces) the chart view: 54 | /// both the view root, the [ChartRootContainer], and all [ChartAreaContainer]s inside. 55 | /// 56 | /// Needed to be held on this [ChartAreaContainer]s for the legacy subsystem 57 | /// to reach data model, as well as the view. 58 | // todo-02-design-legacy : can we move this on a CL class if only needed by legacy? 59 | final ChartViewModel chartViewModel; 60 | 61 | // todo-later : Go over all usages, and move child building to this method 62 | // from constructors. 63 | // In particular: why do we construct in buildAndReplaceChildren in DataContainer, 64 | // while construct in constructor in NewVerticalAxisContainer? 65 | // Etc 66 | @override 67 | void buildAndReplaceChildren() { 68 | buildAndReplaceChildrenDefault(); 69 | } 70 | } 71 | 72 | /// [ChartAreaContainer] which provides ability to connect [LabelLayoutStrategy] to [BoxContainer]. 73 | /// 74 | /// Extensions can create [ChartAreaContainer]s with default or custom layout strategy. 75 | abstract class AdjustableLabelsChartAreaContainer extends ChartAreaContainer implements AdjustableLabels { 76 | /// The strategy of this [AdjustableLabelsChartAreaContainer] and all instances 77 | /// is shared from the (single) [ChartViewModel.inputLabelLayoutStrategyInst]. 78 | LabelLayoutStrategy get labelLayoutStrategy => chartViewModel.inputLabelLayoutStrategyInst; 79 | 80 | AdjustableLabelsChartAreaContainer({ 81 | required ChartViewModel chartViewModel, 82 | }) : super( 83 | chartViewModel: chartViewModel, 84 | ) { 85 | chartViewModel.inputLabelLayoutStrategyInst.onContainer(this); 86 | } 87 | } 88 | 89 | /// A marker of container with adjustable contents, 90 | /// such as labels that can be skipped. 91 | // todo-05-morph LabelLayoutStrategy should be a member of AdjustableContainer, not 92 | // in AdjustableLabelsChartAreaContainer 93 | // Also, AdjustableLabels and perhaps AdjustableLabelsChartAreaContainer should be a mixin. 94 | // But Dart bug #25742 does not allow mixins with named parameters. 95 | 96 | abstract class AdjustableLabels { 97 | bool labelsOverlap(); 98 | } 99 | 100 | /// The behavior mixin class allows to plug in to the [ChartRootContainer] a behavior that is specific for a line chart 101 | /// or vertical bar chart. 102 | /// 103 | /// The behavior is plugged in the [ChartViewModel]. 104 | abstract class ChartBehavior { 105 | /// Behavior allows to start Y axis at data minimum (rather than 0). 106 | /// 107 | /// The request is asked by [DataContainerOptions.extendAxisToOriginRequested], 108 | /// but the implementation of this behavior must confirm it. 109 | /// See the extensions of this class for overrides of this method. 110 | /// 111 | /// [ChartBehavior] is mixed in to [ChartRootContainer]. This method 112 | /// is implemented by concrete [LineChartRootContainer] and [BarChartRootContainer]. 113 | /// - In the stacked containers, such as [BarChartRootContainer], it should return [false], 114 | /// as stacked values should always start at zero, because stacked charts must show absolute values. 115 | /// See [BarChartRootContainer.extendAxisToOrigin]. 116 | /// - In the unstacked containers such as [LineChartRootContainer], this is usually implemented to 117 | /// return the option [DataContainerOptions.extendAxisToOriginRequested], 118 | /// see [LineChartRootContainer.extendAxisToOrigin]. 119 | /// 120 | bool get extendAxisToOrigin; 121 | } 122 | -------------------------------------------------------------------------------- /lib/src/chart/cartesian/container/root_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | // This level 4 | import 'package:flutter_charts/src/chart/cartesian/container/container_common.dart'; 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 7 | import 'package:flutter_charts/src/chart/cartesian/container/data_container.dart'; 8 | import 'package:flutter_charts/src/chart/cartesian/container/axis_corner_container.dart'; 9 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart'; 10 | 11 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 12 | 13 | // comments 14 | import 'package:flutter_charts/src/chart/painter.dart'; 15 | 16 | /// The root [BoxContainer] of the whole chart. 17 | /// 18 | /// Concrete [ChartRootContainer] instance is created new on every [FlutterChartPainter.paint] invocation 19 | /// in the [ChartViewModel.chartRootContainerCreateBuildLayoutPaint]. Note that [ChartViewModel] 20 | /// instance is created only once per chart, NOT recreated on every [FlutterChartPainter.paint] invocation. 21 | /// 22 | /// Child containers calculate coordinates of chart points used for painting grid, labels, chart points etc. 23 | /// 24 | class ChartRootContainer extends ChartAreaContainer { 25 | 26 | ChartRootContainer({ 27 | required this.legendContainer, 28 | required this.horizontalAxisContainer, 29 | required this.verticalAxisContainer, 30 | required this.verticalAxisContainerFirst, 31 | required this.dataContainer, 32 | required ChartViewModel chartViewModel, 33 | }) : super(chartViewModel: chartViewModel) { 34 | logger.Logger().d(' Constructing ChartRootContainer'); 35 | // Attach children passed in constructor, previously created in ViewModel, to self 36 | 37 | // Create YDEX_cellDefinersTable, with definers arranged the same way as cells, 38 | // - with 4 cells, in 2x2 arrangement 39 | // - layoutSequence, on each cell as we want 40 | 41 | // [vertAxisDefiner] : Definer for vertical axis container. Vertical axis determines the width 42 | // of the first table column, and also the width left for the remainder of the table. 43 | // Note: Everything pre-layout is ordered by the sequence, actual layout by the cell positions in table 44 | TableLayoutCellDefiner vertAxisDefiner = TableLayoutCellDefiner( 45 | layoutSequence: 2, 46 | cellMinSizer: TableLayoutCellMinSizer.fromMinima( 47 | cellWidthMinimum: 65.0, // todo-012 will go away when we use VerticalAxisContainerFirst pre-layout 48 | cellHeightMinimum: 0.0, 49 | ), 50 | ); 51 | 52 | // [YDEX_cellDefinersTable] is table with the following order of containers (left to right, top to bottom): 53 | // VerticalAxisContainer, DataContainer, EmptyAxisCornerContainer, HorizontalAxisContainer 54 | List> YDEX_cellDefinersTable = [ 55 | [vertAxisDefiner, TableLayoutCellDefiner(layoutSequence: 3)], 56 | [TableLayoutCellDefiner(layoutSequence: 1), TableLayoutCellDefiner(layoutSequence: 0)], 57 | ]; 58 | 59 | TableLayoutDefiner tableLayoutDefiner = TableLayoutDefiner( 60 | cellDefinersTable: YDEX_cellDefinersTable, 61 | cellsAlignerDefiner: ChartTableLayoutCellsAlignerDefiner.sizeOf( // or just 2x2 62 | cellDefinersTable: YDEX_cellDefinersTable, 63 | ), 64 | ); 65 | 66 | BoxContainer axisCornerContainer = AxisCornerContainer(chartViewModel: chartViewModel); 67 | 68 | // verticalAxisContainer and horizontalAxisContainer are already transposed during creation. 69 | TableLayouter chartBody = TableLayouter( 70 | tableLayoutDefiner: tableLayoutDefiner, 71 | cellsTable: [ 72 | [verticalAxisContainer, dataContainer], 73 | [axisCornerContainer, horizontalAxisContainer], 74 | ], 75 | ); 76 | 77 | // Configure children, Legend on top, Table Layouter with X, Y, DataContainer below. 78 | addChildren( 79 | [ 80 | TableLayouter( 81 | tableLayoutDefiner: TableLayoutDefiner.defaultRowWiseForTableSize( 82 | numRows: 2, 83 | numColumns: 1, 84 | ), 85 | cellsTable: [ 86 | [legendContainer], 87 | [chartBody], 88 | ], 89 | ), 90 | ], 91 | ); 92 | } 93 | 94 | /// todo-012 The members are only needed during layout of deeper children (e.g., BarPointContainer) to access the members' sizes or constraints 95 | /// Maybe we can remove the members and access them inside children by key??? LIKELY NOT BY KEY, BECAUSE, DUE TO SURRONDING MEMBERS IN 96 | /// LAYOUT OBJECTS, THEY ARE NOT AMONG CHILDREN. 97 | /// Members that display the Areas of chart. 98 | late LegendContainer legendContainer; 99 | // covariant needed on some, probably not all 100 | covariant late TransposingAxisLabels horizontalAxisContainer; 101 | covariant late TransposingAxisLabels verticalAxisContainer; 102 | covariant late TransposingAxisLabels verticalAxisContainerFirst; 103 | covariant late DataContainer dataContainer; 104 | 105 | /// Override [BoxContainerHierarchy.isRoot] to prevent checking this root container on parent, 106 | /// which is never set on instances of this [ChartRootContainer]. 107 | @override 108 | bool get isRoot => true; 109 | } 110 | -------------------------------------------------------------------------------- /lib/src/chart/chart_label_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/widgets.dart' as widgets show TextSpan, TextPainter; 2 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart'; 3 | import 'package:vector_math/vector_math.dart' as vector_math show Matrix2; 4 | 5 | // this level or equivalent 6 | import 'package:flutter_charts/src/morphic/container/label_container.dart'; 7 | import 'package:flutter_charts/src/chart/cartesian/container/container_common.dart' as container_common show ChartAreaContainer; 8 | import 'package:flutter_charts/src/chart/view_model/view_model.dart' as view_model; 9 | import 'package:flutter_charts/src/chart/options.dart' show ChartOptions; 10 | 11 | /// Container of one label anywhere on the chart, in Labels, Axis, Titles, etc. 12 | /// 13 | /// The [layoutSize] is exactly that of by the contained 14 | /// layed out [textPainter] (this [ChartLabelContainer] has no margins, padding, 15 | /// or additional content in addition to the [_textPainter). 16 | /// 17 | /// However, if this object is tilted, as specified by [labelTiltMatrix], the 18 | /// [layoutSize] is determined by the rotated layed out [textPainter]. The 19 | /// math and [layoutSize] of this tilt is provided by [_tiltedLabelEnvelope]. 20 | /// 21 | /// Most members are mutable so that clients can experiment with different 22 | /// ways to set text style, until the label fits a predefined allowed size. 23 | /// 24 | /// Notes: 25 | /// - Instances manage the text to be presented as label, 26 | /// and create a member [textPainter], instance of [widgets.TextPainter] 27 | /// from the label. The contained [textPainter] is used for all layout 28 | /// and painting. 29 | /// - All methods (and constructor) of this class always call 30 | /// [textPainter.layout] immediately after a change. 31 | /// Consequently, there is no need to check for 32 | /// a "needs layout" method - the underlying [textPainter] 33 | /// is always layed out, ready to be painted. 34 | class ChartLabelContainer extends container_common.ChartAreaContainer with TiltableLabelContainerMixin { 35 | 36 | // Allows to configure certain sizes, colors, and layout. 37 | // final LabelStyle _labelStyle; 38 | 39 | /// Constructs an instance for a label, it's text style, and label's 40 | /// maximum width. 41 | /// 42 | /// Note: Does not set parent container's [_boxConstraints] and [chartViewModel]. 43 | /// It is currently assumed clients will not call any methods using those members. 44 | ChartLabelContainer({ 45 | required view_model.ChartViewModel chartViewModel, 46 | required String label, 47 | required vector_math.Matrix2 labelTiltMatrix, 48 | required LabelStyle labelStyle, 49 | }) : 50 | super( 51 | chartViewModel: chartViewModel, 52 | ) { 53 | this.labelTiltMatrix = labelTiltMatrix; 54 | textPainter = widgets.TextPainter( 55 | text: widgets.TextSpan( 56 | text: label, 57 | style: labelStyle.textStyle, // All labels share one style object 58 | ), 59 | textDirection: labelStyle.textDirection, 60 | textAlign: labelStyle.textAlign, 61 | // center in available space todo-02 textScaleFactor does nothing ?? 62 | textScaleFactor: labelStyle.textScaleFactor, 63 | // removed, causes lockup: ellipsis: "...", // forces a single line - without it, wraps at width 64 | ); 65 | 66 | // _labelStyle = labelStyle, 67 | // var text = new widgets.TextSpan( 68 | // text: label, 69 | // style: _labelStyle.textStyle, // All labels share one style object 70 | // ); 71 | // _textPainter = new widgets.TextPainter( 72 | // text: text, 73 | // textDirection: _labelStyle.textDirection, 74 | // textAlign: _labelStyle.textAlign, 75 | // // center in available space 76 | // textScaleFactor: _labelStyle.textScaleFactor, 77 | // // todo-04 add to test - was removed, causes lockup: ellipsis: "...", // forces a single line - without it, wraps at width 78 | // ); // textScaleFactor does nothing ?? 79 | } 80 | 81 | @override 82 | double calcLabelMaxWidthFromLayoutOptionsAndConstraints() { 83 | // todo-013 : this seems incorrect - used for all labels, yet it acts as legend label!! 84 | // used only to get label max size in rotated labels. 85 | ChartOptions options = chartViewModel.chartOptions; 86 | double indicatorSquareSide = options.legendOptions.legendColorIndicatorWidth; 87 | double indicatorToLabelPad = options.legendOptions.legendItemIndicatorToLabelPad; 88 | double betweenLegendItemsPadding = options.legendOptions.betweenLegendItemsPadding; 89 | 90 | // labelMaxWidth from options and constraints on class with this mixin 91 | return constraints.maxSize.width - (indicatorSquareSide + indicatorToLabelPad + betweenLegendItemsPadding); 92 | } 93 | } 94 | 95 | /// Container of an axis label, a marker extension of [ChartLabelContainer] with no additional operations to it's 96 | /// superclass. 97 | /// 98 | /// Should be used for axis labels, and layed out with any standard layouters, 99 | /// most likely an extension of the [ExternalTicksBoxLayouter]. 100 | /// 101 | class AxisLabelContainer extends ChartLabelContainer { 102 | AxisLabelContainer({ 103 | required view_model.ChartViewModel chartViewModel, 104 | required String label, 105 | required vector_math.Matrix2 labelTiltMatrix, 106 | required LabelStyle labelStyle, 107 | }) : super( 108 | chartViewModel: chartViewModel, 109 | label: label, 110 | labelTiltMatrix: labelTiltMatrix, 111 | labelStyle: labelStyle, 112 | ); 113 | } 114 | -------------------------------------------------------------------------------- /lib/src/chart/future/container_future_additions_and_changes.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Size, Offset; 2 | import 'dart:math' as math show Rectangle; 3 | 4 | import 'package:flutter_charts/src/morphic/container/constraints.dart' show ContainerConstraints; 5 | 6 | // todo-05: Container core rules: 7 | // 1) I do not expose position, offset, or layoutSize. 8 | // I stay put until someone calls transform on me, OR it's special case applyParentOffset. 9 | // Is that possible? 10 | // 2) The layout() method finds, iteratively, the sizes of all Container children of the top Container. 11 | // The paint() method must NOT paint beyond the size of any Container 12 | 13 | 14 | // todo-05 : Shape and extensions (Box, Pie), Container and extensions, Layout, Painter ------------------------------- 15 | 16 | /// Shape is the set of points in a Container. 17 | /// 18 | /// Returned from [layout]. 19 | class Shape { 20 | Object? get surface => null; // represents non positioned surface after getting size in layout 21 | Object? get positionedSurface => null; // represents surface after positioning during layout 22 | } 23 | 24 | class BoxShape extends Shape { 25 | @override 26 | ui.Size get surface => ui.Size.zero; 27 | @override 28 | math.Rectangle get positionedSurface => const math.Rectangle(0.0, 0.0, 0.0, 0.0); 29 | } 30 | 31 | /// Represents not-positioned pie shape. Internal coordinates are polar, but can ask for containing rectangle. 32 | /// Equivalent to Size in Box shapes (internally in cartesian coordinates) 33 | class Pie { 34 | // todo-05 add distance and angle, and implement 35 | double angle = 0.0; // radians 36 | double radius = 0.0; // pixels ? 37 | } 38 | 39 | /// Represents a positioned pie shape. Positioning is in Cartesian coordinates represented by Offset. 40 | /// Equivalent to Rectangle in Box shapes. 41 | class PositionedPie extends Pie { 42 | ui.Offset offset = const ui.Offset(0.0, 0.0); 43 | } 44 | 45 | // todo-05 implement 46 | class PieShape extends Shape { 47 | @override 48 | Pie get surface => Pie(); 49 | @override 50 | PositionedPie get positionedSurface => PositionedPie(); 51 | } 52 | 53 | // todo-05 : Constraints and extensions ------------------------------------------------------------------------------- 54 | 55 | class PieContainerConstraints extends ContainerConstraints { 56 | } 57 | 58 | // todo-05 : BoxContainerConstraints - see constraints.dart ------------------------------------------------------------ 59 | 60 | // todo-05 : split: 61 | // - Container to BoxContainer and PieContainer 62 | // - Shape to BoxShape (wraps Size) and PieShape 63 | // - ContainerConstraint to BoxContainerConstraint and PieContainerConstraint 64 | // todo-05 : Change Container.layout to 65 | // Shape layout({required covariant ContainerConstraints constraints}); // Must set Shape (Size for now) on layoutableBoxParentSandbox 66 | // This base layout maybe eventually configures some constraints caching and debugging. 67 | // Extensions of Container: BoxContainer, PieContainer override layout as 68 | // BoxShape layout({required covariant BoxContainerConstraints constraints}); // Must set BoxShape (essentially, this is Size) on layoutableBoxParentSandbox 69 | // PieShape layout({required covariant PieContainerConstraints constraints}); // Must set PieShape on layoutableBoxParentSandbox 70 | 71 | 72 | -------------------------------------------------------------------------------- /lib/src/chart/model/random_chart_data.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math show Random; 2 | 3 | import 'package:flutter_charts/src/chart/options.dart'; 4 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 5 | 6 | // The single unnamed constructor (like primary factory in Newspeak). Must call super. 7 | /// Generator of sample data for testing the charts. 8 | /// 9 | class RandomChartModel extends ChartModel { 10 | RandomChartModel({ 11 | required dataRows, 12 | required inputUserLabels, 13 | required legendNames, 14 | required chartOptions, 15 | outputUserLabels, 16 | legendColors, 17 | }) : super( 18 | dataRows: dataRows, 19 | inputUserLabels: inputUserLabels, 20 | legendNames: legendNames, 21 | chartOptions: chartOptions, 22 | outputUserLabels: outputUserLabels, 23 | legendColors: legendColors, 24 | ); 25 | 26 | // Redirecting constructors just redirects to an 'unnamed' constructor on same class - the RandomChartModel(args) constructor. 27 | /// Generate random data for chart, with number of x labels given by 28 | /// [numXLabels] and number of data series given by [numDataRows]. 29 | /// 30 | /// If [useMonthNames] is set to false, random 31 | /// 32 | RandomChartModel.generated({ 33 | required ChartOptions chartOptions, 34 | bool useUserProvidedYLabels = false, 35 | int numXLabels = 6, 36 | int numDataRows = 4, 37 | bool useMonthNames = true, 38 | int maxLabelLength = 8, 39 | bool overlapDataYs = false, 40 | legendColors, 41 | }) : this( 42 | dataRows: randomDataYs(numXLabels, numDataRows, overlapDataYs), 43 | inputUserLabels: randomDataXLabels(numXLabels), 44 | legendNames: randomDataRowsLegends(numDataRows), 45 | chartOptions: chartOptions, 46 | outputUserLabels: randomDataYLabels(useUserProvidedYLabels), 47 | legendColors: legendColors, 48 | ); 49 | } 50 | 51 | /// Sets up legends names, first several explicitly, rest randomly. 52 | /// 53 | /// This is used if user does not set legends. 54 | /// This should be kept in sync with colors below. 55 | List randomDataRowsLegends(int dataRowsCount) { 56 | List defaultLegends = List.empty(growable: true); 57 | 58 | if (dataRowsCount >= 1) { 59 | defaultLegends.add('YELLOW' /*' with really long description'*/); 60 | } 61 | if (dataRowsCount >= 2) { 62 | defaultLegends.add('GREEN'); 63 | } 64 | if (dataRowsCount >= 3) { 65 | defaultLegends.add('BLUE'); 66 | } 67 | if (dataRowsCount >= 4) { 68 | defaultLegends.add('BLACK'); 69 | } 70 | if (dataRowsCount >= 5) { 71 | defaultLegends.add('GREY'); 72 | } 73 | if (dataRowsCount >= 6) { 74 | defaultLegends.add('ORANGE'); 75 | } 76 | if (dataRowsCount > 6) { 77 | for (int i = 3; i < dataRowsCount; i++) { 78 | // todo-1 when large value is generated, it paints outside canvas, fix. 79 | int number = math.Random().nextInt(10000); 80 | defaultLegends.add('OTHER ${number.toString()}'); 81 | } 82 | } 83 | return defaultLegends; 84 | } 85 | 86 | /// Generate list of "random" [inputUserLabels] as monthNames or weekday names. 87 | /// 88 | /// 89 | List randomDataXLabels(int numXLabels) { 90 | List xLabelsDows = ['First', 'Second', 'Third', 'Fourth', 'Fifth', 'Sixth', 'Seventh']; 91 | return xLabelsDows.getRange(0, numXLabels).toList(); 92 | } 93 | 94 | List? randomDataYLabels(bool useUserProvidedYLabels) { 95 | List? outputUserLabels; 96 | if (useUserProvidedYLabels) { 97 | outputUserLabels = ['NONE', 'OK', 'GOOD', 'BETTER', '100%']; 98 | } 99 | return outputUserLabels; 100 | } 101 | 102 | List> randomDataYs(int numXLabels, int numDataRows, bool overlapDataYs) { 103 | List> dataRows = List.empty(growable: true); 104 | 105 | double scale = 200.0; 106 | 107 | math.Random rgen = math.Random(); 108 | 109 | int maxDataY = 4; 110 | double pushUpStep = overlapDataYs ? 0.0 : maxDataY.toDouble(); 111 | 112 | for (int rowIndex = 0; rowIndex < numDataRows; rowIndex++) { 113 | dataRows.add(_randomDataOneRow( 114 | rgen: rgen, 115 | max: maxDataY, 116 | pushUpBy: (rowIndex - 1) * pushUpStep, 117 | scale: scale, 118 | numXLabels: numXLabels, 119 | )); 120 | } 121 | return dataRows; 122 | } 123 | 124 | List _randomDataOneRow({ 125 | required math.Random rgen, 126 | required int max, 127 | required double pushUpBy, 128 | required double scale, 129 | required int numXLabels, 130 | }) { 131 | List valuesRow = List.empty(growable: true); 132 | for (int i = 0; i < numXLabels; i++) { 133 | valuesRow.add((rgen.nextInt(max) + pushUpBy) * scale); 134 | } 135 | return valuesRow; 136 | } 137 | -------------------------------------------------------------------------------- /lib/src/coded_layout/chart/chart_type/bar/presenter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Rect, Offset, Paint; 2 | // base libraries 3 | import 'package:flutter_charts/src/coded_layout/chart/presenter.dart'; 4 | import 'package:flutter_charts/src/coded_layout/chart/container.dart'; 5 | import 'package:flutter_charts/src/coded_layout/chart/axis_container.dart'; 6 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 7 | 8 | /// PointPresenter of the atomic/leaf element of one data point on the 9 | /// vertical bar chart - a simple rectangle, in member [presentedRect], 10 | /// for which it calculates size and color. 11 | /// 12 | /// See [PointPresenter]. 13 | class VerticalBarPointPresenter extends PointPresenter { 14 | late ui.Rect presentedRect; 15 | late ui.Paint valuesRowPaint; 16 | 17 | VerticalBarPointPresenter({ 18 | required StackableValuePoint point, 19 | StackableValuePoint? nextRightColumnValuePoint, 20 | required int rowIndex, 21 | required ChartViewModel chartViewModel, 22 | }) : super( 23 | nextRightColumnValuePoint: nextRightColumnValuePoint, 24 | rowIndex: rowIndex, 25 | chartViewModel: chartViewModel, 26 | ) { 27 | // todo-1 move colors creation to super (shared for VerticalBar and LineAndHotspot) 28 | valuesRowPaint = ui.Paint(); 29 | valuesRowPaint.color = chartViewModel.getLegendItemAt(rowIndex).color; 30 | 31 | ui.Offset barMidBottom = point.scaledFrom; 32 | ui.Offset barMidTop = point.scaledTo; 33 | HorizontalAxisContainerCL horizontalAxisContainerCL = chartViewModel.chartRootContainer.horizontalAxisContainer as HorizontalAxisContainerCL; 34 | double barWidth = horizontalAxisContainerCL.xGridStep * 35 | chartViewModel.chartOptions.dataContainerOptions.gridStepWidthPortionUsedByAtomicPointPresenter; 36 | 37 | ui.Offset barLeftTop = barMidTop.translate(-1 * barWidth / 2, 0.0); 38 | ui.Offset barRightBottom = barMidBottom.translate(1 * barWidth / 2, 0.0); 39 | 40 | presentedRect = ui.Rect.fromPoints(barLeftTop, barRightBottom); 41 | } 42 | } 43 | 44 | /// Creator of the [VerticalBarPointPresenter] instances - the leaf visual 45 | /// elements on the bar chart (rectangle one data value). 46 | /// 47 | /// See [PointPresenterCreator]. 48 | class VerticalBarLeafPointPresenterCreator extends PointPresenterCreator { 49 | VerticalBarLeafPointPresenterCreator() : super(); 50 | 51 | @override 52 | PointPresenter createPointPresenter({ 53 | required StackableValuePoint point, 54 | StackableValuePoint? nextRightColumnValuePoint, 55 | required int rowIndex, 56 | required ChartViewModel chartViewModel, 57 | }) { 58 | return VerticalBarPointPresenter( 59 | point: point, 60 | nextRightColumnValuePoint: nextRightColumnValuePoint, 61 | rowIndex: rowIndex, 62 | chartViewModel: chartViewModel, 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/coded_layout/chart/chart_type/bar/root_container.dart: -------------------------------------------------------------------------------- 1 | // base libraries 2 | import 'package:flutter_charts/src/coded_layout/chart/container.dart'; 3 | import 'package:flutter_charts/src/coded_layout/chart/axis_container.dart'; 4 | import 'package:flutter_charts/src/coded_layout/chart/data_container.dart'; 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/cartesian/container/root_container.dart'; 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/switch_view_model/view_model_cl.dart'; 9 | 10 | // this level 11 | import 'presenter.dart'; // OLD 12 | 13 | 14 | /// The container-hierarchy root container of the vertical bar chart in the coded_layout legacy version. 15 | class BarChartRootContainerCL extends ChartRootContainerCL implements ChartRootContainer { 16 | BarChartRootContainerCL({ 17 | required LegendContainer legendContainer, 18 | required HorizontalAxisContainerCL horizontalAxisContainer, 19 | required OutputAxisContainerCL verticalAxisContainerFirst, 20 | required OutputAxisContainerCL verticalAxisContainer, 21 | required DataContainerCL dataContainer, 22 | required ChartViewModel chartViewModel, 23 | }) : super( 24 | legendContainer: legendContainer, 25 | horizontalAxisContainer: horizontalAxisContainer, 26 | verticalAxisContainerFirst: verticalAxisContainerFirst, 27 | verticalAxisContainer: verticalAxisContainer, 28 | dataContainer: dataContainer, 29 | chartViewModel: chartViewModel, 30 | ) { 31 | (chartViewModel as SwitchChartViewModelCL).pointPresenterCreator = VerticalBarLeafPointPresenterCreator(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/coded_layout/chart/chart_type/line/presenter.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Offset, Paint; 2 | 3 | // base libraries 4 | import 'package:flutter_charts/src/coded_layout/chart/container.dart'; 5 | import 'package:flutter_charts/src/coded_layout/chart/line_container.dart'; 6 | import 'package:flutter_charts/src/coded_layout/chart/presenter.dart'; // OLD 7 | 8 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 9 | 10 | /// PointPresenter of the atomic/leaf element of one data point on the 11 | /// line chart - the point at which data value is shown, 12 | /// and the line from this data value point to the next data value point 13 | /// on the right. 14 | /// 15 | /// The line leads from this [offsetPoint] 16 | /// to the [offsetPoint] of the [LineAndHotspotPointPresenter] 17 | /// which is next in the [PointPresentersColumn.pointPresenters] list. 18 | class LineAndHotspotPointPresenter extends PointPresenter { 19 | late LineContainerCL lineContainer; 20 | late ui.Offset offsetPoint; // offset where the data point will be painted 21 | late ui.Paint innerPaint; 22 | late ui.Paint outerPaint; 23 | double innerRadius = 0.0; 24 | double outerRadius = 0.0; 25 | 26 | late ui.Paint rowDataPaint; 27 | 28 | LineAndHotspotPointPresenter({ 29 | required StackableValuePoint point, 30 | StackableValuePoint? nextRightColumnValuePoint, 31 | required int rowIndex, 32 | required ChartViewModel chartViewModel, 33 | }) : super( 34 | nextRightColumnValuePoint: nextRightColumnValuePoint, 35 | rowIndex: rowIndex, 36 | chartViewModel: chartViewModel, 37 | ) { 38 | var options = chartViewModel.chartOptions; 39 | 40 | // todo-1 move colors creation to super (shared for VerticalBar and LineAndHotspot) 41 | rowDataPaint = ui.Paint(); 42 | rowDataPaint.color = chartViewModel.getLegendItemAt(rowIndex).color; 43 | 44 | ui.Offset fromPoint = point.scaledTo; 45 | ui.Offset? toPoint = nextRightColumnValuePoint?.scaledTo; 46 | toPoint ??= fromPoint; 47 | lineContainer = LineContainerCL( 48 | chartViewModel: chartViewModel, 49 | lineFrom: fromPoint, 50 | lineTo: toPoint, 51 | linePaint: rowDataPaint..strokeWidth = options.lineChartOptions.lineStrokeWidth); 52 | offsetPoint = fromPoint; // point is the left (from) end of the line 53 | innerPaint = ui.Paint()..color = options.lineChartOptions.hotspotInnerPaintColor; 54 | outerPaint = ui.Paint()..color = options.lineChartOptions.hotspotOuterPaintColor; 55 | innerRadius = options.lineChartOptions.hotspotInnerRadius; 56 | outerRadius = options.lineChartOptions.hotspotOuterRadius; 57 | } 58 | } 59 | 60 | /// Creator of the [LineAndHotspotPointPresenter] instances - the leaf visual 61 | /// elements on the line chart (point and line showing one data value). 62 | /// 63 | /// See [PointPresenterCreator]. 64 | class LineAndHotspotLeafPointPresenterCreator extends PointPresenterCreator { 65 | LineAndHotspotLeafPointPresenterCreator() : super(); 66 | 67 | @override 68 | PointPresenter createPointPresenter({ 69 | required StackableValuePoint point, 70 | StackableValuePoint? nextRightColumnValuePoint, 71 | required int rowIndex, 72 | required ChartViewModel chartViewModel, 73 | }) { 74 | return LineAndHotspotPointPresenter( 75 | point: point, 76 | nextRightColumnValuePoint: nextRightColumnValuePoint, 77 | rowIndex: rowIndex, 78 | chartViewModel: chartViewModel, 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/src/coded_layout/chart/chart_type/line/root_container.dart: -------------------------------------------------------------------------------- 1 | // base libraries 2 | import 'package:flutter_charts/src/coded_layout/chart/container.dart'; 3 | import 'package:flutter_charts/src/coded_layout/chart/axis_container.dart'; 4 | import 'package:flutter_charts/src/coded_layout/chart/data_container.dart'; 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/cartesian/container/root_container.dart'; 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/switch_view_model/view_model_cl.dart'; 9 | 10 | // this level 11 | import 'presenter.dart'; // OLD 12 | 13 | /// The container-hierarchy root container of the line chart in the coded_layout legacy version. 14 | class LineChartRootContainerCL extends ChartRootContainerCL implements ChartRootContainer { 15 | LineChartRootContainerCL({ 16 | required LegendContainer legendContainer, 17 | required HorizontalAxisContainerCL horizontalAxisContainer, 18 | required OutputAxisContainerCL verticalAxisContainerFirst, 19 | required OutputAxisContainerCL verticalAxisContainer, 20 | required DataContainerCL dataContainer, 21 | required ChartViewModel chartViewModel, 22 | }) : super( 23 | legendContainer: legendContainer, 24 | horizontalAxisContainer: horizontalAxisContainer, 25 | verticalAxisContainerFirst: verticalAxisContainerFirst, 26 | verticalAxisContainer: verticalAxisContainer, 27 | dataContainer: dataContainer, 28 | chartViewModel: chartViewModel, 29 | ) { 30 | (chartViewModel as SwitchChartViewModelCL).pointPresenterCreator = LineAndHotspotLeafPointPresenterCreator(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/coded_layout/chart/line_container.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui show Offset, Paint, Canvas; 2 | 3 | // this level 4 | 5 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart' show LayoutableBox; 6 | import 'package:flutter_charts/src/chart/cartesian/container/container_common.dart' as container_common show ChartAreaContainer; 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | 9 | 10 | /// Manages [lineFrom] and [lineTo] positions and [linePaint] for a line segment. 11 | class LineContainerCL extends container_common.ChartAreaContainer { 12 | /// Points from which line starts and ends. NOT added to children ATM. 13 | ui.Offset lineFrom; 14 | ui.Offset lineTo; 15 | ui.Paint linePaint; 16 | 17 | // todo-02-full-autolayout : manualLayedOutFromX and friends ADDED TEMPORARILY to be set during construction 18 | // : of [LineContainer] in [GridLinesContainer.buildAndReplaceChildren] 19 | // : where these layout values are calculated, held on, 20 | // : and used later in self [layout], to set [lineFrom] and [lineTo] 21 | // : THIS IS TEMPORARY FOR MANUAL LAYOUT TO SHUFFLE VALUES FROM PARENT LAYOUT 22 | // : (GridLinesContainer, something else??) TO LineContainer.layout() 23 | /// With manual layout, holds on to the layout value of horizontal or vertical lines, 24 | /// between the lifecycle events of [LineContainerCL] 25 | /// creation in parent [buildAndReplaceChildren] 26 | /// and it's layout in parent [layout]. 27 | /// 28 | /// ONLY used on horizontal xLineContainer or vertical yLineContainer, maintains the 29 | /// coordinate that remains the same: y on xLineContainer, x on yLineContainer. 30 | /// 31 | double manualLayedOutFromX; 32 | double manualLayedOutFromY; 33 | double manualLayedOutToX; 34 | double manualLayedOutToY; 35 | 36 | LineContainerCL({ 37 | required ChartViewModel chartViewModel, 38 | required this.lineFrom, 39 | required this.lineTo, 40 | required this.linePaint, 41 | this.manualLayedOutFromX = 0.0, 42 | this.manualLayedOutFromY = 0.0, 43 | this.manualLayedOutToX = 0.0, 44 | this.manualLayedOutToY = 0.0, 45 | }) : super( 46 | chartViewModel: chartViewModel, 47 | ); 48 | 49 | // ##### Implementors of method in superclass [Container]. 50 | 51 | /// Implementor of method in superclass [Container]. 52 | /// 53 | /// Ensure [layoutSize] is set. 54 | /// Note that because this leaf container overrides [layout] here, 55 | /// it does not need to override [layout_Post_Leaf_SetSize_FromInternals]. 56 | @override 57 | void layout() { 58 | buildAndReplaceChildren(); 59 | // Use the coordinates manually layed out during creation in [GridLinesContainer] by 60 | lineFrom = ui.Offset(manualLayedOutFromX, manualLayedOutFromY); 61 | lineTo = ui.Offset(manualLayedOutToX, manualLayedOutToY); 62 | 63 | layoutSize = constraints.size; 64 | } 65 | 66 | /// Override method in superclass [Container]. 67 | @override 68 | void applyParentOffset(LayoutableBox caller, ui.Offset offset) { 69 | super.applyParentOffset(caller, offset); 70 | lineFrom += offset; 71 | lineTo += offset; 72 | } 73 | 74 | @override 75 | void paint(ui.Canvas canvas) { 76 | canvas.drawLine(lineFrom, lineTo, linePaint); 77 | } 78 | 79 | @override 80 | void buildAndReplaceChildren() { 81 | buildAndReplaceChildrenDefault(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/src/morphic/container/container_edge_padding.dart: -------------------------------------------------------------------------------- 1 | 2 | // this level 3 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 4 | 5 | /// Edge padding for the [Padder] layouter. 6 | /// 7 | /// Script-writing order dependent members [start] and [end] define padding in logical pixels 8 | /// on the left and the right of the child for left-to-right scripts; 9 | /// on the right and the left for right-to-left scripts 10 | /// 11 | /// [top] and [bottom] define padding in logical pixels on the top and the bottom of the child. 12 | /// 13 | /// Assuming left to right, using a construct such as 14 | /// ```dart 15 | /// Padder( 16 | /// edgePadding: EdgePadding(start: 1, top: 2, end: 3, bottom:4), 17 | /// child: Child(), 18 | /// ) 19 | /// ``` 20 | /// The child is surrounded by 1, 2, 3, and 4 pixels, and it's width is increased by 1+3 pixels, 21 | /// it's height by 2+4 pixels from child's width and height. 22 | class EdgePadding { 23 | 24 | // Generative unnamed 25 | const EdgePadding({ 26 | required this.start, 27 | required this.top, 28 | required this.end, 29 | required this.bottom, 30 | }); 31 | 32 | const EdgePadding.withSides({ 33 | this.start = 0.0, 34 | this.top = 0.0, 35 | this.end = 0.0, 36 | this.bottom = 0.0, 37 | }); 38 | 39 | factory EdgePadding.TransposingWithSides({ 40 | required ChartOrientation chartOrientation, 41 | double start = 0.0, 42 | double top = 0.0, 43 | double end = 0.0, 44 | double bottom = 0.0, 45 | }) { 46 | switch(chartOrientation) { 47 | case ChartOrientation.column: 48 | return EdgePadding.withSides(start: start, top: top, end: end, bottom: bottom); 49 | case ChartOrientation.row: 50 | return EdgePadding.withSides(start: bottom, top: end, end: top, bottom: start); 51 | } 52 | } 53 | 54 | // constructor const EdgePadding.none() : this.withSides(); 55 | static const EdgePadding none = EdgePadding.withSides(); // member field 56 | 57 | const EdgePadding.withAllSides(double value) 58 | : start = value, 59 | top = value, 60 | end = value, 61 | bottom = value; 62 | 63 | /// Padding copy of self with all sides reversed signs. 64 | /// 65 | /// Useful for inflating and deflating Rectangles. 66 | EdgePadding negate() => EdgePadding(start: -start, top: -top, end: -end, bottom: -bottom); 67 | 68 | final double start; 69 | 70 | final double top; 71 | 72 | final double end; 73 | 74 | final double bottom; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /lib/src/morphic/container/container_key.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart' show immutable; 2 | 3 | // this level 4 | import 'package:flutter_charts/src/morphic/container/container_layouter_base.dart'; 5 | 6 | /// [ContainerKey] is a unique identifier of a [BoxContainer]. 7 | /// 8 | /// The meaning of 'unique' depends on the 'context'. 9 | /// 10 | /// In the current implementation, the only supported 'uniqueness context' is 'siblings of [BoxContainerHierarchy]'. 11 | /// In other words, extensions of [ContainerKey] currently support the ability to identify [BoxContainer] 12 | /// uniquely among it's children in the [BoxContainerHierarchy]. 13 | /// 14 | /// In the future the 'uniqueness context' may be 'application', or other well-defined subsets of it. 15 | @immutable 16 | abstract class ContainerKey { 17 | 18 | /// Single generative constructor constructs Key without value, 19 | /// allows extensions to define `const` constructor. 20 | /// 21 | /// This trick ensures the default no-arg constructor `ContainerKey()` is not generated, 22 | /// and so ContainerKey cannot be extended outside of this library `container_key.dart`. 23 | /// 24 | /// Note: 25 | /// Trying to use 26 | /// `ContainerKey();` 27 | /// causes a compile error 'the unnamed constructor is already defined' 28 | /// 29 | const ContainerKey._simple(); 30 | 31 | /// Default way to create instance of [ContainerKey] extension. 32 | /// 33 | /// Note this creates a siblings unique key. 34 | /// Must override if uniqueness in other context key is needed. 35 | const factory ContainerKey(String value) = SiblingsValueKey; 36 | } 37 | 38 | /// [SiblingsKey] is a [ContainerKey] intended to be unique among siblings 39 | /// of the same parent in the [BoxContainerHierarchy]. 40 | /// 41 | @immutable 42 | abstract class SiblingsKey extends ContainerKey { 43 | /// Default constructor. 44 | /// 45 | /// Must be [const] to enable extensions' [const] constructors. 46 | const SiblingsKey() : super._simple(); 47 | 48 | } 49 | 50 | /// A [SiblingsKey] extension uses a parametrized [value] as identifier. 51 | /// 52 | /// It is assumed to be created and set on [BoxContainer] during construction, unique 53 | /// among siblings. That means, the creator of the [BoxContainer]s must be aware 54 | /// of any future siblings, or generate the key sufficiently randomly. 55 | @immutable 56 | class SiblingsValueKey extends SiblingsKey { 57 | final T value; 58 | 59 | const SiblingsValueKey(this.value) : super(); 60 | 61 | @override 62 | String toString() { 63 | return '$runtimeType: value=$value'; 64 | } 65 | 66 | @override 67 | bool operator ==(Object other) => 68 | other is SiblingsValueKey && other.runtimeType == runtimeType && other.value == value; 69 | 70 | @override 71 | int get hashCode => value.hashCode * 17; 72 | } 73 | 74 | /// Allows implementations to be identified by a user-defined unique key. 75 | /// 76 | /// Uniqueness depends on context, and is not described by this class: 77 | /// Uniqueness can be global, in hierarchy, among siblings etc. 78 | abstract class Keyed { 79 | ContainerKey get key; 80 | } 81 | 82 | /// Manager of [Keyed] objects in member list [keyedMembers] which [ContainerKey]s must be kept unique 83 | /// within the [keyedMembers]. 84 | /// 85 | /// Works as a mixin on behalf of it's extension, by delegating the [keyedMembers] getter (a list of [Keyed] objects) 86 | /// to it's extension's member. 87 | /// 88 | /// The method [ensureKeyedMembersHaveUniqueKeys] must be called by the extension 89 | /// every time after the list underlying the [keyedMembers] getter is changed. 90 | /// 91 | /// For example, a [BoxContainer] we want siblings should be unique, 92 | /// so we ensure [BoxContainer] implements the [UniqueKeyedObjectsManager], 93 | /// and we forward the [BoxContainer]'s [_children] to the [UniqueKeyedObjectsManager]'s [keyedMembers]; 94 | /// we also ensure that in [BoxContainer]'s constructor, after [BoxContainer]'s [_children] change, we call [ensureKeyedMembersHaveUniqueKeys]. 95 | abstract class UniqueKeyedObjectsManager { 96 | 97 | /// Holder of the [Keyed] members, which keys must stay unique. 98 | /// 99 | /// Serves as a backing [Iterable] of the [Keyed] objects 100 | /// this holder manages. 101 | /// 102 | /// Implementors need to override this 103 | /// method to start holding uniquely [Keyed] objects. 104 | List get keyedMembers; 105 | 106 | Iterable get _memberKeys => keyedMembers.map((Keyed keyed) => keyed.key); 107 | 108 | Keyed getKeyedByKey(ContainerKey containerKey) { 109 | return keyedMembers.firstWhere((Keyed keyed) => keyed.key == containerKey); 110 | } 111 | 112 | /// Checks uniqueness of all managed [Keyed] members. 113 | /// 114 | /// Implementors must call this method every time after the list backing 115 | /// the [keyedMembers] is modified. 116 | /// 117 | /// As by default, the [BoxContainer._children], is the list backing the [UniqueKeyedObjectsManager.keyedMembers], 118 | /// this method must be called after changing [_children]. 119 | void ensureKeyedMembersHaveUniqueKeys() { 120 | // toSet converts to set using ==. 121 | // If lengths do not match, there are at least two == keys in [keys]. 122 | Set toSet = _memberKeys.toSet(); 123 | if (toSet.length != _memberKeys.length) { 124 | throw StateError('ensureKeyedMembersHaveUniqueKeys: keys $_memberKeys of members $keyedMembers are not unique'); 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /lib/src/morphic/container/morphic_dart_enums.dart: -------------------------------------------------------------------------------- 1 | 2 | // this level 3 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 4 | 5 | /// Library defines enums which belong to Flutter-dependent [container_layouter_base.dart] 6 | /// but packaged here for testability in dart testing. 7 | 8 | 9 | /// Position in label on which the axis tick, defining the label's data position, is placed. 10 | enum ExternalTickAtPosition { 11 | childStart, 12 | childCenter, 13 | childEnd, 14 | } 15 | 16 | /// Describes axis orientation in culture-neutral, and data dependent/independent neutral terms. 17 | /// 18 | enum LayoutAxis { 19 | horizontal, 20 | vertical; 21 | 22 | LayoutAxis perpendicularAxis() { 23 | switch (this) { 24 | case LayoutAxis.horizontal: 25 | return LayoutAxis.vertical; 26 | case LayoutAxis.vertical: 27 | return LayoutAxis.horizontal; 28 | } 29 | } 30 | 31 | } 32 | 33 | /// Describes the type of data shown on a [LayoutAxis], for a [ChartOrientation]. 34 | /// 35 | /// Given a [ChartOrientation], the [LayoutAxis] on which a given [DataDependency] 36 | /// is shown, is defined by [ChartOrientation.layoutAxisForDataDependency]. 37 | enum DataDependency { 38 | inputData, 39 | outputData, 40 | } 41 | 42 | /// On behalf of [PointsBarModel], represents the sign of the values of [PointModel] points 43 | /// which should be added to the [PointsBarModel]. 44 | /// 45 | /// Motivation: In order to display both negative and positive values on the bar chart or line chart, 46 | /// the [ChartModel] manages the positive and negative values separately in 47 | /// [ChartModel.dataColumnPointsModelPositiveList] and [ChartModel.dataColumnPointsModelNegativeList]. 48 | /// This enum supports creating and later using (processing, view making) the positive and negative 49 | /// bars separately. 50 | enum Sign { 51 | positiveOr0, 52 | negative, 53 | any; 54 | 55 | /// Checks if the sign of a the passed [value] is the sign required by this enum instance. 56 | bool isValueMySign({ 57 | required double value, 58 | }) { 59 | switch (this) { 60 | case Sign.positiveOr0: 61 | return (value >= 0.0); 62 | case Sign.negative: 63 | return (value < 0.0); 64 | case Sign.any: 65 | return true; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/src/morphic/util/extensible_enum.dart: -------------------------------------------------------------------------------- 1 | /// Base class for extensible pseudo-enums. 2 | /// 3 | abstract class BaseExtensibleEnum { 4 | 5 | const BaseExtensibleEnum(this.i); 6 | 7 | final int i; 8 | 9 | @override 10 | String toString() => '$runtimeType: instance i=$i'; 11 | } 12 | -------------------------------------------------------------------------------- /lib/src/switch_view_model/auto_layout/bar/view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 4 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 5 | 6 | // base libraries 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 9 | import 'package:flutter_charts/src/chart/cartesian/chart_type/bar/container/root_container.dart'; 10 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 11 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 12 | import 'package:flutter_charts/src/chart/cartesian/chart_type/bar/container/data_container.dart'; 13 | 14 | // this level: switch/auto_layout/bar 15 | import 'package:flutter_charts/src/switch_view_model/view_model.dart'; // NEW SWITCH 16 | 17 | /// Concrete [ChartViewModel] for [BarChart]. 18 | /// 19 | /// See [ChartViewModel] for help. 20 | class SwitchBarChartViewModel extends SwitchChartViewModel { 21 | SwitchBarChartViewModel({ 22 | required ChartModel chartModel, 23 | required ChartType chartType, 24 | required ChartOrientation chartOrientation, 25 | required LiveOrTesting liveOrTesting, 26 | required ChartStacking chartStacking, 27 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 28 | }) : super( 29 | chartModel: chartModel, 30 | chartType: chartType, 31 | chartOrientation: chartOrientation, 32 | chartStacking: chartStacking, 33 | liveOrTesting: liveOrTesting, 34 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 35 | ) { 36 | logger.Logger().d('$runtimeType created'); 37 | } 38 | 39 | /// Concrete implementation returns the root for vertical bar chart. 40 | @override 41 | BarChartRootContainer makeChartRootContainer({required ChartViewModel chartViewModel}) { 42 | return BarChartRootContainer( 43 | legendContainer: LegendContainer(chartViewModel: this), 44 | horizontalAxisContainer: TransposingAxisLabels.HorizontalAxis(chartViewModel: this), 45 | verticalAxisContainerFirst: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 46 | verticalAxisContainer: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 47 | dataContainer: BarChartDataContainer(chartViewModel: this), 48 | chartViewModel: chartViewModel, 49 | ); 50 | } 51 | 52 | /// Implements [ChartBehavior] mixin abstract method. 53 | /// 54 | /// Overridden to [false] on this bar chart container, where the y axis must start from 0. 55 | /// 56 | @override 57 | bool get extendAxisToOrigin => true; 58 | } 59 | -------------------------------------------------------------------------------- /lib/src/switch_view_model/auto_layout/line/view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | 4 | // base libraries 5 | import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 6 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 9 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 10 | import 'package:flutter_charts/src/chart/cartesian/chart_type/line/container/data_container.dart'; 11 | 12 | import 'package:flutter_charts/src/chart/cartesian/chart_type/line/container/root_container.dart'; 13 | 14 | // this level: switch/auto_layout/bar 15 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 16 | import 'package:flutter_charts/src/switch_view_model/view_model.dart'; // NEW SWITCH 17 | 18 | /// Concrete [ChartViewModel] for [LineChart]. 19 | /// 20 | /// See [ChartViewModel] for help. 21 | class SwitchLineChartViewModel extends SwitchChartViewModel { 22 | SwitchLineChartViewModel({ 23 | required ChartModel chartModel, 24 | required ChartType chartType, 25 | required ChartOrientation chartOrientation, 26 | required ChartStacking chartStacking, 27 | required LiveOrTesting liveOrTesting, 28 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 29 | }) : super( 30 | chartModel: chartModel, 31 | chartType: chartType, 32 | chartOrientation: chartOrientation, 33 | chartStacking: chartStacking, 34 | liveOrTesting: liveOrTesting, 35 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 36 | ) { 37 | logger.Logger().d('$runtimeType created'); 38 | } 39 | 40 | /// Concrete implementation returns the root for vertical bar chart. 41 | @override 42 | LineChartRootContainer makeChartRootContainer({required ChartViewModel chartViewModel}) { 43 | return LineChartRootContainer( 44 | legendContainer: LegendContainer(chartViewModel: this), 45 | horizontalAxisContainer: TransposingAxisLabels.HorizontalAxis(chartViewModel: this), 46 | verticalAxisContainerFirst: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 47 | verticalAxisContainer: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 48 | dataContainer: LineChartDataContainer(chartViewModel: this), 49 | chartViewModel: chartViewModel, 50 | ); 51 | } 52 | 53 | /// Implements [ChartBehavior] mixin abstract method. 54 | /// 55 | /// If resolved to [true], Y axis will start on the minimum of Y values, otherwise at [0.0]. 56 | /// 57 | /// This is the method used in code logic when building the Y labels and axis. 58 | /// 59 | /// The related variable [DataContainerOptions.extendAxisToOriginRequested], 60 | /// is merely a request that may not be granted in some situations. 61 | /// 62 | /// On this line chart container, allow the y axis start from 0 if requested by options. 63 | @override 64 | bool get extendAxisToOrigin => chartOptions.dataContainerOptions.extendAxisToOriginRequested; 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/switch_view_model/coded_layout/bar/view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | // this level 4 | import 'package:flutter_charts/src/coded_layout/chart/chart_type/bar/root_container.dart'; 5 | 6 | // base libraries 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/coded_layout/chart/axis_container.dart'; 9 | import 'package:flutter_charts/src/coded_layout/chart/data_container.dart'; 10 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 11 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 12 | 13 | import 'package:flutter_charts/src/switch_view_model/view_model_cl.dart'; // OLD 14 | import 'package:flutter_charts/src/switch_view_model/view_model.dart' show directionWrapperAroundCL; 15 | 16 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 17 | 18 | import 'package:flutter_charts/test/src/chart/cartesian/container/legend_container.dart' as testing_legend_container; 19 | 20 | 21 | class SwitchBarChartViewModelCL extends SwitchChartViewModelCL { 22 | SwitchBarChartViewModelCL({ 23 | required ChartModel chartModel, 24 | required ChartType chartType, 25 | required ChartOrientation chartOrientation, 26 | required ChartStacking chartStacking, 27 | required LiveOrTesting liveOrTesting, 28 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 29 | }) : super( 30 | chartModel: chartModel, 31 | chartType: chartType, 32 | chartOrientation: chartOrientation, 33 | chartStacking: chartStacking, 34 | liveOrTesting: liveOrTesting, 35 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 36 | ) { 37 | logger.Logger().d('$runtimeType created'); 38 | } 39 | 40 | @override 41 | BarChartRootContainerCL makeChartRootContainer({required ChartViewModel chartViewModel}) { 42 | return BarChartRootContainerCL( 43 | legendContainer: testing_legend_container.LegendContainer(chartViewModel: this), 44 | horizontalAxisContainer: HorizontalAxisContainerCL( 45 | chartViewModel: this, 46 | directionWrapperAround: directionWrapperAroundCL, 47 | ), 48 | verticalAxisContainerFirst: OutputAxisContainerCL( 49 | chartViewModel: this, 50 | directionWrapperAround: directionWrapperAroundCL, 51 | ), 52 | verticalAxisContainer: OutputAxisContainerCL( 53 | chartViewModel: this, 54 | directionWrapperAround: directionWrapperAroundCL, 55 | ), 56 | dataContainer: BarChartDataContainerCL(chartViewModel: this), 57 | chartViewModel: chartViewModel, 58 | ); 59 | } 60 | 61 | @override 62 | bool get extendAxisToOrigin => true; 63 | } 64 | -------------------------------------------------------------------------------- /lib/src/switch_view_model/coded_layout/line/view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | // base libraries 4 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 5 | import 'package:flutter_charts/src/coded_layout/chart/axis_container.dart'; 6 | import 'package:flutter_charts/src/coded_layout/chart/data_container.dart'; 7 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 8 | 9 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 10 | 11 | // this level 12 | import 'package:flutter_charts/src/coded_layout/chart/chart_type/line/root_container.dart'; 13 | 14 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 15 | import 'package:flutter_charts/src/switch_view_model/view_model_cl.dart'; // OLD 16 | import 'package:flutter_charts/src/switch_view_model/view_model.dart' show directionWrapperAroundCL; 17 | 18 | import 'package:flutter_charts/test/src/chart/cartesian/container/legend_container.dart' as testing_legend_container; 19 | 20 | class SwitchLineChartViewModelCL extends SwitchChartViewModelCL { 21 | SwitchLineChartViewModelCL({ 22 | required ChartModel chartModel, 23 | required ChartType chartType, 24 | required ChartOrientation chartOrientation, 25 | required ChartStacking chartStacking, 26 | required LiveOrTesting liveOrTesting, 27 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 28 | }) : super( 29 | chartModel: chartModel, 30 | chartType: chartType, 31 | chartOrientation: chartOrientation, 32 | chartStacking: chartStacking, 33 | liveOrTesting: liveOrTesting, 34 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 35 | ) { 36 | logger.Logger().d('$runtimeType created'); 37 | } 38 | 39 | @override 40 | LineChartRootContainerCL makeChartRootContainer({required ChartViewModel chartViewModel}) { 41 | return LineChartRootContainerCL( 42 | legendContainer: testing_legend_container.LegendContainer(chartViewModel: this), 43 | horizontalAxisContainer: HorizontalAxisContainerCL( 44 | chartViewModel: this, 45 | directionWrapperAround: directionWrapperAroundCL, 46 | ), 47 | verticalAxisContainerFirst: OutputAxisContainerCL( 48 | chartViewModel: this, 49 | directionWrapperAround: directionWrapperAroundCL, 50 | ), 51 | verticalAxisContainer: OutputAxisContainerCL( 52 | chartViewModel: this, 53 | directionWrapperAround: directionWrapperAroundCL, 54 | ), 55 | dataContainer: LineChartDataContainerCL(chartViewModel: this), 56 | chartViewModel: chartViewModel, 57 | ); 58 | } 59 | 60 | /// Implements [ChartBehavior] mixin abstract method. 61 | /// 62 | /// If resolved to [true], Y axis will start on the minimum of Y values, otherwise at [0.0]. 63 | /// 64 | /// This is the method used in code logic when building the Y labels and axis. 65 | /// 66 | /// The related variable [DataContainerOptions.extendAxisToOriginRequested], 67 | /// is merely a request that may not be granted in some situations. 68 | /// 69 | /// On this line chart container, allow the y axis start from 0 if requested by options. 70 | @override 71 | bool get extendAxisToOrigin => chartOptions.dataContainerOptions.extendAxisToOriginRequested; 72 | 73 | } 74 | -------------------------------------------------------------------------------- /lib/src/switch_view_model/view_model_cl.dart: -------------------------------------------------------------------------------- 1 | // import 'package:logger/logger.dart' as logger; 2 | // import 'dart:developer' as dart_developer; 3 | 4 | // this level 5 | import 'package:flutter_charts/src/switch_view_model/view_model.dart'; // NEW SWITCH 6 | 7 | import 'package:flutter_charts/src/coded_layout/chart/container.dart' as container; // OLD CONTAINER 8 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; // NEW 9 | import 'package:flutter_charts/src/chart/model/data_model.dart' as model; 10 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 11 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 12 | 13 | import 'package:flutter_charts/src/coded_layout/chart/presenter.dart' as presenter; // OLD - ok to use in switch 14 | 15 | abstract class SwitchChartViewModelCL extends SwitchChartViewModel { 16 | 17 | SwitchChartViewModelCL({ 18 | required model.ChartModel chartModel, 19 | required ChartType chartType, 20 | required ChartOrientation chartOrientation, 21 | required ChartStacking chartStacking, 22 | required LiveOrTesting liveOrTesting, 23 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 24 | }) : super( 25 | chartModel: chartModel, 26 | chartType: chartType, 27 | chartOrientation: chartOrientation, 28 | chartStacking: chartStacking, 29 | liveOrTesting: liveOrTesting, 30 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 31 | ); 32 | 33 | /// Makes pointPresenters, the visuals painted on each chart column that 34 | /// represent data, (points and lines for the line chart, 35 | /// rectangles for the bar chart, and so on). 36 | /// 37 | /// See [PointPresenterCreator] and [PointPresenter] for more details. 38 | late presenter.PointPresenterCreator pointPresenterCreator; // equivalent of NEW ChartViewModel in OLD layout 39 | 40 | /// Overridden view models for chart areas. 41 | @override 42 | container.ChartRootContainerCL makeChartRootContainer({required ChartViewModel chartViewModel}); 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /lib/src/util/collection.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection' as collection show ListBase; 2 | 3 | class CustomList extends collection.ListBase { 4 | 5 | /// Makes this custom list growable on/off on construction. 6 | final bool _growable; 7 | 8 | /// Delegate to which we pass all concrete methods of the [CustomList] class. 9 | late final List delegate; 10 | 11 | /// The single UNNAMED, and one of GENERATIVE constructors. 1 unnamed which is also generative always works. 12 | CustomList({required bool growable}) 13 | : _growable = growable, 14 | super() { 15 | delegate = List.empty(growable: _growable); 16 | } 17 | 18 | // ListBase implements all read operations using only the 19 | // - `length` and 20 | // - `operator[]` and members. 21 | // It implements write operations using those and 22 | // - `add`, 23 | // - `length=` and 24 | // - `operator[]=` 25 | // Classes using this base classs should implement those five operations. 26 | 27 | @override 28 | set length(int newLength) { 29 | delegate.length = newLength; 30 | } 31 | 32 | @override 33 | int get length => delegate.length; 34 | 35 | @override 36 | E operator [](int index) => delegate[index]; 37 | 38 | @override 39 | void operator []=(int index, E value) { 40 | delegate[index] = value; 41 | } 42 | 43 | /// The [add] method must be overridden for lists that do NOT 44 | /// allow `null` as element. 45 | @override 46 | void add(E element) { 47 | delegate.add(element); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/src/util/extensions_dart.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math show min, max; 2 | 3 | // this level 4 | import 'package:flutter_charts/src/util/util_dart.dart'; 5 | 6 | import 'package:flutter_charts/src/morphic/container/morphic_dart_enums.dart' show Sign; 7 | 8 | /// Extensions on the [String] class. 9 | /// 10 | extension StringExtension on String { 11 | /// Convert this string to enum. 12 | /// 13 | /// In more detail: 14 | /// - If this string is a valid enum name in the passed enumValues, returns the enum value 15 | /// represented by this string. 16 | /// - If this string does not represent an enum in the passed enumValues, 17 | /// a StateError is thrown, indicating the values that failed. 18 | T asEnum(List enumValues) { 19 | try { 20 | return enumValues.singleWhere((v) => this == enumName(v)); 21 | } on Error { 22 | // on Error catch (e) { 23 | throw StateError('String $this is not in enum list $enumValues.'); 24 | } 25 | } 26 | } 27 | 28 | extension IterableExtension on Iterable { 29 | E reduceOrElse(E Function(E value, E element) combine, {E Function()? orElse}) { 30 | if (isNotEmpty) { 31 | return reduce(combine); 32 | } 33 | if (orElse != null) { 34 | return orElse(); 35 | } 36 | throw StateError('Iterable $this has no elements. this=${toList()}'); 37 | } 38 | 39 | double extremeValueWithSign(Sign sign) { 40 | switch(sign) { 41 | case Sign.positiveOr0: 42 | return fold(0.0, (prev, element) => math.max(prev, element as double)); 43 | case Sign.negative: 44 | return fold(0.0, (prev, element) => math.min(prev, element as double)); 45 | case Sign.any: 46 | throw StateError('method extremeWithSign cannot be applied on Sign.any'); 47 | } 48 | } 49 | } 50 | 51 | extension ListExtension on List> { 52 | List expandIt() => expand((item) => item).toList(); 53 | 54 | /// Replace each element of this list with multiple elements, each element in the multiple 55 | /// is a list of two items: first item is the element of this list, the second item is element of the 56 | /// passed [multiplyBy] list in order. 57 | /// 58 | /// Example: 59 | /// ['1', '2', '3'].multiplyElementsBy( ['a', 'b'] ) -> [[1, a], [1, b], [2, a], [2, b], [3, a], [3, b]] 60 | List multiplyElementsBy(List multiplyBy) { 61 | return map((item) => List.generate(multiplyBy.length, (int index) => [item, multiplyBy[index]])).expand((item) => item).toList(); 62 | } 63 | } 64 | 65 | List expandList(List listList) => listList.expand((item) => item).toList(); 66 | 67 | // List is List<[E, T]> 68 | List multiplyListElementsBy(List list, List multiplyBy) => 69 | list.map((item) => List.generate(multiplyBy.length, (int index) => [item, multiplyBy[index]])).expand((item) => item).toList(); 70 | 71 | /* No practical use as * is not overridable for vector and matrix 72 | import 'vector/vector_2d.dart'; 73 | import 'vector/matrix_2d.dart'; 74 | extension NumExtension on num { 75 | /// Multiply (scale) vector by number, for use in linear algebra. 76 | Vector operator *(Vector v) { 77 | return v.scaleBy(this); 78 | } 79 | 80 | /// Multiply (scale) matrix by number, for use in linear algebra. 81 | Matrix operator *(Matrix m) { 82 | return m.scaleBy(this); 83 | } 84 | } 85 | */ 86 | -------------------------------------------------------------------------------- /lib/src/util/util_flutter.dart: -------------------------------------------------------------------------------- 1 | /// Utility that contain only Dart code BUT DOES import 'dart:ui' or anything Flutter. 2 | /// See util_dart.dart for reason. 3 | import 'dart:math' as math; 4 | import 'dart:ui' show Rect, Size, Offset; 5 | 6 | // this level 7 | import 'package:flutter_charts/src/util/util_dart.dart'; 8 | import 'package:flutter_charts/src/util/extensions_dart.dart'; 9 | 10 | import 'package:flutter_charts/src/morphic/ui2d/point.dart'; 11 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart' show ChartOrientation; 12 | 13 | 14 | /// Returns the smallest rectangle which contains all passed [rectangles]. 15 | /// 16 | /// If the [rectangles] list is empty, an origin-based, zero-sized rectangle is returned. 17 | Rect boundingRect(List rectangles, /*{double Function()? orElse}*/) { 18 | return Rect.fromLTRB( 19 | rectangles.map((Rect rectangle) => rectangle.left).reduceOrElse(math.min, orElse: () => 0.0), // left 20 | rectangles.map((Rect rectangle) => rectangle.top).reduceOrElse(math.min, orElse: () => 0.0), // top, 21 | rectangles.map((Rect rectangle) => rectangle.right).reduceOrElse(math.max, orElse: () => 0.0), // right 22 | rectangles.map((Rect rectangle) => rectangle.bottom).reduceOrElse(math.max, orElse: () => 0.0), // bottom 23 | ); 24 | } 25 | 26 | void assertSizeResultsSame(Size result, Size otherResult) { 27 | if (!(isCloserThanEpsilon(result.width, otherResult.width) && 28 | isCloserThanEpsilon(result.height, otherResult.height))) { 29 | String msg = ' ### Log.Warning: Size results do not match. Result was $result, Other result was $otherResult.'; 30 | print(msg); 31 | throw StateError(msg); 32 | } 33 | } 34 | 35 | void assertOffsetResultsSame(Offset result, Offset otherResult) { 36 | if (!(isCloserThanEpsilon(result.dx, otherResult.dx) && 37 | isCloserThanEpsilon(result.dy, otherResult.dy))) { 38 | String msg = ' ### Log.Warning: Offset results do not match. Result was $result, Other result was $otherResult.'; 39 | print(msg); 40 | throw StateError(msg); 41 | } 42 | } 43 | 44 | /// Holder class defining the ranges and orientation in one place for the benefit 45 | /// of [PointOffset.affmapBetweenRanges]. 46 | /// 47 | /// todo-02-design : Should it contain ChartStacking information? 48 | class FromTransposing2DValueRange { 49 | 50 | FromTransposing2DValueRange ({ 51 | required this.inputDataRange, 52 | required this.outputDataRange, 53 | required this.chartOrientation, 54 | }); 55 | 56 | final Interval inputDataRange; 57 | final Interval outputDataRange; 58 | final ChartOrientation chartOrientation; 59 | 60 | FromTransposing2DValueRange subsetForSignOfPointOffsetBeforeAffmap({required PointOffset pointOffset,}) { 61 | return FromTransposing2DValueRange( 62 | inputDataRange: inputDataRange.portionForSignOfValue(pointOffset.inputValue), 63 | outputDataRange: outputDataRange.portionForSignOfValue(pointOffset.outputValue), 64 | chartOrientation: chartOrientation, 65 | ); 66 | } 67 | } 68 | 69 | /// Pixel 2D range encapsulates the 'to range' of values that ore affmap-ed 70 | /// from a [FromTransposing2DValueRange] instance. 71 | /// 72 | /// Always starts both dimensions from 0. 73 | /// 74 | /// Although this mentions 'pixels', it should be part of model, 75 | /// as the name is merely a convenience to define a 'to range' of 76 | /// values that ore affmap-ed from [FromTransposing2DValueRange]. 77 | class To2DPixelRange { 78 | 79 | To2DPixelRange({ 80 | // sizerWidth or constraints width 81 | required double width, 82 | // sizerHeight or constraints height 83 | required double height, 84 | }) : horizontalPixelRange = Interval(0, width), verticalPixelRange = Interval(0, height); 85 | 86 | final Interval horizontalPixelRange; 87 | final Interval verticalPixelRange; 88 | 89 | Size get size => Size(horizontalPixelRange.max, verticalPixelRange.max); 90 | } 91 | -------------------------------------------------------------------------------- /lib/src/util/vector/vector_2d.dart: -------------------------------------------------------------------------------- 1 | 2 | /// Vector. Equivalent to 1 Dimensional matrix. 3 | class Vector { 4 | Vector(List from) 5 | : _storage = from; 6 | 7 | final List _storage; 8 | get length => _storage.length; 9 | 10 | /// Vector addition 11 | Vector operator +(Vector other) { 12 | _validate(other); 13 | return Vector(List.generate(length, (index) => _storage[index] + other._storage[index])); 14 | } 15 | 16 | /// Point-wise product 17 | Vector operator *(Vector other) { 18 | _validate(other); 19 | return Vector(List.generate(length, (index) => _storage[index] * other._storage[index])); 20 | } 21 | 22 | T operator [](int index) => _storage[index]; 23 | 24 | Vector abs() { 25 | return Vector(_storage.map((element) => element.abs()).toList()); 26 | } 27 | 28 | /// Inner product 29 | num innerProduct(Vector other) { 30 | _validate(other); 31 | return List.generate(length, (index) => _storage[index] * other._storage[index]).fold(0, (a,b) => a + b); 32 | } 33 | 34 | Vector scaleBy(num scale) { 35 | return Vector(List.generate(length, (index) => scale * this[index])); // this[index] == _storage[index] 36 | } 37 | 38 | void _validate(Vector other) { 39 | if (length != other.length) throw StateError('$runtimeType: Uneven length, this=$length, other=${other.length}'); 40 | } 41 | 42 | void ensureLength(int length, {String? elseMessage}) { 43 | if (this.length != length) { 44 | throw StateError('$runtimeType instance=$this ${elseMessage ?? ""}'); 45 | } 46 | } 47 | 48 | @override 49 | bool operator ==(Object other) { 50 | if (other is! Vector) return false; 51 | if (_storage.length != other._storage.length) return false; 52 | 53 | for (int i = 0; i < _storage.length; i++) { 54 | if (_storage[i] != other._storage[i]) { 55 | return false; 56 | } 57 | } 58 | return true; 59 | } 60 | 61 | @override 62 | int get hashCode => _storage.hashCode; 63 | 64 | } -------------------------------------------------------------------------------- /lib/test/src/README.org: -------------------------------------------------------------------------------- 1 | This directory 2 | 3 | ~flutter_charts/test/src~ 4 | 5 | has subdirectory structure equivalent to 6 | 7 | ~flutter_charts/lib/src~ 8 | 9 | and contains classes used only in tests, but are not test classes. 10 | 11 | Most it's classes are testing extensions of base classes; those testing extensions are used in tests and integration tests. 12 | 13 | Note: 14 | 15 | The subdirectory ~flutter_charts/test/src/example~ is not equivalently placed; it contains the main example used in tests. 16 | 17 | The intent of this ~example~ subdirectory is to hold a ~main.dart~ used in tests and integration tests, 18 | while the ~flutter_charts/example~ is used to be published on *pub*. -------------------------------------------------------------------------------- /lib/test/src/chart/options.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_charts/src/chart/options.dart' as chart_options; 2 | 3 | class LegendAndItemLayoutEnum extends chart_options.LegendAndItemLayoutEnum { 4 | 5 | const LegendAndItemLayoutEnum(super.i); 6 | 7 | static const legendIsColumnStartLooseItemIsRowStartLoose = chart_options.LegendAndItemLayoutEnum(1001); // See comment on legendIsColumnStartTightItemIsRowStartTight 8 | static const legendIsColumnStartTightItemIsRowStartTight = chart_options.LegendAndItemLayoutEnum(1002); // legend items in column 9 | static const legendIsRowCenterLooseItemIsRowEndLoose = chart_options.LegendAndItemLayoutEnum(1003); // Item row is not top = chart_options.LegendAndItemLayoutEnum(XX); forced to 'start' = chart_options.LegendAndItemLayoutEnum(XX); 'tight' = chart_options.LegendAndItemLayoutEnum(XX); so noop 10 | static const legendIsRowStartTightItemIsRowStartTightSecondGreedy = chart_options.LegendAndItemLayoutEnum(1005); // second Item is greedy wrapped 11 | static const legendIsRowStartTightItemIsRowStartTightItemChildrenPadded = chart_options.LegendAndItemLayoutEnum(1006); 12 | static const legendIsRowStartTightItemIsRowStartTightItemChildrenAligned = chart_options.LegendAndItemLayoutEnum(1007); 13 | } -------------------------------------------------------------------------------- /lib/test/src/switch_view_model/coded_layout/bar/view_model.dart: -------------------------------------------------------------------------------- 1 | // import 'package:logger/logger.dart' as logger; 2 | 3 | import 'package:flutter_charts/test/src/chart/cartesian/container/legend_container.dart' as testing_legend_container; 4 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 5 | 6 | // base libraries 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/switch_view_model/auto_layout/bar/view_model.dart' as bar_chart_view_model; 9 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 10 | import 'package:flutter_charts/src/chart/cartesian/chart_type/bar/container/root_container.dart'; 11 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 12 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 13 | import 'package:flutter_charts/src/chart/cartesian/chart_type/bar/container/data_container.dart'; 14 | 15 | /// Concrete [ChartViewModel] for [BarChart]. 16 | /// 17 | /// See [ChartViewModel] for help. 18 | class SwitchBarChartViewModel extends bar_chart_view_model.SwitchBarChartViewModel { 19 | SwitchBarChartViewModel({ 20 | required ChartModel chartModel, 21 | required ChartType chartType, 22 | required ChartOrientation chartOrientation, 23 | required LiveOrTesting liveOrTesting, 24 | required ChartStacking chartStacking, 25 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 26 | }) : super( 27 | chartModel: chartModel, 28 | chartType: chartType, 29 | chartOrientation: chartOrientation, 30 | chartStacking: chartStacking, 31 | liveOrTesting: liveOrTesting, 32 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 33 | ); 34 | 35 | /// Concrete implementation returns the root for vertical bar chart. 36 | @override 37 | BarChartRootContainer makeChartRootContainer({required ChartViewModel chartViewModel}) { 38 | return BarChartRootContainer( 39 | legendContainer: testing_legend_container.LegendContainer(chartViewModel: this), 40 | horizontalAxisContainer: TransposingAxisLabels.HorizontalAxis(chartViewModel: this), 41 | verticalAxisContainerFirst: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 42 | verticalAxisContainer: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 43 | dataContainer: BarChartDataContainer(chartViewModel: this), 44 | chartViewModel: chartViewModel, 45 | ); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /lib/test/src/switch_view_model/coded_layout/line/view_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:logger/logger.dart' as logger; 2 | 3 | // base libraries 4 | // import 'package:flutter_charts/src/chart/cartesian/container/legend_container.dart'; 5 | import 'package:flutter_charts/test/src/chart/cartesian/container/legend_container.dart' as testing_legend_container; 6 | import 'package:flutter_charts/src/chart/cartesian/container/axislabels_axislines_gridlines_container.dart'; 7 | import 'package:flutter_charts/src/chart/view_model/view_model.dart'; 8 | import 'package:flutter_charts/src/switch_view_model/auto_layout/line/view_model.dart' as line_chart_view_model; 9 | import 'package:flutter_charts/src/chart/model/data_model.dart'; 10 | import 'package:flutter_charts/src/chart/iterative_layout_strategy.dart' as strategy show LabelLayoutStrategy; 11 | import 'package:flutter_charts/src/chart/cartesian/chart_type/line/container/data_container.dart'; 12 | 13 | import 'package:flutter_charts/src/chart/cartesian/chart_type/line/container/root_container.dart'; 14 | 15 | // this level: switch/auto_layout/bar 16 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 17 | 18 | /// Concrete [ChartViewModel] for [LineChart]. 19 | /// 20 | /// See [ChartViewModel] for help. 21 | class SwitchLineChartViewModel extends line_chart_view_model.SwitchLineChartViewModel { 22 | SwitchLineChartViewModel({ 23 | required ChartModel chartModel, 24 | required ChartType chartType, 25 | required ChartOrientation chartOrientation, 26 | required ChartStacking chartStacking, 27 | required LiveOrTesting liveOrTesting, 28 | strategy.LabelLayoutStrategy? inputLabelLayoutStrategy, 29 | }) : super( 30 | chartModel: chartModel, 31 | chartType: chartType, 32 | chartOrientation: chartOrientation, 33 | chartStacking: chartStacking, 34 | liveOrTesting: liveOrTesting, 35 | inputLabelLayoutStrategy: inputLabelLayoutStrategy, 36 | ) { 37 | logger.Logger().d('$runtimeType created'); 38 | } 39 | 40 | /// Concrete implementation returns the root for vertical bar chart. 41 | @override 42 | LineChartRootContainer makeChartRootContainer({required ChartViewModel chartViewModel}) { 43 | return LineChartRootContainer( 44 | legendContainer: testing_legend_container.LegendContainer(chartViewModel: this), 45 | horizontalAxisContainer: TransposingAxisLabels.HorizontalAxis(chartViewModel: this), 46 | verticalAxisContainerFirst: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 47 | verticalAxisContainer: TransposingAxisLabels.VerticalAxis(chartViewModel: this), 48 | dataContainer: LineChartDataContainer(chartViewModel: this), 49 | chartViewModel: chartViewModel, 50 | ); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /lib/test/src/util/test_util.dart: -------------------------------------------------------------------------------- 1 | /// Utilities used in tests and integration tests. 2 | /// 3 | 4 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 5 | import 'package:flutter_charts/flutter_charts.dart' show enumName; 6 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart' show ExampleDescriptor; 7 | 8 | /// Extract paths to screenshots for tests. 9 | /// 10 | /// Paths include filename, and are relative to project root. 11 | class ScreenshotPaths { 12 | 13 | ScreenshotPaths({ 14 | required this.exampleDescriptor, 15 | }); 16 | 17 | final ExampleDescriptor exampleDescriptor; 18 | 19 | late final String _expectedScreenshotPath = _relativePath(_expectedScreenshotDirName(), exampleDescriptor); 20 | String get expectedScreenshotPath => _expectedScreenshotPath; 21 | late final String _actualScreenshotPath = _relativePath(_screenshotDirName(), exampleDescriptor); 22 | String get actualScreenshotPath => _actualScreenshotPath; 23 | 24 | /// Path to screenshot file the test uses for each test. 25 | String _relativePath(String screenshotDirName, ExampleDescriptor exampleDescriptor) { 26 | return '$screenshotDirName/${_screenshotFileName(exampleDescriptor)}'; 27 | } 28 | 29 | /// Path to screenshot file which this test generates. 30 | /// 31 | /// Generated from enum values. 32 | /// Examples: 33 | /// - 'ex10RandomData_lineChart.png' (for old layout) 34 | /// - 'ex10RandomData_lineChart_NEW.png' (for new layout) 35 | String _screenshotFileName( 36 | ExampleDescriptor exampleDescriptor, 37 | ) { 38 | /* todo-00-done 39 | ChartLayouter chartLayouter = exampleDescriptor.chartLayouter; 40 | String newLayoutSuffix = ''; 41 | if (!(chartLayouter == ChartLayouter.oldManualLayouter)) { 42 | newLayoutSuffix = 43 | '_NEW_orientation_${exampleDescriptor.chartOrientation.name}_stacking_${exampleDescriptor.chartStacking.name}'; 44 | } 45 | 46 | return '${enumName(exampleDescriptor.exampleEnum)}_${enumName(exampleDescriptor.chartType)}$newLayoutSuffix.png'; 47 | */ 48 | String version; 49 | switch (exampleDescriptor.chartLayouter) { 50 | case ChartLayouter.newAutoLayouter: 51 | version = 'NEW'; 52 | break; 53 | case ChartLayouter.oldManualLayouter: 54 | version = 'OLD'; 55 | break; 56 | } 57 | // return '${enumName(exampleDescriptor.exampleEnum)}_${enumName(exampleDescriptor.chartType)}$newLayoutSuffix.png'; 58 | return '${enumName(exampleDescriptor.exampleEnum)}' 59 | '_${exampleDescriptor.chartType.name}' 60 | '_${exampleDescriptor.chartOrientation.name}' 61 | '_${exampleDescriptor.chartStacking.name}' 62 | '_${exampleDescriptor.chartLayouter.name}' 63 | '.png'; 64 | } 65 | 66 | /// The name of the directory where screenshots are placed. 67 | /// 68 | /// This test is assumed to run from project's root. 69 | String _screenshotDirName() { 70 | return 'integration_test/screenshots_tested'; 71 | } 72 | 73 | String _expectedScreenshotDirName() { 74 | return 'integration_test/screenshots_expected'; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /test/chart/util/example_descriptor_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart'; 2 | import 'package:flutter_charts/src/morphic/container/chart_support/chart_style.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | main() { 6 | group('Single valid descriptor string', () { 7 | 8 | test('Valid descriptor: Fully descriptive single-ex-matching String', () { 9 | var descriptor = 'ex10RandomData_barChart_column_stacked_oldManualLayouter'; 10 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor]); 11 | 12 | expect(exampleDescriptors.length, 1); 13 | expect(exampleDescriptors[0].exampleEnum, ExampleEnum.ex10RandomData); 14 | expect(exampleDescriptors[0].chartType, ChartType.barChart); 15 | expect(exampleDescriptors[0].chartOrientation, ChartOrientation.column); 16 | expect(exampleDescriptors[0].chartStacking, ChartStacking.stacked); 17 | expect(exampleDescriptors[0].chartLayouter, ChartLayouter.oldManualLayouter); 18 | 19 | }); 20 | 21 | test('Valid descriptor: Partially descriptive single-ex-matching String', () { 22 | var descriptor = 'ex10_barChart_column_stacked_oldManualLayouter'; 23 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor]); 24 | 25 | expect(exampleDescriptors.length, 1); 26 | expect(exampleDescriptors[0].exampleEnum, ExampleEnum.ex10RandomData); 27 | expect(exampleDescriptors[0].chartType, ChartType.barChart); 28 | expect(exampleDescriptors[0].chartOrientation, ChartOrientation.column); 29 | expect(exampleDescriptors[0].chartStacking, ChartStacking.stacked); 30 | expect(exampleDescriptors[0].chartLayouter, ChartLayouter.oldManualLayouter); 31 | 32 | }); 33 | 34 | test('Valid descriptor: Partially descriptive multi-ex-matching String', () { 35 | var descriptor = 'ex_barChart_column_stacked_oldManualLayouter'; 36 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor]); 37 | 38 | expect(exampleDescriptors.length > 1, true); 39 | 40 | /* not true, although they look the same on toString : 41 | var sortedExampleDescriptors = List.from(exampleDescriptors) 42 | ..sort((d1, d2) { 43 | return d1.exampleEnum.toString().compareTo(d2.exampleEnum.toString()); 44 | }); 45 | print(exampleDescriptors); 46 | print(sortedExampleDescriptors); 47 | expect(exampleDescriptors == sortedExampleDescriptors, true); 48 | */ 49 | 50 | }); 51 | 52 | test('Valid descriptor: Fuzzy descriptive single-ex-matching String', () { 53 | var descriptor = 'ex10RandomData_*_column_stacked_oldManualLayouter'; 54 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor]); 55 | 56 | expect(exampleDescriptors.length, 2); 57 | expect(exampleDescriptors[0].exampleEnum, ExampleEnum.ex10RandomData); 58 | expect(exampleDescriptors[0].chartType, ChartType.lineChart); 59 | expect(exampleDescriptors[0].chartOrientation, ChartOrientation.column); 60 | expect(exampleDescriptors[0].chartStacking, ChartStacking.stacked); 61 | expect(exampleDescriptors[0].chartLayouter, ChartLayouter.oldManualLayouter); 62 | 63 | expect(exampleDescriptors[1].exampleEnum, ExampleEnum.ex10RandomData); 64 | expect(exampleDescriptors[1].chartType, ChartType.barChart); 65 | expect(exampleDescriptors[1].chartOrientation, ChartOrientation.column); 66 | expect(exampleDescriptors[1].chartStacking, ChartStacking.stacked); 67 | expect(exampleDescriptors[1].chartLayouter, ChartLayouter.oldManualLayouter); 68 | }); 69 | 70 | }); 71 | 72 | group('Invalid descriptor string', () { 73 | test('Invalid descriptor: throws StateError with appropriate message', () { 74 | var descriptor = 'ex10_YYYChart_column_stacked_oldManualLayouter'; 75 | // Note: reason does not seem to matter. Not sure how to check for exception text 76 | expect( 77 | () => ExampleDescriptor.parseDescriptors([descriptor]), 78 | throwsStateError, 79 | reason: 'Invalid (zero based) ChartType field 1', 80 | ); 81 | }); 82 | }); 83 | 84 | group('Multi descriptor string', () { 85 | 86 | test('Valid descriptor: 2 Fully descriptive single-ex-matching Strings', () { 87 | var descriptor1 = 'ex10RandomData_barChart_column_stacked_oldManualLayouter'; 88 | var descriptor2 = 'ex10RandomData_barChart_column_stacked_newAutoLayouter'; 89 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor1, descriptor2]); 90 | 91 | expect(exampleDescriptors.length, 2); 92 | 93 | expect(exampleDescriptors[0].exampleEnum, ExampleEnum.ex10RandomData); 94 | expect(exampleDescriptors[0].chartType, ChartType.barChart); 95 | expect(exampleDescriptors[0].chartOrientation, ChartOrientation.column); 96 | expect(exampleDescriptors[0].chartStacking, ChartStacking.stacked); 97 | expect(exampleDescriptors[0].chartLayouter, ChartLayouter.oldManualLayouter); 98 | 99 | expect(exampleDescriptors[1].exampleEnum, ExampleEnum.ex10RandomData); 100 | expect(exampleDescriptors[1].chartType, ChartType.barChart); 101 | expect(exampleDescriptors[1].chartOrientation, ChartOrientation.column); 102 | expect(exampleDescriptors[1].chartStacking, ChartStacking.stacked); 103 | expect(exampleDescriptors[1].chartLayouter, ChartLayouter.newAutoLayouter); 104 | }); 105 | 106 | test('Valid descriptor: 2 Fully descriptive multi-ex-matching Strings', () { 107 | var descriptor1 = 'ex10RandomData_*_column_stacked_*'; 108 | var descriptor2 = 'ex10RandomData_barChart_*_*_newAutoLayouter'; 109 | var exampleDescriptors = ExampleDescriptor.parseDescriptors([descriptor1, descriptor2]); 110 | 111 | expect(exampleDescriptors.length, 8); 112 | 113 | }); 114 | }); 115 | } -------------------------------------------------------------------------------- /test/deprecated_v1/screenshot_validate_deprecated_v1_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'dart:io'; 3 | 4 | import '../../lib/test/src/util/test_util.dart'; 5 | 6 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart' 7 | show ExampleDescriptor; 8 | 9 | /// @Deprecated, see 'test/screenshot_validate_test_new.dart'. 10 | void main() { 11 | test('after screenshot integration, test for sameness', () { 12 | 13 | ExampleDescriptor exampleDescriptor = ExampleDescriptor.requestedExampleToRun(); 14 | 15 | var screenshotPaths = ScreenshotPaths(exampleDescriptor: exampleDescriptor); 16 | String expectedScreenshotPath = screenshotPaths.expectedScreenshotPath; 17 | String screenshotPath = screenshotPaths.actualScreenshotPath; 18 | 19 | // Flag controls if this test runs 'expect'. 20 | // Set to false to generate initial validated screenshots. 21 | bool runExpect = true; 22 | 23 | if (runExpect && !ExampleDescriptor.isExampleWithRandomData(exampleDescriptor)) { 24 | File expectedFile = File(expectedScreenshotPath); 25 | File actualFile = File(screenshotPath); 26 | 27 | // Compare the screenshot just generated with one that was stored as expected. 28 | expectSync( 29 | expectedFile.readAsBytesSync(), 30 | actualFile.readAsBytesSync(), 31 | ); 32 | } 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /test/screenshot_validate_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'dart:io'; 3 | 4 | import '../lib/test/src/util/test_util.dart'; 5 | 6 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart' 7 | show ExampleDescriptor; 8 | 9 | /// Flutter test compares expected screenshots to actual screenshots for all chart examples 10 | /// defined by the '--dart-define' environment variable 'EXAMPLES_DESCRIPTORS', 11 | /// and resolved in [ExampleDescriptor.extractExamplesDescriptorsFromDartDefine]. 12 | /// 13 | void main() { 14 | 15 | // Extract descriptors for examples to run. examplesDescriptors must be pushed via --dart-define=EXAMPLES_DESCRIPTORS. 16 | List examplesDescriptors = ExampleDescriptor.extractExamplesDescriptorsFromDartDefine( 17 | message: 'main() of screenshot_validate_test.dart', 18 | ); 19 | 20 | test('after screenshot integration, test for sameness', () { 21 | 22 | for (var exampleDescriptor in examplesDescriptors) { 23 | 24 | print(' \n\n######### Log.Info.Level1: screenshot_validate_test.dart: Will COMPARE SCREENSHOT of $exampleDescriptor'); 25 | 26 | var screenshotPaths = ScreenshotPaths(exampleDescriptor: exampleDescriptor); 27 | String expectedScreenshotPath = screenshotPaths.expectedScreenshotPath; 28 | String screenshotPath = screenshotPaths.actualScreenshotPath; 29 | 30 | // Flag controls if this test runs 'expect'. 31 | // Set to false to generate initial validated screenshots. 32 | bool runExpect = true; 33 | 34 | if (runExpect && !ExampleDescriptor.isExampleWithRandomData(exampleDescriptor)) { 35 | File expectedFile = File(expectedScreenshotPath); 36 | File actualFile = File(screenshotPath); 37 | 38 | // Compare the screenshot just generated with one that was stored as expected. 39 | expectSync( 40 | expectedFile.readAsBytesSync(), 41 | actualFile.readAsBytesSync(), 42 | ); 43 | } 44 | } 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /test/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | # The parent directory tmp is for programs and files generated during tests. 2 | 3 | # Presence of this .gitignore commands to ignore everything but itself. 4 | # This achieves the directory is NOT ignored, and shows up on github, 5 | # while all files in this directory (which are temporary) are ignored. 6 | 7 | # * ignores everything (files and subfolders), !.gitignore keeps this file. 8 | * 9 | !.gitignore 10 | -------------------------------------------------------------------------------- /test/util/extensions_dart_test.dart: -------------------------------------------------------------------------------- 1 | /// Tests the methods in the `string_extension` package. 2 | 3 | import 'package:test/test.dart'; 4 | 5 | // Tested package 6 | import 'package:flutter_charts/src/util/extensions_dart.dart' show StringExtension; 7 | 8 | enum TestedEnum { enum1, enum2 } 9 | 10 | void main() { 11 | // enum related string extensions. 12 | group('enum', () { 13 | test('Convert string literal (representing a valid enum name) to enum', () { 14 | final TestedEnum testedEnum = 'enum1'.asEnum(TestedEnum.values); 15 | expect(testedEnum, TestedEnum.enum1); 16 | }); 17 | 18 | test('Convert string object (representing a valid enum name) to enum', () { 19 | const String enum1 = 'enum1'; 20 | final TestedEnum testedEnum = enum1.asEnum(TestedEnum.values); 21 | expect(testedEnum, TestedEnum.enum1); 22 | }); 23 | 24 | test('Convert string which does not have representation should cause exception', () { 25 | // Checking error thrown requires first argument to be a Function, 26 | // NOT a function call such as just "NOT_IN_ENUM".asEnum(TestedEnum.values). 27 | expect(() => 'NOT_IN_ENUM'.asEnum(TestedEnum.values), throwsStateError); 28 | }); 29 | 30 | test('Convert string which does not have representation should cause exception. Test the exception string.', () { 31 | String errorText = ''; 32 | try { 33 | 'NOT_IN_ENUM'.asEnum(TestedEnum.values); 34 | } on Error catch (e) { 35 | errorText = e.toString(); 36 | } 37 | expect(errorText.contains('String NOT_IN_ENUM is not in enum list [TestedEnum.enum1, TestedEnum.enum2]'), true); 38 | }); 39 | }); 40 | 41 | // next group 42 | } 43 | -------------------------------------------------------------------------------- /test/util/function_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | void main() { 4 | 5 | group('Functions', () { 6 | group('Functions == : Same result producing functions are not ==', () { 7 | double f(double arg) => arg * arg; 8 | double g(double arg) => arg * arg; 9 | test('f == g', () { 10 | assert(f == f, true); 11 | assert(g == g, true); 12 | // Always throws, whether true or false. Use expect instead of assert: assert(f == g, true); 13 | expect((f == f), true); 14 | expect((g == g), true); 15 | expect((f == g), false); 16 | }); 17 | }); 18 | }); 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /test/util/vector/vector_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:test/test.dart'; 2 | 3 | // import 'package:flutter_charts/src/util/util_dart.dart'; 4 | 5 | import 'package:flutter_charts/src/util/vector/vector_2d.dart'; 6 | import 'package:flutter_charts/src/util/vector/matrix_2d.dart'; 7 | import 'package:flutter_charts/src/util/vector/function_matrix_2d.dart'; 8 | 9 | void main() { 10 | group('double matrices and vectors', () { 11 | 12 | test('doubleMatrix.applyOnVector', () { 13 | var v = Vector([1.0, 2.0]); 14 | var m = DoubleMatrix2D([ 15 | [10.0, 20.0], 16 | [100.0, 200.0], 17 | ]); 18 | var result = Vector([50.0, 500.0]); 19 | 20 | expect(result == m.applyOnVector(v), true); 21 | }); 22 | 23 | test('doubleMatrix * doubleMatrix', () { 24 | var m1 = DoubleMatrix2D([ 25 | [10.0, 20.0], 26 | [100.0, 200.0], 27 | ]); 28 | var m2 = DoubleMatrix2D([ 29 | [1.0, 2.0], 30 | [3.0, 4.0], 31 | ]); 32 | var result = DoubleMatrix2D([ 33 | [70.0, 100.0], 34 | [700.0, 1000.0], 35 | ]); 36 | var wrongResult = DoubleMatrix2D([ 37 | [70.0, 100.0], 38 | [700.0, 1111.0], 39 | ]); 40 | 41 | expect(result == (m1 * m2), true); 42 | 43 | expect(wrongResult == (m1 * m2), false); 44 | }); 45 | 46 | test('doubleMatrix + doubleMatrix', () { 47 | var m1 = DoubleMatrix2D([ 48 | [10.0, 20.0], 49 | [100.0, 200.0], 50 | ]); 51 | var m2 = DoubleMatrix2D([ 52 | [1.0, 2.0], 53 | [3.0, 4.0], 54 | ]); 55 | var result = DoubleMatrix2D([ 56 | [11.0, 22.0], 57 | [103.0, 204.0], 58 | ]); 59 | var wrongResult = DoubleMatrix2D([ 60 | [11.0, 22.0], 61 | [103.0, 1111.0], 62 | ]); 63 | 64 | expect(result == (m1 + m2), true); 65 | 66 | expect(wrongResult == (m1 + m2), false); 67 | }); 68 | }); 69 | 70 | group('functional matrices and vectors', () { 71 | test('funcMatrix.applyOnVector', () { 72 | var v = Vector([1.0, 2.0]); 73 | var m = FunctionalMatrix2D([ 74 | [(x) => 10 * x, (x) => 20 * x], 75 | [(x) => 100 * x, (x) => 200 * x], 76 | ]); 77 | var result = Vector([50.0, 500.0]); 78 | 79 | expect(result == m.applyOnVector(v), true); 80 | }); 81 | 82 | test('funcMatrix * funcMatrix', () { 83 | var m1 = FunctionalMatrix2D([ 84 | [(x) => 10 * x, (x) => 20 * x], 85 | [(x) => 100 * x, (x) => 200 * x], 86 | ]); 87 | var m2 = FunctionalMatrix2D([ 88 | [(x) => 1 * x, (x) => 2 * x], 89 | [(x) => 3 * x, (x) => 4 * x], 90 | ]); 91 | var result = FunctionalMatrix2D([ 92 | [(x) => 70 * x, (x) => 100 * x], 93 | [(x) => 700 * x, (x) => 1000 * x], 94 | ]); 95 | var wrongResult = FunctionalMatrix2D([ 96 | [(x) => 70 * x, (x) => 100 * x], 97 | [(x) => 700 * x, (x) => 1111 * x], 98 | ]); 99 | 100 | expect(result == (m1 * m2), true); 101 | 102 | expect(wrongResult == (m1 * m2), false); 103 | }); 104 | 105 | test('funcMatrix + funcMatrix', () { 106 | var m1 = FunctionalMatrix2D([ 107 | [(x) => 10 * x, (x) => 20 * x], 108 | [(x) => 100 * x, (x) => 200 * x], 109 | ]); 110 | var m2 = FunctionalMatrix2D([ 111 | [(x) => 1 * x, (x) => 2 * x], 112 | [(x) => 3 * x, (x) => 4 * x], 113 | ]); 114 | var result = FunctionalMatrix2D([ 115 | [(x) => 11 * x, (x) => 22 * x], 116 | [(x) => 103 * x, (x) => 204 * x], 117 | ]); 118 | var wrongResult = FunctionalMatrix2D([ 119 | [(x) => 11 * x, (x) => 22 * x], 120 | [(x) => 103 * x, (x) => 1111 * x], 121 | ]); 122 | 123 | expect(result == (m1 + m2), true); 124 | 125 | expect(wrongResult == (m1 + m2), false); 126 | }); 127 | 128 | }); 129 | 130 | } 131 | 132 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | import 'package:flutter_charts/test/src/test_main.dart' as app; 4 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart' show ExampleMainAndTestSupport; 5 | 6 | /// Flutter widget tests for the example app in 'lib/test/src/test_main.dart'. 7 | /// 8 | /// Tests check some expected values on the main page of the app. 9 | /// 10 | /// Run as 11 | /// ``` shell 12 | /// flutter clean; flutter test test/widget_test.dart 13 | /// ``` 14 | void main() { 15 | group('Widget tests on page 1', () { 16 | testWidgets('find expected text on widgets', (WidgetTester tester) async { 17 | // Build the app. 18 | app.main(); 19 | 20 | await tester.pumpAndSettle(); 21 | 22 | // Verify the counter starts at 0. 23 | expect(find.text('vvvvvvvv:'), findsOneWidget); 24 | 25 | // Finds the floating action button to tap on. 26 | final Finder floatingButton = find.byTooltip(ExampleMainAndTestSupport.floatingButtonTooltipMoveToNextExample); 27 | 28 | // Emulate a tap on the floating action button. 29 | await tester.tap(floatingButton); 30 | 31 | // Trigger a frame. 32 | await tester.pumpAndSettle(); 33 | 34 | // Verify the counter increments by 1. 35 | expect(find.text('vvvvvvvv:'), findsOneWidget); 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /test_driver/integration_test.dart: -------------------------------------------------------------------------------- 1 | /* todo keep this: Active code is to take a screenshot, but this is what we should have for normal testing: 2 | import 'package:integration_test/integration_test_driver.dart'; 3 | Future main() => integrationDriver(); 4 | 5 | // Note: This file is needed for the new integration_test (Flutter 2.5 and later) to work. 6 | // Without this file, there is a warning on 7 | // import 'package:integration_test/integration_test_driver.dart'; 8 | */ 9 | 10 | /// Allows to control apps from tests, while test code runs on a native device, physical or emulated. 11 | import 'dart:io'; 12 | import 'package:flutter_charts/src/chart/util/example_descriptor.dart'; 13 | import 'package:integration_test/integration_test_driver_extended.dart'; 14 | 15 | Future main() async { 16 | 17 | // Extract descriptors for examples to run. examplesDescriptors must be pushed via --dart-define=EXAMPLES_DESCRIPTORS. 18 | // This is here only to show a message whether the env variable was picked up. 19 | // List examplesDescriptors = 20 | ExampleDescriptor.extractExamplesDescriptorsFromDartDefine( 21 | message: 'main() of screenshot_create_test.dart', 22 | ); 23 | 24 | // KEEP NOTE: 2023-05-23: Broken in Flutter somewhere between 3.7(?) and 3.10. 25 | // Added ', [Map? optionalArgs]' optional argument to keep analyzer happy 26 | onScreenshot(String screenshotName, List screenshotBytes, [Map? optionalArgs]) async { 27 | final File image = File(screenshotName); 28 | // Write the image as bytes; flush ensures close before dart exit. 29 | image.writeAsBytesSync(screenshotBytes, mode: FileMode.write, flush: true); 30 | if (image.existsSync()) { 31 | return true; 32 | } 33 | // Return false if the screenshot is invalid. 34 | return false; 35 | } 36 | 37 | try { 38 | await integrationDriver( 39 | onScreenshot: onScreenshot, 40 | ); 41 | } catch (e) { 42 | print(' ### Log.Error: Screenshot test driver "integration_test.dart" threw exception $e'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tool/README-tool.org: -------------------------------------------------------------------------------- 1 | This directory, 2 | 3 | flutter_charts/tool 4 | 5 | Should contain private tools such as shell scripts to build something or run tests. 6 | 7 | From https://dart.dev/tools/pub/package-layout#internal-tools-and-scripts : 8 | 9 | Mature packages often have little helper scripts and programs that people run while developing the package itself. Think things like test runners, documentation generators, or other bits of automation. 10 | 11 | Unlike the scripts in bin, these are not for external users of the package. If you have any of these, place them in a directory called tool. 12 | -------------------------------------------------------------------------------- /tool/demo/run_example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Runs, on device or in emulator, the single example chart in examples/main_run_doc_example.dart 4 | 5 | set -o errexit 6 | 7 | if [[ "$1" == "--help" ]]; then 8 | echo Usage: $0 [exampleEnum] 9 | exit 0 10 | fi 11 | 12 | # if [[ -z "$1" ]]; then 13 | # echo Usage: 14 | # echo $0 ex31_barChart_column_nonStacked_newAutoLayouter 15 | # echo NOT: $0 allSupported 16 | # echo NOT: $0 absoluteMinimumNew 17 | # echo 18 | # echo A single argument giving an example to run is missing, defaulting to ex31_barChart_column_nonStacked_newAutoLayouter. 19 | # exampleEnum="ex31_barChart_column_nonStacked_newAutoLayouter" 20 | # else 21 | # exampleEnum="$1" 22 | # fi 23 | 24 | # This script can only run from project top directory. 25 | if [ -z "$(find . -maxdepth 1 -type d -name integration_test)" ]; then 26 | echo Execution directory must be from project top directory. Failed the test for presence of directory integration_test, exiting. 27 | exit 1 28 | fi 29 | 30 | # To quit the running example, type 'q' on the command line. 31 | 32 | # flutter run \ 33 | # --dart-define=EXAMPLES_DESCRIPTORS="$exampleEnum" \ 34 | # example/main_run_doc_example.dart 35 | 36 | flutter run \ 37 | example/main_run_doc_example.dart 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tool/frequent_commands.org: -------------------------------------------------------------------------------- 1 | * A list of frequent commands in this project. 2 | 3 | ** Most commonly used 4 | 5 | # Run unit tests + all screen-comparing integration tests (allSupported = allSupportedNew + allSupportedOld) 6 | tool/test/run_all_tests.sh allSupported 7 | # Run unit tests + auto-layout screen-comparing integration tests 8 | tool/test/run_all_tests.sh allSupportedNew 9 | # Run unit tests + manual-layout screen-comparing integration tests 10 | tool/test/run_all_tests.sh allSupportedOld 11 | # Run unit tests + single screen-comparing integration test 12 | tool/test/run_all_tests.sh ex31_barChart_column_nonStacked_newAutoLayouter 13 | 14 | 15 | # Create screenshot - needs 'flutter drive' and --driver=integration_test.dart 16 | #+begin_src: sh 17 | # emulator required 18 | flutter emulator --launch "Nexus_6_API_35" 19 | 20 | # Run allSupported tests 21 | flutter drive \ 22 | --dart-define=EXAMPLES_DESCRIPTORS="allSupported" \ 23 | --driver=test_driver/integration_test.dart \ 24 | --target=integration_test/screenshot_create_test.dart 25 | #+end_src 26 | 27 | 28 | ** Misc 29 | 30 | # Launch the emulator 31 | flutter emulator --launch "Nexus_6_API_35" 32 | 33 | # Create app template 34 | flutter create --template=app flutter_charts_app 35 | 36 | # pub related 37 | flutter pub get 38 | flutter pub upgrade 39 | flutter clean; flutter pub get; 40 | -------------------------------------------------------------------------------- /tool/generate_chart_plantuml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # dcdg is a package which generates uml 4 | # if installed 'globally', it will add executable to ~~/.pub-cache/bin~ 5 | # this dir should be added to path 6 | # flutter pub global activate dcdg # Installs ~/.pub-cache/bin/dcdg executable 7 | # export PATH="$PATH":"$HOME/.pub-cache/bin" 8 | # cd my_package 9 | flutter pub global run dcdg -o flutter_charts.plantuml # creates a file with plantuml text 10 | java -jar ~/software/java-based/plantuml/plantuml.1.2017.12.jar flutter_charts.plantuml # Generates flutter_charts.png UML 11 | -------------------------------------------------------------------------------- /tool/make_new_chart_type_structure.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Creates a set of directories and empty dart files for a new chart type. 4 | echo Usage: $0 newChartType 5 | 6 | chartType=${1:-UNSET} 7 | 8 | if [[ -z "$chartType" ]]; then 9 | echo Invalid chartType="$chartType", exiting 10 | exit 1 11 | fi 12 | 13 | echo chartType = $chartType 14 | 15 | mkdir {$chartType} 16 | 17 | for file in \ 18 | $chartType/chart.dart \ 19 | $chartType/container.dart \ 20 | $chartType/options.dart \ 21 | $chartType/painter.dart \ 22 | $chartType/presenters.dart 23 | do 24 | echo "" >> $file 25 | done -------------------------------------------------------------------------------- /tool/test/deprecated_v1/deprecated_frequent_commands.org: -------------------------------------------------------------------------------- 1 | * A list of DEPRECATED frequent commands in this project. 2 | 3 | flutter drive \ 4 | --dart-define=EXAMPLE_TO_RUN=ex31SomeNegativeValues \ 5 | --dart-define=CHART_TYPE=lineChart \ 6 | --driver=test_driver/integration_test.dart \ 7 | --target=integration_test/deprecated_v1/screenshot_create_deprecated_v1_test.dart 8 | 9 | # Test screenshot for equality - only needs unit test 'flutter test' (unit = unit OR integration non-drive test) 10 | flutter test \ 11 | --dart-define=EXAMPLE_TO_RUN=ex31SomeNegativeValues \ 12 | --dart-define=CHART_TYPE=barChart \ 13 | test/deprecated_v1/screenshot_validate_deprecated_v1_test.dart 14 | 15 | # No clean: Run mini set of flutter integration tests in bash using: 16 | d1=$(date +%s); tool/test/deprecated_v1/run_representative_mini_tests.sh; echo TOOK $(($(date +%s) - $d1)) seconds 17 | 18 | # No clean: Run mini set of flutter integration tests in eshell using: 19 | setq d1 (string-to-number (format-time-string "%s")); tool/test/deprecated_v1/run_representative_mini_tests.sh ; setq d2 (string-to-number (format-time-string "%s")); echo "TOOK $(- d2 d1) seconds" 20 | 21 | # Bash with clean: Run all tests of all examples: 22 | d1=$(date +%s); flutter clean; flutter pub upgrade; flutter pub get; tool/test/deprecated_v1/run_deprecated_all_tests.sh; echo TOOK $(($(date +%s) - $d1)) seconds 23 | 24 | # Eshell with clean: Run all tests of all examples: 25 | setq d1 (string-to-number (format-time-string "%s")); flutter clean; flutter pub upgrade; flutter pub get; tool/test/deprecated_v1/run_deprecated_all_tests.sh; ; setq d2 (string-to-number (format-time-string "%s")); echo "TOOK $(- d2 d1) seconds" 26 | 27 | # No clean: Run one example test + it's screenshot sameness: 28 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh "firstRun" ex31SomeNegativeValues 29 | # No clean: Run one example test + it's screenshot sameness: 30 | tool/test/deprecated_v1/run_deprecated_all_tests.sh ex31SomeNegativeValues 31 | 32 | # Run all deprecated tests 33 | tool/test/deprecated_v1/run_deprecated_all_tests.sh 34 | 35 | -------------------------------------------------------------------------------- /tool/test/deprecated_v1/deprecated_run_all_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Bash with clean: Run all tests of all examples: 4 | # d1=$(date +%s); flutter clean; flutter pub upgrade; flutter pub get; tool/test/deprecated_v1/deprecated_run_all_tests.sh; echo TOOK $(($(date +%s) - $d1)) seconds 5 | 6 | # Eshell with clean: Run all tests of all examples: 7 | # setq d1 (string-to-number (format-time-string "%s")); flutter clean; flutter pub upgrade; flutter pub get; tool/test/deprecated_v1/deprecated_run_all_tests.sh; ; setq d2 (string-to-number (format-time-string "%s")); echo "TOOK $(- d2 d1) seconds" 8 | 9 | # No clean: Run one example: 10 | # tool/test/deprecated_v1/deprecated_run_all_tests.sh ex31SomeNegativeValues 11 | 12 | set -o errexit 13 | 14 | # Run Dart tests (still as 'flutter test') and Flutter widget tests 'flutter test' 15 | tool/test/run_core_dart_and_flutter_widget_tests.sh 16 | 17 | # Run tests using old layouter 18 | echo 19 | echo ------------------------------------- 20 | echo ------------------------------------- 21 | echo Running screenshot differences tests screenshots validation 22 | echo This runs an integration [drive] screenshot create test first, followed by widget test that compares screenshots actual/expected 23 | echo First argument is $1 24 | 25 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh firstRun ex900ErrorFixUserDataAllZero 26 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun 27 | 28 | # Run tests using the new layouter 29 | tool/test/deprecated_v1/run_deprecated_core_integration_tests.sh 30 | -------------------------------------------------------------------------------- /tool/test/deprecated_v1/deprecated_run_core_integration_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | echo 6 | echo ------------------------------------- 7 | echo ------------------------------------- 8 | echo Running representative MINI screenshot validations 9 | echo Runs an integration [drive] screenshot create test first, followed by widget test that compares screenshots actual/expected 10 | echo firstRun does --pub, nextRun ignores it. 11 | 12 | 13 | echo 14 | echo ------------------------------------- 15 | echo ------------------------------------- 16 | echo Running screenshot actual/expected test for NEW LAYOUT 17 | 18 | # ------------------------------------------ 19 | # ex75 - only positives : barChart 20 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=stacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh firstRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded barChart 21 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded barChart 22 | 23 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=stacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded barChart 24 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded barChart 25 | 26 | # ex75 - only positives : lineChart, only nonStacked 27 | # CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=stacked tool/test/deprecated_v1/deprecated_integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded lineChart 28 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded lineChart 29 | 30 | # CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=stacked tool/test/deprecated_v1/deprecated_integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded lineChart 31 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded lineChart 32 | 33 | # ------------------------------------------ 34 | # ex31 - positives and negatives - barChart 35 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=stacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues barChart 36 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues barChart 37 | 38 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=stacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues barChart 39 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues barChart 40 | 41 | # ex31 - positives and negatives - lineChart, only nonStacked 42 | # CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=stacked tool/test/deprecated_v1/deprecated_integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues lineChart 43 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=column CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues lineChart 44 | 45 | # CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=stacked tool/test/deprecated_v1/deprecated_integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues lineChart 46 | CHART_LAYOUTER=newAutoLayouter CHART_ORIENTATION=row CHART_STACKING=nonStacked tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex31SomeNegativeValues lineChart 47 | 48 | -------------------------------------------------------------------------------- /tool/test/deprecated_v1/deprecated_run_representative_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | # Run Dart tests (still as 'flutter test') and Flutter widget tests 'flutter test' 6 | tool/test/run_core_dart_and_flutter_widget_tests.sh 7 | 8 | # Run mini set of flutter integration tests in bash using: 9 | # d1=$(date +%s); tool/test/deprecated_v1/deprecated_run_representative_tests.sh; echo TOOK $(($(date +%s) - $d1)) seconds 10 | # Run mini set of flutter integration tests in eshell using: 11 | # setq d1 (string-to-number (format-time-string "%s")); tool/test/deprecated_v1/deprecated_run_representative_tests.sh ; setq d2 (string-to-number (format-time-string "%s")); echo "TOOK $(- d2 d1) seconds" 12 | # with clean, add before tool/test/deprecated_v1/run: ; flutter clean; flutter pub upgrade; flutter pub get; 13 | # To run one example: 14 | # tool/test/deprecated_v1/deprecated_run_all_tests.sh ex31SomeNegativeValues 15 | 16 | echo 17 | echo ------------------------------------- 18 | echo ------------------------------------- 19 | echo Running representative screenshot validations 20 | echo Runs an integration [drive] screenshot create test first, followed by widget test that compares screenshots actual/expected 21 | echo firstRun does --pub, nextRun ignores it. 22 | 23 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh firstRun ex900ErrorFixUserDataAllZero 24 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex30AnimalsBySeasonWithLabelLayoutStrategy 25 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex35AnimalsBySeasonNoLabelsShown 26 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex40LanguagesWithYOrdinalUserLabelsAndUserColors 27 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex52AnimalsBySeasonLogarithmicScale 28 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex60LabelsIteration2 # 29 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex60LabelsIteration3 30 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex60LabelsIteration4 31 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex70AnimalsBySeasonLegendIsColumnStartLooseItemIsRowStartLoose 32 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex71AnimalsBySeasonLegendIsColumnStartTightItemIsRowStartTight # 33 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex72AnimalsBySeasonLegendIsRowCenterLooseItemIsRowEndLoose 34 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex73AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTight # 35 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex74AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightSecondGreedy # 36 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex75AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenPadded # 37 | tool/test/deprecated_v1/integration_test_create_then_validate_screenshots.sh nextRun ex76AnimalsBySeasonLegendIsRowStartTightItemIsRowStartTightItemChildrenAligned 38 | 39 | # Run tests using the new layouter 40 | tool/test/deprecated_v1/run_deprecated_core_integration_tests.sh 41 | -------------------------------------------------------------------------------- /tool/test/deprecated_v1/deprecated_start_emulator_and_generate_example_descriptor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generates a program that can be used to run or test all examples 4 | # defined in enum 'ExampleEnum'. 5 | # 6 | # Should be 'sourced', as it results in setting an environment variable which contains a program name, 7 | # which the calling script can run. 8 | # 9 | # In more detail, this script does the following: 10 | # - If Android AVD emulator is not running, starts one. 11 | # - Next, uses the program 12 | # 'dart run lib/src/chart/util/example_descriptor.dart' 13 | # to generate a temp script, which name is placed in the variable named 14 | # 'example_descriptor_generated_program' 15 | # The program $example_descriptor_generated_program 16 | # can be executed from the script sourcing this script, 17 | # to run the or tests all examples declared in ExampleEnum. 18 | 19 | # Input $1: ExampleEnum value, for example ex10RandomData. 20 | # If empty or not set, all examples are included in the generated run. 21 | # Output: variable name 'example_descriptor_generated_program', which contains the name of the 22 | # generated program 23 | 24 | isFirstRun=$1 25 | exampleEnum=$2 26 | chartTypeEnum=$3 27 | chartOrientation=$4 28 | chartStacking=$5 29 | isUseOldLayouter=$6 30 | 31 | # if [[ $isFirstRun == true ]]; then 32 | tool/test/start_emulator.sh 33 | # fi 34 | 35 | # Define the name of the program which the scripts sourcing this file can execute. 36 | example_descriptor_generated_program=test/tmp/example_descriptor_generated_program_$RANDOM.sh 37 | 38 | # Dart run example_descriptor.dart which generates a script with dart_defines. 39 | echo Running \"dart run lib/src/chart/util/example_descriptor.dart \'"$exampleEnum"\' \'"$chartTypeEnum"\' \'"$chartOrientation"\' \'"$chartStacking"\' \'"$isUseOldLayouter"\'\" 40 | echo which creates $example_descriptor_generated_program 41 | 42 | echo "# Sample of how this runs:" > $example_descriptor_generated_program 43 | echo "# flutter drive \ 44 | --dart-define=EXAMPLE_TO_RUN=ex75 \ 45 | --dart-define=CHART_TYPE=barChart \ 46 | --dart-define=CHART_ORIENTATION=row \ 47 | --dart-define=CHART_STACKING=stacked \ 48 | --dart-define=CHART_LAYOUTER=newAutoLayouter \ 49 | --driver=test_driver/integration_test.dart --target=integration_test/deprecated_v1/screenshot_create_deprecated_v1_test.dart" >> $example_descriptor_generated_program 50 | 51 | dart run lib/src/chart/util/example_descriptor.dart \ 52 | "$exampleEnum" \ 53 | "$chartTypeEnum" \ 54 | "$chartOrientation" \ 55 | "$chartStacking" \ 56 | "$isUseOldLayouter" >> $example_descriptor_generated_program 57 | 58 | chmod u+x $example_descriptor_generated_program 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /tool/test/run_all_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Bash with clean: Run all tests of all examples: 4 | # d1=$(date +%s); flutter clean; flutter pub upgrade; flutter pub get; tool/test/run_all_tests.sh absoluteMinimumNew; echo TOOK $(($(date +%s) - $d1)) seconds 5 | 6 | # Eshell with clean: Run all tests of all examples: 7 | # setq d1 (string-to-number (format-time-string "%s")); flutter clean; flutter pub upgrade; flutter pub get; tool/test/run_all_tests.sh absoluteMinimumNew; ; setq d2 (string-to-number (format-time-string "%s")); echo "TOOK $(- d2 d1) seconds" 8 | 9 | # No clean: Run one example: 10 | # tool/test/run_all_tests.sh ex31_barChart_column_stacked_newAutoLayouter ex75_lineChart_row_nonStacked_newAutoLayouter 11 | 12 | # Possible groups: 13 | # minimumNew 14 | # allSupportedNew 15 | # minimumOld 16 | # allSupportedOld 17 | # minimum 18 | # allSupported 19 | 20 | 21 | set -o errexit 22 | 23 | # Run Dart tests (still as 'flutter test') and Flutter widget tests 'flutter test' 24 | tool/test/run_core_dart_and_flutter_widget_tests.sh 25 | 26 | # Run on-device-driven 'flutter drive' integration test 'screenshot_create_test.dart', 27 | # followed by on-computer 'flutter test' unit test 'screenshot_validate_test.dart'. 28 | tool/test/run_screenshots_compare_integration_test.sh "$@" 29 | 30 | 31 | -------------------------------------------------------------------------------- /tool/test/run_core_dart_and_flutter_widget_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Runs all tests except screenshot tests 4 | 5 | set -o errexit 6 | 7 | echo 8 | echo ------------------------------------- 9 | echo ------------------------------------- 10 | echo Running Dart files testing, which is still run with Flutter: flutter test test/util/util_labels_test.dart - etc.. 11 | flutter test test/chart/util/example_descriptor_test.dart 12 | 13 | flutter test test/chart/layouter_one_dimensional_test.dart 14 | 15 | flutter test test/util/vector/vector_test.dart 16 | 17 | flutter test test/util/extensions_dart_test.dart 18 | flutter test test/util/util_dart_test.dart 19 | flutter test test/util/util_flutter_test.dart 20 | flutter test test/util/util_labels_test.dart 21 | flutter test test/util/function_test.dart 22 | 23 | echo 24 | echo ------------------------------------- 25 | echo ------------------------------------- 26 | echo Running Flutter widget tests: flutter test test/widget_test.dart 27 | flutter test test/widget_test.dart 28 | 29 | echo 30 | echo ------------------------------------- 31 | echo ------------------------------------- 32 | echo RERUNNING All Flutter widget tests, showing all names: flutter test --reporter expanded 33 | flutter test --reporter expanded 34 | -------------------------------------------------------------------------------- /tool/test/run_screenshots_compare_integration_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Run test which generates screenshots of all examples named in the passed arguments 4 | # followed by screenshot expected/actual comparison for the same set of examples. 5 | 6 | set -o errexit 7 | 8 | if [[ $# -eq 0 ]]; then 9 | echo 'Specify at least one example or group from the command line, exiting' 10 | exit 1 11 | fi 12 | 13 | examplesDescriptors="$@" 14 | 15 | # Start emulator 16 | tool/test/start_emulator.sh 17 | 18 | flutter drive \ 19 | --dart-define=EXAMPLES_DESCRIPTORS="$examplesDescriptors" \ 20 | --driver=test_driver/integration_test.dart \ 21 | --target=integration_test/screenshot_create_test.dart 22 | 23 | flutter test \ 24 | --dart-define=EXAMPLES_DESCRIPTORS="$examplesDescriptors" \ 25 | test/screenshot_validate_test.dart 26 | -------------------------------------------------------------------------------- /tool/test/start_emulator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # - If Android AVD emulator is not running, starts one. 4 | 5 | # This is the AVD emulator we request to exist 6 | emulator_used="Nexus_6_API_35" 7 | 8 | echo Check if emulator exists 9 | if ! flutter emulators 2>/dev/null | grep --quiet "$emulator_used "; then 10 | echo "Emulator $emulator_used does not exist. Please create it, our integration tests depend on it. Exiting" 11 | exit 1 12 | fi 13 | 14 | echo Check if the emulator named $emulator_used is connected to a running device. 15 | # The only way to find out if the emulator is connected is to run ps, searching for the device name. 16 | # The potential alternative "flutter devices" lists only the short device name such as e3565. 17 | if ! ps -alef | grep "$emulator_used" | grep -v grep ; then 18 | echo No AVD devices running using the emulator $emulator_used. Launching the emulator. 19 | flutter emulators --launch "$emulator_used" 20 | echo Sleep 22 on server to give the emulator time to start fully. Sleep 40 on laptop. 21 | sleep 22 22 | echo The AVD emulator $emulator_used succesfully launched. 23 | else 24 | echo The emulator $emulator_used appears running and connected. 25 | fi 26 | 27 | # Sleep for a bit and check that SOME device is running 28 | sleep 1 29 | if ! flutter devices 2>/dev/null | grep --quiet "emulator-"; then 30 | echo "Unexpected error: flutter devices is telling us that no emulators are connected to a device. Exiting" 31 | exit 1 32 | fi 33 | 34 | echo Checking processes for running emulator name. 35 | device_id=$(flutter devices 2>/dev/null | grep "emulator-" | sed 's/.*\(emulator\-[0-9]\+\).*/\1/') 36 | echo Emulator $emulator_used is running as device_id="$device_id". 37 | --------------------------------------------------------------------------------