--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+ <classpathentry kind="src" path="src"/>\r
+ <classpathentry kind="src" path="gen"/>\r
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
+ <classpathentry kind="output" path="bin/classes"/>\r
+</classpath>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+ <name>achartengine</name>\r
+ <comment></comment>\r
+ <projects>\r
+ </projects>\r
+ <buildSpec>\r
+ <buildCommand>\r
+ <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>org.eclipse.jdt.core.javabuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ <buildCommand>\r
+ <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+ <arguments>\r
+ </arguments>\r
+ </buildCommand>\r
+ </buildSpec>\r
+ <natures>\r
+ <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+ <nature>org.eclipse.jdt.core.javanature</nature>\r
+ </natures>\r
+</projectDescription>\r
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.achartengine.chartdemo.demo"
+ android:versionCode="1"
+ android:versionName="1.0.0">
+
+<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="7"></uses-sdk>
+</manifest>
\ No newline at end of file
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
+android.library=true
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.BarChart;\r
+import org.achartengine.chart.BarChart.Type;\r
+import org.achartengine.chart.BubbleChart;\r
+import org.achartengine.chart.CombinedXYChart;\r
+import org.achartengine.chart.CubicLineChart;\r
+import org.achartengine.chart.DialChart;\r
+import org.achartengine.chart.DoughnutChart;\r
+import org.achartengine.chart.LineChart;\r
+import org.achartengine.chart.PieChart;\r
+import org.achartengine.chart.RangeBarChart;\r
+import org.achartengine.chart.ScatterChart;\r
+import org.achartengine.chart.TimeChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.model.MultipleCategorySeries;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.DialRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.content.Context;\r
+import android.content.Intent;\r
+\r
+/**\r
+ * Utility methods for creating chart views or intents.\r
+ */\r
+public class ChartFactory {\r
+ /** The key for the chart data. */\r
+ public static final String CHART = "chart";\r
+\r
+ /** The key for the chart graphical activity title. */\r
+ public static final String TITLE = "title";\r
+\r
+ private ChartFactory() {\r
+ // empty for now\r
+ }\r
+\r
+ /**\r
+ * Creates a line chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a line chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getLineChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new LineChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a cubic line chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a line chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getCubeLineChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new CubicLineChart(dataset, renderer, smoothness);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a scatter chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a scatter chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getScatterChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new ScatterChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a bubble chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a scatter chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getBubbleChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new BubbleChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a time chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param format the date format pattern to be used for displaying the X axis\r
+ * date labels. If null, a default appropriate format will be used.\r
+ * @return a time chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getTimeChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String format) {\r
+ checkParameters(dataset, renderer);\r
+ TimeChart chart = new TimeChart(dataset, renderer);\r
+ chart.setDateFormat(format);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a bar chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param type the bar chart type\r
+ * @return a bar chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getBarChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new BarChart(dataset, renderer, type);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a range bar chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param type the range bar chart type\r
+ * @return a bar chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final GraphicalView getRangeBarChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+ checkParameters(dataset, renderer);\r
+ XYChart chart = new RangeBarChart(dataset, renderer, type);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a combined XY chart view.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param types the chart types (cannot be null)\r
+ * @return a combined XY chart graphical view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if a dataset number of items is different than the number of\r
+ * series renderers or number of chart types\r
+ */\r
+ public static final GraphicalView getCombinedXYChartView(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types) {\r
+ if (dataset == null || renderer == null || types == null\r
+ || dataset.getSeriesCount() != types.length) {\r
+ throw new IllegalArgumentException(\r
+ "Dataset, renderer and types should be not null and the datasets series count should be equal to the types length");\r
+ }\r
+ checkParameters(dataset, renderer);\r
+ CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a pie chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @return a pie chart view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final GraphicalView getPieChartView(Context context, CategorySeries dataset,\r
+ DefaultRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ PieChart chart = new PieChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a dial chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the dial renderer (cannot be null)\r
+ * @return a pie chart view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final GraphicalView getDialChartView(Context context, CategorySeries dataset,\r
+ DialRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ DialChart chart = new DialChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * Creates a doughnut chart intent that can be used to start the graphical\r
+ * view activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @return a pie chart view\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final GraphicalView getDoughnutChartView(Context context,\r
+ MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+ checkParameters(dataset, renderer);\r
+ DoughnutChart chart = new DoughnutChart(dataset, renderer);\r
+ return new GraphicalView(context, chart);\r
+ }\r
+\r
+ /**\r
+ * \r
+ * Creates a line chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a line chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ return getLineChartIntent(context, dataset, renderer, "");\r
+ }\r
+\r
+ /**\r
+ * \r
+ * Creates a cubic line chart intent that can be used to start the graphical\r
+ * view activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a line chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getCubicLineChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {\r
+ return getCubicLineChartIntent(context, dataset, renderer, smoothness, "");\r
+ }\r
+\r
+ /**\r
+ * Creates a scatter chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a scatter chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getScatterChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ return getScatterChartIntent(context, dataset, renderer, "");\r
+ }\r
+\r
+ /**\r
+ * Creates a bubble chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @return a scatter chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ return getBubbleChartIntent(context, dataset, renderer, "");\r
+ }\r
+\r
+ /**\r
+ * Creates a time chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param format the date format pattern to be used for displaying the X axis\r
+ * date labels. If null, a default appropriate format will be used.\r
+ * @return a time chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, String format) {\r
+ return getTimeChartIntent(context, dataset, renderer, format, "");\r
+ }\r
+\r
+ /**\r
+ * Creates a bar chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param type the bar chart type\r
+ * @return a bar chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, Type type) {\r
+ return getBarChartIntent(context, dataset, renderer, type, "");\r
+ }\r
+\r
+ /**\r
+ * Creates a line chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title. If this is null,\r
+ * then the title bar will be hidden. If a blank title is passed in,\r
+ * then the title bar will be the default. Pass in any other string\r
+ * to set a custom title.\r
+ * @return a line chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ XYChart chart = new LineChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a line chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title. If this is null,\r
+ * then the title bar will be hidden. If a blank title is passed in,\r
+ * then the title bar will be the default. Pass in any other string\r
+ * to set a custom title.\r
+ * @return a line chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getCubicLineChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness,\r
+ String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ XYChart chart = new CubicLineChart(dataset, renderer, smoothness);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a scatter chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a scatter chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getScatterChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ XYChart chart = new ScatterChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a bubble chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a scatter chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ XYChart chart = new BubbleChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a time chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param format the date format pattern to be used for displaying the X axis\r
+ * date labels. If null, a default appropriate format will be used\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a time chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, String format, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ TimeChart chart = new TimeChart(dataset, renderer);\r
+ chart.setDateFormat(format);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a bar chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param type the bar chart type\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a bar chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer, Type type, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ BarChart chart = new BarChart(dataset, renderer, type);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a range bar chart intent that can be used to start the graphical\r
+ * view activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param type the range bar chart type\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a range bar chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ public static final Intent getRangeBarChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type,\r
+ String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ RangeBarChart chart = new RangeBarChart(dataset, renderer, type);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a combined XY chart intent that can be used to start the graphical\r
+ * view activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @param types the chart types (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a combined XY chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if a dataset number of items is different than the number of\r
+ * series renderers or number of chart types\r
+ */\r
+ public static final Intent getCombinedXYChartIntent(Context context,\r
+ XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types,\r
+ String activityTitle) {\r
+ if (dataset == null || renderer == null || types == null\r
+ || dataset.getSeriesCount() != types.length) {\r
+ throw new IllegalArgumentException(\r
+ "Datasets, renderers and types should be not null and the datasets series count should be equal to the types length");\r
+ }\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a pie chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a pie chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final Intent getPieChartIntent(Context context, CategorySeries dataset,\r
+ DefaultRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ PieChart chart = new PieChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a doughnut chart intent that can be used to start the graphical\r
+ * view activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the multiple category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a pie chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final Intent getDoughnutChartIntent(Context context,\r
+ MultipleCategorySeries dataset, DefaultRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ DoughnutChart chart = new DoughnutChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Creates a dial chart intent that can be used to start the graphical view\r
+ * activity.\r
+ * \r
+ * @param context the context\r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the dial renderer (cannot be null)\r
+ * @param activityTitle the graphical chart activity title\r
+ * @return a dial chart intent\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ public static final Intent getDialChartIntent(Context context, CategorySeries dataset,\r
+ DialRenderer renderer, String activityTitle) {\r
+ checkParameters(dataset, renderer);\r
+ Intent intent = new Intent(context, GraphicalActivity.class);\r
+ DialChart chart = new DialChart(dataset, renderer);\r
+ intent.putExtra(CHART, chart);\r
+ intent.putExtra(TITLE, activityTitle);\r
+ return intent;\r
+ }\r
+\r
+ /**\r
+ * Checks the validity of the dataset and renderer parameters.\r
+ * \r
+ * @param dataset the multiple series dataset (cannot be null)\r
+ * @param renderer the multiple series renderer (cannot be null)\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset and the renderer don't include the same number of\r
+ * series\r
+ */\r
+ private static void checkParameters(XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ if (dataset == null || renderer == null\r
+ || dataset.getSeriesCount() != renderer.getSeriesRendererCount()) {\r
+ throw new IllegalArgumentException(\r
+ "Dataset and renderer should be not null and should have the same number of series");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks the validity of the dataset and renderer parameters.\r
+ * \r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ private static void checkParameters(CategorySeries dataset, DefaultRenderer renderer) {\r
+ if (dataset == null || renderer == null\r
+ || dataset.getItemCount() != renderer.getSeriesRendererCount()) {\r
+ throw new IllegalArgumentException(\r
+ "Dataset and renderer should be not null and the dataset number of items should be equal to the number of series renderers");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Checks the validity of the dataset and renderer parameters.\r
+ * \r
+ * @param dataset the category series dataset (cannot be null)\r
+ * @param renderer the series renderer (cannot be null)\r
+ * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+ * if the dataset number of items is different than the number of\r
+ * series renderers\r
+ */\r
+ private static void checkParameters(MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+ if (dataset == null || renderer == null\r
+ || !checkMultipleSeriesItems(dataset, renderer.getSeriesRendererCount())) {\r
+ throw new IllegalArgumentException(\r
+ "Titles and values should be not null and the dataset number of items should be equal to the number of series renderers");\r
+ }\r
+ }\r
+\r
+ private static boolean checkMultipleSeriesItems(MultipleCategorySeries dataset, int value) {\r
+ int count = dataset.getCategoriesCount();\r
+ boolean equal = true;\r
+ for (int k = 0; k < count && equal; k++) {\r
+ equal = dataset.getValues(k).length == dataset.getTitles(k).length;\r
+ }\r
+ return equal;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+\r
+import android.app.Activity;\r
+import android.os.Bundle;\r
+import android.view.Window;\r
+\r
+/**\r
+ * An activity that encapsulates a graphical view of the chart.\r
+ */\r
+public class GraphicalActivity extends Activity {\r
+ /** The encapsulated graphical view. */\r
+ private GraphicalView mView;\r
+ /** The chart to be drawn. */\r
+ private AbstractChart mChart;\r
+\r
+ @Override\r
+ protected void onCreate(Bundle savedInstanceState) {\r
+ super.onCreate(savedInstanceState);\r
+ Bundle extras = getIntent().getExtras();\r
+ mChart = (AbstractChart) extras.getSerializable(ChartFactory.CHART);\r
+ mView = new GraphicalView(this, mChart);\r
+ String title = extras.getString(ChartFactory.TITLE);\r
+ if (title == null) {\r
+ requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+ } else if (title.length() > 0) {\r
+ setTitle(title);\r
+ }\r
+ setContentView(mView);\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.tools.FitZoom;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.Zoom;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.content.Context;\r
+import android.graphics.Bitmap;\r
+import android.graphics.BitmapFactory;\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+import android.os.Build;\r
+import android.os.Handler;\r
+import android.view.MotionEvent;\r
+import android.view.View;\r
+\r
+/**\r
+ * The view that encapsulates the graphical chart.\r
+ */\r
+public class GraphicalView extends View {\r
+ /** The chart to be drawn. */\r
+ private AbstractChart mChart;\r
+ /** The chart renderer. */\r
+ private DefaultRenderer mRenderer;\r
+ /** The view bounds. */\r
+ private Rect mRect = new Rect();\r
+ /** The user interface thread handler. */\r
+ private Handler mHandler;\r
+ /** The zoom buttons rectangle. */\r
+ private RectF mZoomR = new RectF();\r
+ /** The zoom in icon. */\r
+ private Bitmap zoomInImage;\r
+ /** The zoom out icon. */\r
+ private Bitmap zoomOutImage;\r
+ /** The fit zoom icon. */\r
+ private Bitmap fitZoomImage;\r
+ /** The zoom area size. */\r
+ private int zoomSize = 50;\r
+ /** The zoom buttons background color. */\r
+ private static final int ZOOM_BUTTONS_COLOR = Color.argb(175, 150, 150, 150);\r
+ /** The zoom in tool. */\r
+ private Zoom mZoomIn;\r
+ /** The zoom out tool. */\r
+ private Zoom mZoomOut;\r
+ /** The fit zoom tool. */\r
+ private FitZoom mFitZoom;\r
+ /** The paint to be used when drawing the chart. */\r
+ private Paint mPaint = new Paint();\r
+ /** The touch handler. */\r
+ private ITouchHandler mTouchHandler;\r
+ /** The old x coordinate. */\r
+ private float oldX;\r
+ /** The old y coordinate. */\r
+ private float oldY;\r
+\r
+ /**\r
+ * Creates a new graphical view.\r
+ * \r
+ * @param context the context\r
+ * @param chart the chart to be drawn\r
+ */\r
+ public GraphicalView(Context context, AbstractChart chart) {\r
+ super(context);\r
+ mChart = chart;\r
+ mHandler = new Handler();\r
+ if (mChart instanceof XYChart) {\r
+ mRenderer = ((XYChart) mChart).getRenderer();\r
+ } else {\r
+ mRenderer = ((RoundChart) mChart).getRenderer();\r
+ }\r
+ if (mRenderer.isZoomButtonsVisible()) {\r
+ zoomInImage = BitmapFactory.decodeStream(GraphicalView.class\r
+ .getResourceAsStream("image/zoom_in.png"));\r
+ zoomOutImage = BitmapFactory.decodeStream(GraphicalView.class\r
+ .getResourceAsStream("image/zoom_out.png"));\r
+ fitZoomImage = BitmapFactory.decodeStream(GraphicalView.class\r
+ .getResourceAsStream("image/zoom-1.png"));\r
+ }\r
+\r
+ if (mRenderer instanceof XYMultipleSeriesRenderer\r
+ && ((XYMultipleSeriesRenderer) mRenderer).getMarginsColor() == XYMultipleSeriesRenderer.NO_COLOR) {\r
+ ((XYMultipleSeriesRenderer) mRenderer).setMarginsColor(mPaint.getColor());\r
+ }\r
+ if (mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()\r
+ || mRenderer.isExternalZoomEnabled()) {\r
+ mZoomIn = new Zoom(mChart, true, mRenderer.getZoomRate());\r
+ mZoomOut = new Zoom(mChart, false, mRenderer.getZoomRate());\r
+ mFitZoom = new FitZoom(mChart);\r
+ }\r
+ int version = 7;\r
+ try {\r
+ version = Integer.valueOf(Build.VERSION.SDK);\r
+ } catch (Exception e) {\r
+ // do nothing\r
+ }\r
+ if (version < 7) {\r
+ mTouchHandler = new TouchHandlerOld(this, mChart);\r
+ } else {\r
+ mTouchHandler = new TouchHandler(this, mChart);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the current series selection object.\r
+ * \r
+ * @return the series selection\r
+ */\r
+ public SeriesSelection getCurrentSeriesAndPoint() {\r
+ return mChart.getSeriesAndPointForScreenCoordinate(new Point(oldX, oldY));\r
+ }\r
+\r
+ /**\r
+ * Transforms the currently selected screen point to a real point.\r
+ * \r
+ * @param scale the scale\r
+ * @return the currently selected real point\r
+ */\r
+ public double[] toRealPoint(int scale) {\r
+ if (mChart instanceof XYChart) {\r
+ XYChart chart = (XYChart) mChart;\r
+ return chart.toRealPoint(oldX, oldY, scale);\r
+ }\r
+ return null;\r
+ }\r
+\r
+ @Override\r
+ protected void onDraw(Canvas canvas) {\r
+ super.onDraw(canvas);\r
+ canvas.getClipBounds(mRect);\r
+ int top = mRect.top;\r
+ int left = mRect.left;\r
+ int width = mRect.width();\r
+ int height = mRect.height();\r
+ if (mRenderer.isInScroll()) {\r
+ top = 0;\r
+ left = 0;\r
+ width = getMeasuredWidth();\r
+ height = getMeasuredHeight();\r
+ }\r
+ mChart.draw(canvas, left, top, width, height, mPaint);\r
+ if (mRenderer != null && mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()) {\r
+ mPaint.setColor(ZOOM_BUTTONS_COLOR);\r
+ zoomSize = Math.max(zoomSize, Math.min(width, height) / 7);\r
+ mZoomR.set(left + width - zoomSize * 3, top + height - zoomSize * 0.775f, left + width, top\r
+ + height);\r
+ canvas.drawRoundRect(mZoomR, zoomSize / 3, zoomSize / 3, mPaint);\r
+ float buttonY = top + height - zoomSize * 0.625f;\r
+ canvas.drawBitmap(zoomInImage, left + width - zoomSize * 2.75f, buttonY, null);\r
+ canvas.drawBitmap(zoomOutImage, left + width - zoomSize * 1.75f, buttonY, null);\r
+ canvas.drawBitmap(fitZoomImage, left + width - zoomSize * 0.75f, buttonY, null);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the zoom rate.\r
+ * \r
+ * @param rate the zoom rate\r
+ */\r
+ public void setZoomRate(float rate) {\r
+ if (mZoomIn != null && mZoomOut != null) {\r
+ mZoomIn.setZoomRate(rate);\r
+ mZoomOut.setZoomRate(rate);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Do a chart zoom in.\r
+ */\r
+ public void zoomIn() {\r
+ if (mZoomIn != null) {\r
+ mZoomIn.apply(Zoom.ZOOM_AXIS_XY);\r
+ repaint();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Do a chart zoom out.\r
+ */\r
+ public void zoomOut() {\r
+ if (mZoomOut != null) {\r
+ mZoomOut.apply(Zoom.ZOOM_AXIS_XY);\r
+ repaint();\r
+ }\r
+ }\r
+ \r
+\r
+\r
+ /**\r
+ * Do a chart zoom reset / fit zoom.\r
+ */\r
+ public void zoomReset() {\r
+ if (mFitZoom != null) {\r
+ mFitZoom.apply();\r
+ mZoomIn.notifyZoomResetListeners();\r
+ repaint();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a new zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public void addZoomListener(ZoomListener listener, boolean onButtons, boolean onPinch) {\r
+ if (onButtons) {\r
+ if (mZoomIn != null) {\r
+ mZoomIn.addZoomListener(listener);\r
+ mZoomOut.addZoomListener(listener);\r
+ }\r
+ if (onPinch) {\r
+ mTouchHandler.addZoomListener(listener);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes a zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public synchronized void removeZoomListener(ZoomListener listener) {\r
+ if (mZoomIn != null) {\r
+ mZoomIn.removeZoomListener(listener);\r
+ mZoomOut.removeZoomListener(listener);\r
+ }\r
+ mTouchHandler.removeZoomListener(listener);\r
+ }\r
+\r
+ /**\r
+ * Adds a new pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void addPanListener(PanListener listener) {\r
+ mTouchHandler.addPanListener(listener);\r
+ }\r
+\r
+ /**\r
+ * Removes a pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void removePanListener(PanListener listener) {\r
+ mTouchHandler.removePanListener(listener);\r
+ }\r
+\r
+ protected RectF getZoomRectangle() {\r
+ return mZoomR;\r
+ }\r
+\r
+ @Override\r
+ public boolean onTouchEvent(MotionEvent event) {\r
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
+ // save the x and y so they can be used in the click and long press\r
+ // listeners\r
+ oldX = event.getX();\r
+ oldY = event.getY();\r
+ }\r
+ if (mRenderer != null && (mRenderer.isPanEnabled() || mRenderer.isZoomEnabled())) {\r
+ if (mTouchHandler.handleTouch(event)) {\r
+ return true;\r
+ }\r
+ }\r
+ return super.onTouchEvent(event);\r
+ }\r
+\r
+ /**\r
+ * Schedule a view content repaint.\r
+ */\r
+ public void repaint() {\r
+ mHandler.post(new Runnable() {\r
+ public void run() {\r
+ invalidate();\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * Schedule a view content repaint, in the specified rectangle area.\r
+ * \r
+ * @param left the left position of the area to be repainted\r
+ * @param top the top position of the area to be repainted\r
+ * @param right the right position of the area to be repainted\r
+ * @param bottom the bottom position of the area to be repainted\r
+ */\r
+ public void repaint(final int left, final int top, final int right, final int bottom) {\r
+ mHandler.post(new Runnable() {\r
+ public void run() {\r
+ invalidate(left, top, right, bottom);\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * Saves the content of the graphical view to a bitmap.\r
+ * \r
+ * @return the bitmap\r
+ */\r
+ public Bitmap toBitmap() {\r
+ setDrawingCacheEnabled(false);\r
+ if (!isDrawingCacheEnabled()) {\r
+ setDrawingCacheEnabled(true);\r
+ }\r
+ if (mRenderer.isApplyBackgroundColor()) {\r
+ setDrawingCacheBackgroundColor(mRenderer.getBackgroundColor());\r
+ }\r
+ setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);\r
+ return getDrawingCache(true);\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * The interface to be implemented by the touch handlers.\r
+ */\r
+public interface ITouchHandler {\r
+ /**\r
+ * Handles the touch event.\r
+ * \r
+ * @param event the touch event\r
+ * @return true if the event was handled\r
+ */\r
+ boolean handleTouch(MotionEvent event);\r
+ \r
+ /**\r
+ * Adds a new zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ void addZoomListener(ZoomListener listener);\r
+\r
+ /**\r
+ * Removes a zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ void removeZoomListener(ZoomListener listener);\r
+ \r
+ /**\r
+ * Adds a new pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ void addPanListener(PanListener listener);\r
+\r
+ /**\r
+ * Removes a pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ void removePanListener(PanListener listener);\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.tools.Pan;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.Zoom;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.graphics.RectF;\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * The main handler of the touch events.\r
+ */\r
+public class TouchHandler implements ITouchHandler {\r
+ /** The chart renderer. */\r
+ private DefaultRenderer mRenderer;\r
+ /** The old x coordinate. */\r
+ private float oldX;\r
+ /** The old y coordinate. */\r
+ private float oldY;\r
+ /** The old x2 coordinate. */\r
+ private float oldX2;\r
+ /** The old y2 coordinate. */\r
+ private float oldY2;\r
+ /** The zoom buttons rectangle. */\r
+ private RectF zoomR = new RectF();\r
+ /** The pan tool. */\r
+ private Pan mPan;\r
+ /** The zoom for the pinch gesture. */\r
+ private Zoom mPinchZoom;\r
+ /** The graphical view. */\r
+ private GraphicalView graphicalView;\r
+\r
+ /**\r
+ * Creates a new graphical view.\r
+ * \r
+ * @param view the graphical view\r
+ * @param chart the chart to be drawn\r
+ */\r
+ public TouchHandler(GraphicalView view, AbstractChart chart) {\r
+ graphicalView = view;\r
+ zoomR = graphicalView.getZoomRectangle();\r
+ if (chart instanceof XYChart) {\r
+ mRenderer = ((XYChart) chart).getRenderer();\r
+ } else {\r
+ mRenderer = ((RoundChart) chart).getRenderer();\r
+ }\r
+ if (mRenderer.isPanEnabled()) {\r
+ mPan = new Pan(chart);\r
+ }\r
+ if (mRenderer.isZoomEnabled()) {\r
+ mPinchZoom = new Zoom(chart, true, 1);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Handles the touch event.\r
+ * \r
+ * @param event the touch event\r
+ */\r
+ public boolean handleTouch(MotionEvent event) {\r
+ int action = event.getAction();\r
+ if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {\r
+ if (oldX >= 0 || oldY >= 0) {\r
+ float newX = event.getX(0);\r
+ float newY = event.getY(0);\r
+ if (event.getPointerCount() > 1 && (oldX2 >= 0 || oldY2 >= 0) && mRenderer.isZoomEnabled()) {\r
+ float newX2 = event.getX(1);\r
+ float newY2 = event.getY(1);\r
+ float newDeltaX = Math.abs(newX - newX2);\r
+ float newDeltaY = Math.abs(newY - newY2);\r
+ float oldDeltaX = Math.abs(oldX - oldX2);\r
+ float oldDeltaY = Math.abs(oldY - oldY2);\r
+ float zoomRate = 1;\r
+\r
+ float tan1 = Math.abs(newY - oldY) / Math.abs(newX - oldX);\r
+ float tan2 = Math.abs(newY2 - oldY2) / Math.abs(newX2 - oldX2);\r
+ if ( tan1 <= 0.577 && tan2 <= 0.577) {\r
+ // horizontal pinch zoom, |deltaY| / |deltaX| is [0 ~ 0.577], 0.577 is the approximate value of tan(Pi/6)\r
+ zoomRate = newDeltaX / oldDeltaX;\r
+ if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+ mPinchZoom.setZoomRate(zoomRate);\r
+ mPinchZoom.apply(Zoom.ZOOM_AXIS_X);\r
+ }\r
+ } else if ( tan1 >= 1.732 && tan2 >= 1.732 ) {\r
+ // pinch zoom vertically, |deltaY| / |deltaX| is [1.732 ~ infinity], 1.732 is the approximate value of tan(Pi/3)\r
+ zoomRate = newDeltaY / oldDeltaY;\r
+ if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+ mPinchZoom.setZoomRate(zoomRate);\r
+ mPinchZoom.apply(Zoom.ZOOM_AXIS_Y);\r
+ }\r
+ } else if ( (tan1 > 0.577 && tan1 < 1.732) && (tan2 > 0.577 && tan2 < 1.732) ){\r
+ // pinch zoom diagonally\r
+ if (Math.abs(newX - oldX) >= Math.abs(newY - oldY)) {\r
+ zoomRate = newDeltaX / oldDeltaX;\r
+ } else {\r
+ zoomRate = newDeltaY / oldDeltaY;\r
+ }\r
+ if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+ mPinchZoom.setZoomRate(zoomRate);\r
+ mPinchZoom.apply(Zoom.ZOOM_AXIS_XY);\r
+ }\r
+ }\r
+ oldX2 = newX2;\r
+ oldY2 = newY2;\r
+ } else if (mRenderer.isPanEnabled()) {\r
+ mPan.apply(oldX, oldY, newX, newY);\r
+ oldX2 = 0;\r
+ oldY2 = 0;\r
+ }\r
+ oldX = newX;\r
+ oldY = newY;\r
+ graphicalView.repaint();\r
+ return true;\r
+ }\r
+ } else if (action == MotionEvent.ACTION_DOWN) {\r
+ oldX = event.getX(0);\r
+ oldY = event.getY(0);\r
+ if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {\r
+ if (oldX < zoomR.left + zoomR.width() / 3) {\r
+ graphicalView.zoomIn();\r
+ } else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {\r
+ graphicalView.zoomOut();\r
+ } else {\r
+ graphicalView.zoomReset();\r
+ }\r
+ return true;\r
+ }\r
+ } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {\r
+ oldX = 0;\r
+ oldY = 0;\r
+ oldX2 = 0;\r
+ oldY2 = 0;\r
+ if (action == MotionEvent.ACTION_POINTER_UP) {\r
+ oldX = -1;\r
+ oldY = -1;\r
+ }\r
+ }\r
+ return !mRenderer.isClickEnabled();\r
+ }\r
+\r
+ /**\r
+ * Adds a new zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public void addZoomListener(ZoomListener listener) {\r
+ if (mPinchZoom != null) {\r
+ mPinchZoom.addZoomListener(listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes a zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public void removeZoomListener(ZoomListener listener) {\r
+ if (mPinchZoom != null) {\r
+ mPinchZoom.removeZoomListener(listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a new pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void addPanListener(PanListener listener) {\r
+ if (mPan != null) {\r
+ mPan.addPanListener(listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes a pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void removePanListener(PanListener listener) {\r
+ if (mPan != null) {\r
+ mPan.removePanListener(listener);\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.tools.Pan;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.graphics.RectF;\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * A handler implementation for touch events for older platforms.\r
+ */\r
+public class TouchHandlerOld implements ITouchHandler {\r
+ /** The chart renderer. */\r
+ private DefaultRenderer mRenderer;\r
+ /** The old x coordinate. */\r
+ private float oldX;\r
+ /** The old y coordinate. */\r
+ private float oldY;\r
+ /** The zoom buttons rectangle. */\r
+ private RectF zoomR = new RectF();\r
+ /** The pan tool. */\r
+ private Pan mPan;\r
+ /** The graphical view. */\r
+ private GraphicalView graphicalView;\r
+\r
+ /**\r
+ * Creates an implementation of the old version of the touch handler.\r
+ * \r
+ * @param view the graphical view\r
+ * @param chart the chart to be drawn\r
+ */\r
+ public TouchHandlerOld(GraphicalView view, AbstractChart chart) {\r
+ graphicalView = view;\r
+ zoomR = graphicalView.getZoomRectangle();\r
+ if (chart instanceof XYChart) {\r
+ mRenderer = ((XYChart) chart).getRenderer();\r
+ } else {\r
+ mRenderer = ((RoundChart) chart).getRenderer();\r
+ }\r
+ if (mRenderer.isPanEnabled()) {\r
+ mPan = new Pan(chart);\r
+ }\r
+ }\r
+\r
+ public boolean handleTouch(MotionEvent event) {\r
+ int action = event.getAction();\r
+ if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {\r
+ if (oldX >= 0 || oldY >= 0) {\r
+ float newX = event.getX();\r
+ float newY = event.getY();\r
+ if (mRenderer.isPanEnabled()) {\r
+ mPan.apply(oldX, oldY, newX, newY);\r
+ }\r
+ oldX = newX;\r
+ oldY = newY;\r
+ graphicalView.repaint();\r
+ return true;\r
+ }\r
+ } else if (action == MotionEvent.ACTION_DOWN) {\r
+ oldX = event.getX();\r
+ oldY = event.getY();\r
+ if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {\r
+ if (oldX < zoomR.left + zoomR.width() / 3) {\r
+ graphicalView.zoomIn();\r
+ } else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {\r
+ graphicalView.zoomOut();\r
+ } else {\r
+ graphicalView.zoomReset();\r
+ }\r
+ return true;\r
+ }\r
+ } else if (action == MotionEvent.ACTION_UP) {\r
+ oldX = 0;\r
+ oldY = 0;\r
+ }\r
+ return !mRenderer.isClickEnabled();\r
+ }\r
+\r
+ /**\r
+ * Adds a new zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public void addZoomListener(ZoomListener listener) {\r
+ }\r
+\r
+ /**\r
+ * Removes a zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public void removeZoomListener(ZoomListener listener) {\r
+ }\r
+\r
+ /**\r
+ * Adds a new pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void addPanListener(PanListener listener) {\r
+ if (mPan != null) {\r
+ mPan.addPanListener(listener);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes a pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public void removePanListener(PanListener listener) {\r
+ if (mPan != null) {\r
+ mPan.removePanListener(listener);\r
+ }\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.io.Serializable;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.Path;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * An abstract class to be implemented by the chart rendering classes.\r
+ */\r
+public abstract class AbstractChart implements Serializable {\r
+ /**\r
+ * The graphical representation of the chart.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param height the height of the view to draw to\r
+ * @param paint the paint\r
+ */\r
+ public abstract void draw(Canvas canvas, int x, int y, int width, int height, Paint paint);\r
+\r
+ /**\r
+ * Draws the chart background.\r
+ * \r
+ * @param renderer the chart renderer\r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param height the height of the view to draw to\r
+ * @param paint the paint used for drawing\r
+ * @param newColor if a new color is to be used\r
+ * @param color the color to be used\r
+ */\r
+ protected void drawBackground(DefaultRenderer renderer, Canvas canvas, int x, int y, int width,\r
+ int height, Paint paint, boolean newColor, int color) {\r
+ if (renderer.isApplyBackgroundColor() || newColor) {\r
+ if (newColor) {\r
+ paint.setColor(color);\r
+ } else {\r
+ paint.setColor(renderer.getBackgroundColor());\r
+ }\r
+ paint.setStyle(Style.FILL);\r
+ canvas.drawRect(x, y, x + width, y + height, paint);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Draws the chart legend.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param titles the titles to go to the legend\r
+ * @param left the left X value of the area to draw to\r
+ * @param right the right X value of the area to draw to\r
+ * @param y the y value of the area to draw to\r
+ * @param width the width of the area to draw to\r
+ * @param height the height of the area to draw to\r
+ * @param legendSize the legend size\r
+ * @param paint the paint to be used for drawing\r
+ * @param calculate if only calculating the legend size\r
+ * \r
+ * @return the legend height\r
+ */\r
+ protected int drawLegend(Canvas canvas, DefaultRenderer renderer, String[] titles, int left,\r
+ int right, int y, int width, int height, int legendSize, Paint paint, boolean calculate) {\r
+ float size = 32;\r
+ if (renderer.isShowLegend()) {\r
+ float currentX = left;\r
+ float currentY = y + height - legendSize + size;\r
+ paint.setTextAlign(Align.LEFT);\r
+ paint.setTextSize(renderer.getLegendTextSize());\r
+ int sLength = Math.min(titles.length, renderer.getSeriesRendererCount());\r
+ for (int i = 0; i < sLength; i++) {\r
+ final float lineSize = getLegendShapeWidth(i);\r
+ String text = titles[i];\r
+ if (titles.length == renderer.getSeriesRendererCount()) {\r
+ paint.setColor(renderer.getSeriesRendererAt(i).getColor());\r
+ } else {\r
+ paint.setColor(Color.LTGRAY);\r
+ }\r
+ float[] widths = new float[text.length()];\r
+ paint.getTextWidths(text, widths);\r
+ float sum = 0;\r
+ for (float value : widths) {\r
+ sum += value;\r
+ }\r
+ float extraSize = lineSize + 10 + sum;\r
+ float currentWidth = currentX + extraSize;\r
+\r
+ if (i > 0 && getExceed(currentWidth, renderer, right, width)) {\r
+ currentX = left;\r
+ currentY += renderer.getLegendTextSize();\r
+ size += renderer.getLegendTextSize();\r
+ currentWidth = currentX + extraSize;\r
+ }\r
+ if (getExceed(currentWidth, renderer, right, width)) {\r
+ float maxWidth = right - currentX - lineSize - 10;\r
+ if (isVertical(renderer)) {\r
+ maxWidth = width - currentX - lineSize - 10;\r
+ }\r
+ int nr = paint.breakText(text, true, maxWidth, widths);\r
+ text = text.substring(0, nr) + "...";\r
+ }\r
+ if (!calculate) {\r
+ drawLegendShape(canvas, renderer.getSeriesRendererAt(i), currentX, currentY, i, paint);\r
+ drawString(canvas, text, currentX + lineSize + 5, currentY + 5, paint);\r
+ }\r
+ currentX += extraSize;\r
+ }\r
+ }\r
+ return Math.round(size + renderer.getLegendTextSize());\r
+ }\r
+\r
+ /**\r
+ * Draw a multiple lines string.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param text the text to be painted\r
+ * @param x the x value of the area to draw to\r
+ * @param y the y value of the area to draw to\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ protected void drawString(Canvas canvas, String text, float x, float y, Paint paint) {\r
+ String[] lines = text.split("\n");\r
+ Rect rect = new Rect();\r
+ int yOff = 0;\r
+ for (int i = 0; i < lines.length; ++i) {\r
+ canvas.drawText(lines[i], x, y + yOff, paint);\r
+ paint.getTextBounds(lines[i], 0, lines[i].length(), rect);\r
+ yOff = yOff + rect.height() + 5; // space between lines is 5\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Calculates if the current width exceeds the total width.\r
+ * \r
+ * @param currentWidth the current width\r
+ * @param renderer the renderer\r
+ * @param right the right side pixel value\r
+ * @param width the total width\r
+ * @return if the current width exceeds the total width\r
+ */\r
+ protected boolean getExceed(float currentWidth, DefaultRenderer renderer, int right, int width) {\r
+ boolean exceed = currentWidth > right;\r
+ if (isVertical(renderer)) {\r
+ exceed = currentWidth > width;\r
+ }\r
+ return exceed;\r
+ }\r
+\r
+ /**\r
+ * Checks if the current chart is rendered as vertical.\r
+ * \r
+ * @param renderer the renderer\r
+ * @return if the chart is rendered as a vertical one\r
+ */\r
+ public boolean isVertical(DefaultRenderer renderer) {\r
+ return renderer instanceof XYMultipleSeriesRenderer\r
+ && ((XYMultipleSeriesRenderer) renderer).getOrientation() == Orientation.VERTICAL;\r
+ }\r
+ \r
+ /**\r
+ * Makes sure the fraction digit is not displayed, if not needed.\r
+ * \r
+ * @param label the input label value\r
+ * @return the label without the useless fraction digit\r
+ */\r
+ protected String getLabel(double label) {\r
+ String text = "";\r
+ if (label == Math.round(label)) {\r
+ text = Math.round(label) + "";\r
+ } else {\r
+ text = label + "";\r
+ }\r
+ return text;\r
+ }\r
+\r
+ private static float[] calculateDrawPoints(float p1x, float p1y, float p2x, float p2y,\r
+ int screenHeight, int screenWidth) {\r
+ float drawP1x;\r
+ float drawP1y;\r
+ float drawP2x;\r
+ float drawP2y;\r
+\r
+ if (p1y > screenHeight) {\r
+ // Intersection with the top of the screen\r
+ float m = (p2y - p1y) / (p2x - p1x);\r
+ drawP1x = (screenHeight - p1y + m * p1x) / m;\r
+ drawP1y = screenHeight;\r
+\r
+ if (drawP1x < 0) {\r
+ // If Intersection is left of the screen we calculate the intersection\r
+ // with the left border\r
+ drawP1x = 0;\r
+ drawP1y = p1y - m * p1x;\r
+ } else if (drawP1x > screenWidth) {\r
+ // If Intersection is right of the screen we calculate the intersection\r
+ // with the right border\r
+ drawP1x = screenWidth;\r
+ drawP1y = m * screenWidth + p1y - m * p1x;\r
+ }\r
+ } else if (p1y < 0) {\r
+ float m = (p2y - p1y) / (p2x - p1x);\r
+ drawP1x = (-p1y + m * p1x) / m;\r
+ drawP1y = 0;\r
+ if (drawP1x < 0) {\r
+ drawP1x = 0;\r
+ drawP1y = p1y - m * p1x;\r
+ } else if (drawP1x > screenWidth) {\r
+ drawP1x = screenWidth;\r
+ drawP1y = m * screenWidth + p1y - m * p1x;\r
+ }\r
+ } else {\r
+ // If the point is in the screen use it\r
+ drawP1x = p1x;\r
+ drawP1y = p1y;\r
+ }\r
+\r
+ if (p2y > screenHeight) {\r
+ float m = (p2y - p1y) / (p2x - p1x);\r
+ drawP2x = (screenHeight - p1y + m * p1x) / m;\r
+ drawP2y = screenHeight;\r
+ if (drawP2x < 0) {\r
+ drawP2x = 0;\r
+ drawP2y = p1y - m * p1x;\r
+ } else if (drawP2x > screenWidth) {\r
+ drawP2x = screenWidth;\r
+ drawP2y = m * screenWidth + p1y - m * p1x;\r
+ }\r
+ } else if (p2y < 0) {\r
+ float m = (p2y - p1y) / (p2x - p1x);\r
+ drawP2x = (-p1y + m * p1x) / m;\r
+ drawP2y = 0;\r
+ if (drawP2x < 0) {\r
+ drawP2x = 0;\r
+ drawP2y = p1y - m * p1x;\r
+ } else if (drawP2x > screenWidth) {\r
+ drawP2x = screenWidth;\r
+ drawP2y = m * screenWidth + p1y - m * p1x;\r
+ }\r
+ } else {\r
+ // If the point is in the screen use it\r
+ drawP2x = p2x;\r
+ drawP2y = p2y;\r
+ }\r
+\r
+ return new float[] { drawP1x, drawP1y, drawP2x, drawP2y };\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a path.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param points the points that are contained in the path to paint\r
+ * @param paint the paint to be used for painting\r
+ * @param circular if the path ends with the start point\r
+ */\r
+ protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {\r
+ Path path = new Path();\r
+ int height = canvas.getHeight();\r
+ int width = canvas.getWidth();\r
+\r
+ float[] tempDrawPoints;\r
+ if (points.length < 4) {\r
+ return;\r
+ }\r
+ tempDrawPoints = calculateDrawPoints(points[0], points[1], points[2], points[3], height, width);\r
+ path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);\r
+ path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);\r
+\r
+ for (int i = 4; i < points.length; i += 2) {\r
+ if ((points[i - 1] < 0 && points[i + 1] < 0)\r
+ || (points[i - 1] > height && points[i + 1] > height)) {\r
+ continue;\r
+ }\r
+ tempDrawPoints = calculateDrawPoints(points[i - 2], points[i - 1], points[i], points[i + 1],\r
+ height, width);\r
+ if (!circular) {\r
+ path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);\r
+ }\r
+ path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);\r
+ }\r
+ if (circular) {\r
+ path.lineTo(points[0], points[1]);\r
+ }\r
+ canvas.drawPath(path, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public abstract int getLegendShapeWidth(int seriesIndex);\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public abstract void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x,\r
+ float y, int seriesIndex, Paint paint);\r
+\r
+ /**\r
+ * Calculates the best text to fit into the available space.\r
+ * \r
+ * @param text the entire text\r
+ * @param width the width to fit the text into\r
+ * @param paint the paint\r
+ * @return the text to fit into the space\r
+ */\r
+ private String getFitText(String text, float width, Paint paint) {\r
+ String newText = text;\r
+ int length = text.length();\r
+ int diff = 0;\r
+ while (paint.measureText(newText) > width && diff < length) {\r
+ diff++;\r
+ newText = text.substring(0, length - diff) + "...";\r
+ }\r
+ if (diff == length) {\r
+ newText = "...";\r
+ }\r
+ return newText;\r
+ }\r
+\r
+ /**\r
+ * Calculates the current legend size.\r
+ * \r
+ * @param renderer the renderer\r
+ * @param defaultHeight the default height\r
+ * @param extraHeight the added extra height\r
+ * @return the legend size\r
+ */\r
+ protected int getLegendSize(DefaultRenderer renderer, int defaultHeight, float extraHeight) {\r
+ int legendSize = renderer.getLegendHeight();\r
+ if (renderer.isShowLegend() && legendSize == 0) {\r
+ legendSize = defaultHeight;\r
+ }\r
+ if (!renderer.isShowLegend() && renderer.isShowLabels()) {\r
+ legendSize = (int) (renderer.getLabelsTextSize() * 4 / 3 + extraHeight);\r
+ }\r
+ return legendSize;\r
+ }\r
+\r
+ /**\r
+ * Draws a text label.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param labelText the label text\r
+ * @param renderer the renderer\r
+ * @param prevLabelsBounds the previous rendered label bounds\r
+ * @param centerX the round chart center on X axis\r
+ * @param centerY the round chart center on Y axis\r
+ * @param shortRadius the short radius for the round chart\r
+ * @param longRadius the long radius for the round chart\r
+ * @param currentAngle the current angle\r
+ * @param angle the label extra angle\r
+ * @param left the left side\r
+ * @param right the right side\r
+ * @param color the label color\r
+ * @param paint the paint\r
+ * @param line if a line to the label should be drawn\r
+ */\r
+ protected void drawLabel(Canvas canvas, String labelText, DefaultRenderer renderer,\r
+ List<RectF> prevLabelsBounds, int centerX, int centerY, float shortRadius, float longRadius,\r
+ float currentAngle, float angle, int left, int right, int color, Paint paint, boolean line) {\r
+ if (renderer.isShowLabels()) {\r
+ paint.setColor(color);\r
+ double rAngle = Math.toRadians(90 - (currentAngle + angle / 2));\r
+ double sinValue = Math.sin(rAngle);\r
+ double cosValue = Math.cos(rAngle);\r
+ int x1 = Math.round(centerX + (float) (shortRadius * sinValue));\r
+ int y1 = Math.round(centerY + (float) (shortRadius * cosValue));\r
+ int x2 = Math.round(centerX + (float) (longRadius * sinValue));\r
+ int y2 = Math.round(centerY + (float) (longRadius * cosValue));\r
+\r
+ float size = renderer.getLabelsTextSize();\r
+ float extra = Math.max(size / 2, 10);\r
+ paint.setTextAlign(Align.LEFT);\r
+ if (x1 > x2) {\r
+ extra = -extra;\r
+ paint.setTextAlign(Align.RIGHT);\r
+ }\r
+ float xLabel = x2 + extra;\r
+ float yLabel = y2;\r
+ float width = right - xLabel;\r
+ if (x1 > x2) {\r
+ width = xLabel - left;\r
+ }\r
+ labelText = getFitText(labelText, width, paint);\r
+ float widthLabel = paint.measureText(labelText);\r
+ boolean okBounds = false;\r
+ while (!okBounds && line) {\r
+ boolean intersects = false;\r
+ int length = prevLabelsBounds.size();\r
+ for (int j = 0; j < length && !intersects; j++) {\r
+ RectF prevLabelBounds = prevLabelsBounds.get(j);\r
+ if (prevLabelBounds.intersects(xLabel, yLabel, xLabel + widthLabel, yLabel + size)) {\r
+ intersects = true;\r
+ yLabel = Math.max(yLabel, prevLabelBounds.bottom);\r
+ }\r
+ }\r
+ okBounds = !intersects;\r
+ }\r
+\r
+ if (line) {\r
+ y2 = (int) (yLabel - size / 2);\r
+ canvas.drawLine(x1, y1, x2, y2, paint);\r
+ canvas.drawLine(x2, y2, x2 + extra, y2, paint);\r
+ } else {\r
+ paint.setTextAlign(Align.CENTER);\r
+ }\r
+ canvas.drawText(labelText, xLabel, yLabel, paint);\r
+ if (line) {\r
+ prevLabelsBounds.add(new RectF(xLabel, yLabel, xLabel + widthLabel, yLabel + size));\r
+ }\r
+ }\r
+ }\r
+\r
+ public boolean isNullValue(double value) {\r
+ return Double.isNaN(value) || Double.isInfinite(value) || value == MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Given screen coordinates, returns the series and point indexes of a chart\r
+ * element. If there is no chart element (line, point, bar, etc) at those\r
+ * coordinates, null is returned.\r
+ * \r
+ * @param screenPoint\r
+ * @return the series and point indexes\r
+ */\r
+ public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {\r
+ return null;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+import android.graphics.drawable.GradientDrawable;\r
+import android.graphics.drawable.GradientDrawable.Orientation;\r
+\r
+/**\r
+ * The bar chart rendering class.\r
+ */\r
+public class BarChart extends XYChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Bar";\r
+ /** The legend shape width. */\r
+ private static final int SHAPE_WIDTH = 12;\r
+ /** The chart type. */\r
+ protected Type mType = Type.DEFAULT;\r
+\r
+ /**\r
+ * The bar chart type enum.\r
+ */\r
+ public enum Type {\r
+ DEFAULT, STACKED;\r
+ }\r
+\r
+ BarChart() {\r
+ }\r
+\r
+ BarChart(Type type) {\r
+ mType = type;\r
+ }\r
+\r
+ /**\r
+ * Builds a new bar chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ * @param type the bar chart type\r
+ */\r
+ public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+ super(dataset, renderer);\r
+ mType = type;\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ int length = points.length;\r
+ ClickableArea[] ret = new ClickableArea[length / 2];\r
+ float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+ for (int i = 0; i < length; i += 2) {\r
+ float x = points[i];\r
+ float y = points[i + 1];\r
+ if (mType == Type.STACKED) {\r
+ ret[i / 2] = new ClickableArea(new RectF(x - halfDiffX, y, x + halfDiffX, yAxisValue),\r
+ values[i], values[i + 1]);\r
+ } else {\r
+ float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+ ret[i / 2] = new ClickableArea(new RectF(startX, y, startX + 2 * halfDiffX, yAxisValue),\r
+ values[i], values[i + 1]);\r
+ }\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ int length = points.length;\r
+ paint.setColor(seriesRenderer.getColor());\r
+ paint.setStyle(Style.FILL);\r
+ float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+ for (int i = 0; i < length; i += 2) {\r
+ float x = points[i];\r
+ float y = points[i + 1];\r
+ drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);\r
+ }\r
+ paint.setColor(seriesRenderer.getColor());\r
+ }\r
+\r
+ /**\r
+ * Draws a bar.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param xMin the X axis minimum\r
+ * @param yMin the Y axis minimum\r
+ * @param xMax the X axis maximum\r
+ * @param yMax the Y axis maximum\r
+ * @param halfDiffX half the size of a bar\r
+ * @param seriesNr the total number of series\r
+ * @param seriesIndex the current series index\r
+ * @param paint the paint\r
+ */\r
+ protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,\r
+ float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {\r
+ int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();\r
+ if (mType == Type.STACKED) {\r
+ drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);\r
+ } else {\r
+ float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+ drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Draws a bar.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param xMin the X axis minimum\r
+ * @param yMin the Y axis minimum\r
+ * @param xMax the X axis maximum\r
+ * @param yMax the Y axis maximum\r
+ * @param scale the scale index\r
+ * @param seriesIndex the current series index\r
+ * @param paint the paint\r
+ */\r
+ private void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,\r
+ int seriesIndex, Paint paint) {\r
+ SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);\r
+ if (renderer.isGradientEnabled()) {\r
+ float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];\r
+ float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },\r
+ scale)[1];\r
+ float gradientMinY = Math.max(minY, Math.min(yMin, yMax));\r
+ float gradientMaxY = Math.min(maxY, Math.max(yMin, yMax));\r
+ int gradientMinColor = renderer.getGradientStopColor();\r
+ int gradientMaxColor = renderer.getGradientStartColor();\r
+ int gradientStartColor = gradientMaxColor;\r
+ int gradientStopColor = gradientMinColor;\r
+\r
+ if (yMin < minY) {\r
+ paint.setColor(gradientMinColor);\r
+ canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),\r
+ Math.round(gradientMinY), paint);\r
+ } else {\r
+ gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,\r
+ (maxY - gradientMinY) / (maxY - minY));\r
+ }\r
+ if (yMax > maxY) {\r
+ paint.setColor(gradientMaxColor);\r
+ canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),\r
+ Math.round(yMax), paint);\r
+ } else {\r
+ gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,\r
+ (gradientMaxY - minY) / (maxY - minY));\r
+ }\r
+ GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {\r
+ gradientStartColor, gradientStopColor });\r
+ gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),\r
+ Math.round(gradientMaxY));\r
+ gradient.draw(canvas);\r
+ } else {\r
+ if (Math.abs(yMin - yMax) < 1) {\r
+ if (yMin < yMax) {\r
+ yMax = yMin + 1;\r
+ } else {\r
+ yMax = yMin - 1;\r
+ }\r
+ }\r
+ canvas\r
+ .drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);\r
+ }\r
+ }\r
+\r
+ private int getGradientPartialColor(int minColor, int maxColor, float fraction) {\r
+ int alpha = Math.round(fraction * Color.alpha(minColor) + (1 - fraction)\r
+ * Color.alpha(maxColor));\r
+ int r = Math.round(fraction * Color.red(minColor) + (1 - fraction) * Color.red(maxColor));\r
+ int g = Math.round(fraction * Color.green(minColor) + (1 - fraction) * Color.green(maxColor));\r
+ int b = Math.round(fraction * Color.blue(minColor) + (1 - fraction) * Color.blue((maxColor)));\r
+ return Color.argb(alpha, r, g, b);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the series values as text.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param series the series to be painted\r
+ * @param renderer the series renderer\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+ Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ float halfDiffX = getHalfDiffX(points, points.length, seriesNr);\r
+ for (int i = 0; i < points.length; i += 2) {\r
+ int index = startIndex + i / 2;\r
+ double value = series.getY(index);\r
+ if (!isNullValue(value)) {\r
+ float x = points[i];\r
+ if (mType == Type.DEFAULT) {\r
+ x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;\r
+ }\r
+ if (value >= 0) {\r
+ drawText(canvas, getLabel(value), x, points[i + 1] - renderer.getChartValuesSpacing(),\r
+ paint, 0);\r
+ } else {\r
+ drawText(canvas, getLabel(value), x, points[i + 1] + renderer.getChartValuesTextSize()\r
+ + renderer.getChartValuesSpacing() - 3, paint, 0);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ float halfShapeWidth = SHAPE_WIDTH / 2;\r
+ canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);\r
+ }\r
+\r
+ /**\r
+ * Calculates and returns the half-distance in the graphical representation of\r
+ * 2 consecutive points.\r
+ * \r
+ * @param points the points\r
+ * @param length the points length\r
+ * @param seriesNr the series number\r
+ * @return the calculated half-distance value\r
+ */\r
+ protected float getHalfDiffX(float[] points, int length, int seriesNr) {\r
+ int div = length;\r
+ if (length > 2) {\r
+ div = length - 2;\r
+ }\r
+ float halfDiffX = (points[length - 2] - points[0]) / div;\r
+ if (halfDiffX == 0) {\r
+ halfDiffX = 10;\r
+ }\r
+\r
+ if (mType != Type.STACKED) {\r
+ halfDiffX /= seriesNr;\r
+ }\r
+ return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));\r
+ }\r
+\r
+ /**\r
+ * Returns the value of a constant used to calculate the half-distance.\r
+ * \r
+ * @return the constant value\r
+ */\r
+ protected float getCoeficient() {\r
+ return 1f;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart should display the null values.\r
+ * \r
+ * @return if null values should be rendered\r
+ */\r
+ protected boolean isRenderNullValues() {\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Returns the default axis minimum.\r
+ * \r
+ * @return the default axis minimum\r
+ */\r
+ public double getDefaultMinimum() {\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYValueSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The bubble chart rendering class.\r
+ */\r
+public class BubbleChart extends XYChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Bubble";\r
+ /** The legend shape width. */\r
+ private static final int SHAPE_WIDTH = 10;\r
+ /** The minimum bubble size. */\r
+ private static final int MIN_BUBBLE_SIZE = 2;\r
+ /** The maximum bubble size. */\r
+ private static final int MAX_BUBBLE_SIZE = 20;\r
+\r
+ BubbleChart() {\r
+ }\r
+\r
+ /**\r
+ * Builds a new bubble chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ */\r
+ public BubbleChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ super(dataset, renderer);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+ paint.setColor(renderer.getColor());\r
+ paint.setStyle(Style.FILL);\r
+ int length = points.length;\r
+ XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);\r
+ double max = series.getMaxValue();\r
+ double coef = MAX_BUBBLE_SIZE / max;\r
+ for (int i = 0; i < length; i += 2) {\r
+ double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;\r
+ drawCircle(canvas, paint, points[i], points[i + 1], (float) size);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ int length = points.length;\r
+ XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);\r
+ double max = series.getMaxValue();\r
+ double coef = MAX_BUBBLE_SIZE / max;\r
+ ClickableArea[] ret = new ClickableArea[length / 2];\r
+ for (int i = 0; i < length; i += 2) {\r
+ double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;\r
+ ret[i / 2] = new ClickableArea(new RectF(points[i] - (float) size, points[i + 1]\r
+ - (float) size, points[i] + (float) size, points[i + 1] + (float) size), values[i],\r
+ values[i + 1]);\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ paint.setStyle(Style.FILL);\r
+ drawCircle(canvas, paint, x + SHAPE_WIDTH, y, 3);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a circle point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param radius the bubble radius\r
+ */\r
+ private void drawCircle(Canvas canvas, Paint paint, float x, float y, float radius) {\r
+ canvas.drawCircle(x, y, radius, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import android.graphics.RectF;\r
+\r
+public class ClickableArea {\r
+ private RectF rect;\r
+ private double x;\r
+ private double y;\r
+\r
+ public ClickableArea(RectF rect, double x, double y) {\r
+ super();\r
+ this.rect = rect;\r
+ this.x = x;\r
+ this.y = y;\r
+ }\r
+\r
+ public RectF getRect() {\r
+ return rect;\r
+ }\r
+\r
+ public double getX() {\r
+ return x;\r
+ }\r
+\r
+ public double getY() {\r
+ return y;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.List;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+\r
+/**\r
+ * The combined XY chart rendering class.\r
+ */\r
+public class CombinedXYChart extends XYChart {\r
+ /** The embedded XY charts. */\r
+ private XYChart[] mCharts;\r
+ /** The supported charts for being combined. */\r
+ private Class[] xyChartTypes = new Class[] { TimeChart.class, LineChart.class,\r
+ CubicLineChart.class, BarChart.class, BubbleChart.class, ScatterChart.class,\r
+ RangeBarChart.class, RangeStackedBarChart.class };\r
+\r
+ /**\r
+ * Builds a new combined XY chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ * @param types the XY chart types\r
+ */\r
+ public CombinedXYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,\r
+ String[] types) {\r
+ super(dataset, renderer);\r
+ int length = types.length;\r
+ mCharts = new XYChart[length];\r
+ for (int i = 0; i < length; i++) {\r
+ try {\r
+ mCharts[i] = getXYChart(types[i]);\r
+ } catch (Exception e) {\r
+ // ignore\r
+ }\r
+ if (mCharts[i] == null) {\r
+ throw new IllegalArgumentException("Unknown chart type " + types[i]);\r
+ } else {\r
+ XYMultipleSeriesDataset newDataset = new XYMultipleSeriesDataset();\r
+ newDataset.addSeries(dataset.getSeriesAt(i));\r
+ XYMultipleSeriesRenderer newRenderer = new XYMultipleSeriesRenderer();\r
+ // TODO: copy other parameters here\r
+ newRenderer.setBarSpacing(renderer.getBarSpacing());\r
+ newRenderer.setPointSize(renderer.getPointSize());\r
+ int scale = dataset.getSeriesAt(i).getScaleNumber();\r
+ if (renderer.isMinXSet(scale)) {\r
+ newRenderer.setXAxisMin(renderer.getXAxisMin(scale));\r
+ }\r
+ if (renderer.isMaxXSet(scale)) {\r
+ newRenderer.setXAxisMax(renderer.getXAxisMax(scale));\r
+ }\r
+ if (renderer.isMinYSet(scale)) {\r
+ newRenderer.setYAxisMin(renderer.getYAxisMin(scale));\r
+ }\r
+ if (renderer.isMaxYSet(scale)) {\r
+ newRenderer.setYAxisMax(renderer.getYAxisMax(scale));\r
+ }\r
+ newRenderer.addSeriesRenderer(renderer.getSeriesRendererAt(i));\r
+ mCharts[i].setDatasetRenderer(newDataset, newRenderer);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns a chart instance based on the provided type.\r
+ * \r
+ * @param type the chart type\r
+ * @return an instance of a chart implementation\r
+ * @throws IllegalAccessException\r
+ * @throws InstantiationException\r
+ */\r
+ private XYChart getXYChart(String type) throws IllegalAccessException, InstantiationException {\r
+ XYChart chart = null;\r
+ int length = xyChartTypes.length;\r
+ for (int i = 0; i < length && chart == null; i++) {\r
+ XYChart newChart = (XYChart) xyChartTypes[i].newInstance();\r
+ if (type.equals(newChart.getChartType())) {\r
+ chart = newChart;\r
+ }\r
+ }\r
+ return chart;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ mCharts[seriesIndex].setScreenR(getScreenR());\r
+ mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)\r
+ .getScaleNumber()), 0);\r
+ mCharts[seriesIndex].drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, 0,\r
+ startIndex);\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ return mCharts[seriesIndex].clickableAreasForPoints(points, values, yAxisValue, 0, startIndex);\r
+ }\r
+\r
+ @Override\r
+ protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,\r
+ int startIndex) {\r
+ mCharts[seriesIndex].setScreenR(getScreenR());\r
+ mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)\r
+ .getScaleNumber()), 0);\r
+ mCharts[seriesIndex].drawSeries(series, canvas, paint, pointsList, seriesRenderer, yAxisValue,\r
+ 0, or, startIndex);\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return mCharts[seriesIndex].getLegendShapeWidth(0);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ mCharts[seriesIndex].drawLegendShape(canvas, renderer, x, y, 0, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return "Combined";\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Path;\r
+\r
+/**\r
+ * The interpolated (cubic) line chart rendering class.\r
+ */\r
+public class CubicLineChart extends LineChart {\r
+ /** The chart type. */\r
+ public static final String TYPE = "Cubic";\r
+\r
+ private float firstMultiplier;\r
+\r
+ private float secondMultiplier;\r
+\r
+ private Point p1 = new Point();\r
+\r
+ private Point p2 = new Point();\r
+\r
+ private Point p3 = new Point();\r
+\r
+ public CubicLineChart() {\r
+ // default is to have first control point at about 33% of the distance,\r
+ firstMultiplier = 0.33f;\r
+ // and the next at 66% of the distance.\r
+ secondMultiplier = 1 - firstMultiplier;\r
+ }\r
+\r
+ /**\r
+ * Builds a cubic line chart.\r
+ * \r
+ * @param dataset the dataset\r
+ * @param renderer the renderer\r
+ * @param smoothness smoothness determines how smooth the curve should be,\r
+ * range [0->0.5] super smooth, 0.5, means that it might not get\r
+ * close to control points if you have random data // less smooth,\r
+ * (close to 0) means that it will most likely touch all control //\r
+ * points\r
+ */\r
+ public CubicLineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,\r
+ float smoothness) {\r
+ super(dataset, renderer);\r
+ firstMultiplier = smoothness;\r
+ secondMultiplier = 1 - firstMultiplier;\r
+ }\r
+\r
+ @Override\r
+ protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {\r
+ Path p = new Path();\r
+ float x = points[0];\r
+ float y = points[1];\r
+ p.moveTo(x, y);\r
+\r
+ int length = points.length;\r
+ if (circular) {\r
+ length -= 4;\r
+ }\r
+\r
+ for (int i = 0; i < length; i += 2) {\r
+ int nextIndex = i + 2 < length ? i + 2 : i;\r
+ int nextNextIndex = i + 4 < length ? i + 4 : nextIndex;\r
+ calc(points, p1, i, nextIndex, secondMultiplier);\r
+ p2.setX(points[nextIndex]);\r
+ p2.setY(points[nextIndex + 1]);\r
+ calc(points, p3, nextIndex, nextNextIndex, firstMultiplier);\r
+ // From last point, approaching x1/y1 and x2/y2 and ends up at x3/y3\r
+ p.cubicTo(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());\r
+ }\r
+ if (circular) {\r
+ for (int i = length; i < length + 4; i += 2) {\r
+ p.lineTo(points[i], points[i + 1]);\r
+ }\r
+ p.lineTo(points[0], points[1]);\r
+ }\r
+ canvas.drawPath(p, paint);\r
+ }\r
+\r
+ private void calc(float[] points, Point result, int index1, int index2, final float multiplier) {\r
+ float p1x = points[index1];\r
+ float p1y = points[index1 + 1];\r
+ float p2x = points[index2];\r
+ float p2y = points[index2 + 1];\r
+\r
+ float diffX = p2x - p1x; // p2.x - p1.x;\r
+ float diffY = p2y - p1y; // p2.y - p1.y;\r
+ result.setX(p1x + (diffX * multiplier));\r
+ result.setY(p1y + (diffY * multiplier));\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.DialRenderer;\r
+import org.achartengine.renderer.DialRenderer.Type;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Style;\r
+\r
+/**\r
+ * The dial chart rendering class.\r
+ */\r
+public class DialChart extends RoundChart {\r
+ /** The radius of the needle. */\r
+ private static final int NEEDLE_RADIUS = 10;\r
+ /** The series renderer. */\r
+ private DialRenderer mRenderer;\r
+\r
+ /**\r
+ * Builds a new dial chart instance.\r
+ * \r
+ * @param dataset the series dataset\r
+ * @param renderer the dial renderer\r
+ */\r
+ public DialChart(CategorySeries dataset, DialRenderer renderer) {\r
+ super(dataset, renderer);\r
+ mRenderer = renderer;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the dial chart.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param height the height of the view to draw to\r
+ * @param paint the paint\r
+ */\r
+ @Override\r
+ public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+ paint.setAntiAlias(mRenderer.isAntialiasing());\r
+ paint.setStyle(Style.FILL);\r
+ paint.setTextSize(mRenderer.getLabelsTextSize());\r
+ int legendSize = getLegendSize(mRenderer, height / 5, 0);\r
+ int left = x;\r
+ int top = y;\r
+ int right = x + width;\r
+\r
+ int sLength = mDataset.getItemCount();\r
+ String[] titles = new String[sLength];\r
+ for (int i = 0; i < sLength; i++) {\r
+ titles[i] = mDataset.getCategory(i);\r
+ }\r
+\r
+ if (mRenderer.isFitLegend()) {\r
+ legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,\r
+ paint, true);\r
+ }\r
+ int bottom = y + height - legendSize;\r
+ drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+\r
+ int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));\r
+ int radius = (int) (mRadius * 0.35 * mRenderer.getScale());\r
+ if (mCenterX == NO_VALUE) {\r
+ mCenterX = (left + right) / 2;\r
+ }\r
+ if (mCenterY == NO_VALUE) {\r
+ mCenterY = (bottom + top) / 2;\r
+ }\r
+ float shortRadius = radius * 0.9f;\r
+ float longRadius = radius * 1.1f;\r
+ double min = mRenderer.getMinValue();\r
+ double max = mRenderer.getMaxValue();\r
+ double angleMin = mRenderer.getAngleMin();\r
+ double angleMax = mRenderer.getAngleMax();\r
+ if (!mRenderer.isMinValueSet() || !mRenderer.isMaxValueSet()) {\r
+ int count = mRenderer.getSeriesRendererCount();\r
+ for (int i = 0; i < count; i++) {\r
+ double value = mDataset.getValue(i);\r
+ if (!mRenderer.isMinValueSet()) {\r
+ min = Math.min(min, value);\r
+ }\r
+ if (!mRenderer.isMaxValueSet()) {\r
+ max = Math.max(max, value);\r
+ }\r
+ }\r
+ }\r
+ if (min == max) {\r
+ min = min * 0.5;\r
+ max = max * 1.5;\r
+ }\r
+\r
+ paint.setColor(mRenderer.getLabelsColor());\r
+ double minorTicks = mRenderer.getMinorTicksSpacing();\r
+ double majorTicks = mRenderer.getMajorTicksSpacing();\r
+ if (minorTicks == MathHelper.NULL_VALUE) {\r
+ minorTicks = (max - min) / 30;\r
+ }\r
+ if (majorTicks == MathHelper.NULL_VALUE) {\r
+ majorTicks = (max - min) / 10;\r
+ }\r
+ drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, radius,\r
+ minorTicks, paint, false);\r
+ drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, shortRadius,\r
+ majorTicks, paint, true);\r
+\r
+ int count = mRenderer.getSeriesRendererCount();\r
+ for (int i = 0; i < count; i++) {\r
+ double angle = getAngleForValue(mDataset.getValue(i), angleMin, angleMax, min, max);\r
+ paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());\r
+ boolean type = mRenderer.getVisualTypeForIndex(i) == Type.ARROW;\r
+ drawNeedle(canvas, angle, mCenterX, mCenterY, shortRadius, type, paint);\r
+ }\r
+ drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+ drawTitle(canvas, x, y, width, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the angle for a specific chart value.\r
+ * \r
+ * @param value the chart value\r
+ * @param minAngle the minimum chart angle value\r
+ * @param maxAngle the maximum chart angle value\r
+ * @param min the minimum chart value\r
+ * @param max the maximum chart value\r
+ * @return the angle\r
+ */\r
+ private double getAngleForValue(double value, double minAngle, double maxAngle, double min,\r
+ double max) {\r
+ double angleDiff = maxAngle - minAngle;\r
+ double diff = max - min;\r
+ return Math.toRadians(minAngle + (value - min) * angleDiff / diff);\r
+ }\r
+\r
+ /**\r
+ * Draws the chart tick lines.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param min the minimum chart value\r
+ * @param max the maximum chart value\r
+ * @param minAngle the minimum chart angle value\r
+ * @param maxAngle the maximum chart angle value\r
+ * @param centerX the center x value\r
+ * @param centerY the center y value\r
+ * @param longRadius the long radius\r
+ * @param shortRadius the short radius\r
+ * @param ticks the tick spacing\r
+ * @param paint the paint settings\r
+ * @param labels paint the labels\r
+ * @return the angle\r
+ */\r
+ private void drawTicks(Canvas canvas, double min, double max, double minAngle, double maxAngle,\r
+ int centerX, int centerY, double longRadius, double shortRadius, double ticks, Paint paint,\r
+ boolean labels) {\r
+ for (double i = min; i <= max; i += ticks) {\r
+ double angle = getAngleForValue(i, minAngle, maxAngle, min, max);\r
+ double sinValue = Math.sin(angle);\r
+ double cosValue = Math.cos(angle);\r
+ int x1 = Math.round(centerX + (float) (shortRadius * sinValue));\r
+ int y1 = Math.round(centerY + (float) (shortRadius * cosValue));\r
+ int x2 = Math.round(centerX + (float) (longRadius * sinValue));\r
+ int y2 = Math.round(centerY + (float) (longRadius * cosValue));\r
+ canvas.drawLine(x1, y1, x2, y2, paint);\r
+ if (labels) {\r
+ paint.setTextAlign(Align.LEFT);\r
+ if (x1 <= x2) {\r
+ paint.setTextAlign(Align.RIGHT);\r
+ }\r
+ String text = i + "";\r
+ if (Math.round(i) == (long) i) {\r
+ text = (long) i + "";\r
+ }\r
+ canvas.drawText(text, x1, y1, paint);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the angle for a specific chart value.\r
+ * \r
+ * @param canvas the canvas\r
+ * @param angle the needle angle value\r
+ * @param centerX the center x value\r
+ * @param centerY the center y value\r
+ * @param radius the radius\r
+ * @param arrow if a needle or an arrow to be painted\r
+ * @param paint the paint settings\r
+ * @return the angle\r
+ */\r
+ private void drawNeedle(Canvas canvas, double angle, int centerX, int centerY, double radius,\r
+ boolean arrow, Paint paint) {\r
+ double diff = Math.toRadians(90);\r
+ int needleSinValue = (int) (NEEDLE_RADIUS * Math.sin(angle - diff));\r
+ int needleCosValue = (int) (NEEDLE_RADIUS * Math.cos(angle - diff));\r
+ int needleX = (int) (radius * Math.sin(angle));\r
+ int needleY = (int) (radius * Math.cos(angle));\r
+ int needleCenterX = centerX + needleX;\r
+ int needleCenterY = centerY + needleY;\r
+ float[] points;\r
+ if (arrow) {\r
+ int arrowBaseX = centerX + (int) (radius * 0.85 * Math.sin(angle));\r
+ int arrowBaseY = centerY + (int) (radius * 0.85 * Math.cos(angle));\r
+ points = new float[] { arrowBaseX - needleSinValue, arrowBaseY - needleCosValue,\r
+ needleCenterX, needleCenterY, arrowBaseX + needleSinValue, arrowBaseY + needleCosValue };\r
+ float width = paint.getStrokeWidth();\r
+ paint.setStrokeWidth(5);\r
+ canvas.drawLine(centerX, centerY, needleCenterX, needleCenterY, paint);\r
+ paint.setStrokeWidth(width);\r
+ } else {\r
+ points = new float[] { centerX - needleSinValue, centerY - needleCosValue, needleCenterX,\r
+ needleCenterY, centerX + needleSinValue, centerY + needleCosValue };\r
+ }\r
+ drawPath(canvas, points, paint, true);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.MultipleCategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The doughnut chart rendering class.\r
+ */\r
+public class DoughnutChart extends RoundChart {\r
+ /** The series dataset. */\r
+ private MultipleCategorySeries mDataset;\r
+ /** A step variable to control the size of the legend shape. */\r
+ private int mStep;\r
+\r
+ /**\r
+ * Builds a new doughnut chart instance.\r
+ * \r
+ * @param dataset the series dataset\r
+ * @param renderer the series renderer\r
+ */\r
+ public DoughnutChart(MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+ super(null, renderer);\r
+ mDataset = dataset;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the doughnut chart.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param height the height of the view to draw to\r
+ * @param paint the paint\r
+ */\r
+ @Override\r
+ public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+ paint.setAntiAlias(mRenderer.isAntialiasing());\r
+ paint.setStyle(Style.FILL);\r
+ paint.setTextSize(mRenderer.getLabelsTextSize());\r
+ int legendSize = getLegendSize(mRenderer, height / 5, 0);\r
+ int left = x;\r
+ int top = y;\r
+ int right = x + width;\r
+ int cLength = mDataset.getCategoriesCount();\r
+ String[] categories = new String[cLength];\r
+ for (int category = 0; category < cLength; category++) {\r
+ categories[category] = mDataset.getCategory(category);\r
+ }\r
+ if (mRenderer.isFitLegend()) {\r
+ legendSize = drawLegend(canvas, mRenderer, categories, left, right, y, width, height,\r
+ legendSize, paint, true);\r
+ }\r
+\r
+ int bottom = y + height - legendSize;\r
+ drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+ mStep = SHAPE_WIDTH * 3 / 4;\r
+\r
+ int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));\r
+ double rCoef = 0.35 * mRenderer.getScale();\r
+ double decCoef = 0.2 / cLength;\r
+ int radius = (int) (mRadius * rCoef);\r
+ if (mCenterX == NO_VALUE) {\r
+ mCenterX = (left + right) / 2;\r
+ }\r
+ if (mCenterY == NO_VALUE) {\r
+ mCenterY = (bottom + top) / 2;\r
+ }\r
+ float shortRadius = radius * 0.9f;\r
+ float longRadius = radius * 1.1f;\r
+ List<RectF> prevLabelsBounds = new ArrayList<RectF>();\r
+ for (int category = 0; category < cLength; category++) {\r
+ int sLength = mDataset.getItemCount(category);\r
+ double total = 0;\r
+ String[] titles = new String[sLength];\r
+ for (int i = 0; i < sLength; i++) {\r
+ total += mDataset.getValues(category)[i];\r
+ titles[i] = mDataset.getTitles(category)[i];\r
+ }\r
+ float currentAngle = mRenderer.getStartAngle();\r
+ RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY\r
+ + radius);\r
+ for (int i = 0; i < sLength; i++) {\r
+ paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());\r
+ float value = (float) mDataset.getValues(category)[i];\r
+ float angle = (float) (value / total * 360);\r
+ canvas.drawArc(oval, currentAngle, angle, true, paint);\r
+ drawLabel(canvas, mDataset.getTitles(category)[i], mRenderer, prevLabelsBounds, mCenterX,\r
+ mCenterY, shortRadius, longRadius, currentAngle, angle, left, right,\r
+ mRenderer.getLabelsColor(), paint, true);\r
+ currentAngle += angle;\r
+ }\r
+ radius -= (int) mRadius * decCoef;\r
+ shortRadius -= mRadius * decCoef - 2;\r
+ if (mRenderer.getBackgroundColor() != 0) {\r
+ paint.setColor(mRenderer.getBackgroundColor());\r
+ } else {\r
+ paint.setColor(Color.WHITE);\r
+ }\r
+ paint.setStyle(Style.FILL);\r
+ oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);\r
+ canvas.drawArc(oval, 0, 360, true, paint);\r
+ radius -= 1;\r
+ }\r
+ prevLabelsBounds.clear();\r
+ drawLegend(canvas, mRenderer, categories, left, right, y, width, height, legendSize, paint,\r
+ false);\r
+ drawTitle(canvas, x, y, width, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ mStep--;\r
+ canvas.drawCircle(x + SHAPE_WIDTH - mStep, y, mStep, paint);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The line chart rendering class.\r
+ */\r
+public class LineChart extends XYChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Line";\r
+ /** The legend shape width. */\r
+ private static final int SHAPE_WIDTH = 30;\r
+ /** The scatter chart to be used to draw the data points. */\r
+ private ScatterChart pointsChart;\r
+\r
+ LineChart() {\r
+ }\r
+\r
+ /**\r
+ * Builds a new line chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ */\r
+ public LineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ super(dataset, renderer);\r
+ pointsChart = new ScatterChart(dataset, renderer);\r
+ }\r
+\r
+ /**\r
+ * Sets the series and the renderer.\r
+ * \r
+ * @param dataset the series dataset\r
+ * @param renderer the series renderer\r
+ */\r
+ protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ super.setDatasetRenderer(dataset, renderer);\r
+ pointsChart = new ScatterChart(dataset, renderer);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ int length = points.length;\r
+ XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+ float lineWidth = paint.getStrokeWidth();\r
+ paint.setStrokeWidth(renderer.getLineWidth());\r
+ if (renderer.isFillBelowLine()) {\r
+ paint.setColor(renderer.getFillBelowLineColor());\r
+ int pLength = points.length;\r
+ float[] fillPoints = new float[pLength + 4];\r
+ System.arraycopy(points, 0, fillPoints, 0, length);\r
+ fillPoints[0] = points[0] + 1;\r
+ fillPoints[length] = fillPoints[length - 2];\r
+ fillPoints[length + 1] = yAxisValue;\r
+ fillPoints[length + 2] = fillPoints[0];\r
+ fillPoints[length + 3] = fillPoints[length + 1];\r
+ for (int i = 0; i < length + 4; i += 2) {\r
+ if (fillPoints[i + 1] < 0) {\r
+ fillPoints[i + 1] = 0;\r
+ }\r
+ }\r
+ paint.setStyle(Style.FILL);\r
+ drawPath(canvas, fillPoints, paint, true);\r
+ }\r
+ paint.setColor(seriesRenderer.getColor());\r
+ paint.setStyle(Style.STROKE);\r
+ drawPath(canvas, points, paint, false);\r
+ paint.setStrokeWidth(lineWidth);\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ int length = points.length;\r
+ ClickableArea[] ret = new ClickableArea[length / 2];\r
+ for (int i = 0; i < length; i += 2) {\r
+ int selectableBuffer = mRenderer.getSelectableBuffer();\r
+ ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]\r
+ - selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),\r
+ values[i], values[i + 1]);\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ canvas.drawLine(x, y, x + SHAPE_WIDTH, y, paint);\r
+ if (isRenderPoints(renderer)) {\r
+ pointsChart.drawLegendShape(canvas, renderer, x + 5, y, seriesIndex, paint);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart should display the points as a certain shape.\r
+ * \r
+ * @param renderer the series renderer\r
+ */\r
+ public boolean isRenderPoints(SimpleSeriesRenderer renderer) {\r
+ return ((XYSeriesRenderer) renderer).getPointStyle() != PointStyle.POINT;\r
+ }\r
+\r
+ /**\r
+ * Returns the scatter chart to be used for drawing the data points.\r
+ * \r
+ * @return the data points scatter chart\r
+ */\r
+ public ScatterChart getPointsChart() {\r
+ return pointsChart;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.achartengine.model.CategorySeries;
+import org.achartengine.model.Point;
+import org.achartengine.model.SeriesSelection;
+import org.achartengine.renderer.DefaultRenderer;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+
+/**
+ * The pie chart rendering class.
+ */
+public class PieChart extends RoundChart {
+ /** Handles returning values when tapping on PieChart. */
+ private PieMapper mPieMapper;
+
+ /**
+ * Builds a new pie chart instance.
+ *
+ * @param dataset the series dataset
+ * @param renderer the series renderer
+ */
+ public PieChart(CategorySeries dataset, DefaultRenderer renderer) {
+ super(dataset, renderer);
+ mPieMapper = new PieMapper();
+ }
+
+ /**
+ * The graphical representation of the pie chart.
+ *
+ * @param canvas the canvas to paint to
+ * @param x the top left x value of the view to draw to
+ * @param y the top left y value of the view to draw to
+ * @param width the width of the view to draw to
+ * @param height the height of the view to draw to
+ * @param paint the paint
+ */
+ @Override
+ public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
+ paint.setAntiAlias(mRenderer.isAntialiasing());
+ paint.setStyle(Style.FILL);
+ paint.setTextSize(mRenderer.getLabelsTextSize());
+ int legendSize = getLegendSize(mRenderer, height / 5, 0);
+ int left = x;
+ int top = y;
+ int right = x + width;
+ int sLength = mDataset.getItemCount();
+ double total = 0;
+ String[] titles = new String[sLength];
+ for (int i = 0; i < sLength; i++) {
+ total += mDataset.getValue(i);
+ titles[i] = mDataset.getCategory(i);
+ }
+ if (mRenderer.isFitLegend()) {
+ legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
+ paint, true);
+ }
+ int bottom = y + height - legendSize;
+ drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
+
+ float currentAngle = mRenderer.getStartAngle();
+ int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
+ int radius = (int) (mRadius * 0.35 * mRenderer.getScale());
+
+ if (mCenterX == NO_VALUE) {
+ mCenterX = (left + right) / 2;
+ }
+ if (mCenterY == NO_VALUE) {
+ mCenterY = (bottom + top) / 2;
+ }
+
+ // Hook in clip detection after center has been calculated
+ mPieMapper.setDimensions(radius, mCenterX, mCenterY);
+ boolean loadPieCfg = !mPieMapper.areAllSegmentPresent(sLength);
+ if (loadPieCfg) {
+ mPieMapper.clearPieSegments();
+ }
+
+ float shortRadius = radius * 0.9f;
+ float longRadius = radius * 1.1f;
+
+ RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY
+ + radius);
+ List<RectF> prevLabelsBounds = new ArrayList<RectF>();
+
+ for (int i = 0; i < sLength; i++) {
+ paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
+ float value = (float) mDataset.getValue(i);
+ float angle = (float) (value / total * 360);
+ canvas.drawArc(oval, currentAngle, angle, true, paint);
+ drawLabel(canvas, mDataset.getCategory(i), mRenderer, prevLabelsBounds, mCenterX, mCenterY,
+ shortRadius, longRadius, currentAngle, angle, left, right, mRenderer.getLabelsColor(),
+ paint, true);
+ if (mRenderer.isDisplayValues()) {
+ drawLabel(canvas, getLabel(mDataset.getValue(i)), mRenderer, prevLabelsBounds, mCenterX,
+ mCenterY, shortRadius / 2, longRadius / 2, currentAngle, angle, left, right,
+ mRenderer.getLabelsColor(), paint, false);
+ }
+
+ // Save details for getSeries functionality
+ if (loadPieCfg) {
+ mPieMapper.addPieSegment(i, value, currentAngle, angle);
+ }
+ currentAngle += angle;
+ }
+ prevLabelsBounds.clear();
+ drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
+ drawTitle(canvas, x, y, width, paint);
+ }
+
+ public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
+ return mPieMapper.getSeriesAndPointForScreenCoordinate(screenPoint);
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.achartengine.model.Point;
+import org.achartengine.model.SeriesSelection;
+
+/**
+ * PieChart Segment Selection Management.
+ */
+public class PieMapper implements Serializable {
+
+ private List<PieSegment> mPieSegmentList = new ArrayList<PieSegment>();
+
+ private int mPieChartRadius;
+
+ private int mCenterX, mCenterY;
+
+ /**
+ * Set PieChart location on screen.
+ *
+ * @param pieRadius
+ * @param centerX
+ * @param centerY
+ */
+ public void setDimensions(int pieRadius, int centerX, int centerY) {
+ mPieChartRadius = pieRadius;
+ mCenterX = centerX;
+ mCenterY = centerY;
+ }
+
+ /**
+ * If we have all PieChart Config then there is no point in reloading it
+ *
+ * @param datasetSize
+ * @return true if cfg for each segment is present
+ */
+ public boolean areAllSegmentPresent(int datasetSize) {
+ return mPieSegmentList.size() == datasetSize;
+ }
+
+ /**
+ * Add configuration for a PieChart Segment
+ *
+ * @param dataIndex
+ * @param value
+ * @param startAngle
+ * @param angle
+ */
+ public void addPieSegment(int dataIndex, float value, float startAngle, float angle) {
+ mPieSegmentList.add(new PieSegment(dataIndex, value, startAngle, angle));
+ }
+
+ /**
+ * Clears the pie segments list.
+ */
+ public void clearPieSegments() {
+ mPieSegmentList.clear();
+ }
+
+ /**
+ * Fetches angle relative to pie chart center point where 3 O'Clock is 0 and
+ * 12 O'Clock is 270degrees
+ *
+ * @param screenPoint
+ * @return angle in degress from 0-360.
+ */
+ public double getAngle(Point screenPoint) {
+ double dx = screenPoint.getX() - mCenterX;
+ // Minus to correct for coord re-mapping
+ double dy = -(screenPoint.getY() - mCenterY);
+
+ double inRads = Math.atan2(dy, dx);
+
+ // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12
+ // O'clock
+ if (inRads < 0)
+ inRads = Math.abs(inRads);
+ else
+ inRads = 2 * Math.PI - inRads;
+
+ return Math.toDegrees(inRads);
+ }
+
+ /**
+ * Checks if Point falls within PieChart
+ *
+ * @param screenPoint
+ * @return true if in PieChart
+ */
+ public boolean isOnPieChart(Point screenPoint) {
+ // Using a bit of Pythagoras
+ // inside circle if (x-center_x)**2 + (y-center_y)**2 <= radius**2:
+
+ double sqValue = (Math.pow(mCenterX - screenPoint.getX(), 2) + Math.pow(
+ mCenterY - screenPoint.getY(), 2));
+
+ double radiusSquared = mPieChartRadius * mPieChartRadius;
+ boolean isOnPieChart = sqValue <= radiusSquared;
+ return isOnPieChart;
+ }
+
+ /**
+ * Fetches the SeriesSelection for the PieSegment selected.
+ *
+ * @param screenPoint - the user tap location
+ * @return null if screen point is not in PieChart or its config if it is
+ */
+ public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
+ if (isOnPieChart(screenPoint)) {
+ double angleFromPieCenter = getAngle(screenPoint);
+
+ for (PieSegment pieSeg : mPieSegmentList) {
+ if (pieSeg.isInSegment(angleFromPieCenter)) {
+ return new SeriesSelection(0, pieSeg.getDataIndex(), pieSeg.getValue(),
+ pieSeg.getValue());
+ }
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.io.Serializable;
+
+/**
+ * Holds An PieChart Segment
+ */
+public class PieSegment implements Serializable {
+ private float mStartAngle;
+
+ private float mEndAngle;
+
+ private int mDataIndex;
+
+ private float mValue;
+
+ public PieSegment(int dataIndex, float value, float startAngle, float angle) {
+ mStartAngle = startAngle;
+ mEndAngle = angle + startAngle;
+ mDataIndex = dataIndex;
+ mValue = value;
+ }
+
+ /**
+ * Checks if angle falls in segment.
+ *
+ * @param angle
+ * @return true if in segment, false otherwise.
+ */
+ public boolean isInSegment(double angle) {
+ return angle >= mStartAngle && angle <= mEndAngle;
+ }
+
+ protected float getStartAngle() {
+ return mStartAngle;
+ }
+
+ protected float getEndAngle() {
+ return mEndAngle;
+ }
+
+ protected int getDataIndex() {
+ return mDataIndex;
+ }
+
+ protected float getValue() {
+ return mValue;
+ }
+
+ public String toString() {
+ return "mDataIndex=" + mDataIndex + ",mValue=" + mValue + ",mStartAngle=" + mStartAngle
+ + ",mEndAngle=" + mEndAngle;
+ }
+
+}
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+/**
+ * The chart point style enumerator.
+ */
+public enum PointStyle {
+ X("x"), CIRCLE("circle"), TRIANGLE("triangle"), SQUARE("square"), DIAMOND("diamond"), POINT(
+ "point");
+
+ /** The point shape name. */
+ private String mName;
+
+ /**
+ * The point style enum constructor.
+ *
+ * @param name the name
+ */
+ private PointStyle(String name) {
+ mName = name;
+ }
+
+ /**
+ * Returns the point shape name.
+ *
+ * @return the point shape name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the point shape name.
+ *
+ * @return the point shape name
+ */
+ public String toString() {
+ return getName();
+ }
+
+ /**
+ * Return the point shape that has the provided symbol.
+ *
+ * @param name the point style name
+ * @return the point shape
+ */
+ public static PointStyle getPointStyleForName(String name) {
+ PointStyle pointStyle = null;
+ PointStyle[] styles = values();
+ int length = styles.length;
+ for (int i = 0; i < length && pointStyle == null; i++) {
+ if (styles[i].mName.equals(name)) {
+ pointStyle = styles[i];
+ }
+ }
+ return pointStyle;
+ }
+
+ /**
+ * Returns the point shape index based on the given name.
+ *
+ * @return the point shape index
+ */
+ public static int getIndexForName(String name) {
+ int index = -1;
+ PointStyle[] styles = values();
+ int length = styles.length;
+ for (int i = 0; i < length && index < 0; i++) {
+ if (styles[i].mName.equals(name)) {
+ index = i;
+ }
+ }
+ return Math.max(0, index);
+ }
+
+}
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+\r
+/**\r
+ * The range bar chart rendering class.\r
+ */\r
+public class RangeBarChart extends BarChart {\r
+ /** The chart type. */\r
+ public static final String TYPE = "RangeBar";\r
+\r
+ RangeBarChart() {\r
+ }\r
+\r
+ RangeBarChart(Type type) {\r
+ super(type);\r
+ }\r
+\r
+ /**\r
+ * Builds a new range bar chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ * @param type the range bar chart type\r
+ */\r
+ public RangeBarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+ super(dataset, renderer, type);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ int length = points.length;\r
+ paint.setColor(seriesRenderer.getColor());\r
+ paint.setStyle(Style.FILL);\r
+ float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+ int start = 0;\r
+ if (startIndex > 0) {\r
+ start = 2;\r
+ }\r
+ for (int i = start; i < length; i += 4) {\r
+ if (points.length > i + 3) {\r
+ float xMin = points[i];\r
+ float yMin = points[i + 1];\r
+ // xMin = xMax\r
+ float xMax = points[i + 2];\r
+ float yMax = points[i + 3];\r
+ drawBar(canvas, xMin, yMin, xMax, yMax, halfDiffX, seriesNr, seriesIndex, paint);\r
+ }\r
+ }\r
+ paint.setColor(seriesRenderer.getColor());\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the series values as text.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param series the series to be painted\r
+ * @param renderer the series renderer\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+ Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+ int seriesNr = mDataset.getSeriesCount();\r
+ float halfDiffX = getHalfDiffX(points, points.length, seriesNr);\r
+ int start = 0;\r
+ if (startIndex > 0) {\r
+ start = 2;\r
+ }\r
+ for (int i = start; i < points.length; i += 4) {\r
+ int index = startIndex + i / 2;\r
+ float x = points[i];\r
+ if (mType == Type.DEFAULT) {\r
+ x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;\r
+ }\r
+\r
+ if (!isNullValue(series.getY(index + 1)) && points.length > i + 3) {\r
+ // draw the maximum value\r
+ drawText(canvas, getLabel(series.getY(index + 1)), x,\r
+ points[i + 3] - renderer.getChartValuesSpacing(), paint, 0);\r
+ }\r
+ if (!isNullValue(series.getY(index)) && points.length > i + 1) {\r
+ // draw the minimum value\r
+ drawText(canvas, getLabel(series.getY(index)), x,\r
+ points[i + 1] + renderer.getChartValuesTextSize() + renderer.getChartValuesSpacing()\r
+ - 3, paint, 0);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the value of a constant used to calculate the half-distance.\r
+ * \r
+ * @return the constant value\r
+ */\r
+ protected float getCoeficient() {\r
+ return 0.5f;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+public class RangeStackedBarChart extends RangeBarChart {\r
+ /** The chart type. */\r
+ public static final String TYPE = "RangeStackedBar";\r
+\r
+ RangeStackedBarChart() {\r
+ super(Type.STACKED);\r
+ }\r
+\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * An abstract class to be extended by round like chart rendering classes.\r
+ */\r
+public abstract class RoundChart extends AbstractChart {\r
+ /** The legend shape width. */\r
+ protected static final int SHAPE_WIDTH = 10;\r
+ /** The series dataset. */\r
+ protected CategorySeries mDataset;\r
+ /** The series renderer. */\r
+ protected DefaultRenderer mRenderer;\r
+ /** A no value constant. */\r
+ protected static final int NO_VALUE = Integer.MAX_VALUE;\r
+ /** The chart center X axis. */\r
+ protected int mCenterX = NO_VALUE;\r
+ /** The chart center y axis. */\r
+ protected int mCenterY = NO_VALUE;\r
+\r
+ /**\r
+ * Round chart.\r
+ * \r
+ * @param dataset the series dataset\r
+ * @param renderer the series renderer\r
+ */\r
+ public RoundChart(CategorySeries dataset, DefaultRenderer renderer) {\r
+ mDataset = dataset;\r
+ mRenderer = renderer;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the round chart title.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param paint the paint\r
+ */\r
+ public void drawTitle(Canvas canvas, int x, int y, int width, Paint paint) {\r
+ if (mRenderer.isShowLabels()) {\r
+ paint.setColor(mRenderer.getLabelsColor());\r
+ paint.setTextAlign(Align.CENTER);\r
+ paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+ drawString(canvas, mRenderer.getChartTitle(), x + width / 2,\r
+ y + mRenderer.getChartTitleTextSize(), paint);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ canvas.drawRect(x, y - SHAPE_WIDTH / 2, x + SHAPE_WIDTH, y + SHAPE_WIDTH / 2, paint);\r
+ }\r
+\r
+ /**\r
+ * Returns the renderer.\r
+ * \r
+ * @return the renderer\r
+ */\r
+ public DefaultRenderer getRenderer() {\r
+ return mRenderer;\r
+ }\r
+\r
+ /**\r
+ * Returns the center on X axis.\r
+ * \r
+ * @return the center on X axis\r
+ */\r
+ public int getCenterX() {\r
+ return mCenterX;\r
+ }\r
+\r
+ /**\r
+ * Returns the center on Y axis.\r
+ * \r
+ * @return the center on Y axis\r
+ */\r
+ public int getCenterY() {\r
+ return mCenterY;\r
+ }\r
+\r
+ /**\r
+ * Sets a new center on X axis.\r
+ * \r
+ * @param centerX center on X axis\r
+ */\r
+ public void setCenterX(int centerX) {\r
+ mCenterX = centerX;\r
+ }\r
+\r
+ /**\r
+ * Sets a new center on Y axis.\r
+ * \r
+ * @param centerY center on Y axis\r
+ */\r
+ public void setCenterY(int centerY) {\r
+ mCenterY = centerY;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The scatter chart rendering class.\r
+ */\r
+public class ScatterChart extends XYChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Scatter";\r
+ /** The default point shape size. */\r
+ private static final float SIZE = 3;\r
+ /** The legend shape width. */\r
+ private static final int SHAPE_WIDTH = 10;\r
+ /** The point shape size. */\r
+ private float size = SIZE;\r
+\r
+ ScatterChart() {\r
+ }\r
+\r
+ /**\r
+ * Builds a new scatter chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ */\r
+ public ScatterChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ super(dataset, renderer);\r
+ size = renderer.getPointSize();\r
+ }\r
+\r
+ // TODO: javadoc\r
+ protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ super.setDatasetRenderer(dataset, renderer);\r
+ size = renderer.getPointSize();\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+ XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+ paint.setColor(renderer.getColor());\r
+ if (renderer.isFillPoints()) {\r
+ paint.setStyle(Style.FILL);\r
+ } else {\r
+ paint.setStyle(Style.STROKE);\r
+ }\r
+ int length = points.length;\r
+ switch (renderer.getPointStyle()) {\r
+ case X:\r
+ for (int i = 0; i < length; i += 2) {\r
+ drawX(canvas, paint, points[i], points[i + 1]);\r
+ }\r
+ break;\r
+ case CIRCLE:\r
+ for (int i = 0; i < length; i += 2) {\r
+ drawCircle(canvas, paint, points[i], points[i + 1]);\r
+ }\r
+ break;\r
+ case TRIANGLE:\r
+ float[] path = new float[6];\r
+ for (int i = 0; i < length; i += 2) {\r
+ drawTriangle(canvas, paint, path, points[i], points[i + 1]);\r
+ }\r
+ break;\r
+ case SQUARE:\r
+ for (int i = 0; i < length; i += 2) {\r
+ drawSquare(canvas, paint, points[i], points[i + 1]);\r
+ }\r
+ break;\r
+ case DIAMOND:\r
+ path = new float[8];\r
+ for (int i = 0; i < length; i += 2) {\r
+ drawDiamond(canvas, paint, path, points[i], points[i + 1]);\r
+ }\r
+ break;\r
+ case POINT:\r
+ canvas.drawPoints(points, paint);\r
+ break;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex) {\r
+ int length = points.length;\r
+ ClickableArea[] ret = new ClickableArea[length / 2];\r
+ for (int i = 0; i < length; i += 2) {\r
+ int selectableBuffer = mRenderer.getSelectableBuffer();\r
+ ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]\r
+ - selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),\r
+ values[i], values[i + 1]);\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ /**\r
+ * Returns the legend shape width.\r
+ * \r
+ * @param seriesIndex the series index\r
+ * @return the legend shape width\r
+ */\r
+ public int getLegendShapeWidth(int seriesIndex) {\r
+ return SHAPE_WIDTH;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the legend shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param renderer the series renderer\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ * @param seriesIndex the series index\r
+ * @param paint the paint to be used for drawing\r
+ */\r
+ public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+ int seriesIndex, Paint paint) {\r
+ if (((XYSeriesRenderer) renderer).isFillPoints()) {\r
+ paint.setStyle(Style.FILL);\r
+ } else {\r
+ paint.setStyle(Style.STROKE);\r
+ }\r
+ switch (((XYSeriesRenderer) renderer).getPointStyle()) {\r
+ case X:\r
+ drawX(canvas, paint, x + SHAPE_WIDTH, y);\r
+ break;\r
+ case CIRCLE:\r
+ drawCircle(canvas, paint, x + SHAPE_WIDTH, y);\r
+ break;\r
+ case TRIANGLE:\r
+ drawTriangle(canvas, paint, new float[6], x + SHAPE_WIDTH, y);\r
+ break;\r
+ case SQUARE:\r
+ drawSquare(canvas, paint, x + SHAPE_WIDTH, y);\r
+ break;\r
+ case DIAMOND:\r
+ drawDiamond(canvas, paint, new float[8], x + SHAPE_WIDTH, y);\r
+ break;\r
+ case POINT:\r
+ canvas.drawPoint(x + SHAPE_WIDTH, y, paint);\r
+ break;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of an X point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ */\r
+ private void drawX(Canvas canvas, Paint paint, float x, float y) {\r
+ canvas.drawLine(x - size, y - size, x + size, y + size, paint);\r
+ canvas.drawLine(x + size, y - size, x - size, y + size, paint);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a circle point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ */\r
+ private void drawCircle(Canvas canvas, Paint paint, float x, float y) {\r
+ canvas.drawCircle(x, y, size, paint);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a triangle point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param path the triangle path\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ */\r
+ private void drawTriangle(Canvas canvas, Paint paint, float[] path, float x, float y) {\r
+ path[0] = x;\r
+ path[1] = y - size - size / 2;\r
+ path[2] = x - size;\r
+ path[3] = y + size;\r
+ path[4] = x + size;\r
+ path[5] = path[3];\r
+ drawPath(canvas, path, paint, true);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a square point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ */\r
+ private void drawSquare(Canvas canvas, Paint paint, float x, float y) {\r
+ canvas.drawRect(x - size, y - size, x + size, y + size, paint);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a diamond point shape.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param path the diamond path\r
+ * @param x the x value of the point the shape should be drawn at\r
+ * @param y the y value of the point the shape should be drawn at\r
+ */\r
+ private void drawDiamond(Canvas canvas, Paint paint, float[] path, float x, float y) {\r
+ path[0] = x;\r
+ path[1] = y - size;\r
+ path[2] = x - size;\r
+ path[3] = y;\r
+ path[4] = x;\r
+ path[5] = y + size;\r
+ path[6] = x + size;\r
+ path[7] = y;\r
+ drawPath(canvas, path, paint, true);\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.text.DateFormat;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+\r
+/**\r
+ * The time chart rendering class.\r
+ */\r
+public class TimeChart extends LineChart {\r
+ /** The constant to identify this chart type. */\r
+ public static final String TYPE = "Time";\r
+ /** The number of milliseconds in a day. */\r
+ public static final long DAY = 24 * 60 * 60 * 1000;\r
+ /** The date format pattern to be used in formatting the X axis labels. */\r
+ private String mDateFormat;\r
+ /** The starting point for labels. */\r
+ private Double mStartPoint;\r
+\r
+ TimeChart() {\r
+ }\r
+\r
+ /**\r
+ * Builds a new time chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ */\r
+ public TimeChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ super(dataset, renderer);\r
+ }\r
+\r
+ /**\r
+ * Returns the date format pattern to be used for formatting the X axis\r
+ * labels.\r
+ * \r
+ * @return the date format pattern for the X axis labels\r
+ */\r
+ public String getDateFormat() {\r
+ return mDateFormat;\r
+ }\r
+\r
+ /**\r
+ * Sets the date format pattern to be used for formatting the X axis labels.\r
+ * \r
+ * @param format the date format pattern for the X axis labels. If null, an\r
+ * appropriate default format will be used.\r
+ */\r
+ public void setDateFormat(String format) {\r
+ mDateFormat = format;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the labels on the X axis.\r
+ * \r
+ * @param xLabels the X labels values\r
+ * @param xTextLabelLocations the X text label locations\r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param left the left value of the labels area\r
+ * @param top the top value of the labels area\r
+ * @param bottom the bottom value of the labels area\r
+ * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+ * @param minX the minimum value on the X axis in the chart\r
+ * @param maxX the maximum value on the X axis in the chart\r
+ */\r
+ @Override\r
+ protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,\r
+ Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {\r
+ int length = xLabels.size();\r
+ if (length > 0) {\r
+ boolean showLabels = mRenderer.isShowLabels();\r
+ boolean showGridY = mRenderer.isShowGridY();\r
+ DateFormat format = getDateFormat(xLabels.get(0), xLabels.get(length - 1));\r
+ for (int i = 0; i < length; i++) {\r
+ long label = Math.round(xLabels.get(i));\r
+ float xLabel = (float) (left + xPixelsPerUnit * (label - minX));\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getXLabelsColor());\r
+ canvas\r
+ .drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+ drawText(canvas, format.format(new Date(label)), xLabel,\r
+ bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());\r
+ }\r
+ if (showGridY) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+ }\r
+ }\r
+ }\r
+ drawXTextLabels(xTextLabelLocations, canvas, paint, true, left, top, bottom, xPixelsPerUnit,\r
+ minX, maxX);\r
+ }\r
+\r
+ /**\r
+ * Returns the date format pattern to be used, based on the date range.\r
+ * \r
+ * @param start the start date in milliseconds\r
+ * @param end the end date in milliseconds\r
+ * @return the date format\r
+ */\r
+ private DateFormat getDateFormat(double start, double end) {\r
+ if (mDateFormat != null) {\r
+ SimpleDateFormat format = null;\r
+ try {\r
+ format = new SimpleDateFormat(mDateFormat);\r
+ return format;\r
+ } catch (Exception e) {\r
+ // do nothing here\r
+ }\r
+ }\r
+ DateFormat format = SimpleDateFormat.getDateInstance(SimpleDateFormat.MEDIUM);\r
+ double diff = end - start;\r
+ if (diff > DAY && diff < 5 * DAY) {\r
+ format = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);\r
+ } else if (diff < DAY) {\r
+ format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM);\r
+ }\r
+ return format;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public String getChartType() {\r
+ return TYPE;\r
+ }\r
+\r
+ protected List<Double> getXLabels(double min, double max, int count) {\r
+ final List<Double> result = new ArrayList<Double>();\r
+ if (!mRenderer.isXRoundedLabels()) {\r
+ if (mDataset.getSeriesCount() > 0) {\r
+ XYSeries series = mDataset.getSeriesAt(0);\r
+ int length = series.getItemCount();\r
+ int intervalLength = 0;\r
+ int startIndex = -1;\r
+ for (int i = 0; i < length; i++) {\r
+ double value = series.getX(i);\r
+ if (min <= value && value <= max) {\r
+ intervalLength++;\r
+ if (startIndex < 0) {\r
+ startIndex = i;\r
+ }\r
+ }\r
+ }\r
+ if (intervalLength < count) {\r
+ for (int i = startIndex; i < startIndex + intervalLength; i++) {\r
+ result.add(series.getX(i));\r
+ }\r
+ } else {\r
+ float step = (float) intervalLength / count;\r
+ int intervalCount = 0;\r
+ for (int i = 0; i < length && intervalCount < count; i++) {\r
+ double value = series.getX(Math.round(i * step));\r
+ if (min <= value && value <= max) {\r
+ result.add(value);\r
+ intervalCount++;\r
+ }\r
+ }\r
+ }\r
+ return result;\r
+ } else {\r
+ return super.getXLabels(min, max, count);\r
+ }\r
+ }\r
+ if (mStartPoint == null) {\r
+ mStartPoint = min - (min % DAY) + DAY + new Date(Math.round(min)).getTimezoneOffset() * 60\r
+ * 1000;\r
+ }\r
+ if (count > 25) {\r
+ count = 25;\r
+ }\r
+\r
+ \r
+ final double cycleMath = (max - min) / count;\r
+ if (cycleMath <= 0) {\r
+ return result;\r
+ }\r
+ double cycle = DAY;\r
+\r
+ if (cycleMath <= DAY) {\r
+ while (cycleMath < cycle / 2) {\r
+ cycle = cycle / 2;\r
+ }\r
+ } else {\r
+ while (cycleMath > cycle) {\r
+ cycle = cycle * 2;\r
+ }\r
+ }\r
+\r
+ double val = mStartPoint - Math.floor((mStartPoint - min) / cycle) * cycle;\r
+ int i = 0;\r
+ while (val < max && i++ <= count) {\r
+ result.add(val);\r
+ val += cycle;\r
+ }\r
+\r
+ return result;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.SortedMap;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.BasicStroke;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.DashPathEffect;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Cap;\r
+import android.graphics.Paint.Join;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.PathEffect;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+import android.graphics.Typeface;\r
+\r
+/**\r
+ * The XY chart rendering class.\r
+ */\r
+public abstract class XYChart extends AbstractChart {\r
+ /** The multiple series dataset. */\r
+ protected XYMultipleSeriesDataset mDataset;\r
+ /** The multiple series renderer. */\r
+ protected XYMultipleSeriesRenderer mRenderer;\r
+ /** The current scale value. */\r
+ private float mScale;\r
+ /** The current translate value. */\r
+ private float mTranslate;\r
+ /** The canvas center point. */\r
+ private Point mCenter;\r
+ /** The visible chart area, in screen coordinates. */\r
+ private Rect mScreenR;\r
+ /** The calculated range. */\r
+ private final Map<Integer, double[]> mCalcRange = new HashMap<Integer, double[]>();\r
+\r
+ /**\r
+ * The clickable areas for all points. The array index is the series index,\r
+ * and the RectF list index is the point index in that series.\r
+ */\r
+ private Map<Integer, List<ClickableArea>> clickableAreas = new HashMap<Integer, List<ClickableArea>>();\r
+\r
+ protected XYChart() {\r
+ }\r
+\r
+ /**\r
+ * Builds a new XY chart instance.\r
+ * \r
+ * @param dataset the multiple series dataset\r
+ * @param renderer the multiple series renderer\r
+ */\r
+ public XYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+ mDataset = dataset;\r
+ mRenderer = renderer;\r
+ }\r
+\r
+ // TODO: javadoc\r
+ protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+ XYMultipleSeriesRenderer renderer) {\r
+ mDataset = dataset;\r
+ mRenderer = renderer;\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the XY chart.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param x the top left x value of the view to draw to\r
+ * @param y the top left y value of the view to draw to\r
+ * @param width the width of the view to draw to\r
+ * @param height the height of the view to draw to\r
+ * @param paint the paint\r
+ */\r
+ public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+ paint.setAntiAlias(mRenderer.isAntialiasing());\r
+ int legendSize = getLegendSize(mRenderer, height / 5, mRenderer.getAxisTitleTextSize());\r
+ int[] margins = mRenderer.getMargins();\r
+ int left = x + margins[1];\r
+ int top = y + margins[0];\r
+ int right = x + width - margins[3];\r
+ int sLength = mDataset.getSeriesCount();\r
+ String[] titles = new String[sLength];\r
+ for (int i = 0; i < sLength; i++) {\r
+ titles[i] = mDataset.getSeriesAt(i).getTitle();\r
+ }\r
+ if (mRenderer.isFitLegend() && mRenderer.isShowLegend()) {\r
+ legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,\r
+ paint, true);\r
+ }\r
+ int bottom = y + height - margins[2] - legendSize;\r
+ if (mScreenR == null) {\r
+ mScreenR = new Rect();\r
+ }\r
+ mScreenR.set(left, top, right, bottom);\r
+ drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+\r
+ if (paint.getTypeface() == null\r
+ || !paint.getTypeface().toString().equals(mRenderer.getTextTypefaceName())\r
+ || paint.getTypeface().getStyle() != mRenderer.getTextTypefaceStyle()) {\r
+ paint.setTypeface(Typeface.create(mRenderer.getTextTypefaceName(),\r
+ mRenderer.getTextTypefaceStyle()));\r
+ }\r
+ Orientation or = mRenderer.getOrientation();\r
+ if (or == Orientation.VERTICAL) {\r
+ right -= legendSize;\r
+ bottom += legendSize - 20;\r
+ }\r
+ int angle = or.getAngle();\r
+ boolean rotate = angle == 90;\r
+ mScale = (float) (height) / width;\r
+ mTranslate = Math.abs(width - height) / 2;\r
+ if (mScale < 1) {\r
+ mTranslate *= -1;\r
+ }\r
+ mCenter = new Point((x + width) / 2, (y + height) / 2);\r
+ if (rotate) {\r
+ transform(canvas, angle, false);\r
+ }\r
+\r
+ int maxScaleNumber = -Integer.MAX_VALUE;\r
+ for (int i = 0; i < sLength; i++) {\r
+ maxScaleNumber = Math.max(maxScaleNumber, mDataset.getSeriesAt(i).getScaleNumber());\r
+ }\r
+ maxScaleNumber++;\r
+ if (maxScaleNumber < 0) {\r
+ return;\r
+ }\r
+ double[] minX = new double[maxScaleNumber];\r
+ double[] maxX = new double[maxScaleNumber];\r
+ double[] minY = new double[maxScaleNumber];\r
+ double[] maxY = new double[maxScaleNumber];\r
+ boolean[] isMinXSet = new boolean[maxScaleNumber];\r
+ boolean[] isMaxXSet = new boolean[maxScaleNumber];\r
+ boolean[] isMinYSet = new boolean[maxScaleNumber];\r
+ boolean[] isMaxYSet = new boolean[maxScaleNumber];\r
+\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ minX[i] = mRenderer.getXAxisMin(i);\r
+ maxX[i] = mRenderer.getXAxisMax(i);\r
+ minY[i] = mRenderer.getYAxisMin(i);\r
+ maxY[i] = mRenderer.getYAxisMax(i);\r
+ isMinXSet[i] = mRenderer.isMinXSet(i);\r
+ isMaxXSet[i] = mRenderer.isMaxXSet(i);\r
+ isMinYSet[i] = mRenderer.isMinYSet(i);\r
+ isMaxYSet[i] = mRenderer.isMaxYSet(i);\r
+ if (mCalcRange.get(i) == null) {\r
+ mCalcRange.put(i, new double[4]);\r
+ }\r
+ }\r
+ double[] xPixelsPerUnit = new double[maxScaleNumber];\r
+ double[] yPixelsPerUnit = new double[maxScaleNumber];\r
+ for (int i = 0; i < sLength; i++) {\r
+ XYSeries series = mDataset.getSeriesAt(i);\r
+ int scale = series.getScaleNumber();\r
+ if (series.getItemCount() == 0) {\r
+ continue;\r
+ }\r
+ if (!isMinXSet[scale]) {\r
+ double minimumX = series.getMinX();\r
+ minX[scale] = Math.min(minX[scale], minimumX);\r
+ mCalcRange.get(scale)[0] = minX[scale];\r
+ }\r
+ if (!isMaxXSet[scale]) {\r
+ double maximumX = series.getMaxX();\r
+ maxX[scale] = Math.max(maxX[scale], maximumX);\r
+ mCalcRange.get(scale)[1] = maxX[scale];\r
+ }\r
+ if (!isMinYSet[scale]) {\r
+ double minimumY = series.getMinY();\r
+ minY[scale] = Math.min(minY[scale], (float) minimumY);\r
+ mCalcRange.get(scale)[2] = minY[scale];\r
+ }\r
+ if (!isMaxYSet[scale]) {\r
+ double maximumY = series.getMaxY();\r
+ maxY[scale] = Math.max(maxY[scale], (float) maximumY);\r
+ mCalcRange.get(scale)[3] = maxY[scale];\r
+ }\r
+ }\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ if (maxX[i] - minX[i] != 0) {\r
+ xPixelsPerUnit[i] = (right - left) / (maxX[i] - minX[i]);\r
+ }\r
+ if (maxY[i] - minY[i] != 0) {\r
+ yPixelsPerUnit[i] = (float) ((bottom - top) / (maxY[i] - minY[i]));\r
+ }\r
+ }\r
+\r
+ boolean hasValues = false;\r
+ // use a linked list for these reasons:\r
+ // 1) Avoid a large contiguous memory allocation\r
+ // 2) We don't need random seeking, only sequential reading/writing, so\r
+ // linked list makes sense\r
+ clickableAreas = new HashMap<Integer, List<ClickableArea>>();\r
+ for (int i = 0; i < sLength; i++) {\r
+ XYSeries series = mDataset.getSeriesAt(i);\r
+ int scale = series.getScaleNumber();\r
+ if (series.getItemCount() == 0) {\r
+ continue;\r
+ }\r
+\r
+ hasValues = true;\r
+ SimpleSeriesRenderer seriesRenderer = mRenderer.getSeriesRendererAt(i);\r
+\r
+ // int originalValuesLength = series.getItemCount();\r
+ // int valuesLength = originalValuesLength;\r
+ // int length = valuesLength * 2;\r
+\r
+ List<Float> points = new ArrayList<Float>();\r
+ List<Double> values = new ArrayList<Double>();\r
+ float yAxisValue = Math.min(bottom, (float) (bottom + yPixelsPerUnit[scale] * minY[scale]));\r
+ LinkedList<ClickableArea> clickableArea = new LinkedList<ClickableArea>();\r
+\r
+ clickableAreas.put(i, clickableArea);\r
+\r
+ SortedMap<Double, Double> range = series.getRange(minX[scale], maxX[scale], 1);\r
+ int startIndex = -1;\r
+\r
+ for (Entry<Double, Double> value : range.entrySet()) {\r
+\r
+ double xValue = value.getKey();\r
+ double yValue = value.getValue();\r
+ if (startIndex < 0) {\r
+ startIndex = series.getIndexForKey(xValue);\r
+ }\r
+\r
+ // points.add((float) (left + xPixelsPerUnit[scale]\r
+ // * (value.getKey().floatValue() - minX[scale])));\r
+ // points.add((float) (bottom - yPixelsPerUnit[scale]\r
+ // * (value.getValue().floatValue() - minY[scale])));\r
+ values.add(value.getKey());\r
+ values.add(value.getValue());\r
+\r
+ if (!isNullValue(yValue)) {\r
+ points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));\r
+ points.add((float) (bottom - yPixelsPerUnit[scale] * (yValue - minY[scale])));\r
+ } else if (isRenderNullValues()) {\r
+ points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));\r
+ points.add((float) (bottom - yPixelsPerUnit[scale] * (-minY[scale])));\r
+ } else {\r
+ if (points.size() > 0) {\r
+ drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex);\r
+ ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(\r
+ MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i,\r
+ startIndex);\r
+ clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));\r
+ points.clear();\r
+ values.clear();\r
+ }\r
+ clickableArea.add(null);\r
+ }\r
+ }\r
+\r
+ if (points.size() > 0) {\r
+ drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex);\r
+ ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(\r
+ MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i, startIndex);\r
+ clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));\r
+ }\r
+ }\r
+\r
+ // draw stuff over the margins such as data doesn't render on these areas\r
+ drawBackground(mRenderer, canvas, x, bottom, width, height - bottom, paint, true,\r
+ mRenderer.getMarginsColor());\r
+ drawBackground(mRenderer, canvas, x, y, width, margins[0], paint, true,\r
+ mRenderer.getMarginsColor());\r
+ if (or == Orientation.HORIZONTAL) {\r
+ drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,\r
+ mRenderer.getMarginsColor());\r
+ drawBackground(mRenderer, canvas, right, y, margins[3], height - y, paint, true,\r
+ mRenderer.getMarginsColor());\r
+ } else if (or == Orientation.VERTICAL) {\r
+ drawBackground(mRenderer, canvas, right, y, width - right, height - y, paint, true,\r
+ mRenderer.getMarginsColor());\r
+ drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,\r
+ mRenderer.getMarginsColor());\r
+ }\r
+\r
+ boolean showLabels = mRenderer.isShowLabels() && hasValues;\r
+ boolean showGridX = mRenderer.isShowGridX();\r
+ boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();\r
+ if (showLabels || showGridX) {\r
+ List<Double> xLabels = getValidLabels(getXLabels(minX[0], maxX[0], mRenderer.getXLabels()));\r
+ Map<Integer, List<Double>> allYLabels = getYLabels(minY, maxY, maxScaleNumber);\r
+\r
+ int xLabelsLeft = left;\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getXLabelsColor());\r
+ paint.setTextSize(mRenderer.getLabelsTextSize());\r
+ paint.setTextAlign(mRenderer.getXLabelsAlign());\r
+ if (mRenderer.getXLabelsAlign() == Align.LEFT) {\r
+ xLabelsLeft += mRenderer.getLabelsTextSize() / 4;\r
+ }\r
+ }\r
+ drawXLabels(xLabels, mRenderer.getXTextLabelLocations(), canvas, paint, xLabelsLeft, top,\r
+ bottom, xPixelsPerUnit[0], minX[0], maxX[0]);\r
+ drawYLabels(allYLabels, canvas, paint, maxScaleNumber, left, right, bottom, yPixelsPerUnit,\r
+ minY);\r
+\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getLabelsColor());\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ Align axisAlign = mRenderer.getYAxisAlign(i);\r
+ Double[] yTextLabelLocations = mRenderer.getYTextLabelLocations(i);\r
+ for (Double location : yTextLabelLocations) {\r
+ if (minY[i] <= location && location <= maxY[i]) {\r
+ float yLabel = (float) (bottom - yPixelsPerUnit[i]\r
+ * (location.doubleValue() - minY[i]));\r
+ String label = mRenderer.getYTextLabel(location, i);\r
+ paint.setColor(mRenderer.getYLabelsColor(i));\r
+ paint.setTextAlign(mRenderer.getYLabelsAlign(i));\r
+ if (or == Orientation.HORIZONTAL) {\r
+ if (axisAlign == Align.LEFT) {\r
+ canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);\r
+ drawText(canvas, label, left, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+ } else {\r
+ canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);\r
+ drawText(canvas, label, right, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+ }\r
+ \r
+ if (showCustomTextGrid) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(left, yLabel, right, yLabel, paint);\r
+ }\r
+ } else {\r
+ canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);\r
+ drawText(canvas, label, right + 10, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+ if (showCustomTextGrid) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(right, yLabel, left, yLabel, paint);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getLabelsColor());\r
+ float size = mRenderer.getAxisTitleTextSize();\r
+ paint.setTextSize(size);\r
+ paint.setTextAlign(Align.CENTER);\r
+ if (or == Orientation.HORIZONTAL) {\r
+ drawText(canvas, mRenderer.getXTitle(), x + width / 2,\r
+ bottom + mRenderer.getLabelsTextSize() * 4 / 3 + size, paint, 0);\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ Align axisAlign = mRenderer.getYAxisAlign(i);\r
+ if (axisAlign == Align.LEFT) {\r
+ drawText(canvas, mRenderer.getYTitle(i), x + size, y + height / 2, paint, -90);\r
+ } else {\r
+ drawText(canvas, mRenderer.getYTitle(i), x + width, y + height / 2, paint, -90);\r
+ }\r
+ }\r
+ paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+ drawText(canvas, mRenderer.getChartTitle(), x + width / 2,\r
+ y + mRenderer.getChartTitleTextSize(), paint, 0);\r
+ } else if (or == Orientation.VERTICAL) {\r
+ drawText(canvas, mRenderer.getXTitle(), x + width / 2, y + height - size, paint, -90);\r
+ drawText(canvas, mRenderer.getYTitle(), right + 20, y + height / 2, paint, 0);\r
+ paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+ drawText(canvas, mRenderer.getChartTitle(), x + size, top + height / 2, paint, 0);\r
+ }\r
+ }\r
+ }\r
+ if (or == Orientation.HORIZONTAL) {\r
+ drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+ } else if (or == Orientation.VERTICAL) {\r
+ transform(canvas, angle, true);\r
+ drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+ transform(canvas, angle, false);\r
+ }\r
+ if (mRenderer.isShowAxes()) {\r
+ paint.setColor(mRenderer.getAxesColor());\r
+ canvas.drawLine(left, bottom, right, bottom, paint);\r
+ boolean rightAxis = false;\r
+ for (int i = 0; i < maxScaleNumber && !rightAxis; i++) {\r
+ rightAxis = mRenderer.getYAxisAlign(i) == Align.RIGHT;\r
+ }\r
+ if (or == Orientation.HORIZONTAL) {\r
+ canvas.drawLine(left, top, left, bottom, paint);\r
+ if (rightAxis) {\r
+ canvas.drawLine(right, top, right, bottom, paint);\r
+ }\r
+ } else if (or == Orientation.VERTICAL) {\r
+ canvas.drawLine(right, top, right, bottom, paint);\r
+ }\r
+ }\r
+ if (rotate) {\r
+ transform(canvas, angle, true);\r
+ }\r
+ }\r
+\r
+ protected List<Double> getXLabels(double min, double max, int count) {\r
+ return MathHelper.getLabels(min, max, count);\r
+ }\r
+\r
+ protected Map<Integer, List<Double>> getYLabels(double[] minY, double[] maxY, int maxScaleNumber) {\r
+ Map<Integer, List<Double>> allYLabels = new HashMap<Integer, List<Double>>();\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ allYLabels.put(i,\r
+ getValidLabels(MathHelper.getLabels(minY[i], maxY[i], mRenderer.getYLabels())));\r
+ }\r
+ return allYLabels;\r
+ }\r
+\r
+ protected Rect getScreenR() {\r
+ return mScreenR;\r
+ }\r
+\r
+ protected void setScreenR(Rect screenR) {\r
+ mScreenR = screenR;\r
+ }\r
+\r
+ private List<Double> getValidLabels(List<Double> labels) {\r
+ List<Double> result = new ArrayList<Double>(labels);\r
+ for (Double label : labels) {\r
+ if (label.isNaN()) {\r
+ result.remove(label);\r
+ }\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Draws the series.\r
+ * \r
+ * @param series the series\r
+ * @param canvas the canvas\r
+ * @param paint the paint object\r
+ * @param pointsList the points to be rendered\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the y axis value in pixels\r
+ * @param seriesIndex the series index\r
+ * @param or the orientation\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,\r
+ int startIndex) {\r
+ BasicStroke stroke = seriesRenderer.getStroke();\r
+ Cap cap = paint.getStrokeCap();\r
+ Join join = paint.getStrokeJoin();\r
+ float miter = paint.getStrokeMiter();\r
+ PathEffect pathEffect = paint.getPathEffect();\r
+ Style style = paint.getStyle();\r
+ if (stroke != null) {\r
+ PathEffect effect = null;\r
+ if (stroke.getIntervals() != null) {\r
+ effect = new DashPathEffect(stroke.getIntervals(), stroke.getPhase());\r
+ }\r
+ setStroke(stroke.getCap(), stroke.getJoin(), stroke.getMiter(), Style.FILL_AND_STROKE,\r
+ effect, paint);\r
+ }\r
+ float[] points = MathHelper.getFloats(pointsList);\r
+ drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex, startIndex);\r
+ if (isRenderPoints(seriesRenderer)) {\r
+ ScatterChart pointsChart = getPointsChart();\r
+ if (pointsChart != null) {\r
+ pointsChart.drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex,\r
+ startIndex);\r
+ }\r
+ }\r
+ paint.setTextSize(seriesRenderer.getChartValuesTextSize());\r
+ if (or == Orientation.HORIZONTAL) {\r
+ paint.setTextAlign(Align.CENTER);\r
+ } else {\r
+ paint.setTextAlign(Align.LEFT);\r
+ }\r
+ if (seriesRenderer.isDisplayChartValues()) {\r
+ paint.setTextAlign(seriesRenderer.getChartValuesTextAlign());\r
+ drawChartValuesText(canvas, series, seriesRenderer, paint, points, seriesIndex, startIndex);\r
+ }\r
+ if (stroke != null) {\r
+ setStroke(cap, join, miter, style, pathEffect, paint);\r
+ }\r
+ }\r
+\r
+ private void setStroke(Cap cap, Join join, float miter, Style style, PathEffect pathEffect,\r
+ Paint paint) {\r
+ paint.setStrokeCap(cap);\r
+ paint.setStrokeJoin(join);\r
+ paint.setStrokeMiter(miter);\r
+ paint.setPathEffect(pathEffect);\r
+ paint.setStyle(style);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the series values as text.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param series the series to be painted\r
+ * @param renderer the series renderer\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+ Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+ if (points.length > 1) { // there are more than one point\r
+ // record the first point's position\r
+ float previousPointX = points[0];\r
+ float previousPointY = points[1];\r
+ for (int k = 0; k < points.length; k += 2) {\r
+ if (k == 2) { // decide whether to display first two points' values or not\r
+ if (Math.abs(points[2]- points[0]) > 100 || Math.abs(points[3] - points[1]) > 100) {\r
+ // first point\r
+ drawText(canvas, getLabel(series.getY(startIndex)), points[0], points[1]\r
+ - renderer.getChartValuesSpacing(), paint, 0);\r
+ // second point\r
+ drawText(canvas, getLabel(series.getY(startIndex + 1)), points[2], points[3]\r
+ - renderer.getChartValuesSpacing(), paint, 0);\r
+\r
+ previousPointX = points[2];\r
+ previousPointY = points[3];\r
+ }\r
+ } else if (k > 2) {\r
+ // compare current point's position with the previous point's, if they are not too close, display\r
+ if (Math.abs(points[k]- previousPointX) > 100 || Math.abs(points[k+1] - previousPointY) > 100) {\r
+ drawText(canvas, getLabel(series.getY(startIndex + k / 2)), points[k], points[k + 1]\r
+ - renderer.getChartValuesSpacing(), paint, 0);\r
+ previousPointX = points[k];\r
+ previousPointY = points[k+1];\r
+ }\r
+ }\r
+ }\r
+ } else { // if only one point, display it\r
+ for (int k = 0; k < points.length; k += 2) {\r
+ drawText(canvas, getLabel(series.getY(startIndex + k / 2)), points[k], points[k + 1]\r
+ - renderer.getChartValuesSpacing(), paint, 0);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a text, to handle both HORIZONTAL and\r
+ * VERTICAL orientations and extra rotation angles.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param text the text to be rendered\r
+ * @param x the X axis location of the text\r
+ * @param y the Y axis location of the text\r
+ * @param paint the paint to be used for drawing\r
+ * @param extraAngle the text angle\r
+ */\r
+ protected void drawText(Canvas canvas, String text, float x, float y, Paint paint,\r
+ float extraAngle) {\r
+ float angle = -mRenderer.getOrientation().getAngle() + extraAngle;\r
+ if (angle != 0) {\r
+ // canvas.scale(1 / mScale, mScale);\r
+ canvas.rotate(angle, x, y);\r
+ }\r
+ drawString(canvas, text, x, y, paint);\r
+ if (angle != 0) {\r
+ canvas.rotate(-angle, x, y);\r
+ // canvas.scale(mScale, 1 / mScale);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Transform the canvas such as it can handle both HORIZONTAL and VERTICAL\r
+ * orientations.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param angle the angle of rotation\r
+ * @param inverse if the inverse transform needs to be applied\r
+ */\r
+ private void transform(Canvas canvas, float angle, boolean inverse) {\r
+ if (inverse) {\r
+ canvas.scale(1 / mScale, mScale);\r
+ canvas.translate(mTranslate, -mTranslate);\r
+ canvas.rotate(-angle, mCenter.getX(), mCenter.getY());\r
+ } else {\r
+ canvas.rotate(angle, mCenter.getX(), mCenter.getY());\r
+ canvas.translate(-mTranslate, mTranslate);\r
+ canvas.scale(mScale, 1 / mScale);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the labels on the X axis.\r
+ * \r
+ * @param xLabels the X labels values\r
+ * @param xTextLabelLocations the X text label locations\r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param left the left value of the labels area\r
+ * @param top the top value of the labels area\r
+ * @param bottom the bottom value of the labels area\r
+ * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+ * @param minX the minimum value on the X axis in the chart\r
+ * @param maxX the maximum value on the X axis in the chart\r
+ */\r
+ protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,\r
+ Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {\r
+ int length = xLabels.size();\r
+ boolean showLabels = mRenderer.isShowLabels();\r
+ boolean showGridY = mRenderer.isShowGridY();\r
+ for (int i = 0; i < length; i++) {\r
+ double label = xLabels.get(i);\r
+ float xLabel = (float) (left + xPixelsPerUnit * (label - minX));\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getXLabelsColor());\r
+ canvas.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+ drawText(canvas, getLabel(label), xLabel, bottom + mRenderer.getLabelsTextSize() * 4 / 3,\r
+ paint, mRenderer.getXLabelsAngle());\r
+ }\r
+ if (showGridY) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+ }\r
+ }\r
+ drawXTextLabels(xTextLabelLocations, canvas, paint, showLabels, left, top, bottom,\r
+ xPixelsPerUnit, minX, maxX);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the labels on the X axis.\r
+ * \r
+ * @param allYLabels the Y labels values\r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param maxScaleNumber the maximum scale number\r
+ * @param left the left value of the labels area\r
+ * @param right the right value of the labels area\r
+ * @param bottom the bottom value of the labels area\r
+ * @param yPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+ * @param minY the minimum value on the Y axis in the chart\r
+ */\r
+ protected void drawYLabels(Map<Integer, List<Double>> allYLabels, Canvas canvas, Paint paint,\r
+ int maxScaleNumber, int left, int right, int bottom, double[] yPixelsPerUnit, double[] minY) {\r
+ Orientation or = mRenderer.getOrientation();\r
+ boolean showGridX = mRenderer.isShowGridX();\r
+ boolean showLabels = mRenderer.isShowLabels();\r
+ for (int i = 0; i < maxScaleNumber; i++) {\r
+ paint.setTextAlign(mRenderer.getYLabelsAlign(i));\r
+ List<Double> yLabels = allYLabels.get(i);\r
+ int length = yLabels.size();\r
+ for (int j = 0; j < length; j++) {\r
+ double label = yLabels.get(j);\r
+ Align axisAlign = mRenderer.getYAxisAlign(i);\r
+ boolean textLabel = mRenderer.getYTextLabel(label, i) != null;\r
+ float yLabel = (float) (bottom - yPixelsPerUnit[i] * (label - minY[i]));\r
+ if (or == Orientation.HORIZONTAL) {\r
+ if (showLabels && !textLabel) {\r
+ paint.setColor(mRenderer.getYLabelsColor(i));\r
+ if (axisAlign == Align.LEFT) {\r
+ canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);\r
+ drawText(canvas, getLabel(label), left, yLabel - 2, paint,\r
+ mRenderer.getYLabelsAngle());\r
+ } else {\r
+ canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);\r
+ drawText(canvas, getLabel(label), right, yLabel - 2, paint,\r
+ mRenderer.getYLabelsAngle());\r
+ }\r
+ }\r
+ if (showGridX) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(left, yLabel, right, yLabel, paint);\r
+ }\r
+ } else if (or == Orientation.VERTICAL) {\r
+ if (showLabels && !textLabel) {\r
+ paint.setColor(mRenderer.getYLabelsColor(i));\r
+ canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);\r
+ drawText(canvas, getLabel(label), right + 10, yLabel - 2, paint,\r
+ mRenderer.getYLabelsAngle());\r
+ }\r
+ if (showGridX) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(right, yLabel, left, yLabel, paint);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of the text labels on the X axis.\r
+ * \r
+ * @param xTextLabelLocations the X text label locations\r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param left the left value of the labels area\r
+ * @param top the top value of the labels area\r
+ * @param bottom the bottom value of the labels area\r
+ * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+ * @param minX the minimum value on the X axis in the chart\r
+ * @param maxX the maximum value on the X axis in the chart\r
+ */\r
+ protected void drawXTextLabels(Double[] xTextLabelLocations, Canvas canvas, Paint paint,\r
+ boolean showLabels, int left, int top, int bottom, double xPixelsPerUnit, double minX,\r
+ double maxX) {\r
+ boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();\r
+ if (showLabels) {\r
+ paint.setColor(mRenderer.getXLabelsColor());\r
+ for (Double location : xTextLabelLocations) {\r
+ if (minX <= location && location <= maxX) {\r
+ float xLabel = (float) (left + xPixelsPerUnit * (location.doubleValue() - minX));\r
+ paint.setColor(mRenderer.getXLabelsColor());\r
+ canvas\r
+ .drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+ drawText(canvas, mRenderer.getXTextLabel(location), xLabel,\r
+ bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());\r
+ if (showCustomTextGrid) {\r
+ paint.setColor(mRenderer.getGridColor());\r
+ canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // TODO: docs\r
+ public XYMultipleSeriesRenderer getRenderer() {\r
+ return mRenderer;\r
+ }\r
+\r
+ public XYMultipleSeriesDataset getDataset() {\r
+ return mDataset;\r
+ }\r
+\r
+ public double[] getCalcRange(int scale) {\r
+ return mCalcRange.get(scale);\r
+ }\r
+\r
+ public void setCalcRange(double[] range, int scale) {\r
+ mCalcRange.put(scale, range);\r
+ }\r
+\r
+ public double[] toRealPoint(float screenX, float screenY) {\r
+ return toRealPoint(screenX, screenY, 0);\r
+ }\r
+\r
+ public double[] toScreenPoint(double[] realPoint) {\r
+ return toScreenPoint(realPoint, 0);\r
+ }\r
+\r
+ private int getLabelLinePos(Align align) {\r
+ int pos = 4;\r
+ if (align == Align.LEFT) {\r
+ pos = -pos;\r
+ }\r
+ return pos;\r
+ }\r
+\r
+ /**\r
+ * Transforms a screen point to a real coordinates point.\r
+ * \r
+ * @param screenX the screen x axis value\r
+ * @param screenY the screen y axis value\r
+ * @return the real coordinates point\r
+ */\r
+ public double[] toRealPoint(float screenX, float screenY, int scale) {\r
+ double realMinX = mRenderer.getXAxisMin(scale);\r
+ double realMaxX = mRenderer.getXAxisMax(scale);\r
+ double realMinY = mRenderer.getYAxisMin(scale);\r
+ double realMaxY = mRenderer.getYAxisMax(scale);\r
+ return new double[] {\r
+ (screenX - mScreenR.left) * (realMaxX - realMinX) / mScreenR.width() + realMinX,\r
+ (mScreenR.top + mScreenR.height() - screenY) * (realMaxY - realMinY) / mScreenR.height()\r
+ + realMinY };\r
+ }\r
+\r
+ public double[] toScreenPoint(double[] realPoint, int scale) {\r
+ double realMinX = mRenderer.getXAxisMin(scale);\r
+ double realMaxX = mRenderer.getXAxisMax(scale);\r
+ double realMinY = mRenderer.getYAxisMin(scale);\r
+ double realMaxY = mRenderer.getYAxisMax(scale);\r
+ if (!mRenderer.isMinXSet(scale) || !mRenderer.isMaxXSet(scale) || !mRenderer.isMinXSet(scale)\r
+ || !mRenderer.isMaxYSet(scale)) {\r
+ double[] calcRange = getCalcRange(scale);\r
+ realMinX = calcRange[0];\r
+ realMaxX = calcRange[1];\r
+ realMinY = calcRange[2];\r
+ realMaxY = calcRange[3];\r
+ }\r
+ return new double[] {\r
+ (realPoint[0] - realMinX) * mScreenR.width() / (realMaxX - realMinX) + mScreenR.left,\r
+ (realMaxY - realPoint[1]) * mScreenR.height() / (realMaxY - realMinY) + mScreenR.top };\r
+ }\r
+\r
+ public SeriesSelection getSeriesAndPointForScreenCoordinate(final Point screenPoint) {\r
+ if (clickableAreas != null)\r
+ for (int seriesIndex = clickableAreas.size() - 1; seriesIndex >= 0; seriesIndex--) {\r
+ // series 0 is drawn first. Then series 1 is drawn on top, and series 2\r
+ // on top of that.\r
+ // we want to know what the user clicked on, so traverse them in the\r
+ // order they appear on the screen.\r
+ int pointIndex = 0;\r
+ if (clickableAreas.get(seriesIndex) != null) {\r
+ RectF rectangle;\r
+ for (ClickableArea area : clickableAreas.get(seriesIndex)) {\r
+ rectangle = area.getRect();\r
+ if (rectangle != null && rectangle.contains(screenPoint.getX(), screenPoint.getY())) {\r
+ return new SeriesSelection(seriesIndex, pointIndex, area.getX(), area.getY());\r
+ }\r
+ pointIndex++;\r
+ }\r
+ }\r
+ }\r
+ return super.getSeriesAndPointForScreenCoordinate(screenPoint);\r
+ }\r
+\r
+ /**\r
+ * The graphical representation of a series.\r
+ * \r
+ * @param canvas the canvas to paint to\r
+ * @param paint the paint to be used for drawing\r
+ * @param points the array of points to be used for drawing the series\r
+ * @param seriesRenderer the series renderer\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series currently being drawn\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ public abstract void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+ SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex);\r
+\r
+ /**\r
+ * Returns the clickable areas for all passed points\r
+ * \r
+ * @param points the array of points\r
+ * @param values the array of values of each point\r
+ * @param yAxisValue the minimum value of the y axis\r
+ * @param seriesIndex the index of the series to which the points belong\r
+ * @return an array of rectangles with the clickable area\r
+ * @param startIndex the start index of the rendering points\r
+ */\r
+ protected abstract ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+ float yAxisValue, int seriesIndex, int startIndex);\r
+\r
+ /**\r
+ * Returns if the chart should display the null values.\r
+ * \r
+ * @return if null values should be rendered\r
+ */\r
+ protected boolean isRenderNullValues() {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart should display the points as a certain shape.\r
+ * \r
+ * @param renderer the series renderer\r
+ */\r
+ public boolean isRenderPoints(SimpleSeriesRenderer renderer) {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * Returns the default axis minimum.\r
+ * \r
+ * @return the default axis minimum\r
+ */\r
+ public double getDefaultMinimum() {\r
+ return MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the scatter chart to be used for drawing the data points.\r
+ * \r
+ * @return the data points scatter chart\r
+ */\r
+ public ScatterChart getPointsChart() {\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart type identifier.\r
+ * \r
+ * @return the chart type\r
+ */\r
+ public abstract String getChartType();\r
+\r
+}\r
--- /dev/null
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides the classes that handle the actual rendering / drawing of the charts, based on the provided model and renderer.\r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series for the category charts like the pie ones.\r
+ */\r
+public class CategorySeries implements Serializable {\r
+ /** The series title. */\r
+ private String mTitle;\r
+ /** The series categories. */\r
+ private List<String> mCategories = new ArrayList<String>();\r
+ /** The series values. */\r
+ private List<Double> mValues = new ArrayList<Double>();\r
+\r
+ /**\r
+ * Builds a new category series.\r
+ * \r
+ * @param title the series title\r
+ */\r
+ public CategorySeries(String title) {\r
+ mTitle = title;\r
+ }\r
+\r
+ /**\r
+ * Returns the series title.\r
+ * \r
+ * @return the series title\r
+ */\r
+ public String getTitle() {\r
+ return mTitle;\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series\r
+ * \r
+ * @param value the new value\r
+ */\r
+ public synchronized void add(double value) {\r
+ add(mCategories.size() + "", value);\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param category the category\r
+ * @param value the new value\r
+ */\r
+ public synchronized void add(String category, double value) {\r
+ mCategories.add(category);\r
+ mValues.add(value);\r
+ }\r
+\r
+ /**\r
+ * Replaces the value at the specific index in the series.\r
+ * \r
+ * @param index the index in the series\r
+ * @param category the category\r
+ * @param value the new value\r
+ */\r
+ public synchronized void set(int index, String category, double value) {\r
+ mCategories.set(index, category);\r
+ mValues.set(index, value);\r
+ }\r
+\r
+ /**\r
+ * Removes an existing value from the series.\r
+ * \r
+ * @param index the index in the series of the value to remove\r
+ */\r
+ public synchronized void remove(int index) {\r
+ mCategories.remove(index);\r
+ mValues.remove(index);\r
+ }\r
+\r
+ /**\r
+ * Removes all the existing values from the series.\r
+ */\r
+ public synchronized void clear() {\r
+ mCategories.clear();\r
+ mValues.clear();\r
+ }\r
+\r
+ /**\r
+ * Returns the value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the value at the index\r
+ */\r
+ public synchronized double getValue(int index) {\r
+ return mValues.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the category name at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the category name at the index\r
+ */\r
+ public synchronized String getCategory(int index) {\r
+ return mCategories.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the series item count.\r
+ * \r
+ * @return the series item count\r
+ */\r
+ public synchronized int getItemCount() {\r
+ return mCategories.size();\r
+ }\r
+\r
+ /**\r
+ * Transforms the category series to an XY series.\r
+ * \r
+ * @return the XY series\r
+ */\r
+ public XYSeries toXYSeries() {\r
+ XYSeries xySeries = new XYSeries(mTitle);\r
+ int k = 0;\r
+ for (double value : mValues) {\r
+ xySeries.add(++k, value);\r
+ }\r
+ return xySeries;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series for the multiple category charts like the doughnut.\r
+ */\r
+public class MultipleCategorySeries implements Serializable {\r
+ /** The series title. */\r
+ private String mTitle;\r
+ /** The series local keys. */\r
+ private List<String> mCategories = new ArrayList<String>();\r
+ /** The series name. */\r
+ private List<String[]> mTitles = new ArrayList<String[]>();\r
+ /** The series values. */\r
+ private List<double[]> mValues = new ArrayList<double[]>();\r
+\r
+ /**\r
+ * Builds a new category series.\r
+ * \r
+ * @param title the series title\r
+ */\r
+ public MultipleCategorySeries(String title) {\r
+ mTitle = title;\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series\r
+ * \r
+ * @param titles the titles to be used as labels\r
+ * @param values the new value\r
+ */\r
+ public void add(String[] titles, double[] values) {\r
+ add(mCategories.size() + "", titles, values);\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param category the category name\r
+ * @param titles the titles to be used as labels\r
+ * @param values the new value\r
+ */\r
+ public void add(String category, String[] titles, double[] values) {\r
+ mCategories.add(category);\r
+ mTitles.add(titles);\r
+ mValues.add(values);\r
+ }\r
+\r
+ /**\r
+ * Removes an existing value from the series.\r
+ * \r
+ * @param index the index in the series of the value to remove\r
+ */\r
+ public void remove(int index) {\r
+ mCategories.remove(index);\r
+ mTitles.remove(index);\r
+ mValues.remove(index);\r
+ }\r
+\r
+ /**\r
+ * Removes all the existing values from the series.\r
+ */\r
+ public void clear() {\r
+ mCategories.clear();\r
+ mTitles.clear();\r
+ mValues.clear();\r
+ }\r
+\r
+ /**\r
+ * Returns the values at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the value at the index\r
+ */\r
+ public double[] getValues(int index) {\r
+ return mValues.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the category name at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the category name at the index\r
+ */\r
+ public String getCategory(int index) {\r
+ return mCategories.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the categories count.\r
+ * \r
+ * @return the categories count\r
+ */\r
+ public int getCategoriesCount() {\r
+ return mCategories.size();\r
+ }\r
+\r
+ /**\r
+ * Returns the series item count.\r
+ * \r
+ * @param index the index\r
+ * @return the series item count\r
+ */\r
+ public int getItemCount(int index) {\r
+ return mValues.get(index).length;\r
+ }\r
+\r
+ /**\r
+ * Returns the series titles.\r
+ * \r
+ * @param index the index\r
+ * @return the series titles\r
+ */\r
+ public String[] getTitles(int index) {\r
+ return mTitles.get(index);\r
+ }\r
+\r
+ /**\r
+ * Transforms the category series to an XY series.\r
+ * \r
+ * @return the XY series\r
+ */\r
+ public XYSeries toXYSeries() {\r
+ XYSeries xySeries = new XYSeries(mTitle);\r
+ return xySeries;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+\r
+/**\r
+ * A class to encapsulate the definition of a point.\r
+ */\r
+public final class Point implements Serializable {\r
+ /** The X axis coordinate value. */\r
+ private float mX;\r
+ /** The Y axis coordinate value. */\r
+ private float mY;\r
+ \r
+ public Point() {\r
+ }\r
+ \r
+ public Point(float x, float y) {\r
+ mX = x;\r
+ mY = y;\r
+ }\r
+ \r
+ public float getX() {\r
+ return mX;\r
+ }\r
+\r
+ public float getY() {\r
+ return mY;\r
+ }\r
+ \r
+ public void setX(float x) {\r
+ mX = x;\r
+ }\r
+ \r
+ public void setY(float y) {\r
+ mY = y;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+/**\r
+ * A series for the range category charts like the range bar.\r
+ */\r
+public class RangeCategorySeries extends CategorySeries {\r
+ /** The series values. */\r
+ private List<Double> mMaxValues = new ArrayList<Double>();\r
+ /**\r
+ * Builds a new category series.\r
+ * \r
+ * @param title the series title\r
+ */\r
+ public RangeCategorySeries(String title) {\r
+ super(title);\r
+ }\r
+ /**\r
+ * Adds new values to the series\r
+ * \r
+ * @param minValue the new minimum value\r
+ * @param maxValue the new maximum value\r
+ */\r
+ public synchronized void add(double minValue, double maxValue) {\r
+ super.add(minValue);\r
+ mMaxValues.add(maxValue);\r
+ }\r
+\r
+ /**\r
+ * Adds new values to the series.\r
+ * \r
+ * @param category the category\r
+ * @param minValue the new minimum value\r
+ * @param maxValue the new maximum value\r
+ */\r
+ public synchronized void add(String category, double minValue, double maxValue) {\r
+ super.add(category, minValue);\r
+ mMaxValues.add(maxValue);\r
+ }\r
+\r
+ /**\r
+ * Removes existing values from the series.\r
+ * \r
+ * @param index the index in the series of the values to remove\r
+ */\r
+ public synchronized void remove(int index) {\r
+ super.remove(index);\r
+ mMaxValues.remove(index);\r
+ }\r
+\r
+ /**\r
+ * Removes all the existing values from the series.\r
+ */\r
+ public synchronized void clear() {\r
+ super.clear();\r
+ mMaxValues.clear();\r
+ }\r
+\r
+ /**\r
+ * Returns the minimum value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the minimum value at the index\r
+ */\r
+ public double getMinimumValue(int index) {\r
+ return getValue(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the maximum value at the index\r
+ */\r
+ public double getMaximumValue(int index) {\r
+ return mMaxValues.get(index);\r
+ }\r
+\r
+ /**\r
+ * Transforms the range category series to an XY series.\r
+ * \r
+ * @return the XY series\r
+ */\r
+ public XYSeries toXYSeries() {\r
+ XYSeries xySeries = new XYSeries(getTitle());\r
+ int length = getItemCount();\r
+ for (int k = 0; k < length; k++) {\r
+ xySeries.add(k + 1, getMinimumValue(k));\r
+ // the new fast XYSeries implementation doesn't allow 2 values at the same X,\r
+ // so I had to do a hack until I find a better solution\r
+ xySeries.add(k + 1.000001, getMaximumValue(k));\r
+ }\r
+ return xySeries;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+public class SeriesSelection {\r
+ private int mSeriesIndex;\r
+\r
+ private int mPointIndex;\r
+\r
+ private double mXValue;\r
+\r
+ private double mValue;\r
+\r
+ public SeriesSelection(int seriesIndex, int pointIndex, double xValue, double value) {\r
+ mSeriesIndex = seriesIndex;\r
+ mPointIndex = pointIndex;\r
+ mXValue = xValue;\r
+ mValue = value;\r
+ }\r
+\r
+ public int getSeriesIndex() {\r
+ return mSeriesIndex;\r
+ }\r
+\r
+ public int getPointIndex() {\r
+ return mPointIndex;\r
+ }\r
+\r
+ public double getXValue() {\r
+ return mXValue;\r
+ }\r
+\r
+ public double getValue() {\r
+ return mValue;\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.Date;\r
+\r
+/**\r
+ * A series for the date / time charts.\r
+ */\r
+public class TimeSeries extends XYSeries {\r
+\r
+ /**\r
+ * Builds a new date / time series.\r
+ * \r
+ * @param title the series title\r
+ */\r
+ public TimeSeries(String title) {\r
+ super(title);\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param x the date / time value for the X axis\r
+ * @param y the value for the Y axis\r
+ */\r
+ public synchronized void add(Date x, double y) {\r
+ super.add(x.getTime(), y);\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series that includes 0 to many XYSeries.\r
+ */\r
+public class XYMultipleSeriesDataset implements Serializable {\r
+ /** The included series. */\r
+ private List<XYSeries> mSeries = new ArrayList<XYSeries>();\r
+\r
+ /**\r
+ * Adds a new XY series to the list.\r
+ * \r
+ * @param series the XY series to ass\r
+ */\r
+ public synchronized void addSeries(XYSeries series) {\r
+ mSeries.add(series);\r
+ }\r
+\r
+ /**\r
+ * Adds a new XY series to the list.\r
+ * \r
+ * @param index the index in the series list\r
+ * @param series the XY series to ass\r
+ */\r
+ public synchronized void addSeries(int index, XYSeries series) {\r
+ mSeries.add(index, series);\r
+ }\r
+\r
+ /**\r
+ * Removes the XY series from the list.\r
+ * \r
+ * @param index the index in the series list of the series to remove\r
+ */\r
+ public synchronized void removeSeries(int index) {\r
+ mSeries.remove(index);\r
+ }\r
+\r
+ /**\r
+ * Removes the XY series from the list.\r
+ * \r
+ * @param series the XY series to be removed\r
+ */\r
+ public synchronized void removeSeries(XYSeries series) {\r
+ mSeries.remove(series);\r
+ }\r
+\r
+ /**\r
+ * Returns the XY series at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the XY series at the index\r
+ */\r
+ public synchronized XYSeries getSeriesAt(int index) {\r
+ return mSeries.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the XY series count.\r
+ * \r
+ * @return the XY series count\r
+ */\r
+ public synchronized int getSeriesCount() {\r
+ return mSeries.size();\r
+ }\r
+\r
+ /**\r
+ * Returns an array of the XY series.\r
+ * \r
+ * @return the XY series array\r
+ */\r
+ public synchronized XYSeries[] getSeries() {\r
+ return mSeries.toArray(new XYSeries[0]);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.Iterator;\r
+import java.util.SortedMap;\r
+\r
+import org.achartengine.util.IndexXYMap;\r
+import org.achartengine.util.MathHelper;\r
+import org.achartengine.util.XYEntry;\r
+\r
+/**\r
+ * An XY series encapsulates values for XY charts like line, time, area,\r
+ * scatter... charts.\r
+ */\r
+public class XYSeries implements Serializable {\r
+ /** The series title. */\r
+ private String mTitle;\r
+ /** A map to contain values for X and Y axes and index for each bundle */\r
+ private final IndexXYMap<Double, Double> mXY = new IndexXYMap<Double, Double>();\r
+ /** The minimum value for the X axis. */\r
+ private double mMinX = MathHelper.NULL_VALUE;\r
+ /** The maximum value for the X axis. */\r
+ private double mMaxX = -MathHelper.NULL_VALUE;\r
+ /** The minimum value for the Y axis. */\r
+ private double mMinY = MathHelper.NULL_VALUE;\r
+ /** The maximum value for the Y axis. */\r
+ private double mMaxY = -MathHelper.NULL_VALUE;\r
+ /** The scale number for this series. */\r
+ private final int mScaleNumber;\r
+\r
+ /**\r
+ * Builds a new XY series.\r
+ * \r
+ * @param title the series title.\r
+ */\r
+ public XYSeries(String title) {\r
+ this(title, 0);\r
+ }\r
+\r
+ /**\r
+ * Builds a new XY series.\r
+ * \r
+ * @param title the series title.\r
+ * @param scaleNumber the series scale number\r
+ */\r
+ public XYSeries(String title, int scaleNumber) {\r
+ mTitle = title;\r
+ mScaleNumber = scaleNumber;\r
+ initRange();\r
+ }\r
+\r
+ public int getScaleNumber() {\r
+ return mScaleNumber;\r
+ }\r
+\r
+ /**\r
+ * Initializes the range for both axes.\r
+ */\r
+ private void initRange() {\r
+ mMinX = MathHelper.NULL_VALUE;\r
+ mMaxX = -MathHelper.NULL_VALUE;\r
+ mMinY = MathHelper.NULL_VALUE;\r
+ mMaxY = -MathHelper.NULL_VALUE;\r
+ int length = getItemCount();\r
+ for (int k = 0; k < length; k++) {\r
+ double x = getX(k);\r
+ double y = getY(k);\r
+ updateRange(x, y);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Updates the range on both axes.\r
+ * \r
+ * @param x the new x value\r
+ * @param y the new y value\r
+ */\r
+ private void updateRange(double x, double y) {\r
+ mMinX = Math.min(mMinX, x);\r
+ mMaxX = Math.max(mMaxX, x);\r
+ mMinY = Math.min(mMinY, y);\r
+ mMaxY = Math.max(mMaxY, y);\r
+ }\r
+\r
+ /**\r
+ * Returns the series title.\r
+ * \r
+ * @return the series title\r
+ */\r
+ public String getTitle() {\r
+ return mTitle;\r
+ }\r
+\r
+ /**\r
+ * Sets the series title.\r
+ * \r
+ * @param title the series title\r
+ */\r
+ public void setTitle(String title) {\r
+ mTitle = title;\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param x the value for the X axis\r
+ * @param y the value for the Y axis\r
+ */\r
+ public synchronized void add(double x, double y) {\r
+ mXY.put(x, y);\r
+ updateRange(x, y);\r
+ }\r
+\r
+ /**\r
+ * Removes an existing value from the series.\r
+ * \r
+ * @param index the index in the series of the value to remove\r
+ */\r
+ public synchronized void remove(int index) {\r
+ XYEntry<Double, Double> removedEntry = mXY.removeByIndex(index);\r
+ double removedX = removedEntry.getKey();\r
+ double removedY = removedEntry.getValue();\r
+ if (removedX == mMinX || removedX == mMaxX || removedY == mMinY || removedY == mMaxY) {\r
+ initRange();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes all the existing values from the series.\r
+ */\r
+ public synchronized void clear() {\r
+ mXY.clear();\r
+ initRange();\r
+ }\r
+\r
+ /**\r
+ * Returns the X axis value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the X value\r
+ */\r
+ public synchronized double getX(int index) {\r
+ return mXY.getXByIndex(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the Y axis value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the Y value\r
+ */\r
+ public synchronized double getY(int index) {\r
+ return mXY.getYByIndex(index);\r
+ }\r
+\r
+ /**\r
+ * Returns submap of x and y values according to the given start and end\r
+ * \r
+ * @param start start x value\r
+ * @param stop stop x value\r
+ * @return a submap of x and y values\r
+ */\r
+ public synchronized SortedMap<Double, Double> getRange(double start, double stop,\r
+ int beforeAfterPoints) {\r
+ // we need to add one point before the start and one point after the end (if\r
+ // there are any)\r
+ // to ensure that line doesn't end before the end of the screen\r
+\r
+ // this would be simply: start = mXY.lowerKey(start) but NavigableMap is\r
+ // available since API 9\r
+ SortedMap<Double, Double> headMap = mXY.headMap(start);\r
+ if (!headMap.isEmpty()) {\r
+ start = headMap.lastKey();\r
+ }\r
+\r
+ // this would be simply: end = mXY.higherKey(end) but NavigableMap is\r
+ // available since API 9\r
+ // so we have to do this hack in order to support older versions\r
+ SortedMap<Double, Double> tailMap = mXY.tailMap(stop);\r
+ if (!tailMap.isEmpty()) {\r
+ Iterator<Double> tailIterator = tailMap.keySet().iterator();\r
+ Double next = tailIterator.next();\r
+ if (tailIterator.hasNext()) {\r
+ stop = tailIterator.next();\r
+ } else {\r
+ stop += next;\r
+ }\r
+ }\r
+ return mXY.subMap(start, stop);\r
+ }\r
+\r
+ public int getIndexForKey(double key) {\r
+ return mXY.getIndexForKey(key);\r
+ }\r
+\r
+ /**\r
+ * Returns the series item count.\r
+ * \r
+ * @return the series item count\r
+ */\r
+ public synchronized int getItemCount() {\r
+ return mXY.size();\r
+ }\r
+\r
+ /**\r
+ * Returns the minimum value on the X axis.\r
+ * \r
+ * @return the X axis minimum value\r
+ */\r
+ public double getMinX() {\r
+ return mMinX;\r
+ }\r
+\r
+ /**\r
+ * Returns the minimum value on the Y axis.\r
+ * \r
+ * @return the Y axis minimum value\r
+ */\r
+ public double getMinY() {\r
+ return mMinY;\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum value on the X axis.\r
+ * \r
+ * @return the X axis maximum value\r
+ */\r
+ public double getMaxX() {\r
+ return mMaxX;\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum value on the Y axis.\r
+ * \r
+ * @return the Y axis maximum value\r
+ */\r
+ public double getMaxY() {\r
+ return mMaxY;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+/**\r
+ * An extension of the XY series which adds a third dimension. It is used for XY\r
+ * charts like bubble.\r
+ */\r
+public class XYValueSeries extends XYSeries {\r
+ /** A list to contain the series values. */\r
+ private List<Double> mValue = new ArrayList<Double>();\r
+ /** The minimum value. */\r
+ private double mMinValue = MathHelper.NULL_VALUE;\r
+ /** The maximum value. */\r
+ private double mMaxValue = -MathHelper.NULL_VALUE;\r
+\r
+ /**\r
+ * Builds a new XY value series.\r
+ * \r
+ * @param title the series title.\r
+ */\r
+ public XYValueSeries(String title) {\r
+ super(title);\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param x the value for the X axis\r
+ * @param y the value for the Y axis\r
+ * @param value the value\r
+ */\r
+ public synchronized void add(double x, double y, double value) {\r
+ super.add(x, y);\r
+ mValue.add(value);\r
+ updateRange(value);\r
+ }\r
+\r
+ /**\r
+ * Initializes the values range.\r
+ */\r
+ private void initRange() {\r
+ mMinValue = MathHelper.NULL_VALUE;\r
+ mMaxValue = MathHelper.NULL_VALUE;\r
+ int length = getItemCount();\r
+ for (int k = 0; k < length; k++) {\r
+ updateRange(getValue(k));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Updates the values range.\r
+ * \r
+ * @param value the new value\r
+ */\r
+ private void updateRange(double value) {\r
+ mMinValue = Math.min(mMinValue, value);\r
+ mMaxValue = Math.max(mMaxValue, value);\r
+ }\r
+\r
+ /**\r
+ * Adds a new value to the series.\r
+ * \r
+ * @param x the value for the X axis\r
+ * @param y the value for the Y axis\r
+ */\r
+ public synchronized void add(double x, double y) {\r
+ add(x, y, 0d);\r
+ }\r
+\r
+ /**\r
+ * Removes an existing value from the series.\r
+ * \r
+ * @param index the index in the series of the value to remove\r
+ */\r
+ public synchronized void remove(int index) {\r
+ super.remove(index);\r
+ double removedValue = mValue.remove(index);\r
+ if (removedValue == mMinValue || removedValue == mMaxValue) {\r
+ initRange();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Removes all the values from the series.\r
+ */\r
+ public synchronized void clear() {\r
+ super.clear();\r
+ mValue.clear();\r
+ initRange();\r
+ }\r
+\r
+ /**\r
+ * Returns the value at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the value\r
+ */\r
+ public synchronized double getValue(int index) {\r
+ return mValue.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the minimum value.\r
+ * \r
+ * @return the minimum value\r
+ */\r
+ public double getMinValue() {\r
+ return mMinValue;\r
+ }\r
+\r
+ /**\r
+ * Returns the maximum value.\r
+ * \r
+ * @return the maximum value\r
+ */\r
+ public double getMaxValue() {\r
+ return mMaxValue;\r
+ }\r
+\r
+}\r
--- /dev/null
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides the classes that handle the data values (data model) to be used by displaying the charts.\r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+The main classes, including the ChartFactory, GraphicalActivity and GraphicalView.\r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+\r
+import android.graphics.Paint.Cap;\r
+import android.graphics.Paint.Join;\r
+\r
+/**\r
+ * A descriptor for the stroke style.\r
+ */\r
+public class BasicStroke implements Serializable {\r
+ /** The solid line style. */\r
+ public static final BasicStroke SOLID = new BasicStroke(Cap.BUTT, Join.MITER, 4, null, 0);\r
+ /** The dashed line style. */\r
+ public static final BasicStroke DASHED = new BasicStroke(Cap.ROUND, Join.BEVEL, 10, new float[] {\r
+ 10, 10 }, 1);\r
+ /** The dot line style. */\r
+ public static final BasicStroke DOTTED = new BasicStroke(Cap.ROUND, Join.BEVEL, 5, new float[] {\r
+ 2, 10 }, 1);\r
+ /** The stroke cap. */\r
+ private Cap mCap;\r
+ /** The stroke join. */\r
+ private Join mJoin;\r
+ /** The stroke miter. */\r
+ private float mMiter;\r
+ /** The path effect intervals. */\r
+ private float[] mIntervals;\r
+ /** The path effect phase. */\r
+ private float mPhase;\r
+\r
+ /**\r
+ * Build a new basic stroke style.\r
+ * \r
+ * @param cap the stroke cap\r
+ * @param join the stroke join\r
+ * @param miter the stroke miter\r
+ * @param intervals the path effect intervals\r
+ * @param phase the path effect phase\r
+ */\r
+ public BasicStroke(Cap cap, Join join, float miter, float[] intervals, float phase) {\r
+ mCap = cap;\r
+ mJoin = join;\r
+ mMiter = miter;\r
+ mIntervals = intervals;\r
+ }\r
+\r
+ /**\r
+ * Returns the stroke cap.\r
+ * \r
+ * @return the stroke cap\r
+ */\r
+ public Cap getCap() {\r
+ return mCap;\r
+ }\r
+\r
+ /**\r
+ * Returns the stroke join.\r
+ * \r
+ * @return the stroke join\r
+ */\r
+ public Join getJoin() {\r
+ return mJoin;\r
+ }\r
+\r
+ /**\r
+ * Returns the stroke miter.\r
+ * \r
+ * @return the stroke miter\r
+ */\r
+ public float getMiter() {\r
+ return mMiter;\r
+ }\r
+\r
+ /**\r
+ * Returns the path effect intervals.\r
+ * \r
+ * @return the path effect intervals\r
+ */\r
+ public float[] getIntervals() {\r
+ return mIntervals;\r
+ }\r
+\r
+ /**\r
+ * Returns the path effect phase.\r
+ * \r
+ * @return the path effect phase\r
+ */\r
+ public float getPhase() {\r
+ return mPhase;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Typeface;\r
+\r
+/**\r
+ * An abstract renderer to be extended by the multiple series classes.\r
+ */\r
+public class DefaultRenderer implements Serializable {\r
+ /** The chart title. */\r
+ private String mChartTitle = "";\r
+ /** The chart title text size. */\r
+ private float mChartTitleTextSize = 15;\r
+ /** A no color constant. */\r
+ public static final int NO_COLOR = 0;\r
+ /** The default background color. */\r
+ public static final int BACKGROUND_COLOR = Color.BLACK;\r
+ /** The default color for text. */\r
+ public static final int TEXT_COLOR = Color.LTGRAY;\r
+ /** A text font for regular text, like the chart labels. */\r
+ private static final Typeface REGULAR_TEXT_FONT = Typeface\r
+ .create(Typeface.SERIF, Typeface.NORMAL);\r
+ /** The typeface name for the texts. */\r
+ private String mTextTypefaceName = REGULAR_TEXT_FONT.toString();\r
+ /** The typeface style for the texts. */\r
+ private int mTextTypefaceStyle = Typeface.NORMAL;\r
+ /** The chart background color. */\r
+ private int mBackgroundColor;\r
+ /** If the background color is applied. */\r
+ private boolean mApplyBackgroundColor;\r
+ /** If the axes are visible. */\r
+ private boolean mShowAxes = true;\r
+ /** The axes color. */\r
+ private int mAxesColor = TEXT_COLOR;\r
+ /** If the labels are visible. */\r
+ private boolean mShowLabels = true;\r
+ /** The labels color. */\r
+ private int mLabelsColor = TEXT_COLOR;\r
+ /** The labels text size. */\r
+ private float mLabelsTextSize = 10;\r
+ /** If the legend is visible. */\r
+ private boolean mShowLegend = true;\r
+ /** The legend text size. */\r
+ private float mLegendTextSize = 12;\r
+ /** If the legend should size to fit. */\r
+ private boolean mFitLegend = false;\r
+ /** If the X axis grid should be displayed. */\r
+ private boolean mShowGridX = false;\r
+ /** If the Y axis grid should be displayed. */\r
+ private boolean mShowGridY = false;\r
+ /** If the custom text grid should be displayed. */\r
+ private boolean mShowCustomTextGrid = false;\r
+ /** The simple renderers that are included in this multiple series renderer. */\r
+ private List<SimpleSeriesRenderer> mRenderers = new ArrayList<SimpleSeriesRenderer>();\r
+ /** The antialiasing flag. */\r
+ private boolean mAntialiasing = true;\r
+ /** The legend height. */\r
+ private int mLegendHeight = 0;\r
+ /** The margins size. */\r
+ private int[] mMargins = new int[] { 20, 30, 10, 20 };\r
+ /** A value to be used for scaling the chart. */\r
+ private float mScale = 1;\r
+ /** A flag for enabling the pan. */\r
+ private boolean mPanEnabled = true;\r
+ /** A flag for enabling the zoom. */\r
+ private boolean mZoomEnabled = true;\r
+ /** A flag for enabling the visibility of the zoom buttons. */\r
+ private boolean mZoomButtonsVisible = false;\r
+ /** The zoom rate. */\r
+ private float mZoomRate = 1.5f;\r
+ /** A flag for enabling the external zoom. */\r
+ private boolean mExternalZoomEnabled = false;\r
+ /** The original chart scale. */\r
+ private float mOriginalScale = mScale;\r
+ /** A flag for enabling the click on elements. */\r
+ private boolean mClickEnabled = false;\r
+ /** The selectable radius around a clickable point. */\r
+ private int selectableBuffer = 15;\r
+ /** If the chart should display the values (available for pie chart). */\r
+ private boolean mDisplayValues;\r
+\r
+ /**\r
+ * A flag to be set if the chart is inside a scroll and doesn't need to shrink\r
+ * when not enough space.\r
+ */\r
+ private boolean mInScroll;\r
+ /** The start angle for circular charts such as pie, doughnut, etc. */\r
+ private float mStartAngle = 0;\r
+\r
+ /**\r
+ * Returns the chart title.\r
+ * \r
+ * @return the chart title\r
+ */\r
+ public String getChartTitle() {\r
+ return mChartTitle;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart title.\r
+ * \r
+ * @param title the chart title\r
+ */\r
+ public void setChartTitle(String title) {\r
+ mChartTitle = title;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart title text size.\r
+ * \r
+ * @return the chart title text size\r
+ */\r
+ public float getChartTitleTextSize() {\r
+ return mChartTitleTextSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart title text size.\r
+ * \r
+ * @param textSize the chart title text size\r
+ */\r
+ public void setChartTitleTextSize(float textSize) {\r
+ mChartTitleTextSize = textSize;\r
+ }\r
+\r
+ /**\r
+ * Adds a simple renderer to the multiple renderer.\r
+ * \r
+ * @param renderer the renderer to be added\r
+ */\r
+ public void addSeriesRenderer(SimpleSeriesRenderer renderer) {\r
+ mRenderers.add(renderer);\r
+ }\r
+\r
+ /**\r
+ * Adds a simple renderer to the multiple renderer.\r
+ * \r
+ * @param index the index in the renderers list\r
+ * @param renderer the renderer to be added\r
+ */\r
+ public void addSeriesRenderer(int index, SimpleSeriesRenderer renderer) {\r
+ mRenderers.add(index, renderer);\r
+ }\r
+\r
+ /**\r
+ * Removes a simple renderer from the multiple renderer.\r
+ * \r
+ * @param renderer the renderer to be removed\r
+ */\r
+ public void removeSeriesRenderer(SimpleSeriesRenderer renderer) {\r
+ mRenderers.remove(renderer);\r
+ }\r
+\r
+ /**\r
+ * Removes all renderers from the multiple renderer.\r
+ */\r
+ public void removeAllRenderers() {\r
+ mRenderers.clear();\r
+ }\r
+\r
+ /**\r
+ * Returns the simple renderer from the multiple renderer list.\r
+ * \r
+ * @param index the index in the simple renderers list\r
+ * @return the simple renderer at the specified index\r
+ */\r
+ public SimpleSeriesRenderer getSeriesRendererAt(int index) {\r
+ return mRenderers.get(index);\r
+ }\r
+\r
+ /**\r
+ * Returns the simple renderers count in the multiple renderer list.\r
+ * \r
+ * @return the simple renderers count\r
+ */\r
+ public int getSeriesRendererCount() {\r
+ return mRenderers.size();\r
+ }\r
+\r
+ /**\r
+ * Returns an array of the simple renderers in the multiple renderer list.\r
+ * \r
+ * @return the simple renderers array\r
+ */\r
+ public SimpleSeriesRenderer[] getSeriesRenderers() {\r
+ return mRenderers.toArray(new SimpleSeriesRenderer[0]);\r
+ }\r
+\r
+ /**\r
+ * Returns the background color.\r
+ * \r
+ * @return the background color\r
+ */\r
+ public int getBackgroundColor() {\r
+ return mBackgroundColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the background color.\r
+ * \r
+ * @param color the background color\r
+ */\r
+ public void setBackgroundColor(int color) {\r
+ mBackgroundColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns if the background color should be applied.\r
+ * \r
+ * @return the apply flag for the background color.\r
+ */\r
+ public boolean isApplyBackgroundColor() {\r
+ return mApplyBackgroundColor;\r
+ }\r
+\r
+ /**\r
+ * Sets if the background color should be applied.\r
+ * \r
+ * @param apply the apply flag for the background color\r
+ */\r
+ public void setApplyBackgroundColor(boolean apply) {\r
+ mApplyBackgroundColor = apply;\r
+ }\r
+\r
+ /**\r
+ * Returns the axes color.\r
+ * \r
+ * @return the axes color\r
+ */\r
+ public int getAxesColor() {\r
+ return mAxesColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the axes color.\r
+ * \r
+ * @param color the axes color\r
+ */\r
+ public void setAxesColor(int color) {\r
+ mAxesColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the labels color.\r
+ * \r
+ * @return the labels color\r
+ */\r
+ public int getLabelsColor() {\r
+ return mLabelsColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the labels color.\r
+ * \r
+ * @param color the labels color\r
+ */\r
+ public void setLabelsColor(int color) {\r
+ mLabelsColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the labels text size.\r
+ * \r
+ * @return the labels text size\r
+ */\r
+ public float getLabelsTextSize() {\r
+ return mLabelsTextSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the labels text size.\r
+ * \r
+ * @param textSize the labels text size\r
+ */\r
+ public void setLabelsTextSize(float textSize) {\r
+ mLabelsTextSize = textSize;\r
+ }\r
+\r
+ /**\r
+ * Returns if the axes should be visible.\r
+ * \r
+ * @return the visibility flag for the axes\r
+ */\r
+ public boolean isShowAxes() {\r
+ return mShowAxes;\r
+ }\r
+\r
+ /**\r
+ * Sets if the axes should be visible.\r
+ * \r
+ * @param showAxes the visibility flag for the axes\r
+ */\r
+ public void setShowAxes(boolean showAxes) {\r
+ mShowAxes = showAxes;\r
+ }\r
+\r
+ /**\r
+ * Returns if the labels should be visible.\r
+ * \r
+ * @return the visibility flag for the labels\r
+ */\r
+ public boolean isShowLabels() {\r
+ return mShowLabels;\r
+ }\r
+\r
+ /**\r
+ * Sets if the labels should be visible.\r
+ * \r
+ * @param showLabels the visibility flag for the labels\r
+ */\r
+ public void setShowLabels(boolean showLabels) {\r
+ mShowLabels = showLabels;\r
+ }\r
+\r
+ /**\r
+ * Returns if the X axis grid should be visible.\r
+ * \r
+ * @return the visibility flag for the X axis grid\r
+ */\r
+ public boolean isShowGridX() {\r
+ return mShowGridX;\r
+ }\r
+\r
+ /**\r
+ * Returns if the Y axis grid should be visible.\r
+ * \r
+ * @return the visibility flag for the Y axis grid\r
+ */\r
+ public boolean isShowGridY() {\r
+ return mShowGridY;\r
+ }\r
+\r
+ /**\r
+ * Sets if the X axis grid should be visible.\r
+ * \r
+ * @param showGrid the visibility flag for the X axis grid\r
+ */\r
+ public void setShowGridX(boolean showGrid) {\r
+ mShowGridX = showGrid;\r
+ }\r
+\r
+ /**\r
+ * Sets if the Y axis grid should be visible.\r
+ * \r
+ * @param showGrid the visibility flag for the Y axis grid\r
+ */\r
+ public void setShowGridY(boolean showGrid) {\r
+ mShowGridY = showGrid;\r
+ }\r
+\r
+ /**\r
+ * Sets if the grid should be visible.\r
+ * \r
+ * @param showGrid the visibility flag for the grid\r
+ */\r
+ public void setShowGrid(boolean showGrid) {\r
+ setShowGridX(showGrid);\r
+ setShowGridY(showGrid);\r
+ }\r
+\r
+ /**\r
+ * Returns if the grid should be visible for custom X or Y labels.\r
+ * \r
+ * @return the visibility flag for the custom text grid\r
+ */\r
+ public boolean isShowCustomTextGrid() {\r
+ return mShowCustomTextGrid;\r
+ }\r
+\r
+ /**\r
+ * Sets if the grid for custom X or Y labels should be visible.\r
+ * \r
+ * @param showGrid the visibility flag for the custom text grid\r
+ */\r
+ public void setShowCustomTextGrid(boolean showGrid) {\r
+ mShowCustomTextGrid = showGrid;\r
+ }\r
+\r
+ /**\r
+ * Returns if the legend should be visible.\r
+ * \r
+ * @return the visibility flag for the legend\r
+ */\r
+ public boolean isShowLegend() {\r
+ return mShowLegend;\r
+ }\r
+\r
+ /**\r
+ * Sets if the legend should be visible.\r
+ * \r
+ * @param showLegend the visibility flag for the legend\r
+ */\r
+ public void setShowLegend(boolean showLegend) {\r
+ mShowLegend = showLegend;\r
+ }\r
+\r
+ /**\r
+ * Returns if the legend should size to fit.\r
+ * \r
+ * @return the fit behavior\r
+ */\r
+ public boolean isFitLegend() {\r
+ return mFitLegend;\r
+ }\r
+\r
+ /**\r
+ * Sets if the legend should size to fit.\r
+ * \r
+ * @param fit the fit behavior\r
+ */\r
+ public void setFitLegend(boolean fit) {\r
+ mFitLegend = fit;\r
+ }\r
+\r
+ /**\r
+ * Returns the text typeface name.\r
+ * \r
+ * @return the text typeface name\r
+ */\r
+ public String getTextTypefaceName() {\r
+ return mTextTypefaceName;\r
+ }\r
+\r
+ /**\r
+ * Returns the text typeface style.\r
+ * \r
+ * @return the text typeface style\r
+ */\r
+ public int getTextTypefaceStyle() {\r
+ return mTextTypefaceStyle;\r
+ }\r
+\r
+ /**\r
+ * Returns the legend text size.\r
+ * \r
+ * @return the legend text size\r
+ */\r
+ public float getLegendTextSize() {\r
+ return mLegendTextSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the legend text size.\r
+ * \r
+ * @param textSize the legend text size\r
+ */\r
+ public void setLegendTextSize(float textSize) {\r
+ mLegendTextSize = textSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the text typeface name and style.\r
+ * \r
+ * @param typefaceName the text typeface name\r
+ * @param style the text typeface style\r
+ */\r
+ public void setTextTypeface(String typefaceName, int style) {\r
+ mTextTypefaceName = typefaceName;\r
+ mTextTypefaceStyle = style;\r
+ }\r
+\r
+ /**\r
+ * Returns the antialiasing flag value.\r
+ * \r
+ * @return the antialiasing value\r
+ */\r
+ public boolean isAntialiasing() {\r
+ return mAntialiasing;\r
+ }\r
+\r
+ /**\r
+ * Sets the antialiasing value.\r
+ * \r
+ * @param antialiasing the antialiasing\r
+ */\r
+ public void setAntialiasing(boolean antialiasing) {\r
+ mAntialiasing = antialiasing;\r
+ }\r
+\r
+ /**\r
+ * Returns the value to be used for scaling the chart.\r
+ * \r
+ * @return the scale value\r
+ */\r
+ public float getScale() {\r
+ return mScale;\r
+ }\r
+\r
+ /**\r
+ * Returns the original value to be used for scaling the chart.\r
+ * \r
+ * @return the original scale value\r
+ */\r
+ public float getOriginalScale() {\r
+ return mOriginalScale;\r
+ }\r
+\r
+ /**\r
+ * Sets the value to be used for scaling the chart. It works on some charts\r
+ * like pie, doughnut, dial.\r
+ * \r
+ * @param scale the scale value\r
+ */\r
+ public void setScale(float scale) {\r
+ mScale = scale;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the zoom.\r
+ * \r
+ * @return if zoom is enabled\r
+ */\r
+ public boolean isZoomEnabled() {\r
+ return mZoomEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the zoom.\r
+ * \r
+ * @param enabled zoom enabled\r
+ */\r
+ public void setZoomEnabled(boolean enabled) {\r
+ mZoomEnabled = enabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the visible state of the zoom buttons.\r
+ * \r
+ * @return if zoom buttons are visible\r
+ */\r
+ public boolean isZoomButtonsVisible() {\r
+ return mZoomButtonsVisible;\r
+ }\r
+\r
+ /**\r
+ * Sets the visible state of the zoom buttons.\r
+ * \r
+ * @param visible if the zoom buttons are visible\r
+ */\r
+ public void setZoomButtonsVisible(boolean visible) {\r
+ mZoomButtonsVisible = visible;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the external (application implemented) zoom.\r
+ * \r
+ * @return if external zoom is enabled\r
+ */\r
+ public boolean isExternalZoomEnabled() {\r
+ return mExternalZoomEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the external (application implemented) zoom.\r
+ * \r
+ * @param enabled external zoom enabled\r
+ */\r
+ public void setExternalZoomEnabled(boolean enabled) {\r
+ mExternalZoomEnabled = enabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the zoom rate.\r
+ * \r
+ * @return the zoom rate\r
+ */\r
+ public float getZoomRate() {\r
+ return mZoomRate;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the pan.\r
+ * \r
+ * @return if pan is enabled\r
+ */\r
+ public boolean isPanEnabled() {\r
+ return mPanEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the pan.\r
+ * \r
+ * @param enabled pan enabled\r
+ */\r
+ public void setPanEnabled(boolean enabled) {\r
+ mPanEnabled = enabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the zoom rate.\r
+ * \r
+ * @param rate the zoom rate\r
+ */\r
+ public void setZoomRate(float rate) {\r
+ mZoomRate = rate;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the click.\r
+ * \r
+ * @return if click is enabled\r
+ */\r
+ public boolean isClickEnabled() {\r
+ return mClickEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the click.\r
+ * \r
+ * @param enabled click enabled\r
+ */\r
+ public void setClickEnabled(boolean enabled) {\r
+ mClickEnabled = enabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the selectable radius value around clickable points.\r
+ * \r
+ * @return the selectable radius\r
+ */\r
+ public int getSelectableBuffer() {\r
+ return selectableBuffer;\r
+ }\r
+\r
+ /**\r
+ * Sets the selectable radius value around clickable points.\r
+ * \r
+ * @param buffer the selectable radius\r
+ */\r
+ public void setSelectableBuffer(int buffer) {\r
+ selectableBuffer = buffer;\r
+ }\r
+\r
+ /**\r
+ * Returns the legend height.\r
+ * \r
+ * @return the legend height\r
+ */\r
+ public int getLegendHeight() {\r
+ return mLegendHeight;\r
+ }\r
+\r
+ /**\r
+ * Sets the legend height, in pixels.\r
+ * \r
+ * @param height the legend height\r
+ */\r
+ public void setLegendHeight(int height) {\r
+ mLegendHeight = height;\r
+ }\r
+\r
+ /**\r
+ * Returns the margin sizes. An array containing the margins in this order:\r
+ * top, left, bottom, right\r
+ * \r
+ * @return the margin sizes\r
+ */\r
+ public int[] getMargins() {\r
+ return mMargins;\r
+ }\r
+\r
+ /**\r
+ * Sets the margins, in pixels.\r
+ * \r
+ * @param margins an array containing the margin size values, in this order:\r
+ * top, left, bottom, right\r
+ */\r
+ public void setMargins(int[] margins) {\r
+ mMargins = margins;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart is inside a scroll view and doesn't need to shrink.\r
+ * \r
+ * @return if it is inside a scroll view\r
+ */\r
+ public boolean isInScroll() {\r
+ return mInScroll;\r
+ }\r
+\r
+ /**\r
+ * To be set if the chart is inside a scroll view and doesn't need to shrink\r
+ * when not enough space.\r
+ * \r
+ * @param inScroll if it is inside a scroll view\r
+ */\r
+ public void setInScroll(boolean inScroll) {\r
+ mInScroll = inScroll;\r
+ }\r
+\r
+ /**\r
+ * Returns the start angle for circular charts such as pie, doughnut. An angle\r
+ * of 0 degrees correspond to the geometric angle of 0 degrees (3 o'clock on a\r
+ * watch.)\r
+ * \r
+ * @return the start angle in degrees\r
+ */\r
+ public float getStartAngle() {\r
+ return mStartAngle;\r
+ }\r
+\r
+ /**\r
+ * Sets the start angle for circular charts such as pie, doughnut, etc. An\r
+ * angle of 0 degrees correspond to the geometric angle of 0 degrees (3\r
+ * o'clock on a watch.)\r
+ * \r
+ * @param startAngle the start angle in degrees\r
+ */\r
+ public void setStartAngle(float startAngle) {\r
+ mStartAngle = startAngle;\r
+ }\r
+\r
+ /**\r
+ * Returns if the values should be displayed as text.\r
+ * \r
+ * @return if the values should be displayed as text\r
+ */\r
+ public boolean isDisplayValues() {\r
+ return mDisplayValues;\r
+ }\r
+\r
+ /**\r
+ * Sets if the values should be displayed as text (supported by pie chart).\r
+ * \r
+ * @param display if the values should be displayed as text\r
+ */\r
+ public void setDisplayValues(boolean display) {\r
+ mDisplayValues = display;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+/**\r
+ * Dial chart renderer.\r
+ */\r
+public class DialRenderer extends DefaultRenderer {\r
+ /** The start angle in the dial range. */\r
+ private double mAngleMin = 330;\r
+ /** The end angle in the dial range. */\r
+ private double mAngleMax = 30;\r
+ /** The start value in dial range. */\r
+ private double mMinValue = MathHelper.NULL_VALUE;\r
+ /** The end value in dial range. */\r
+ private double mMaxValue = -MathHelper.NULL_VALUE;\r
+ /** The spacing for the minor ticks. */\r
+ private double mMinorTickSpacing = MathHelper.NULL_VALUE;\r
+ /** The spacing for the major ticks. */\r
+ private double mMajorTickSpacing = MathHelper.NULL_VALUE;\r
+ /** An array of the renderers types (default is NEEDLE). */\r
+ private List<Type> mVisualTypes = new ArrayList<Type>();\r
+\r
+ public enum Type {\r
+ NEEDLE, ARROW;\r
+ }\r
+\r
+ /**\r
+ * Returns the start angle value of the dial.\r
+ * \r
+ * @return the angle start value\r
+ */\r
+ public double getAngleMin() {\r
+ return mAngleMin;\r
+ }\r
+\r
+ /**\r
+ * Sets the start angle value of the dial.\r
+ * \r
+ * @param min the dial angle start value\r
+ */\r
+ public void setAngleMin(double min) {\r
+ mAngleMin = min;\r
+ }\r
+\r
+ /**\r
+ * Returns the end angle value of the dial.\r
+ * \r
+ * @return the angle end value\r
+ */\r
+ public double getAngleMax() {\r
+ return mAngleMax;\r
+ }\r
+\r
+ /**\r
+ * Sets the end angle value of the dial.\r
+ * \r
+ * @param max the dial angle end value\r
+ */\r
+ public void setAngleMax(double max) {\r
+ mAngleMax = max;\r
+ }\r
+\r
+ /**\r
+ * Returns the start value to be rendered on the dial.\r
+ * \r
+ * @return the start value on dial\r
+ */\r
+ public double getMinValue() {\r
+ return mMinValue;\r
+ }\r
+\r
+ /**\r
+ * Sets the start value to be rendered on the dial.\r
+ * \r
+ * @param min the start value on the dial\r
+ */\r
+ public void setMinValue(double min) {\r
+ mMinValue = min;\r
+ }\r
+\r
+ /**\r
+ * Returns if the minimum dial value was set.\r
+ * \r
+ * @return the minimum dial value was set or not\r
+ */\r
+ public boolean isMinValueSet() {\r
+ return mMinValue != MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the end value to be rendered on the dial.\r
+ * \r
+ * @return the end value on the dial\r
+ */\r
+ public double getMaxValue() {\r
+ return mMaxValue;\r
+ }\r
+\r
+ /**\r
+ * Sets the end value to be rendered on the dial.\r
+ * \r
+ * @param max the end value on the dial\r
+ */\r
+ public void setMaxValue(double max) {\r
+ mMaxValue = max;\r
+ }\r
+\r
+ /**\r
+ * Returns if the maximum dial value was set.\r
+ * \r
+ * @return the maximum dial was set or not\r
+ */\r
+ public boolean isMaxValueSet() {\r
+ return mMaxValue != -MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the minor ticks spacing.\r
+ * \r
+ * @return the minor ticks spacing\r
+ */\r
+ public double getMinorTicksSpacing() {\r
+ return mMinorTickSpacing;\r
+ }\r
+\r
+ /**\r
+ * Sets the minor ticks spacing.\r
+ * \r
+ * @param spacing the minor ticks spacing\r
+ */\r
+ public void setMinorTicksSpacing(double spacing) {\r
+ mMinorTickSpacing = spacing;\r
+ }\r
+\r
+ /**\r
+ * Returns the major ticks spacing.\r
+ * \r
+ * @return the major ticks spacing\r
+ */\r
+ public double getMajorTicksSpacing() {\r
+ return mMajorTickSpacing;\r
+ }\r
+\r
+ /**\r
+ * Sets the major ticks spacing.\r
+ * \r
+ * @param spacing the major ticks spacing\r
+ */\r
+ public void setMajorTicksSpacing(double spacing) {\r
+ mMajorTickSpacing = spacing;\r
+ }\r
+\r
+ /**\r
+ * Returns the visual type at the specified index.\r
+ * \r
+ * @param index the index\r
+ * @return the visual type\r
+ */\r
+ public Type getVisualTypeForIndex(int index) {\r
+ if (index < mVisualTypes.size()) {\r
+ return mVisualTypes.get(index);\r
+ }\r
+ return Type.NEEDLE;\r
+ }\r
+\r
+ /**\r
+ * Sets the visual types.\r
+ * \r
+ * @param types the visual types\r
+ */\r
+ public void setVisualTypes(Type[] types) {\r
+ mVisualTypes.clear();\r
+ mVisualTypes.addAll(Arrays.asList(types));\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * A simple series renderer.\r
+ */\r
+public class SimpleSeriesRenderer implements Serializable {\r
+ /** The series color. */\r
+ private int mColor = Color.BLUE;\r
+ /** If the values should be displayed above the chart points. */\r
+ private boolean mDisplayChartValues;\r
+ /** The chart values text size. */\r
+ private float mChartValuesTextSize = 10;\r
+ /** The chart values text alignment. */\r
+ private Align mChartValuesTextAlign = Align.CENTER;\r
+ /** The chart values spacing from the data point. */\r
+ private float mChartValuesSpacing = 5f;\r
+ /** The stroke style. */\r
+ private BasicStroke mStroke;\r
+ /** If gradient is enabled. */\r
+ private boolean mGradientEnabled = false;\r
+ /** The gradient start value. */\r
+ private double mGradientStartValue;\r
+ /** The gradient start color. */\r
+ private int mGradientStartColor;\r
+ /** The gradient stop value. */\r
+ private double mGradientStopValue;\r
+ /** The gradient stop color. */\r
+ private int mGradientStopColor;\r
+\r
+ /**\r
+ * Returns the series color.\r
+ * \r
+ * @return the series color\r
+ */\r
+ public int getColor() {\r
+ return mColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the series color.\r
+ * \r
+ * @param color the series color\r
+ */\r
+ public void setColor(int color) {\r
+ mColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart point values should be displayed as text.\r
+ * \r
+ * @return if the chart point values should be displayed as text\r
+ */\r
+ public boolean isDisplayChartValues() {\r
+ return mDisplayChartValues;\r
+ }\r
+\r
+ /**\r
+ * Sets if the chart point values should be displayed as text.\r
+ * \r
+ * @param display if the chart point values should be displayed as text\r
+ */\r
+ public void setDisplayChartValues(boolean display) {\r
+ mDisplayChartValues = display;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart values text size.\r
+ * \r
+ * @return the chart values text size\r
+ */\r
+ public float getChartValuesTextSize() {\r
+ return mChartValuesTextSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart values text size.\r
+ * \r
+ * @param textSize the chart values text size\r
+ */\r
+ public void setChartValuesTextSize(float textSize) {\r
+ mChartValuesTextSize = textSize;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart values text align.\r
+ * \r
+ * @return the chart values text align\r
+ */\r
+ public Align getChartValuesTextAlign() {\r
+ return mChartValuesTextAlign;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart values text align.\r
+ * \r
+ * @param align the chart values text align\r
+ */\r
+ public void setChartValuesTextAlign(Align align) {\r
+ mChartValuesTextAlign = align;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart values spacing from the data point.\r
+ * \r
+ * @return the chart values spacing\r
+ */\r
+ public float getChartValuesSpacing() {\r
+ return mChartValuesSpacing;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart values spacing from the data point.\r
+ * \r
+ * @param spacing the chart values spacing (in pixels) from the chart data\r
+ * point\r
+ */\r
+ public void setChartValuesSpacing(float spacing) {\r
+ mChartValuesSpacing = spacing;\r
+ }\r
+\r
+ /**\r
+ * Returns the stroke style.\r
+ * \r
+ * @return the stroke style\r
+ */\r
+ public BasicStroke getStroke() {\r
+ return mStroke;\r
+ }\r
+\r
+ /**\r
+ * Sets the stroke style.\r
+ * \r
+ * @param stroke the stroke style\r
+ */\r
+ public void setStroke(BasicStroke stroke) {\r
+ mStroke = stroke;\r
+ }\r
+\r
+ /**\r
+ * Returns the gradient is enabled value.\r
+ * \r
+ * @return the gradient enabled\r
+ */\r
+ public boolean isGradientEnabled() {\r
+ return mGradientEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the gradient enabled value.\r
+ * \r
+ * @param enabled the gradient enabled\r
+ */\r
+ public void setGradientEnabled(boolean enabled) {\r
+ mGradientEnabled = enabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the gradient start value.\r
+ * \r
+ * @return the gradient start value\r
+ */\r
+ public double getGradientStartValue() {\r
+ return mGradientStartValue;\r
+ }\r
+\r
+ /**\r
+ * Returns the gradient start color.\r
+ * \r
+ * @return the gradient start color\r
+ */\r
+ public int getGradientStartColor() {\r
+ return mGradientStartColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the gradient start value and color.\r
+ * \r
+ * @param start the gradient start value\r
+ * @param color the gradient start color\r
+ */\r
+ public void setGradientStart(double start, int color) {\r
+ mGradientStartValue = start;\r
+ mGradientStartColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the gradient stop value.\r
+ * \r
+ * @return the gradient stop value\r
+ */\r
+ public double getGradientStopValue() {\r
+ return mGradientStopValue;\r
+ }\r
+\r
+ /**\r
+ * Returns the gradient stop color.\r
+ * \r
+ * @return the gradient stop color\r
+ */\r
+ public int getGradientStopColor() {\r
+ return mGradientStopColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the gradient stop value and color.\r
+ * \r
+ * @param start the gradient stop value\r
+ * @param color the gradient stop color\r
+ */\r
+ public void setGradientStop(double start, int color) {\r
+ mGradientStopValue = start;\r
+ mGradientStopColor = color;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.util.HashMap;\r
+import java.util.LinkedHashMap;\r
+import java.util.Map;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * Multiple XY series renderer.\r
+ */\r
+public class XYMultipleSeriesRenderer extends DefaultRenderer {\r
+ /** The X axis title. */\r
+ private String mXTitle = "";\r
+ /** The Y axis title. */\r
+ private String[] mYTitle;\r
+ /** The axis title text size. */\r
+ private float mAxisTitleTextSize = 12;\r
+ /** The start value in the X axis range. */\r
+ private double[] mMinX;\r
+ /** The end value in the X axis range. */\r
+ private double[] mMaxX;\r
+ /** The start value in the Y axis range. */\r
+ private double[] mMinY;\r
+ /** The end value in the Y axis range. */\r
+ private double[] mMaxY;\r
+ /** The approximative number of labels on the x axis. */\r
+ private int mXLabels = 5;\r
+ /** The approximative number of labels on the y axis. */\r
+ private int mYLabels = 5;\r
+ /** The current orientation of the chart. */\r
+ private Orientation mOrientation = Orientation.HORIZONTAL;\r
+ /** The X axis text labels. */\r
+ private Map<Double, String> mXTextLabels = new HashMap<Double, String>();\r
+ /** The Y axis text labels. */\r
+ private Map<Integer, Map<Double, String>> mYTextLabels = new LinkedHashMap<Integer, Map<Double, String>>();\r
+ /** A flag for enabling or not the pan on the X axis. */\r
+ private boolean mPanXEnabled = true;\r
+ /** A flag for enabling or not the pan on the Y axis. */\r
+ private boolean mPanYEnabled = true;\r
+ /** A flag for enabling or not the zoom on the X axis. */\r
+ private boolean mZoomXEnabled = true;\r
+ /** A flag for enabling or not the zoom on the Y axis . */\r
+ private boolean mZoomYEnabled = true;\r
+ /** The spacing between bars, in bar charts. */\r
+ private double mBarSpacing = 0;\r
+ /** The margins colors. */\r
+ private int mMarginsColor = NO_COLOR;\r
+ /** The pan limits. */\r
+ private double[] mPanLimits;\r
+ /** The zoom limits. */\r
+ private double[] mZoomLimits;\r
+ /** The X axis labels rotation angle. */\r
+ private float mXLabelsAngle;\r
+ /** The Y axis labels rotation angle. */\r
+ private float mYLabelsAngle;\r
+ /** The initial axis range. */\r
+ private Map<Integer, double[]> initialRange = new LinkedHashMap<Integer, double[]>();\r
+ /** The point size for charts displaying points. */\r
+ private float mPointSize = 3;\r
+ /** The grid color. */\r
+ private int mGridColor = Color.argb(75, 200, 200, 200);\r
+ /** The number of scales. */\r
+ private int scalesCount;\r
+ /** The X axis labels alignment. */\r
+ private Align xLabelsAlign = Align.CENTER;\r
+ /** The Y axis labels alignment. */\r
+ private Align[] yLabelsAlign;\r
+ /** The Y axis alignment. */\r
+ private Align[] yAxisAlign;\r
+ /** The X axis labels color. */\r
+ private int mXLabelsColor = TEXT_COLOR;\r
+ /** The Y axis labels color. */\r
+ private int[] mYLabelsColor = new int[] { TEXT_COLOR };\r
+ /**\r
+ * If X axis value selection algorithm to be used. Only used by the time\r
+ * charts.\r
+ */\r
+ private boolean mXRoundedLabels = true;\r
+\r
+ /**\r
+ * An enum for the XY chart orientation of the X axis.\r
+ */\r
+ public enum Orientation {\r
+ HORIZONTAL(0), VERTICAL(90);\r
+ /** The rotate angle. */\r
+ private int mAngle = 0;\r
+\r
+ private Orientation(int angle) {\r
+ mAngle = angle;\r
+ }\r
+\r
+ /**\r
+ * Return the orientation rotate angle.\r
+ * \r
+ * @return the orientaion rotate angle\r
+ */\r
+ public int getAngle() {\r
+ return mAngle;\r
+ }\r
+ }\r
+\r
+ public XYMultipleSeriesRenderer() {\r
+ this(1);\r
+ }\r
+\r
+ public XYMultipleSeriesRenderer(int scaleNumber) {\r
+ scalesCount = scaleNumber;\r
+ initAxesRange(scaleNumber);\r
+ }\r
+\r
+ public void initAxesRange(int scales) {\r
+ mYTitle = new String[scales];\r
+ yLabelsAlign = new Align[scales];\r
+ yAxisAlign = new Align[scales];\r
+ mYLabelsColor = new int[scales];\r
+ mMinX = new double[scales];\r
+ mMaxX = new double[scales];\r
+ mMinY = new double[scales];\r
+ mMaxY = new double[scales];\r
+ for (int i = 0; i < scales; i++) {\r
+ mYLabelsColor[i] = TEXT_COLOR;\r
+ initAxesRangeForScale(i);\r
+ }\r
+ }\r
+\r
+ public void initAxesRangeForScale(int i) {\r
+ mMinX[i] = MathHelper.NULL_VALUE;\r
+ mMaxX[i] = -MathHelper.NULL_VALUE;\r
+ mMinY[i] = MathHelper.NULL_VALUE;\r
+ mMaxY[i] = -MathHelper.NULL_VALUE;\r
+ double[] range = new double[] { mMinX[i], mMaxX[i], mMinY[i], mMaxY[i] };\r
+ initialRange.put(i, range);\r
+ mYTitle[i] = "";\r
+ mYTextLabels.put(i, new HashMap<Double, String>());\r
+ yLabelsAlign[i] = Align.CENTER;\r
+ yAxisAlign[i] = Align.LEFT;\r
+ }\r
+\r
+ /**\r
+ * Returns the current orientation of the chart X axis.\r
+ * \r
+ * @return the chart orientation\r
+ */\r
+ public Orientation getOrientation() {\r
+ return mOrientation;\r
+ }\r
+\r
+ /**\r
+ * Sets the current orientation of the chart X axis.\r
+ * \r
+ * @param orientation the chart orientation\r
+ */\r
+ public void setOrientation(Orientation orientation) {\r
+ mOrientation = orientation;\r
+ }\r
+\r
+ /**\r
+ * Returns the title for the X axis.\r
+ * \r
+ * @return the X axis title\r
+ */\r
+ public String getXTitle() {\r
+ return mXTitle;\r
+ }\r
+\r
+ /**\r
+ * Sets the title for the X axis.\r
+ * \r
+ * @param title the X axis title\r
+ */\r
+ public void setXTitle(String title) {\r
+ mXTitle = title;\r
+ }\r
+\r
+ /**\r
+ * Returns the title for the Y axis.\r
+ * \r
+ * @return the Y axis title\r
+ */\r
+ public String getYTitle() {\r
+ return getYTitle(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the title for the Y axis.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the Y axis title\r
+ */\r
+ public String getYTitle(int scale) {\r
+ return mYTitle[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the title for the Y axis.\r
+ * \r
+ * @param title the Y axis title\r
+ */\r
+ public void setYTitle(String title) {\r
+ setYTitle(title, 0);\r
+ }\r
+\r
+ /**\r
+ * Sets the title for the Y axis.\r
+ * \r
+ * @param title the Y axis title\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setYTitle(String title, int scale) {\r
+ mYTitle[scale] = title;\r
+ }\r
+\r
+ /**\r
+ * Returns the axis title text size.\r
+ * \r
+ * @return the axis title text size\r
+ */\r
+ public float getAxisTitleTextSize() {\r
+ return mAxisTitleTextSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the axis title text size.\r
+ * \r
+ * @param textSize the chart axis text size\r
+ */\r
+ public void setAxisTitleTextSize(float textSize) {\r
+ mAxisTitleTextSize = textSize;\r
+ }\r
+\r
+ /**\r
+ * Returns the start value of the X axis range.\r
+ * \r
+ * @return the X axis range start value\r
+ */\r
+ public double getXAxisMin() {\r
+ return getXAxisMin(0);\r
+ }\r
+\r
+ /**\r
+ * Sets the start value of the X axis range.\r
+ * \r
+ * @param min the X axis range start value\r
+ */\r
+ public void setXAxisMin(double min) {\r
+ setXAxisMin(min, 0);\r
+ }\r
+\r
+ /**\r
+ * Returns if the minimum X value was set.\r
+ * \r
+ * @return the minX was set or not\r
+ */\r
+ public boolean isMinXSet() {\r
+ return isMinXSet(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the end value of the X axis range.\r
+ * \r
+ * @return the X axis range end value\r
+ */\r
+ public double getXAxisMax() {\r
+ return getXAxisMax(0);\r
+ }\r
+\r
+ /**\r
+ * Sets the end value of the X axis range.\r
+ * \r
+ * @param max the X axis range end value\r
+ */\r
+ public void setXAxisMax(double max) {\r
+ setXAxisMax(max, 0);\r
+ }\r
+\r
+ /**\r
+ * Returns if the maximum X value was set.\r
+ * \r
+ * @return the maxX was set or not\r
+ */\r
+ public boolean isMaxXSet() {\r
+ return isMaxXSet(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the start value of the Y axis range.\r
+ * \r
+ * @return the Y axis range end value\r
+ */\r
+ public double getYAxisMin() {\r
+ return getYAxisMin(0);\r
+ }\r
+\r
+ /**\r
+ * Sets the start value of the Y axis range.\r
+ * \r
+ * @param min the Y axis range start value\r
+ */\r
+ public void setYAxisMin(double min) {\r
+ setYAxisMin(min, 0);\r
+ }\r
+\r
+ /**\r
+ * Returns if the minimum Y value was set.\r
+ * \r
+ * @return the minY was set or not\r
+ */\r
+ public boolean isMinYSet() {\r
+ return isMinYSet(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the end value of the Y axis range.\r
+ * \r
+ * @return the Y axis range end value\r
+ */\r
+ public double getYAxisMax() {\r
+ return getYAxisMax(0);\r
+ }\r
+\r
+ /**\r
+ * Sets the end value of the Y axis range.\r
+ * \r
+ * @param max the Y axis range end value\r
+ */\r
+ public void setYAxisMax(double max) {\r
+ setYAxisMax(max, 0);\r
+ }\r
+\r
+ /**\r
+ * Returns if the maximum Y value was set.\r
+ * \r
+ * @return the maxY was set or not\r
+ */\r
+ public boolean isMaxYSet() {\r
+ return isMaxYSet(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the start value of the X axis range.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the X axis range start value\r
+ */\r
+ public double getXAxisMin(int scale) {\r
+ return mMinX[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the start value of the X axis range.\r
+ * \r
+ * @param min the X axis range start value\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setXAxisMin(double min, int scale) {\r
+ if (!isMinXSet(scale)) {\r
+ initialRange.get(scale)[0] = min;\r
+ }\r
+ mMinX[scale] = min;\r
+ }\r
+\r
+ /**\r
+ * Returns if the minimum X value was set.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the minX was set or not\r
+ */\r
+ public boolean isMinXSet(int scale) {\r
+ return mMinX[scale] != MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the end value of the X axis range.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the X axis range end value\r
+ */\r
+ public double getXAxisMax(int scale) {\r
+ return mMaxX[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the end value of the X axis range.\r
+ * \r
+ * @param max the X axis range end value\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setXAxisMax(double max, int scale) {\r
+ if (!isMaxXSet(scale)) {\r
+ initialRange.get(scale)[1] = max;\r
+ }\r
+ mMaxX[scale] = max;\r
+ }\r
+\r
+ /**\r
+ * Returns if the maximum X value was set.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the maxX was set or not\r
+ */\r
+ public boolean isMaxXSet(int scale) {\r
+ return mMaxX[scale] != -MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the start value of the Y axis range.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the Y axis range end value\r
+ */\r
+ public double getYAxisMin(int scale) {\r
+ return mMinY[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the start value of the Y axis range.\r
+ * \r
+ * @param min the Y axis range start value\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setYAxisMin(double min, int scale) {\r
+ if (!isMinYSet(scale)) {\r
+ initialRange.get(scale)[2] = min;\r
+ }\r
+ mMinY[scale] = min;\r
+ }\r
+\r
+ /**\r
+ * Returns if the minimum Y value was set.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the minY was set or not\r
+ */\r
+ public boolean isMinYSet(int scale) {\r
+ return mMinY[scale] != MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the end value of the Y axis range.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the Y axis range end value\r
+ */\r
+ public double getYAxisMax(int scale) {\r
+ return mMaxY[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the end value of the Y axis range.\r
+ * \r
+ * @param max the Y axis range end value\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setYAxisMax(double max, int scale) {\r
+ if (!isMaxYSet(scale)) {\r
+ initialRange.get(scale)[3] = max;\r
+ }\r
+ mMaxY[scale] = max;\r
+ }\r
+\r
+ /**\r
+ * Returns if the maximum Y value was set.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the maxY was set or not\r
+ */\r
+ public boolean isMaxYSet(int scale) {\r
+ return mMaxY[scale] != -MathHelper.NULL_VALUE;\r
+ }\r
+\r
+ /**\r
+ * Returns the approximate number of labels for the X axis.\r
+ * \r
+ * @return the approximate number of labels for the X axis\r
+ */\r
+ public int getXLabels() {\r
+ return mXLabels;\r
+ }\r
+\r
+ /**\r
+ * Sets the approximate number of labels for the X axis.\r
+ * \r
+ * @param xLabels the approximate number of labels for the X axis\r
+ */\r
+ public void setXLabels(int xLabels) {\r
+ mXLabels = xLabels;\r
+ }\r
+\r
+ /**\r
+ * Adds a new text label for the specified X axis value.\r
+ * \r
+ * @param x the X axis value\r
+ * @param text the text label\r
+ * @deprecated use addXTextLabel instead\r
+ */\r
+ public void addTextLabel(double x, String text) {\r
+ addXTextLabel(x, text);\r
+ }\r
+\r
+ /**\r
+ * Adds a new text label for the specified X axis value.\r
+ * \r
+ * @param x the X axis value\r
+ * @param text the text label\r
+ */\r
+ public void addXTextLabel(double x, String text) {\r
+ mXTextLabels.put(x, text);\r
+ }\r
+\r
+ /**\r
+ * Returns the X axis text label at the specified X axis value.\r
+ * \r
+ * @param x the X axis value\r
+ * @return the X axis text label\r
+ */\r
+ public String getXTextLabel(Double x) {\r
+ return mXTextLabels.get(x);\r
+ }\r
+\r
+ /**\r
+ * Returns the X text label locations.\r
+ * \r
+ * @return the X text label locations\r
+ */\r
+ public Double[] getXTextLabelLocations() {\r
+ return mXTextLabels.keySet().toArray(new Double[0]);\r
+ }\r
+\r
+ /**\r
+ * Clears the existing text labels.\r
+ * \r
+ * @deprecated use clearXTextLabels instead\r
+ */\r
+ public void clearTextLabels() {\r
+ clearXTextLabels();\r
+ }\r
+\r
+ /**\r
+ * Clears the existing text labels on the X axis.\r
+ */\r
+ public void clearXTextLabels() {\r
+ mXTextLabels.clear();\r
+ }\r
+\r
+ /**\r
+ * If X axis labels should be rounded.\r
+ * \r
+ * @return if rounded time values to be used\r
+ */\r
+ public boolean isXRoundedLabels() {\r
+ return mXRoundedLabels;\r
+ }\r
+\r
+ /**\r
+ * Sets if X axis rounded time values to be used.\r
+ * \r
+ * @param rounded rounded values to be used\r
+ */\r
+ public void setXRoundedLabels(boolean rounded) {\r
+ mXRoundedLabels = rounded;\r
+ }\r
+\r
+ /**\r
+ * Adds a new text label for the specified Y axis value.\r
+ * \r
+ * @param y the Y axis value\r
+ * @param text the text label\r
+ */\r
+ public void addYTextLabel(double y, String text) {\r
+ addYTextLabel(y, text, 0);\r
+ }\r
+\r
+ /**\r
+ * Adds a new text label for the specified Y axis value.\r
+ * \r
+ * @param y the Y axis value\r
+ * @param text the text label\r
+ * @param scale the renderer scale\r
+ */\r
+ public void addYTextLabel(double y, String text, int scale) {\r
+ mYTextLabels.get(scale).put(y, text);\r
+ }\r
+\r
+ /**\r
+ * Returns the Y axis text label at the specified Y axis value.\r
+ * \r
+ * @param y the Y axis value\r
+ * @return the Y axis text label\r
+ */\r
+ public String getYTextLabel(Double y) {\r
+ return getYTextLabel(y, 0);\r
+ }\r
+\r
+ /**\r
+ * Returns the Y axis text label at the specified Y axis value.\r
+ * \r
+ * @param y the Y axis value\r
+ * @param scale the renderer scale\r
+ * @return the Y axis text label\r
+ */\r
+ public String getYTextLabel(Double y, int scale) {\r
+ return mYTextLabels.get(scale).get(y);\r
+ }\r
+\r
+ /**\r
+ * Returns the Y text label locations.\r
+ * \r
+ * @return the Y text label locations\r
+ */\r
+ public Double[] getYTextLabelLocations() {\r
+ return getYTextLabelLocations(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the Y text label locations.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the Y text label locations\r
+ */\r
+ public Double[] getYTextLabelLocations(int scale) {\r
+ return mYTextLabels.get(scale).keySet().toArray(new Double[0]);\r
+ }\r
+\r
+ /**\r
+ * Clears the existing text labels on the Y axis.\r
+ */\r
+ public void clearYTextLabels() {\r
+ clearYTextLabels(0);\r
+ }\r
+\r
+ /**\r
+ * Clears the existing text labels on the Y axis.\r
+ * \r
+ * @param scale the renderer scale\r
+ */\r
+ public void clearYTextLabels(int scale) {\r
+ mYTextLabels.get(scale).clear();\r
+ }\r
+\r
+ /**\r
+ * Returns the approximate number of labels for the Y axis.\r
+ * \r
+ * @return the approximate number of labels for the Y axis\r
+ */\r
+ public int getYLabels() {\r
+ return mYLabels;\r
+ }\r
+\r
+ /**\r
+ * Sets the approximate number of labels for the Y axis.\r
+ * \r
+ * @param yLabels the approximate number of labels for the Y axis\r
+ */\r
+ public void setYLabels(int yLabels) {\r
+ mYLabels = yLabels;\r
+ }\r
+\r
+ /**\r
+ * Sets if the chart point values should be displayed as text.\r
+ * \r
+ * @param display if the chart point values should be displayed as text\r
+ * @deprecated use SimpleSeriesRenderer.setDisplayChartValues() instead\r
+ */\r
+ public void setDisplayChartValues(boolean display) {\r
+ SimpleSeriesRenderer[] renderers = getSeriesRenderers();\r
+ for (SimpleSeriesRenderer renderer : renderers) {\r
+ renderer.setDisplayChartValues(display);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets the chart values text size.\r
+ * \r
+ * @param textSize the chart values text size\r
+ * @deprecated use SimpleSeriesRenderer.setChartValuesTextSize() instead\r
+ */\r
+ public void setChartValuesTextSize(float textSize) {\r
+ SimpleSeriesRenderer[] renderers = getSeriesRenderers();\r
+ for (SimpleSeriesRenderer renderer : renderers) {\r
+ renderer.setChartValuesTextSize(textSize);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the pan on at least one axis.\r
+ * \r
+ * @return if pan is enabled\r
+ */\r
+ public boolean isPanEnabled() {\r
+ return isPanXEnabled() || isPanYEnabled();\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the pan on X axis.\r
+ * \r
+ * @return if pan is enabled on X axis\r
+ */\r
+ public boolean isPanXEnabled() {\r
+ return mPanXEnabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the pan on Y axis.\r
+ * \r
+ * @return if pan is enabled on Y axis\r
+ */\r
+ public boolean isPanYEnabled() {\r
+ return mPanYEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the pan.\r
+ * \r
+ * @param enabledX pan enabled on X axis\r
+ * @param enabledY pan enabled on Y axis\r
+ */\r
+ public void setPanEnabled(boolean enabledX, boolean enabledY) {\r
+ mPanXEnabled = enabledX;\r
+ mPanYEnabled = enabledY;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the zoom on at least one axis.\r
+ * \r
+ * @return if zoom is enabled\r
+ */\r
+ public boolean isZoomEnabled() {\r
+ return isZoomXEnabled() || isZoomYEnabled();\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the zoom on X axis.\r
+ * \r
+ * @return if zoom is enabled on X axis\r
+ */\r
+ public boolean isZoomXEnabled() {\r
+ return mZoomXEnabled;\r
+ }\r
+\r
+ /**\r
+ * Returns the enabled state of the zoom on Y axis.\r
+ * \r
+ * @return if zoom is enabled on Y axis\r
+ */\r
+ public boolean isZoomYEnabled() {\r
+ return mZoomYEnabled;\r
+ }\r
+\r
+ /**\r
+ * Sets the enabled state of the zoom.\r
+ * \r
+ * @param enabledX zoom enabled on X axis\r
+ * @param enabledY zoom enabled on Y axis\r
+ */\r
+ public void setZoomEnabled(boolean enabledX, boolean enabledY) {\r
+ mZoomXEnabled = enabledX;\r
+ mZoomYEnabled = enabledY;\r
+ }\r
+\r
+ /**\r
+ * Returns the spacing between bars, in bar charts.\r
+ * \r
+ * @return the spacing between bars\r
+ * @deprecated use getBarSpacing instead\r
+ */\r
+ public double getBarsSpacing() {\r
+ return getBarSpacing();\r
+ }\r
+\r
+ /**\r
+ * Returns the spacing between bars, in bar charts.\r
+ * \r
+ * @return the spacing between bars\r
+ */\r
+ public double getBarSpacing() {\r
+ return mBarSpacing;\r
+ }\r
+\r
+ /**\r
+ * Sets the spacing between bars, in bar charts. Only available for bar\r
+ * charts. This is a coefficient of the bar width. For instance, if you want\r
+ * the spacing to be a half of the bar width, set this value to 0.5.\r
+ * \r
+ * @param spacing the spacing between bars coefficient\r
+ */\r
+ public void setBarSpacing(double spacing) {\r
+ mBarSpacing = spacing;\r
+ }\r
+\r
+ /**\r
+ * Returns the margins color.\r
+ * \r
+ * @return the margins color\r
+ */\r
+ public int getMarginsColor() {\r
+ return mMarginsColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the color of the margins.\r
+ * \r
+ * @param color the margins color\r
+ */\r
+ public void setMarginsColor(int color) {\r
+ mMarginsColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the grid color.\r
+ * \r
+ * @return the grid color\r
+ */\r
+ public int getGridColor() {\r
+ return mGridColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the color of the grid.\r
+ * \r
+ * @param color the grid color\r
+ */\r
+ public void setGridColor(int color) {\r
+ mGridColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the pan limits.\r
+ * \r
+ * @return the pan limits\r
+ */\r
+ public double[] getPanLimits() {\r
+ return mPanLimits;\r
+ }\r
+\r
+ /**\r
+ * Sets the pan limits as an array of 4 values. Setting it to null or a\r
+ * different size array will disable the panning limitation. Values:\r
+ * [panMinimumX, panMaximumX, panMinimumY, panMaximumY]\r
+ * \r
+ * @param panLimits the pan limits\r
+ */\r
+ public void setPanLimits(double[] panLimits) {\r
+ mPanLimits = panLimits;\r
+ }\r
+\r
+ /**\r
+ * Returns the zoom limits.\r
+ * \r
+ * @return the zoom limits\r
+ */\r
+ public double[] getZoomLimits() {\r
+ return mZoomLimits;\r
+ }\r
+\r
+ /**\r
+ * Sets the zoom limits as an array of 4 values. Setting it to null or a\r
+ * different size array will disable the zooming limitation. Values:\r
+ * [zoomMinimumX, zoomMaximumX, zoomMinimumY, zoomMaximumY]\r
+ * \r
+ * @param zoomLimits the zoom limits\r
+ */\r
+ public void setZoomLimits(double[] zoomLimits) {\r
+ mZoomLimits = zoomLimits;\r
+ }\r
+\r
+ /**\r
+ * Returns the rotation angle of labels for the X axis.\r
+ * \r
+ * @return the rotation angle of labels for the X axis\r
+ */\r
+ public float getXLabelsAngle() {\r
+ return mXLabelsAngle;\r
+ }\r
+\r
+ /**\r
+ * Sets the rotation angle (in degrees) of labels for the X axis.\r
+ * \r
+ * @param angle the rotation angle of labels for the X axis\r
+ */\r
+ public void setXLabelsAngle(float angle) {\r
+ mXLabelsAngle = angle;\r
+ }\r
+\r
+ /**\r
+ * Returns the rotation angle of labels for the Y axis.\r
+ * \r
+ * @return the approximate number of labels for the Y axis\r
+ */\r
+ public float getYLabelsAngle() {\r
+ return mYLabelsAngle;\r
+ }\r
+\r
+ /**\r
+ * Sets the rotation angle (in degrees) of labels for the Y axis.\r
+ * \r
+ * @param angle the rotation angle of labels for the Y axis\r
+ */\r
+ public void setYLabelsAngle(float angle) {\r
+ mYLabelsAngle = angle;\r
+ }\r
+\r
+ /**\r
+ * Returns the size of the points, for charts displaying points.\r
+ * \r
+ * @return the point size\r
+ */\r
+ public float getPointSize() {\r
+ return mPointSize;\r
+ }\r
+\r
+ /**\r
+ * Sets the size of the points, for charts displaying points.\r
+ * \r
+ * @param size the point size\r
+ */\r
+ public void setPointSize(float size) {\r
+ mPointSize = size;\r
+ }\r
+\r
+ public void setRange(double[] range) {\r
+ setRange(range, 0);\r
+ }\r
+\r
+ /**\r
+ * Sets the axes range values.\r
+ * \r
+ * @param range an array having the values in this order: minX, maxX, minY,\r
+ * maxY\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setRange(double[] range, int scale) {\r
+ setXAxisMin(range[0], scale);\r
+ setXAxisMax(range[1], scale);\r
+ setYAxisMin(range[2], scale);\r
+ setYAxisMax(range[3], scale);\r
+ }\r
+\r
+ public boolean isInitialRangeSet() {\r
+ return isInitialRangeSet(0);\r
+ }\r
+\r
+ /**\r
+ * Returns if the initial range is set.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the initial range was set or not\r
+ */\r
+ public boolean isInitialRangeSet(int scale) {\r
+ return initialRange.get(scale) != null;\r
+ }\r
+\r
+ /**\r
+ * Returns the initial range.\r
+ * \r
+ * @return the initial range\r
+ */\r
+ public double[] getInitialRange() {\r
+ return getInitialRange(0);\r
+ }\r
+\r
+ /**\r
+ * Returns the initial range.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return the initial range\r
+ */\r
+ public double[] getInitialRange(int scale) {\r
+ return initialRange.get(scale);\r
+ }\r
+\r
+ /**\r
+ * Sets the axes initial range values. This will be used in the zoom fit tool.\r
+ * \r
+ * @param range an array having the values in this order: minX, maxX, minY,\r
+ * maxY\r
+ */\r
+ public void setInitialRange(double[] range) {\r
+ setInitialRange(range, 0);\r
+ }\r
+\r
+ /**\r
+ * Sets the axes initial range values. This will be used in the zoom fit tool.\r
+ * \r
+ * @param range an array having the values in this order: minX, maxX, minY,\r
+ * maxY\r
+ * @param scale the renderer scale\r
+ */\r
+ public void setInitialRange(double[] range, int scale) {\r
+ initialRange.put(scale, range);\r
+ }\r
+\r
+ /**\r
+ * Returns the X axis labels color.\r
+ * \r
+ * @return the X axis labels color\r
+ */\r
+ public int getXLabelsColor() {\r
+ return mXLabelsColor;\r
+ }\r
+\r
+ /**\r
+ * Returns the Y axis labels color.\r
+ * \r
+ * @return the Y axis labels color\r
+ */\r
+ public int getYLabelsColor(int scale) {\r
+ return mYLabelsColor[scale];\r
+ }\r
+\r
+ /**\r
+ * Sets the X axis labels color.\r
+ * \r
+ * @param color the X axis labels color\r
+ */\r
+ public void setXLabelsColor(int color) {\r
+ mXLabelsColor = color;\r
+ }\r
+\r
+ /**\r
+ * Sets the Y axis labels color.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @param color the Y axis labels color\r
+ */\r
+ public void setYLabelsColor(int scale, int color) {\r
+ mYLabelsColor[scale] = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the X axis labels alignment.\r
+ * \r
+ * @return X labels alignment\r
+ */\r
+ public Align getXLabelsAlign() {\r
+ return xLabelsAlign;\r
+ }\r
+\r
+ /**\r
+ * Sets the X axis labels alignment.\r
+ * \r
+ * @param align the X labels alignment\r
+ */\r
+ public void setXLabelsAlign(Align align) {\r
+ xLabelsAlign = align;\r
+ }\r
+\r
+ /**\r
+ * Returns the Y axis labels alignment.\r
+ * \r
+ * @param scale the renderer scale\r
+ * @return Y labels alignment\r
+ */\r
+ public Align getYLabelsAlign(int scale) {\r
+ return yLabelsAlign[scale];\r
+ }\r
+\r
+ public void setYLabelsAlign(Align align) {\r
+ setYLabelsAlign(align, 0);\r
+ }\r
+\r
+ public Align getYAxisAlign(int scale) {\r
+ return yAxisAlign[scale];\r
+ }\r
+\r
+ public void setYAxisAlign(Align align, int scale) {\r
+ yAxisAlign[scale] = align;\r
+ }\r
+\r
+ /**\r
+ * Sets the Y axis labels alignment.\r
+ * \r
+ * @param align the Y labels alignment\r
+ */\r
+ public void setYLabelsAlign(Align align, int scale) {\r
+ yLabelsAlign[scale] = align;\r
+ }\r
+\r
+ public int getScalesCount() {\r
+ return scalesCount;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import org.achartengine.chart.PointStyle;\r
+\r
+import android.graphics.Color;\r
+\r
+/**\r
+ * A renderer for the XY type series.\r
+ */\r
+public class XYSeriesRenderer extends SimpleSeriesRenderer {\r
+ /** If the chart points should be filled. */\r
+ private boolean mFillPoints = false;\r
+ /** If the chart should be filled below its line. */\r
+ private boolean mFillBelowLine = false;\r
+ /** The fill below the chart line color. */\r
+ private int mFillColor = Color.argb(125, 0, 0, 200);\r
+ /** The point style. */\r
+ private PointStyle mPointStyle = PointStyle.POINT;\r
+ /** The chart line width. */\r
+ private float mLineWidth = 1;\r
+\r
+ /**\r
+ * Returns if the chart should be filled below the line.\r
+ * \r
+ * @return the fill below line status\r
+ */\r
+ public boolean isFillBelowLine() {\r
+ return mFillBelowLine;\r
+ }\r
+\r
+ /**\r
+ * Sets if the line chart should be filled below its line. Filling below the\r
+ * line transforms a line chart into an area chart.\r
+ * \r
+ * @param fill the fill below line flag value\r
+ */\r
+ public void setFillBelowLine(boolean fill) {\r
+ mFillBelowLine = fill;\r
+ }\r
+\r
+ /**\r
+ * Returns if the chart points should be filled.\r
+ * \r
+ * @return the points fill status\r
+ */\r
+ public boolean isFillPoints() {\r
+ return mFillPoints;\r
+ }\r
+\r
+ /**\r
+ * Sets if the chart points should be filled.\r
+ * \r
+ * @param fill the points fill flag value\r
+ */\r
+ public void setFillPoints(boolean fill) {\r
+ mFillPoints = fill;\r
+ }\r
+\r
+ /**\r
+ * Returns the fill below line color.\r
+ * \r
+ * @return the fill below line color\r
+ */\r
+ public int getFillBelowLineColor() {\r
+ return mFillColor;\r
+ }\r
+\r
+ /**\r
+ * Sets the fill below the line color.\r
+ * \r
+ * @param color the fill below line color\r
+ */\r
+ public void setFillBelowLineColor(int color) {\r
+ mFillColor = color;\r
+ }\r
+\r
+ /**\r
+ * Returns the point style.\r
+ * \r
+ * @return the point style\r
+ */\r
+ public PointStyle getPointStyle() {\r
+ return mPointStyle;\r
+ }\r
+\r
+ /**\r
+ * Sets the point style.\r
+ * \r
+ * @param style the point style\r
+ */\r
+ public void setPointStyle(PointStyle style) {\r
+ mPointStyle = style;\r
+ }\r
+\r
+ /**\r
+ * Returns the chart line width.\r
+ * \r
+ * @return the line width\r
+ */\r
+ public float getLineWidth() {\r
+ return mLineWidth;\r
+ }\r
+\r
+ /**\r
+ * Sets the chart line width.\r
+ * \r
+ * @param lineWidth the line width\r
+ */\r
+ public void setLineWidth(float lineWidth) {\r
+ mLineWidth = lineWidth;\r
+ }\r
+ \r
+}\r
--- /dev/null
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides renderer classes that keep the chart rendering / drawing styles.\r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+/**\r
+ * Abstract class for being extended by graphical view tools.\r
+ */\r
+public abstract class AbstractTool {\r
+ /** The chart. */\r
+ protected AbstractChart mChart;\r
+ /** The renderer. */\r
+ protected XYMultipleSeriesRenderer mRenderer;\r
+\r
+ /**\r
+ * Abstract tool constructor.\r
+ * \r
+ * @param chart the chart\r
+ */\r
+ public AbstractTool(AbstractChart chart) {\r
+ mChart = chart;\r
+ if (chart instanceof XYChart) {\r
+ mRenderer = ((XYChart) chart).getRenderer();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Returns the current chart range.\r
+ * \r
+ * @param scale the scale\r
+ * @return the chart range\r
+ */\r
+ public double[] getRange(int scale) {\r
+ double minX = mRenderer.getXAxisMin(scale);\r
+ double maxX = mRenderer.getXAxisMax(scale);\r
+ double minY = mRenderer.getYAxisMin(scale);\r
+ double maxY = mRenderer.getYAxisMax(scale);\r
+ return new double[] { minX, maxX, minY, maxY };\r
+ }\r
+\r
+ /**\r
+ * Sets the range to the calculated one, if not already set.\r
+ * \r
+ * @param range the range\r
+ * @param scale the scale\r
+ */\r
+ public void checkRange(double[] range, int scale) {\r
+ if (mChart instanceof XYChart) {\r
+ double[] calcRange = ((XYChart) mChart).getCalcRange(scale);\r
+ if (calcRange != null) {\r
+ if (!mRenderer.isMinXSet(scale)) {\r
+ range[0] = calcRange[0];\r
+ mRenderer.setXAxisMin(range[0], scale);\r
+ }\r
+ if (!mRenderer.isMaxXSet(scale)) {\r
+ range[1] = calcRange[1];\r
+ mRenderer.setXAxisMax(range[1], scale);\r
+ }\r
+ if (!mRenderer.isMinYSet(scale)) {\r
+ range[2] = calcRange[2];\r
+ mRenderer.setYAxisMin(range[2], scale);\r
+ }\r
+ if (!mRenderer.isMaxYSet(scale)) {\r
+ range[3] = calcRange[3];\r
+ mRenderer.setYAxisMax(range[3], scale);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Sets a new range on the X axis.\r
+ * \r
+ * @param min the minimum value\r
+ * @param max the maximum value\r
+ * @param scale the scale\r
+ */\r
+ protected void setXRange(double min, double max, int scale) {\r
+ mRenderer.setXAxisMin(min, scale);\r
+ mRenderer.setXAxisMax(max, scale);\r
+ }\r
+\r
+ /**\r
+ * Sets a new range on the Y axis.\r
+ * \r
+ * @param min the minimum value\r
+ * @param max the maximum value\r
+ * @param scale the scale\r
+ */\r
+ protected void setYRange(double min, double max, int scale) {\r
+ mRenderer.setYAxisMin(min, scale);\r
+ mRenderer.setYAxisMax(max, scale);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.util.MathHelper;\r
+\r
+public class FitZoom extends AbstractTool {\r
+ /**\r
+ * Builds an instance of the fit zoom tool.\r
+ * \r
+ * @param chart the XY chart\r
+ */\r
+ public FitZoom(AbstractChart chart) {\r
+ super(chart);\r
+ }\r
+\r
+ /**\r
+ * Apply the tool.\r
+ */\r
+ public void apply() {\r
+ if (mChart instanceof XYChart) {\r
+ if (((XYChart) mChart).getDataset() == null) {\r
+ return;\r
+ }\r
+ int scales = mRenderer.getScalesCount();\r
+ if (mRenderer.isInitialRangeSet()) {\r
+ for (int i = 0; i < scales; i++) {\r
+ if (mRenderer.isInitialRangeSet(i)) {\r
+ mRenderer.setRange(mRenderer.getInitialRange(i), i);\r
+ }\r
+ }\r
+ } else {\r
+ XYSeries[] series = ((XYChart) mChart).getDataset().getSeries();\r
+ double[] range = null;\r
+ int length = series.length;\r
+ if (length > 0) {\r
+ for (int i = 0; i < scales; i++) {\r
+ range = new double[] { MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE,\r
+ MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE };\r
+ for (int j = 0; j < length; j++) {\r
+ if (i == series[j].getScaleNumber()) {\r
+ range[0] = Math.min(range[0], series[j].getMinX());\r
+ range[1] = Math.max(range[1], series[j].getMaxX());\r
+ range[2] = Math.min(range[2], series[j].getMinY());\r
+ range[3] = Math.max(range[3], series[j].getMaxY());\r
+ }\r
+ }\r
+ double marginX = Math.abs(range[1] - range[0]) / 40;\r
+ double marginY = Math.abs(range[3] - range[2]) / 40;\r
+ mRenderer.setRange(new double[] { range[0] - marginX, range[1] + marginX,\r
+ range[2] - marginY, range[3] + marginY }, i);\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();\r
+ renderer.setScale(renderer.getOriginalScale());\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+\r
+/**\r
+ * The pan tool.\r
+ */\r
+public class Pan extends AbstractTool {\r
+ /** The pan listeners. */\r
+ private List<PanListener> mPanListeners = new ArrayList<PanListener>();\r
+ /** Pan limits reached on the X axis. */\r
+ private boolean limitsReachedX = false;\r
+ /** Pan limits reached on the X axis. */\r
+ private boolean limitsReachedY = false;\r
+\r
+ /**\r
+ * Builds and instance of the pan tool.\r
+ * \r
+ * @param chart the XY chart\r
+ */\r
+ public Pan(AbstractChart chart) {\r
+ super(chart);\r
+ }\r
+\r
+ /**\r
+ * Apply the tool.\r
+ * \r
+ * @param oldX the previous location on X axis\r
+ * @param oldY the previous location on Y axis\r
+ * @param newX the current location on X axis\r
+ * @param newY the current location on the Y axis\r
+ */\r
+ public void apply(float oldX, float oldY, float newX, float newY) {\r
+ boolean notLimitedUp = true;\r
+ boolean notLimitedBottom = true;\r
+ boolean notLimitedLeft = true;\r
+ boolean notLimitedRight = true;\r
+ if (mChart instanceof XYChart) {\r
+ int scales = mRenderer.getScalesCount();\r
+ double[] limits = mRenderer.getPanLimits();\r
+ boolean limited = limits != null && limits.length == 4;\r
+ XYChart chart = (XYChart) mChart;\r
+ for (int i = 0; i < scales; i++) {\r
+ double[] range = getRange(i);\r
+ double[] calcRange = chart.getCalcRange(i);\r
+ if (limitsReachedX\r
+ && limitsReachedY\r
+ && (range[0] == range[1] && calcRange[0] == calcRange[1] || range[2] == range[3]\r
+ && calcRange[2] == calcRange[3])) {\r
+ return;\r
+ }\r
+ checkRange(range, i);\r
+\r
+ double[] realPoint = chart.toRealPoint(oldX, oldY, i);\r
+ double[] realPoint2 = chart.toRealPoint(newX, newY, i);\r
+ double deltaX = realPoint[0] - realPoint2[0];\r
+ double deltaY = realPoint[1] - realPoint2[1];\r
+ double ratio = getAxisRatio(range);\r
+ if (chart.isVertical(mRenderer)) {\r
+ double newDeltaX = -deltaY * ratio;\r
+ double newDeltaY = deltaX / ratio;\r
+ deltaX = newDeltaX;\r
+ deltaY = newDeltaY;\r
+ }\r
+ if (mRenderer.isPanXEnabled()) {\r
+ if (limits != null) {\r
+ if (notLimitedLeft) {\r
+ notLimitedLeft = limits[0] <= range[0] + deltaX;\r
+ }\r
+ if (notLimitedRight) {\r
+ notLimitedRight = limits[1] >= range[1] + deltaX;\r
+ }\r
+ }\r
+ if (!limited || (notLimitedLeft && notLimitedRight)) {\r
+ setXRange(range[0] + deltaX, range[1] + deltaX, i);\r
+ limitsReachedX = false;\r
+ } else {\r
+ limitsReachedX = true;\r
+ }\r
+ }\r
+ if (mRenderer.isPanYEnabled()) {\r
+ if (limits != null) {\r
+ if (notLimitedBottom) {\r
+ notLimitedBottom = limits[2] <= range[2] + deltaY;\r
+ }\r
+ if (notLimitedUp) {\r
+ notLimitedUp = limits[3] >= range[3] + deltaY;\r
+ }\r
+ }\r
+ if (!limited || (notLimitedBottom && notLimitedUp)) {\r
+ setYRange(range[2] + deltaY, range[3] + deltaY, i);\r
+ limitsReachedY = false;\r
+ } else {\r
+ limitsReachedY = true;\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ RoundChart chart = (RoundChart) mChart;\r
+ chart.setCenterX(chart.getCenterX() + (int) (newX - oldX));\r
+ chart.setCenterY(chart.getCenterY() + (int) (newY - oldY));\r
+ }\r
+ notifyPanListeners();\r
+ }\r
+\r
+ /**\r
+ * Return the X / Y axis range ratio.\r
+ * \r
+ * @param range the axis range\r
+ * @return the ratio\r
+ */\r
+ private double getAxisRatio(double[] range) {\r
+ return Math.abs(range[1] - range[0]) / Math.abs(range[3] - range[2]);\r
+ }\r
+\r
+ /**\r
+ * Notify the pan listeners about a pan.\r
+ */\r
+ private synchronized void notifyPanListeners() {\r
+ for (PanListener listener : mPanListeners) {\r
+ listener.panApplied();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a new pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public synchronized void addPanListener(PanListener listener) {\r
+ mPanListeners.add(listener);\r
+ }\r
+\r
+ /**\r
+ * Removes a pan listener.\r
+ * \r
+ * @param listener pan listener\r
+ */\r
+ public synchronized void removePanListener(PanListener listener) {\r
+ mPanListeners.add(listener);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+/**\r
+ * A pan listener.\r
+ */\r
+public interface PanListener {\r
+\r
+ /**\r
+ * Called when a pan change is triggered.\r
+ */\r
+ void panApplied();\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+\r
+/**\r
+ * The zoom tool.\r
+ */\r
+public class Zoom extends AbstractTool {\r
+ /** A flag to be used to know if this is a zoom in or out. */\r
+ private boolean mZoomIn;\r
+ /** The zoom rate. */\r
+ private float mZoomRate;\r
+ /** The zoom listeners. */\r
+ private List<ZoomListener> mZoomListeners = new ArrayList<ZoomListener>();\r
+ /** Zoom limits reached on the X axis. */\r
+ private boolean limitsReachedX = false;\r
+ /** Zoom limits reached on the Y axis. */\r
+ private boolean limitsReachedY = false;\r
+\r
+ /** Zoom on X axis and Y axis */\r
+ public static final int ZOOM_AXIS_XY = 0;\r
+ /** Zoom on X axis independently */\r
+ public static final int ZOOM_AXIS_X = 1;\r
+ /** Zoom on Y axis independently */\r
+ public static final int ZOOM_AXIS_Y = 2;\r
+\r
+\r
+ /**\r
+ * Builds the zoom tool.\r
+ * \r
+ * @param chart the chart\r
+ * @param in zoom in or out\r
+ * @param rate the zoom rate\r
+ */\r
+ public Zoom(AbstractChart chart, boolean in, float rate) {\r
+ super(chart);\r
+ mZoomIn = in;\r
+ setZoomRate(rate);\r
+ }\r
+\r
+ /**\r
+ * Sets the zoom rate.\r
+ * \r
+ * @param rate\r
+ */\r
+ public void setZoomRate(float rate) {\r
+ mZoomRate = rate;\r
+ }\r
+\r
+ /**\r
+ * Apply the zoom.\r
+ */\r
+ public void apply(int zoom_axis) {\r
+ if (mChart instanceof XYChart) {\r
+ int scales = mRenderer.getScalesCount();\r
+ for (int i = 0; i < scales; i++) {\r
+ double[] range = getRange(i);\r
+ checkRange(range, i);\r
+ double[] limits = mRenderer.getZoomLimits();\r
+\r
+ double centerX = (range[0] + range[1]) / 2;\r
+ double centerY = (range[2] + range[3]) / 2;\r
+ double newWidth = range[1] - range[0];\r
+ double newHeight = range[3] - range[2];\r
+ double newXMin = centerX - newWidth / 2;\r
+ double newXMax = centerX + newWidth / 2;\r
+ double newYMin = centerY - newHeight / 2;\r
+ double newYMax = centerY + newHeight / 2;\r
+\r
+ // if already reached last zoom, then it will always set to reached\r
+ if (i == 0) {\r
+ limitsReachedX = limits != null && (newXMin <= limits[0] || newXMax >= limits[1]);\r
+ limitsReachedY = limits != null && (newYMin <= limits[2] || newYMax >= limits[3]);\r
+ }\r
+\r
+ if (mZoomIn) {\r
+ if (mRenderer.isZoomXEnabled() && // zoom in on X axis\r
+ (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+ if (limitsReachedX && mZoomRate < 1) { \r
+ // ignore pinch zoom out once reached X limit\r
+ } else {\r
+ newWidth /= mZoomRate;\r
+ }\r
+ }\r
+\r
+ if (mRenderer.isZoomYEnabled() && // zoom in on Y axis\r
+ (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+ if (limitsReachedY && mZoomRate < 1) {\r
+ } else {\r
+ newHeight /= mZoomRate;\r
+ }\r
+ }\r
+ } else {\r
+ if (mRenderer.isZoomXEnabled() && !limitsReachedX && // zoom out on X axis\r
+ (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+ newWidth *= mZoomRate;\r
+ }\r
+\r
+ if (mRenderer.isZoomYEnabled() && !limitsReachedY && // zoom out on Y axis\r
+ (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+ newHeight *= mZoomRate;\r
+ }\r
+ }\r
+\r
+ if (mRenderer.isZoomXEnabled() && \r
+ (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+ newXMin = centerX - newWidth / 2;\r
+ newXMax = centerX + newWidth / 2;\r
+ setXRange(newXMin, newXMax, i);\r
+ }\r
+ if (mRenderer.isZoomYEnabled() &&\r
+ (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+ newYMin = centerY - newHeight / 2;\r
+ newYMax = centerY + newHeight / 2;\r
+ setYRange(newYMin, newYMax, i);\r
+ }\r
+ }\r
+ } else {\r
+ DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();\r
+ if (mZoomIn) {\r
+ renderer.setScale(renderer.getScale() * mZoomRate);\r
+ } else {\r
+ renderer.setScale(renderer.getScale() / mZoomRate);\r
+ }\r
+ }\r
+ notifyZoomListeners(new ZoomEvent(mZoomIn, mZoomRate));\r
+ }\r
+\r
+\r
+ /**\r
+ * Notify the zoom listeners about a zoom change.\r
+ * \r
+ * @param e the zoom event\r
+ */\r
+ private synchronized void notifyZoomListeners(ZoomEvent e) {\r
+ for (ZoomListener listener : mZoomListeners) {\r
+ listener.zoomApplied(e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Notify the zoom listeners about a zoom reset.\r
+ */\r
+ public synchronized void notifyZoomResetListeners() {\r
+ for (ZoomListener listener : mZoomListeners) {\r
+ listener.zoomReset();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Adds a new zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public synchronized void addZoomListener(ZoomListener listener) {\r
+ mZoomListeners.add(listener);\r
+ }\r
+\r
+ /**\r
+ * Removes a zoom listener.\r
+ * \r
+ * @param listener zoom listener\r
+ */\r
+ public synchronized void removeZoomListener(ZoomListener listener) {\r
+ mZoomListeners.add(listener);\r
+ }\r
+\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+\r
+/**\r
+ * A zoom event.\r
+ */\r
+public class ZoomEvent {\r
+ /** A flag to be used to know if this is a zoom in or out. */\r
+ private boolean mZoomIn;\r
+ /** The zoom rate. */\r
+ private float mZoomRate;\r
+\r
+ /**\r
+ * Builds the zoom tool.\r
+ * \r
+ * @param in zoom in or out\r
+ * @param rate the zoom rate\r
+ */\r
+ public ZoomEvent(boolean in, float rate) {\r
+ mZoomIn = in;\r
+ mZoomRate = rate;\r
+ }\r
+\r
+ /**\r
+ * Returns the zoom type.\r
+ * \r
+ * @return true if zoom in, false otherwise\r
+ */\r
+ public boolean isZoomIn() {\r
+ return mZoomIn;\r
+ }\r
+ \r
+ /**\r
+ * Returns the zoom rate.\r
+ * \r
+ * @return the zoom rate\r
+ */\r
+ public float getZoomRate() {\r
+ return mZoomRate;\r
+ }\r
+}\r
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+/**\r
+ * A zoom listener.\r
+ */\r
+public interface ZoomListener {\r
+ \r
+ /**\r
+ * Called when a zoom change is triggered.\r
+ * @param e the zoom event\r
+ */\r
+ void zoomApplied(ZoomEvent e);\r
+ \r
+ /**\r
+ * Called when a zoom reset is done.\r
+ */\r
+ void zoomReset();\r
+}\r
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.TreeMap;
+
+/**
+ * This class requires sorted x values
+ */
+public class IndexXYMap<K, V> extends TreeMap<K, V> {
+ private final List<K> indexList = new ArrayList<K>();
+
+ private double maxXDifference = 0;
+
+ public IndexXYMap() {
+ super();
+ }
+
+ public V put(K key, V value) {
+ indexList.add(key);
+ updateMaxXDifference();
+ return super.put(key, value);
+ }
+
+ private void updateMaxXDifference() {
+ if (indexList.size() < 2) {
+ maxXDifference = 0;
+ return;
+ }
+
+ if (Math.abs((Double) indexList.get(indexList.size() - 1)
+ - (Double) indexList.get(indexList.size() - 2)) > maxXDifference)
+ maxXDifference = Math.abs((Double) indexList.get(indexList.size() - 1)
+ - (Double) indexList.get(indexList.size() - 2));
+ }
+
+ public double getMaxXDifference() {
+ return maxXDifference;
+ }
+
+ public void clear() {
+ updateMaxXDifference();
+ super.clear();
+ indexList.clear();
+ }
+
+ /**
+ * Returns X-value according to the given index
+ *
+ * @param index
+ * @return the X value
+ */
+ public K getXByIndex(int index) {
+ return indexList.get(index);
+ }
+
+ /**
+ * Returns Y-value according to the given index
+ *
+ * @param index
+ * @return the Y value
+ */
+ public V getYByIndex(int index) {
+ K key = indexList.get(index);
+ return this.get(key);
+ }
+
+ /**
+ * Returns XY-entry according to the given index
+ *
+ * @param index
+ * @return the X and Y values
+ */
+ public XYEntry<K, V> getByIndex(int index) {
+ K key = indexList.get(index);
+ return new XYEntry<K, V>(key, this.get(key));
+ }
+
+ /**
+ * Removes entry from map by index
+ *
+ * @param index
+ */
+ public XYEntry<K, V> removeByIndex(int index) {
+ K key = indexList.remove(index);
+ return new XYEntry<K, V>(key, this.remove(key));
+ }
+
+ public int getIndexForKey(K key) {
+ return Collections.binarySearch(indexList, key, null);
+ }
+}
--- /dev/null
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.util;\r
+\r
+import java.text.NumberFormat;\r
+import java.text.ParseException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * Utility class for math operations.\r
+ */\r
+public class MathHelper {\r
+ /** A value that is used a null value. */\r
+ public static final double NULL_VALUE = Double.MAX_VALUE;\r
+ /**\r
+ * A number formatter to be used to make sure we have a maximum number of\r
+ * fraction digits in the labels.\r
+ */\r
+ private static final NumberFormat FORMAT = NumberFormat.getNumberInstance();\r
+\r
+ private MathHelper() {\r
+ // empty constructor\r
+ }\r
+\r
+ /**\r
+ * Calculate the minimum and maximum values out of a list of doubles.\r
+ * \r
+ * @param values the input values\r
+ * @return an array with the minimum and maximum values\r
+ */\r
+ public static double[] minmax(List<Double> values) {\r
+ if (values.size() == 0) {\r
+ return new double[2];\r
+ }\r
+ double min = values.get(0);\r
+ double max = min;\r
+ int length = values.size();\r
+ for (int i = 1; i < length; i++) {\r
+ double value = values.get(i);\r
+ min = Math.min(min, value);\r
+ max = Math.max(max, value);\r
+ }\r
+ return new double[] { min, max };\r
+ }\r
+\r
+ /**\r
+ * Computes a reasonable set of labels for a data interval and number of\r
+ * labels.\r
+ * \r
+ * @param start start value\r
+ * @param end final value\r
+ * @param approxNumLabels desired number of labels\r
+ * @return collection containing {start value, end value, increment}\r
+ */\r
+ public static List<Double> getLabels(final double start, final double end,\r
+ final int approxNumLabels) {\r
+ FORMAT.setMaximumFractionDigits(5);\r
+ List<Double> labels = new ArrayList<Double>();\r
+ double[] labelParams = computeLabels(start, end, approxNumLabels);\r
+ // when the start > end the inc will be negative so it will still work\r
+ int numLabels = 1 + (int) ((labelParams[1] - labelParams[0]) / labelParams[2]);\r
+ // we want the range to be inclusive but we don't want to blow up when\r
+ // looping for the case where the min and max are the same. So we loop\r
+ // on\r
+ // numLabels not on the values.\r
+ for (int i = 0; i < numLabels; i++) {\r
+ double z = labelParams[0] + i * labelParams[2];\r
+ try {\r
+ // this way, we avoid a label value like 0.4000000000000000001 instead\r
+ // of 0.4\r
+ z = FORMAT.parse(FORMAT.format(z)).doubleValue();\r
+ } catch (ParseException e) {\r
+ // do nothing here\r
+ }\r
+ labels.add(z);\r
+ }\r
+ return labels;\r
+ }\r
+\r
+ /**\r
+ * Computes a reasonable number of labels for a data range.\r
+ * \r
+ * @param start start value\r
+ * @param end final value\r
+ * @param approxNumLabels desired number of labels\r
+ * @return double[] array containing {start value, end value, increment}\r
+ */\r
+ private static double[] computeLabels(final double start, final double end,\r
+ final int approxNumLabels) {\r
+ if (Math.abs(start - end) < 0.0000001f) {\r
+ return new double[] { start, start, 0 };\r
+ }\r
+ double s = start;\r
+ double e = end;\r
+ boolean switched = false;\r
+ if (s > e) {\r
+ switched = true;\r
+ double tmp = s;\r
+ s = e;\r
+ e = tmp;\r
+ }\r
+ double xStep = roundUp(Math.abs(s - e) / approxNumLabels);\r
+ // Compute x starting point so it is a multiple of xStep.\r
+ double xStart = xStep * Math.ceil(s / xStep);\r
+ double xEnd = xStep * Math.floor(e / xStep);\r
+ if (switched) {\r
+ return new double[] { xEnd, xStart, -1.0 * xStep };\r
+ }\r
+ return new double[] { xStart, xEnd, xStep };\r
+ }\r
+\r
+ /**\r
+ * Given a number, round up to the nearest power of ten times 1, 2, or 5. The\r
+ * argument must be strictly positive.\r
+ */\r
+ private static double roundUp(final double val) {\r
+ int exponent = (int) Math.floor(Math.log10(val));\r
+ double rval = val * Math.pow(10, -exponent);\r
+ if (rval > 5.0) {\r
+ rval = 10.0;\r
+ } else if (rval > 2.0) {\r
+ rval = 5.0;\r
+ } else if (rval > 1.0) {\r
+ rval = 2.0;\r
+ }\r
+ rval *= Math.pow(10, exponent);\r
+ return rval;\r
+ }\r
+\r
+ /**\r
+ * Transforms a list of Float values into an array of float.\r
+ * \r
+ * @param values the list of Float\r
+ * @return the array of floats\r
+ */\r
+ public static float[] getFloats(List<Float> values) {\r
+ int length = values.size();\r
+ float[] result = new float[length];\r
+ for (int i = 0; i < length; i++) {\r
+ result[i] = values.get(i).floatValue();\r
+ }\r
+ return result;\r
+ }\r
+\r
+ /**\r
+ * Transforms a list of Double values into an array of double.\r
+ * \r
+ * @param values the list of Double\r
+ * @return the array of doubles\r
+ */\r
+ public static double[] getDoubles(List<Double> values) {\r
+ int length = values.size();\r
+ double[] result = new double[length];\r
+ for (int i = 0; i < length; i++) {\r
+ result[i] = values.get(i).doubleValue();\r
+ }\r
+ return result;\r
+ }\r
+\r
+}\r
--- /dev/null
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.util;
+
+import java.util.Map.Entry;
+
+/**
+ * A map entry value encapsulating an XY point.
+ */
+public class XYEntry<K, V> implements Entry<K, V> {
+ private final K key;
+
+ private V value;
+
+ public XYEntry(K key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public V setValue(V object) {
+ this.value = object;
+ return this.value;
+ }
+}
\ No newline at end of file
--- /dev/null
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Utility classes that provide helper methods used by most of the other packages.\r
+</body>\r
+</html>
\ No newline at end of file
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
<classpathentry kind="lib" path="libs/android-support-v4.jar"/>\r
<classpathentry kind="lib" path="/OpenRocket/lib/exp4j-0.2.9.jar"/>\r
- <classpathentry kind="lib" path="libs/achartengine-1.0.0.jar" sourcepath="/AChartEngine/src"/>\r
<classpathentry kind="output" path="bin/classes"/>\r
</classpath>\r
target=android-15
android.library.reference.1=../ActionBarSherlock
android.library.reference.2=../TreeViewList
+android.library.reference.3=../achartengine