Compare commits

...

66 commits

Author SHA1 Message Date
yoksnod
a6c3808fd5
Merge pull request #2 from yoksnod/marker-interface-improvements
Added jitpack integration
2020-02-12 14:54:18 +03:00
Dmitry Donskoy
941579e10f Added jitpack integration 2020-02-12 14:53:16 +03:00
yoksnod
21c811ff9a
Merge pull request #1 from yoksnod/marker-interface-improvements
Modified and expanded, made more flexible  marker interaction interface
2020-02-12 14:49:13 +03:00
Dmitry Donskoy
f3a2ec21c9 Modified and expanded, made more flexible marker interaction interface 2020-02-12 14:47:18 +03:00
Daniel Cohen Gindi
9347dd1af7
Merge pull request #4802 from oatrice/fix_crash_solid_color_barchart
fix NPE when use solid color with barchart
2020-02-09 07:34:02 +02:00
Anirut Teerabut
90e523042c
Update BarChartRenderer.java 2020-02-07 22:09:57 +07:00
Anirut Teerabut
33240f9225
Update HorizontalBarChartRenderer.java 2020-02-07 22:09:07 +07:00
Anirut Teerabut
4b67673da9
Update BarChartRenderer.java 2020-02-07 22:03:20 +07:00
Anirut Teerabut
cef967fd71 fix NPE when use solid color with barchart 2020-02-07 17:53:40 +07:00
Daniel Cohen Gindi
eae977306e Merge branch 'fill'
* fill:
  Implement a more generic Fill class instead of GradientColor
2020-01-24 12:53:07 +02:00
Daniel Cohen Gindi
c0e7f56b5d Implement a more generic Fill class instead of GradientColor
Support HorizontalBarChart too.
2020-01-24 12:52:27 +02:00
Daniel Cohen Gindi
351e341ee7 Fixed merge residue 2020-01-24 11:42:03 +02:00
Daniel Cohen Gindi
f05337768d Finalized vertical line collision check 2020-01-23 15:45:57 +02:00
Daniel Cohen Gindi
f8d068d377
Merge pull request #4787 from danielgindi/feature/catching_up_to_ios
Feature/catching up to ios
2020-01-23 15:38:53 +02:00
Daniel Cohen Gindi
5e4a32eb41 Corrected check for line in vertical bounds
https://github.com/danielgindi/Charts/pull/4100
2020-01-23 12:09:06 +02:00
Daniel Cohen Gindi
1de836ac65 Remove unexpected dash line during linear animation
https://github.com/danielgindi/Charts/pull/4094
2020-01-23 11:19:07 +02:00
Daniel Cohen Gindi
0668d30a6b Fixed a bug where a pie slice without highlight enabled is hidden
https://github.com/danielgindi/Charts/pull/3969
2020-01-23 10:54:28 +02:00
Daniel Cohen Gindi
34fefd28e1 maxHeight didn't account for the last label
https://github.com/danielgindi/Charts/pull/3900
2020-01-23 10:18:28 +02:00
Daniel Cohen Gindi
45240c3723 Improved negative offset for horz bar chart
https://github.com/danielgindi/Charts/pull/3854
2020-01-22 16:01:42 +02:00
Daniel Cohen Gindi
14456f475f Renamed values -> entries for consistency
https://github.com/danielgindi/Charts/pull/3847
2020-01-22 14:24:37 +02:00
Daniel Cohen Gindi
e02e9be2fa Multiple colors for valueline
https://github.com/danielgindi/Charts/pull/3709
2020-01-22 14:13:31 +02:00
Daniel Cohen Gindi
fcc5af71ce Call onChartScale listener after double-tap-zoom
https://github.com/danielgindi/Charts/pull/3770
2020-01-22 13:49:10 +02:00
Daniel Cohen Gindi
13aee592b1 Improve min/max calculation
https://github.com/danielgindi/Charts/pull/3650
2020-01-22 13:43:42 +02:00
Daniel Cohen Gindi
c97c8d247f Fixed index out of bounds issue when using stacked bar chart
b03cf16ec4
2020-01-22 13:23:12 +02:00
Daniel Cohen Gindi
ae59e7a19e This is for the inline bubble selection
https://github.com/danielgindi/Charts/pull/3548
2020-01-22 13:12:04 +02:00
Daniel Cohen Gindi
7752efef7e Support for labelXOffset for YAxis label 2020-01-22 13:04:11 +02:00
Daniel Cohen Gindi
58545bbbfa Add option to disable clipping data to contentRect
https://github.com/danielgindi/Charts/pull/3360
2020-01-22 12:46:37 +02:00
Daniel Cohen Gindi
4ce14e6cc9 Add a warning message if pie chart has more than one data set
https://github.com/danielgindi/Charts/pull/3286
2020-01-22 12:42:32 +02:00
Daniel Cohen Gindi
8df9eda7af Call notifyDataChanged for an opportunity for subclasses 2020-01-22 12:39:03 +02:00
Daniel Cohen Gindi
34c3ceaa05 Reset min/max when clearing ChartDataSet
https://github.com/danielgindi/Charts/pull/3265
2020-01-22 12:29:47 +02:00
Daniel Cohen Gindi
ea816e8d6d Added dataIndex param for highlightValue (combined charts)
https://github.com/danielgindi/Charts/pull/2852
2020-01-22 12:25:34 +02:00
Daniel Cohen Gindi
bafb0fbbe4 Use correct color index for bubble chart
https://github.com/danielgindi/Charts/pull/3202
2020-01-22 12:16:48 +02:00
Daniel Cohen Gindi
4549ae17b7 Select correct axis for legend distance calculation in horz bar chart
https://github.com/danielgindi/Charts/pull/2214
2020-01-22 12:15:02 +02:00
Daniel Cohen Gindi
912427e543 Custom text alignment for no-data
https://github.com/danielgindi/Charts/pull/3199
2020-01-22 12:07:37 +02:00
Daniel Cohen Gindi
3f5475077e Avoid race condition for interval/intervalMagnitude
https://github.com/danielgindi/Charts/pull/2377
2020-01-22 11:59:43 +02:00
Daniel Cohen Gindi
2e725e49d3 Make min/max axis labels configurable
https://github.com/danielgindi/Charts/pull/2894
2020-01-22 11:54:08 +02:00
Daniel Cohen Gindi
a4ca1f3fba Fixed axis label disappearing when zooming in
https://github.com/danielgindi/Charts/pull/3132
2020-01-22 11:47:45 +02:00
Daniel Cohen Gindi
634a690d6a Added an implementation of Douglas Peucker with resultCount input
https://github.com/danielgindi/Charts/pull/2848
2020-01-22 11:44:27 +02:00
Daniel Cohen Gindi
1987d7eb64 Consider axis dependency in Combined chart
https://github.com/danielgindi/Charts/pull/2874
2020-01-22 11:04:57 +02:00
Daniel Cohen Gindi
6ebf3fa57a Added highlightColor parameter for pie charts
https://github.com/danielgindi/Charts/pull/2961
2020-01-22 10:27:55 +02:00
Daniel Cohen Gindi
95027fa6a7 Safe guards
These will be even more important when moving to Kotlin ranges
2020-01-22 09:55:00 +02:00
Philipp Jahoda
d86f39cc91
Update README.md 2020-01-20 11:15:12 +01:00
Philipp Jahoda
cb26ed4ef4
Update FUNDING.yml 2019-10-08 14:15:52 +02:00
Philipp Jahoda
dc59171524
Create FUNDING.yml 2019-10-08 14:15:21 +02:00
Philipp Jahoda
726616d079 Merge branch 'master' of github.com:PhilJay/MPAndroidChart 2019-04-27 17:38:41 +02:00
Philipp Jahoda
fffe9a297e Update gradle 2019-04-27 17:38:37 +02:00
Philipp Jahoda
2340e12800
Merge pull request #4512 from duchampdev/percent_formatter_sign_spacing
PercentFormatter: make space between number and percent sign optional
2019-04-27 17:37:13 +02:00
duchampdev
c5667d4f14 fix little typo 2019-04-27 16:06:37 +02:00
duchampdev
0563fb48b0 PercentFormatter: make space between number and percent sign optional 2019-04-27 16:06:10 +02:00
Philipp Jahoda
ed8876cef2
Update README.md 2019-04-07 16:37:14 +02:00
Philipp Jahoda
12b4351d0c
Update README.md 2019-04-07 16:27:59 +02:00
Philipp Jahoda
adb56e75bd
Update README.md 2019-04-07 16:20:14 +02:00
Philipp Jahoda
e95c1eb26a
Update README.md 2019-03-20 17:56:58 +01:00
Philipp Jahoda
0c2ac2d9cc New example app release 2019-03-16 11:53:42 +01:00
Philipp Jahoda
2058f7bf5d Minor changes to project and example 2019-03-16 11:42:04 +01:00
Philipp Jahoda
971640b29d
Update Support_help.md 2019-02-21 09:05:06 +01:00
Philipp Jahoda
7df8a4cedc
Update Feature_request.md 2019-02-21 09:04:40 +01:00
Philipp Jahoda
59028d3bf3
Update Bug_report.md 2019-02-21 09:04:28 +01:00
Philipp Jahoda
c886bb342a
Update README.md 2019-02-20 22:51:10 +01:00
almic
aea2ff3417
Add option to set minimum angles
Allows to force minimum slice angles when drawing charts, which means that any
slices with angles lower than the minimum will be drawn with the minimum angle.

When changing this setting on the fly, you have to call
`notifyDataSetChanged()` and `invalidate()` for the minimum angle to take
effect.

This only functions if all slices can be drawn with the minimum angle. For
example if a chart has 5 slices, the largest functioning minimum angle is
`72f` degrees on a 360 degree chart, or 20% of the chart's `maxAngle`.
2018-11-15 09:51:46 -07:00
almic
42cdba535f
Add Curved Slices to Pie Chart
Finally added support for rounded slices, and somewhat improved the code
for the PieChartRenderer class.
2018-11-12 10:59:48 -07:00
almic
29f4cc5c2c
Remove unnecessary API checks
Also added run configuration for the MPChartExample.
Removed deprecated Legend stuff.
2018-11-11 09:40:37 -07:00
almic
fc0e234298
Remove Deprecated Things
Long deprecated Legend constructor and positioning has been removed, it was
replaced with a new way to position the Legend.

The old Easing options have been removed now, accessing them is as easy as
removing the `EasingOption` part, such that the names look like
`Easing.Linear` or `Easing.EaseInOutQuad` now.
2018-11-07 14:52:25 -07:00
almic
e5b66192e7
New ValueFormatter
I created a simplified value formatter class, which is an abstract class rather
than an interface.

The switch was chosen because the new format has all the methods predefined
(something an interface wouldn't allow) meaning you can extend it and only
change what you want. This also means that you only need one value formatting
class for labels rather than two different classes, it just makes more sense.

Please check the method signatures to learn how to use them, I'm sure you'll
find this new format is much more customizable and faster to use.

I've made the class abstract even though there are no abstract methods or
fields, this is because it would certainly be a mistake to create a
ValueFormatter and not override any methods.

To convert existing code, just use 'extends' instead of 'implements' and change
the names to 'ValueFormatter'. You'll need to change the methods you overwrite
as well, just check the class and use the one you need.
2018-11-07 12:41:53 -07:00
Mick A
608d9e29f5
Fix link error 2018-10-30 08:59:58 -06:00
almic
9148f37f9e
Bump version to 3.1.0-alpha 2018-10-29 13:23:18 -06:00
101 changed files with 2473 additions and 1403 deletions

12
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: mpandroidchart
open_collective: philippjahoda
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -28,10 +28,10 @@ cannot answer support questions here. We will close your issue without a respons
**Device (please complete the following information):**
- Device: [e.g. Google Pixel]
- Android Version [e.g. 7.0]
- Library Version (e.g. 3.0.3)
- Library Version (e.g. 3.1.0-alpha)
**Additional Context**
<!-- Add any other context about the problem here.
If you have source code demonstrating this bug, create a Gist:
If you have source code demonstrating this bug, create a Gist:
https://help.github.com/articles/creating-gists/
and link to it here. -->

View file

@ -33,10 +33,12 @@ support questions here. We will close your issue without a response.
**Device (please complete the following information):**
- Device: [e.g. Google Pixel]
- Android Version [e.g. 7.0]
- Library Version (e.g. 3.0.3)
- Library Version (e.g. 3.1.0-alpha)
**Additional Context**
<!-- Add any other context about the problem here.
If you have source code demonstrating this bug, create a Gist:
If you have source code demonstrating this bug, create a Gist:
https://help.github.com/articles/creating-gists/
and link to it here. -->
ADD A REWARD using [Speed](speedoss.com) to SOLVE this issue QUICKLY and SUPPORT this project.

View file

@ -31,3 +31,4 @@ support questions here. We will close your issue without a response.
**Additional context**
<!-- Add any other context or screenshots about the feature request here. -->
ADD A REWARD using [Speed](speedoss.com) to SOLVE this issue QUICKLY and SUPPORT this project.

View file

@ -14,7 +14,7 @@ Instead, do the following:
1. Download the [Example App](https://play.google.com/store/apps/details?id=com.xxmassdeveloper.mpchartexample) and check out the [source code](https://github.com/PhilJay/MPAndroidChart/tree/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample). 90% of the time there is an example that does exactly what you are trying to do.
1. Look at the [Wiki](https://github.com/PhilJay/MPAndroidChart/wiki) for the official documentation for MPAndroidChart. You can also browse the [javadoc](https://jitpack.io/com/github/PhilJay/MPAndroidChart/v3.0.3/javadoc/) for a more detailed tutorial of the API.
1. Look at the [Wiki](https://github.com/PhilJay/MPAndroidChart/wiki) for the official documentation for MPAndroidChart. You can also browse the [javadoc](https://jitpack.io/com/github/philjay/mpandroidchart/v3.1.0-alpha/javadoc/) for a more detailed tutorial of the API.
1. Go to [StackOverflow](https://stackoverflow.com/questions/tagged/mpandroidchart) and ask your questions there. The community will be much more helpful and willing to offer guidance.
@ -22,3 +22,6 @@ Instead, do the following:
### You have been warned!
From now on, any issues asking for help will get closed with a link to this file.
### Additional Context
ADD A REWARD using [Speed](speedoss.com) to SOLVE this issue QUICKLY and SUPPORT this project.

7
.gitignore vendored
View file

@ -12,8 +12,8 @@
bin/
gen/
generated/
docs/
finalOutput/
projectFilesBackup/
build.xml
@ -23,6 +23,8 @@ local.properties
# Eclipse project files
.classpath
.project
.settings/
.vscode/
# Proguard folder generated by Eclipse
proguard/
@ -31,7 +33,8 @@ proguard/
*.iml
*.ipr
*.iws
.idea/
/.idea/*
!/.idea/runConfigurations
.directory

View file

@ -0,0 +1,52 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="MPChartExample" type="AndroidRunConfigurationType" factoryName="Android App" activateToolWindowBeforeRun="false">
<module name="MPChartExample" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="ARTIFACT_NAME" value="" />
<option name="PM_INSTALL_OPTIONS" value="" />
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
<option name="MODE" value="default_activity" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="SKIP_NOOP_APK_INSTALLATIONS" value="true" />
<option name="FORCE_STOP_RUNNING_APP" value="true" />
<option name="TARGET_SELECTION_MODE" value="SHOW_DIALOG" />
<option name="USE_LAST_SELECTED_DEVICE" value="false" />
<option name="PREFERRED_AVD" value="" />
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
<option name="DEBUGGER_TYPE" value="Auto" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Hybrid>
<Java />
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Sampled (Java)" />
</Profilers>
<option name="DEEP_LINK" value="" />
<option name="ACTIVITY_CLASS" value="" />
<method />
</configuration>
</component>

View file

@ -6,8 +6,8 @@ android {
applicationId "com.xxmassdeveloper.mpchartexample"
minSdkVersion 16
targetSdkVersion 28
versionCode 56
versionName '3.0.3'
versionCode 57
versionName '3.1.0'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -20,7 +20,7 @@ android {
}
dependencies {
implementation "androidx.appcompat:appcompat:1.0.0"
implementation "androidx.appcompat:appcompat:1.0.2"
implementation 'com.google.android.material:material:1.0.0'
implementation project(':MPChartLib')
}

View file

@ -24,6 +24,7 @@
<activity android:name="LineChartTime" />
<activity android:name="BarChartActivity" />
<activity android:name="HorizontalBarChartActivity" />
<activity android:name="HorizontalBarNegativeChartActivity" />
<activity android:name="PieChartActivity" />
<activity android:name="PiePolylineChartActivity" />
<activity android:name="MultiLineChartActivity" />

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
@ -28,15 +27,15 @@ import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.model.GradientColor;
import com.github.mikephil.charting.utils.Fill;
import com.github.mikephil.charting.utils.MPPointF;
import com.xxmassdeveloper.mpchartexample.custom.DayAxisValueFormatter;
import com.xxmassdeveloper.mpchartexample.custom.MyAxisValueFormatter;
import com.xxmassdeveloper.mpchartexample.custom.MyValueFormatter;
import com.xxmassdeveloper.mpchartexample.custom.XYMarkerView;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
@ -86,7 +85,7 @@ public class BarChartActivity extends DemoBase implements OnSeekBarChangeListene
chart.setDrawGridBackground(false);
// chart.setDrawYLabels(false);
IAxisValueFormatter xAxisFormatter = new DayAxisValueFormatter(chart);
ValueFormatter xAxisFormatter = new DayAxisValueFormatter(chart);
XAxis xAxis = chart.getXAxis();
xAxis.setPosition(XAxisPosition.BOTTOM);
@ -96,7 +95,7 @@ public class BarChartActivity extends DemoBase implements OnSeekBarChangeListene
xAxis.setLabelCount(7);
xAxis.setValueFormatter(xAxisFormatter);
IAxisValueFormatter custom = new MyAxisValueFormatter();
ValueFormatter custom = new MyValueFormatter("$");
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setTypeface(tfLight);
@ -165,12 +164,6 @@ public class BarChartActivity extends DemoBase implements OnSeekBarChangeListene
set1.setDrawIcons(false);
// set1.setColors(ColorTemplate.MATERIAL_COLORS);
/*int startColor = ContextCompat.getColor(this, android.R.color.holo_blue_dark);
int endColor = ContextCompat.getColor(this, android.R.color.holo_blue_bright);
set1.setGradientColor(startColor, endColor);*/
int startColor1 = ContextCompat.getColor(this, android.R.color.holo_orange_light);
int startColor2 = ContextCompat.getColor(this, android.R.color.holo_blue_light);
int startColor3 = ContextCompat.getColor(this, android.R.color.holo_orange_light);
@ -182,14 +175,14 @@ public class BarChartActivity extends DemoBase implements OnSeekBarChangeListene
int endColor4 = ContextCompat.getColor(this, android.R.color.holo_red_dark);
int endColor5 = ContextCompat.getColor(this, android.R.color.holo_orange_dark);
List<GradientColor> gradientColors = new ArrayList<>();
gradientColors.add(new GradientColor(startColor1, endColor1));
gradientColors.add(new GradientColor(startColor2, endColor2));
gradientColors.add(new GradientColor(startColor3, endColor3));
gradientColors.add(new GradientColor(startColor4, endColor4));
gradientColors.add(new GradientColor(startColor5, endColor5));
List<Fill> gradientFills = new ArrayList<>();
gradientFills.add(new Fill(startColor1, endColor1));
gradientFills.add(new Fill(startColor2, endColor2));
gradientFills.add(new Fill(startColor3, endColor3));
gradientFills.add(new Fill(startColor4, endColor4));
gradientFills.add(new Fill(startColor5, endColor5));
set1.setGradientColors(gradientColors);
set1.setFills(gradientFills);
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
@ -17,7 +16,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
@ -25,8 +23,8 @@ import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.LargeValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
@ -100,9 +98,9 @@ public class BarChartActivityMultiDataset extends DemoBase implements OnSeekBarC
xAxis.setTypeface(tfLight);
xAxis.setGranularity(1f);
xAxis.setCenterAxisLabels(true);
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return String.valueOf((int) value);
}
});

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.content.Intent;
@ -10,17 +9,13 @@ import android.view.MenuItem;
import android.view.WindowManager;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.utils.ViewPortHandler;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
import java.text.DecimalFormat;
@ -88,9 +83,9 @@ public class BarChartPositiveNegative extends DemoBase {
data.add(new Data(3f, -442.3f, "01-01"));
data.add(new Data(4f, -2280.1f, "01-02"));
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return data.get(Math.min(Math.max((int) value, 0), data.size()-1)).xAxisValue;
}
});
@ -135,7 +130,7 @@ public class BarChartPositiveNegative extends DemoBase {
BarData data = new BarData(set);
data.setValueTextSize(13f);
data.setValueTypeface(tfRegular);
data.setValueFormatter(new ValueFormatter());
data.setValueFormatter(new Formatter());
data.setBarWidth(0.8f);
chart.setData(data);
@ -159,17 +154,17 @@ public class BarChartPositiveNegative extends DemoBase {
}
}
private class ValueFormatter implements IValueFormatter
private class Formatter extends ValueFormatter
{
private final DecimalFormat mFormat;
ValueFormatter() {
Formatter() {
mFormat = new DecimalFormat("######.0");
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
public String getFormattedValue(float value) {
return mFormat.format(value);
}
}

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.content.Intent;
@ -11,7 +10,6 @@ import android.view.WindowManager;
import com.github.mikephil.charting.charts.CombinedChart;
import com.github.mikephil.charting.charts.CombinedChart.DrawOrder;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
@ -31,7 +29,7 @@ import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.data.ScatterData;
import com.github.mikephil.charting.data.ScatterDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
@ -83,9 +81,9 @@ public class CombinedChartActivity extends DemoBase {
xAxis.setPosition(XAxisPosition.BOTH_SIDED);
xAxis.setAxisMinimum(0f);
xAxis.setGranularity(1f);
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return months[(int) value % months.length];
}
});

View file

@ -0,0 +1,292 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.MPPointF;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
import java.util.ArrayList;
import java.util.List;
public class HorizontalBarNegativeChartActivity extends DemoBase implements OnSeekBarChangeListener,
OnChartValueSelectedListener {
private HorizontalBarChart chart;
private SeekBar seekBarX, seekBarY;
private TextView tvX, tvY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_horizontalbarchart);
setTitle("HorizontalBarChartActivity");
tvX = findViewById(R.id.tvXMax);
tvY = findViewById(R.id.tvYMax);
seekBarX = findViewById(R.id.seekBar1);
seekBarY = findViewById(R.id.seekBar2);
seekBarY.setOnSeekBarChangeListener(this);
seekBarX.setOnSeekBarChangeListener(this);
chart = findViewById(R.id.chart1);
chart.setOnChartValueSelectedListener(this);
// chart.setHighlightEnabled(false);
chart.setDrawBarShadow(false);
chart.setDrawValueAboveBar(true);
chart.getDescription().setEnabled(false);
// if more than 60 entries are displayed in the chart, no values will be
// drawn
chart.setMaxVisibleValueCount(60);
// scaling can now only be done on x- and y-axis separately
chart.setPinchZoom(false);
// draw shadows for each bar that show the maximum value
// chart.setDrawBarShadow(true);
chart.setDrawGridBackground(false);
XAxis xl = chart.getXAxis();
xl.setPosition(XAxisPosition.BOTTOM);
xl.setTypeface(tfLight);
xl.setDrawAxisLine(true);
xl.setDrawGridLines(false);
xl.setGranularity(10f);
YAxis yl = chart.getAxisLeft();
yl.setTypeface(tfLight);
yl.setDrawAxisLine(true);
yl.setDrawGridLines(true);
// yl.setInverted(true);
YAxis yr = chart.getAxisRight();
yr.setTypeface(tfLight);
yr.setDrawAxisLine(true);
yr.setDrawGridLines(false);
// yr.setInverted(true);
chart.setFitBars(true);
chart.animateY(2500);
// setting data
seekBarY.setProgress(50);
seekBarX.setProgress(12);
Legend l = chart.getLegend();
l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
l.setDrawInside(false);
l.setFormSize(8f);
l.setXEntrySpace(4f);
}
private void setData(int count, float range) {
float barWidth = 9f;
float spaceForBar = 10f;
ArrayList<BarEntry> values = new ArrayList<>();
for (int i = 0; i < count; i++) {
float val = (float) (Math.random() * range - range / 2);
values.add(new BarEntry(i * spaceForBar, val,
getResources().getDrawable(R.drawable.star)));
}
BarDataSet set1;
if (chart.getData() != null &&
chart.getData().getDataSetCount() > 0) {
set1 = (BarDataSet) chart.getData().getDataSetByIndex(0);
set1.setValues(values);
chart.getData().notifyDataChanged();
chart.notifyDataSetChanged();
} else {
set1 = new BarDataSet(values, "DataSet 1");
set1.setDrawIcons(false);
ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(set1);
BarData data = new BarData(dataSets);
data.setValueTextSize(10f);
data.setValueTypeface(tfLight);
data.setBarWidth(barWidth);
chart.setData(data);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.bar, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.viewGithub: {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarChartActivity.java"));
startActivity(i);
break;
}
case R.id.actionToggleValues: {
List<IBarDataSet> sets = chart.getData()
.getDataSets();
for (IBarDataSet iSet : sets) {
iSet.setDrawValues(!iSet.isDrawValuesEnabled());
}
chart.invalidate();
break;
}
case R.id.actionToggleIcons: {
List<IBarDataSet> sets = chart.getData()
.getDataSets();
for (IBarDataSet iSet : sets) {
iSet.setDrawIcons(!iSet.isDrawIconsEnabled());
}
chart.invalidate();
break;
}
case R.id.actionToggleHighlight: {
if(chart.getData() != null) {
chart.getData().setHighlightEnabled(!chart.getData().isHighlightEnabled());
chart.invalidate();
}
break;
}
case R.id.actionTogglePinch: {
if (chart.isPinchZoomEnabled())
chart.setPinchZoom(false);
else
chart.setPinchZoom(true);
chart.invalidate();
break;
}
case R.id.actionToggleAutoScaleMinMax: {
chart.setAutoScaleMinMaxEnabled(!chart.isAutoScaleMinMaxEnabled());
chart.notifyDataSetChanged();
break;
}
case R.id.actionToggleBarBorders: {
for (IBarDataSet set : chart.getData().getDataSets())
((BarDataSet)set).setBarBorderWidth(set.getBarBorderWidth() == 1.f ? 0.f : 1.f);
chart.invalidate();
break;
}
case R.id.animateX: {
chart.animateX(2000);
break;
}
case R.id.animateY: {
chart.animateY(2000);
break;
}
case R.id.animateXY: {
chart.animateXY(2000, 2000);
break;
}
case R.id.actionSave: {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
saveToGallery();
} else {
requestStoragePermission(chart);
}
break;
}
}
return true;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
tvX.setText(String.valueOf(seekBarX.getProgress()));
tvY.setText(String.valueOf(seekBarY.getProgress()));
setData(seekBarX.getProgress(), seekBarY.getProgress());
chart.setFitBars(true);
chart.invalidate();
}
@Override
protected void saveToGallery() {
saveToGallery(chart, "HorizontalBarChartActivity");
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
private final RectF mOnValueSelectedRectF = new RectF();
@Override
public void onValueSelected(Entry e, Highlight h) {
if (e == null)
return;
RectF bounds = mOnValueSelectedRectF;
chart.getBarBounds((BarEntry) e, bounds);
MPPointF position = chart.getPosition(e, chart.getData().getDataSetByIndex(h.getDataSetIndex())
.getAxisDependency());
Log.i("bounds", bounds.toString());
Log.i("position", position.toString());
MPPointF.recycleInstance(position);
}
@Override
public void onNothingSelected() {}
}

View file

@ -45,7 +45,7 @@ import java.util.List;
* Example of a heavily customized {@link LineChart} with limit lines, custom line shapes, etc.
*
* @since 1.7.4
* @version 3.0.3
* @version 3.1.0
*/
public class LineChartActivity1 extends DemoBase implements OnSeekBarChangeListener,
OnChartValueSelectedListener {

View file

@ -38,7 +38,7 @@ import java.util.List;
* Example of a dual axis {@link LineChart} with multiple data sets.
*
* @since 1.7.4
* @version 3.0.3
* @version 3.1.0
*/
public class LineChartActivity2 extends DemoBase implements OnSeekBarChangeListener,
OnChartValueSelectedListener {

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
@ -16,7 +15,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
@ -24,7 +22,7 @@ import com.github.mikephil.charting.components.YAxis.AxisDependency;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
@ -92,12 +90,12 @@ public class LineChartTime extends DemoBase implements OnSeekBarChangeListener {
xAxis.setTextColor(Color.rgb(255, 192, 56));
xAxis.setCenterAxisLabels(true);
xAxis.setGranularity(1f); // one hour
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
private final SimpleDateFormat mFormat = new SimpleDateFormat("dd MMM HH:mm", Locale.ENGLISH);
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
long millis = TimeUnit.HOURS.toMillis((long) value);
return mFormat.format(new Date(millis));

View file

@ -160,7 +160,7 @@ public class PieChartActivity extends DemoBase implements OnSeekBarChangeListene
//dataSet.setSelectionShift(0f);
PieData data = new PieData(dataSet);
data.setValueFormatter(new PercentFormatter());
data.setValueFormatter(new PercentFormatter(chart));
data.setValueTextSize(11f);
data.setValueTextColor(Color.WHITE);
data.setValueTypeface(tfLight);
@ -210,6 +210,27 @@ public class PieChartActivity extends DemoBase implements OnSeekBarChangeListene
chart.invalidate();
break;
}
case R.id.actionToggleMinAngles: {
if (chart.getMinAngleForSlices() == 0f)
chart.setMinAngleForSlices(36f);
else
chart.setMinAngleForSlices(0f);
chart.notifyDataSetChanged();
chart.invalidate();
break;
}
case R.id.actionToggleCurvedSlices: {
boolean toSet = !chart.isDrawRoundedSlicesEnabled() || !chart.isDrawHoleEnabled();
chart.setDrawRoundedSlices(toSet);
if (toSet && !chart.isDrawHoleEnabled()) {
chart.setDrawHoleEnabled(true);
}
if (toSet && chart.isDrawSlicesUnderHoleEnabled()) {
chart.setDrawSlicesUnderHole(false);
}
chart.invalidate();
break;
}
case R.id.actionDrawCenter: {
if (chart.isDrawCenterTextEnabled())
chart.setDrawCenterText(false);

View file

@ -156,7 +156,6 @@ public class PiePolylineChartActivity extends DemoBase implements OnSeekBarChang
dataSet.setValueLinePart1OffsetPercentage(80.f);
dataSet.setValueLinePart1Length(0.2f);
dataSet.setValueLinePart2Length(0.4f);
//dataSet.setUsingSliceColorAsValueLineColor(true);
//dataSet.setXValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
@ -205,6 +204,27 @@ public class PiePolylineChartActivity extends DemoBase implements OnSeekBarChang
chart.invalidate();
break;
}
case R.id.actionToggleMinAngles: {
if (chart.getMinAngleForSlices() == 0f)
chart.setMinAngleForSlices(36f);
else
chart.setMinAngleForSlices(0f);
chart.notifyDataSetChanged();
chart.invalidate();
break;
}
case R.id.actionToggleCurvedSlices: {
boolean toSet = !chart.isDrawRoundedSlicesEnabled() || !chart.isDrawHoleEnabled();
chart.setDrawRoundedSlices(toSet);
if (toSet && !chart.isDrawHoleEnabled()) {
chart.setDrawHoleEnabled(true);
}
if (toSet && chart.isDrawSlicesUnderHoleEnabled()) {
chart.setDrawSlicesUnderHole(false);
}
chart.invalidate();
break;
}
case R.id.actionDrawCenter: {
if (chart.isDrawCenterTextEnabled())
chart.setDrawCenterText(false);

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
@ -14,7 +13,6 @@ import android.view.WindowManager;
import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.RadarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.components.XAxis;
@ -22,7 +20,7 @@ import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.RadarData;
import com.github.mikephil.charting.data.RadarDataSet;
import com.github.mikephil.charting.data.RadarEntry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.interfaces.datasets.IRadarDataSet;
import com.xxmassdeveloper.mpchartexample.custom.RadarMarkerView;
@ -69,12 +67,12 @@ public class RadarChartActivity extends DemoBase {
xAxis.setTextSize(9f);
xAxis.setYOffset(0f);
xAxis.setXOffset(0f);
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
private final String[] mActivities = new String[]{"Burger", "Steak", "Salad", "Pasta", "Pizza"};
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return mActivities[(int) value % mActivities.length];
}
});

View file

@ -24,11 +24,11 @@ import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.StackedValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.xxmassdeveloper.mpchartexample.custom.MyAxisValueFormatter;
import com.xxmassdeveloper.mpchartexample.custom.MyValueFormatter;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
@ -78,7 +78,7 @@ public class StackedBarActivity extends DemoBase implements OnSeekBarChangeListe
// change the position of the y-labels
YAxis leftAxis = chart.getAxisLeft();
leftAxis.setValueFormatter(new MyAxisValueFormatter());
leftAxis.setValueFormatter(new MyValueFormatter("K"));
leftAxis.setAxisMinimum(0f); // this replaces setStartAtZero(true)
chart.getAxisRight().setEnabled(false);
@ -142,7 +142,7 @@ public class StackedBarActivity extends DemoBase implements OnSeekBarChangeListe
dataSets.add(set1);
BarData data = new BarData(dataSets);
data.setValueFormatter(new MyValueFormatter());
data.setValueFormatter(new StackedValueFormatter(false, "", 1));
data.setValueTextColor(Color.WHITE);
chart.setData(data);

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample;
import android.Manifest;
@ -14,7 +13,6 @@ import android.view.MenuItem;
import android.view.WindowManager;
import com.github.mikephil.charting.charts.HorizontalBarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.XAxis.XAxisPosition;
@ -23,12 +21,10 @@ import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.ViewPortHandler;
import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase;
import java.text.DecimalFormat;
@ -80,12 +76,12 @@ public class StackedBarActivityNegative extends DemoBase implements
xAxis.setCenterAxisLabels(true);
xAxis.setLabelCount(12);
xAxis.setGranularity(10f);
xAxis.setValueFormatter(new IAxisValueFormatter() {
xAxis.setValueFormatter(new ValueFormatter() {
private final DecimalFormat format = new DecimalFormat("###");
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return format.format(value) + "-" + format.format(value + 10);
}
});
@ -242,7 +238,7 @@ public class StackedBarActivityNegative extends DemoBase implements
Log.i("NOTING SELECTED", "");
}
private class CustomFormatter implements IValueFormatter, IAxisValueFormatter {
private class CustomFormatter extends ValueFormatter {
private final DecimalFormat mFormat;
@ -250,15 +246,8 @@ public class StackedBarActivityNegative extends DemoBase implements
mFormat = new DecimalFormat("###");
}
// data
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return mFormat.format(Math.abs(value)) + "m";
}
// YAxis
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return mFormat.format(Math.abs(value)) + "m";
}
}

View file

@ -1,13 +1,12 @@
package com.xxmassdeveloper.mpchartexample.custom;
import com.github.mikephil.charting.charts.BarLineChartBase;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
/**
* Created by philipp on 02/06/16.
*/
public class DayAxisValueFormatter implements IAxisValueFormatter
public class DayAxisValueFormatter extends ValueFormatter
{
private final String[] mMonths = new String[]{
@ -21,7 +20,7 @@ public class DayAxisValueFormatter implements IAxisValueFormatter
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
int days = (int) value;

View file

@ -1,21 +0,0 @@
package com.xxmassdeveloper.mpchartexample.custom;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import java.text.DecimalFormat;
public class MyAxisValueFormatter implements IAxisValueFormatter
{
private final DecimalFormat mFormat;
public MyAxisValueFormatter() {
mFormat = new DecimalFormat("###,###,###,##0.0");
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
return mFormat.format(value) + " $";
}
}

View file

@ -1,7 +1,6 @@
package com.xxmassdeveloper.mpchartexample.custom;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
@ -12,7 +11,7 @@ import java.text.DecimalFormat;
* @deprecated The {@link MyAxisValueFormatter} does exactly the same thing and is more functional.
*/
@Deprecated
public class MyCustomXAxisValueFormatter implements IAxisValueFormatter
public class MyCustomXAxisValueFormatter extends ValueFormatter
{
private final DecimalFormat mFormat;
@ -25,7 +24,7 @@ public class MyCustomXAxisValueFormatter implements IAxisValueFormatter
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
//Log.i("TRANS", "x: " + viewPortHandler.getTransX() + ", y: " + viewPortHandler.getTransY());

View file

@ -1,22 +1,35 @@
package com.xxmassdeveloper.mpchartexample.custom;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.utils.ViewPortHandler;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.formatter.ValueFormatter;
import java.text.DecimalFormat;
public class MyValueFormatter implements IValueFormatter
public class MyValueFormatter extends ValueFormatter
{
private final DecimalFormat mFormat;
private String suffix;
public MyValueFormatter() {
public MyValueFormatter(String suffix) {
mFormat = new DecimalFormat("###,###,###,##0.0");
this.suffix = suffix;
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return mFormat.format(value) + " $";
public String getFormattedValue(float value) {
return mFormat.format(value) + suffix;
}
@Override
public String getAxisLabel(float value, AxisBase axis) {
if (axis instanceof XAxis) {
return mFormat.format(value);
} else if (value > 0) {
return mFormat.format(value) + suffix;
} else {
return mFormat.format(value);
}
}
}

View file

@ -1,4 +1,3 @@
package com.xxmassdeveloper.mpchartexample.custom;
import android.annotation.SuppressLint;
@ -7,7 +6,7 @@ import android.widget.TextView;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;
import com.xxmassdeveloper.mpchartexample.R;
@ -23,11 +22,11 @@ import java.text.DecimalFormat;
public class XYMarkerView extends MarkerView {
private final TextView tvContent;
private final IAxisValueFormatter xAxisValueFormatter;
private final ValueFormatter xAxisValueFormatter;
private final DecimalFormat format;
public XYMarkerView(Context context, IAxisValueFormatter xAxisValueFormatter) {
public XYMarkerView(Context context, ValueFormatter xAxisValueFormatter) {
super(context, R.layout.custom_marker_view);
this.xAxisValueFormatter = xAxisValueFormatter;
@ -40,7 +39,7 @@ public class XYMarkerView extends MarkerView {
@Override
public void refreshContent(Entry e, Highlight highlight) {
tvContent.setText(String.format("x: %s, y: %s", xAxisValueFormatter.getFormattedValue(e.getX(), null), format.format(e.getY())));
tvContent.setText(String.format("x: %s, y: %s", xAxisValueFormatter.getFormattedValue(e.getX()), format.format(e.getY())));
super.refreshContent(e, highlight);
}

View file

@ -1,13 +1,13 @@
package com.xxmassdeveloper.mpchartexample.custom;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
/**
* Created by Philipp Jahoda on 14/09/15.
*/
@SuppressWarnings("unused")
public class YearXAxisFormatter implements IAxisValueFormatter
public class YearXAxisFormatter extends ValueFormatter
{
private final String[] mMonths = new String[]{
@ -19,7 +19,7 @@ public class YearXAxisFormatter implements IAxisValueFormatter
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getAxisLabel(float value, AxisBase axis) {
float percent = value / axis.mAxisRange;
return mMonths[(int) (mMonths.length * percent)];

View file

@ -26,6 +26,7 @@ import com.xxmassdeveloper.mpchartexample.DynamicalAddingActivity;
import com.xxmassdeveloper.mpchartexample.FilledLineActivity;
import com.xxmassdeveloper.mpchartexample.HalfPieChartActivity;
import com.xxmassdeveloper.mpchartexample.HorizontalBarChartActivity;
import com.xxmassdeveloper.mpchartexample.HorizontalBarNegativeChartActivity;
import com.xxmassdeveloper.mpchartexample.InvertedLineChartActivity;
import com.xxmassdeveloper.mpchartexample.LineChartActivity1;
import com.xxmassdeveloper.mpchartexample.LineChartActivity2;
@ -87,40 +88,41 @@ public class MainActivity extends AppCompatActivity implements OnItemClickListen
objects.add(13, new ContentItem("Horizontal", "Render bar chart horizontally."));
objects.add(14, new ContentItem("Stacked", "Stacked bar chart."));
objects.add(15, new ContentItem("Negative", "Positive and negative values with unique colors."));
objects.add(16, new ContentItem("Stacked 2", "Stacked bar chart with negative values."));
objects.add(17, new ContentItem("Sine", "Sine function in bar chart format."));
objects.add(16, new ContentItem("Negative Horizontal", "demonstrates how to create a HorizontalBarChart with positive and negative values."));
objects.add(17, new ContentItem("Stacked 2", "Stacked bar chart with negative values."));
objects.add(18, new ContentItem("Sine", "Sine function in bar chart format."));
////
objects.add(18, new ContentItem("Pie Charts"));
objects.add(19, new ContentItem("Pie Charts"));
objects.add(19, new ContentItem("Basic", "Simple pie chart."));
objects.add(20, new ContentItem("Value Lines", "Stylish lines drawn outward from slices."));
objects.add(21, new ContentItem("Half Pie", "180° (half) pie chart."));
objects.add(20, new ContentItem("Basic", "Simple pie chart."));
objects.add(21, new ContentItem("Value Lines", "Stylish lines drawn outward from slices."));
objects.add(22, new ContentItem("Half Pie", "180° (half) pie chart."));
////
objects.add(22, new ContentItem("Other Charts"));
objects.add(23, new ContentItem("Other Charts"));
objects.add(23, new ContentItem("Combined Chart", "Bar and line chart together."));
objects.add(24, new ContentItem("Scatter Plot", "Simple scatter plot."));
objects.add(25, new ContentItem("Bubble Chart", "Simple bubble chart."));
objects.add(26, new ContentItem("Candlestick", "Simple financial chart."));
objects.add(27, new ContentItem("Radar Chart", "Simple web chart."));
objects.add(24, new ContentItem("Combined Chart", "Bar and line chart together."));
objects.add(25, new ContentItem("Scatter Plot", "Simple scatter plot."));
objects.add(26, new ContentItem("Bubble Chart", "Simple bubble chart."));
objects.add(27, new ContentItem("Candlestick", "Simple financial chart."));
objects.add(28, new ContentItem("Radar Chart", "Simple web chart."));
////
objects.add(28, new ContentItem("Scrolling Charts"));
objects.add(29, new ContentItem("Scrolling Charts"));
objects.add(29, new ContentItem("Multiple", "Various types of charts as fragments."));
objects.add(30, new ContentItem("View Pager", "Swipe through different charts."));
objects.add(31, new ContentItem("Tall Bar Chart", "Bars bigger than your screen!"));
objects.add(32, new ContentItem("Many Bar Charts", "More bars than your screen can handle!"));
objects.add(30, new ContentItem("Multiple", "Various types of charts as fragments."));
objects.add(31, new ContentItem("View Pager", "Swipe through different charts."));
objects.add(32, new ContentItem("Tall Bar Chart", "Bars bigger than your screen!"));
objects.add(33, new ContentItem("Many Bar Charts", "More bars than your screen can handle!"));
////
objects.add(33, new ContentItem("Even More Line Charts"));
objects.add(34, new ContentItem("Even More Line Charts"));
objects.add(34, new ContentItem("Dynamic", "Build a line chart by adding points and sets."));
objects.add(35, new ContentItem("Realtime", "Add data points in realtime."));
objects.add(36, new ContentItem("Hourly", "Uses the current time to add a data point for each hour."));
//objects.add(37, new ContentItem("Realm.io Examples", "See more examples that use Realm.io mobile database."));
objects.add(35, new ContentItem("Dynamic", "Build a line chart by adding points and sets."));
objects.add(36, new ContentItem("Realtime", "Add data points in realtime."));
objects.add(37, new ContentItem("Hourly", "Uses the current time to add a data point for each hour."));
//objects.add(38, new ContentItem("Realm.io Examples", "See more examples that use Realm.io mobile database."));
MyAdapter adapter = new MyAdapter(this, objects);
@ -179,57 +181,60 @@ public class MainActivity extends AppCompatActivity implements OnItemClickListen
i = new Intent(this, BarChartPositiveNegative.class);
break;
case 16:
i = new Intent(this, StackedBarActivityNegative.class);
i = new Intent(this, HorizontalBarNegativeChartActivity.class);
break;
case 17:
i = new Intent(this, StackedBarActivityNegative.class);
break;
case 18:
i = new Intent(this, BarChartActivitySinus.class);
break;
case 19:
case 20:
i = new Intent(this, PieChartActivity.class);
break;
case 20:
case 21:
i = new Intent(this, PiePolylineChartActivity.class);
break;
case 21:
case 22:
i = new Intent(this, HalfPieChartActivity.class);
break;
case 23:
case 24:
i = new Intent(this, CombinedChartActivity.class);
break;
case 24:
case 25:
i = new Intent(this, ScatterChartActivity.class);
break;
case 25:
case 26:
i = new Intent(this, BubbleChartActivity.class);
break;
case 26:
case 27:
i = new Intent(this, CandleStickChartActivity.class);
break;
case 27:
case 28:
i = new Intent(this, RadarChartActivity.class);
break;
case 29:
case 30:
i = new Intent(this, ListViewMultiChartActivity.class);
break;
case 30:
case 31:
i = new Intent(this, SimpleChartDemo.class);
break;
case 31:
case 32:
i = new Intent(this, ScrollViewActivity.class);
break;
case 32:
case 33:
i = new Intent(this, ListViewBarChartActivity.class);
break;
case 34:
case 35:
i = new Intent(this, DynamicalAddingActivity.class);
break;
case 35:
case 36:
i = new Intent(this, RealtimeLineChartActivity.class);
break;
case 36:
case 37:
i = new Intent(this, LineChartTime.class);
break;
/*case 37:
/*case 38:
i = new Intent(this, RealmMainActivity.class);
break;*/
}

View file

@ -12,6 +12,7 @@
android:layout_alignParentTop="true"
android:layout_marginLeft="4dp"
android:text="Medium Text"
android:textColor="@android:color/black"
android:textSize="16sp"/>
<TextView

View file

@ -21,10 +21,18 @@
android:id="@+id/actionTogglePercent"
android:title="@string/actionTogglePercent">
</item>
<item
android:id="@+id/actionToggleMinAngles"
android:title="@string/actionToggleMinAngles">
</item>
<item
android:id="@+id/actionToggleHole"
android:title="@string/actionToggleHole">
</item>
<item
android:id="@+id/actionToggleCurvedSlices"
android:title="@string/actionToggleCurvedSlices">
</item>
<item
android:id="@+id/actionDrawCenter"
android:title="@string/actionDrawCenterText">

View file

@ -40,7 +40,9 @@
<string name="actionClearChart">Clear chart</string>
<string name="actionTogglePercent">Toggle Percent</string>
<string name="actionToggleMinAngles">Toggle Minimum Angles</string>
<string name="actionToggleHole">Toggle Hole</string>
<string name="actionToggleCurvedSlices">Toggle Curved Slices</string>
<string name="actionDrawCenterText">Draw Center Text</string>
<string name="actionToggleHighlightCircle">Toggle Highlight Circle</string>
<string name="actionToggleRotation">Toggle Rotation</string>

View file

@ -10,7 +10,7 @@ android {
minSdkVersion 14
targetSdkVersion 28
versionCode 3
versionName '3.0.3'
versionName '3.1.0'
}
buildTypes {
release {

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.animation;
import android.animation.ObjectAnimator;
@ -160,98 +159,6 @@ public class ChartAnimator {
animatorY.start();
}
/**
* Animates the drawing / rendering of the chart on both x- and y-axis with
* the specified animation time. If animate(...) is called, no further
* calling of invalidate() is necessary to refresh the chart.
*
* @param durationMillisX animation duration along the X axis
* @param durationMillisY animation duration along the Y axis
* @param easingX EasingFunction for the X axis
* @param easingY EasingFunction for the Y axis
*
* @deprecated Use {@link #animateXY(int, int, EasingFunction, EasingFunction)}
* @see #animateXY(int, int, EasingFunction, EasingFunction)
*/
@SuppressWarnings("deprecation")
@Deprecated
public void animateXY(int durationMillisX, int durationMillisY, Easing.EasingOption easingX,
Easing.EasingOption easingY) {
if (android.os.Build.VERSION.SDK_INT < 11)
return;
ObjectAnimator animatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
animatorY.setInterpolator(Easing.getEasingFunctionFromOption(easingY));
animatorY.setDuration(
durationMillisY);
ObjectAnimator animatorX = ObjectAnimator.ofFloat(this, "phaseX", 0f, 1f);
animatorX.setInterpolator(Easing.getEasingFunctionFromOption(easingX));
animatorX.setDuration(
durationMillisX);
// make sure only one animator produces update-callbacks (which then
// call invalidate())
if (durationMillisX > durationMillisY) {
animatorX.addUpdateListener(mListener);
} else {
animatorY.addUpdateListener(mListener);
}
animatorX.start();
animatorY.start();
}
/**
* Animates the rendering of the chart on the x-axis with the specified
* animation time. If animate(...) is called, no further calling of
* invalidate() is necessary to refresh the chart.
*
* @param durationMillis animation duration
* @param easing EasingFunction
*
* @deprecated Use {@link #animateX(int, EasingFunction)}
* @see #animateX(int, EasingFunction)
*/
@SuppressWarnings("deprecation")
@Deprecated
public void animateX(int durationMillis, Easing.EasingOption easing) {
if (android.os.Build.VERSION.SDK_INT < 11)
return;
ObjectAnimator animatorX = ObjectAnimator.ofFloat(this, "phaseX", 0f, 1f);
animatorX.setInterpolator(Easing.getEasingFunctionFromOption(easing));
animatorX.setDuration(durationMillis);
animatorX.addUpdateListener(mListener);
animatorX.start();
}
/**
* Animates the rendering of the chart on the y-axis with the specified
* animation time. If animate(...) is called, no further calling of
* invalidate() is necessary to refresh the chart.
*
* @param durationMillis animation duration
* @param easing EasingFunction
*
* @deprecated Use {@link #animateY(int, EasingFunction)}
* @see #animateY(int, EasingFunction)
*/
@SuppressWarnings("deprecation")
@Deprecated
public void animateY(int durationMillis, Easing.EasingOption easing) {
if (android.os.Build.VERSION.SDK_INT < 11)
return;
ObjectAnimator animatorY = ObjectAnimator.ofFloat(this, "phaseY", 0f, 1f);
animatorY.setInterpolator(Easing.getEasingFunctionFromOption(easing));
animatorY.setDuration(durationMillis);
animatorY.addUpdateListener(mListener);
animatorY.start();
}
/**
* Gets the Y axis phase of the animation.
*

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.animation;
import android.animation.TimeInterpolator;
@ -19,112 +18,6 @@ public class Easing {
float getInterpolation(float input);
}
/**
* Enum holding EasingOption constants
*
* @deprecated Use Easing.Linear instead of Easing.EasingOption.Linear
*/
@Deprecated
public enum EasingOption {
Linear,
EaseInQuad,
EaseOutQuad,
EaseInOutQuad,
EaseInCubic,
EaseOutCubic,
EaseInOutCubic,
EaseInQuart,
EaseOutQuart,
EaseInOutQuart,
EaseInSine,
EaseOutSine,
EaseInOutSine,
EaseInExpo,
EaseOutExpo,
EaseInOutExpo,
EaseInCirc,
EaseOutCirc,
EaseInOutCirc,
EaseInElastic,
EaseOutElastic,
EaseInOutElastic,
EaseInBack,
EaseOutBack,
EaseInOutBack,
EaseInBounce,
EaseOutBounce,
EaseInOutBounce,
}
/**
* Returns the EasingFunction of the given EasingOption
*
* @param easing EasingOption to get
* @return EasingFunction
*/
@Deprecated
public static EasingFunction getEasingFunctionFromOption(EasingOption easing) {
switch (easing) {
default:
case Linear:
return Easing.Linear;
case EaseInQuad:
return Easing.EaseInQuad;
case EaseOutQuad:
return Easing.EaseOutQuad;
case EaseInOutQuad:
return Easing.EaseInOutQuad;
case EaseInCubic:
return Easing.EaseInCubic;
case EaseOutCubic:
return Easing.EaseOutCubic;
case EaseInOutCubic:
return Easing.EaseInOutCubic;
case EaseInQuart:
return Easing.EaseInQuart;
case EaseOutQuart:
return Easing.EaseOutQuart;
case EaseInOutQuart:
return Easing.EaseInOutQuart;
case EaseInSine:
return Easing.EaseInSine;
case EaseOutSine:
return Easing.EaseOutSine;
case EaseInOutSine:
return Easing.EaseInOutSine;
case EaseInExpo:
return Easing.EaseInExpo;
case EaseOutExpo:
return Easing.EaseOutExpo;
case EaseInOutExpo:
return Easing.EaseInOutExpo;
case EaseInCirc:
return Easing.EaseInCirc;
case EaseOutCirc:
return Easing.EaseOutCirc;
case EaseInOutCirc:
return Easing.EaseInOutCirc;
case EaseInElastic:
return Easing.EaseInElastic;
case EaseOutElastic:
return Easing.EaseOutElastic;
case EaseInOutElastic:
return Easing.EaseInOutElastic;
case EaseInBack:
return Easing.EaseInBack;
case EaseOutBack:
return Easing.EaseOutBack;
case EaseInOutBack:
return Easing.EaseInOutBack;
case EaseInBounce:
return Easing.EaseInBounce;
case EaseOutBounce:
return Easing.EaseOutBounce;
case EaseInOutBounce:
return Easing.EaseInOutBounce;
}
}
private static final float DOUBLE_PI = 2f * (float) Math.PI;
@SuppressWarnings("unused")

View file

@ -100,6 +100,8 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
protected boolean mClipValuesToContent = false;
protected boolean mClipDataToContent = true;
/**
* Sets the minimum offset (padding) around the chart, defaults to 15
*/
@ -230,9 +232,12 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
if (mAxisRight.isEnabled() && mAxisRight.isDrawLimitLinesBehindDataEnabled())
mAxisRendererRight.renderLimitLines(canvas);
// make sure the data cannot be drawn outside the content-rect
int clipRestoreCount = canvas.save();
canvas.clipRect(mViewPortHandler.getContentRect());
if (isClipDataToContentEnabled()) {
// make sure the data cannot be drawn outside the content-rect
canvas.clipRect(mViewPortHandler.getContentRect());
}
mRenderer.drawData(canvas);
@ -394,66 +399,70 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
offsets.top = 0.f;
offsets.bottom = 0.f;
// setup offsets for legend
if (mLegend != null && mLegend.isEnabled() && !mLegend.isDrawInsideEnabled()) {
switch (mLegend.getOrientation()) {
case VERTICAL:
if (mLegend == null || !mLegend.isEnabled() || mLegend.isDrawInsideEnabled())
return;
switch (mLegend.getHorizontalAlignment()) {
case LEFT:
offsets.left += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
switch (mLegend.getOrientation()) {
case VERTICAL:
case RIGHT:
offsets.right += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
switch (mLegend.getHorizontalAlignment()) {
case LEFT:
offsets.left += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
case CENTER:
case RIGHT:
offsets.right += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
case CENTER:
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
default:
break;
}
}
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
break;
default:
break;
}
}
case HORIZONTAL:
break;
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
case HORIZONTAL:
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
default:
break;
}
break;
}
break;
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
default:
break;
}
break;
}
}
@ -708,20 +717,14 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
public void zoomAndCenterAnimated(float scaleX, float scaleY, float xValue, float yValue, AxisDependency axis,
long duration) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
MPPointD origin = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
MPPointD origin = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
Runnable job = AnimatedZoomJob.getInstance(mViewPortHandler, this, getTransformer(axis), getAxis(axis), mXAxis
.mAxisRange, scaleX, scaleY, mViewPortHandler.getScaleX(), mViewPortHandler.getScaleY(),
xValue, yValue, (float) origin.x, (float) origin.y, duration);
addViewportJob(job);
Runnable job = AnimatedZoomJob.getInstance(mViewPortHandler, this, getTransformer(axis), getAxis(axis), mXAxis
.mAxisRange, scaleX, scaleY, mViewPortHandler.getScaleX(), mViewPortHandler.getScaleY(),
xValue, yValue, (float) origin.x, (float) origin.y, duration);
addViewportJob(job);
MPPointD.recycleInstance(origin);
} else {
Log.e(LOG_TAG, "Unable to execute zoomAndCenterAnimated(...) on API level < 11");
}
MPPointD.recycleInstance(origin);
}
protected Matrix mFitScreenMatrixBuffer = new Matrix();
@ -874,21 +877,16 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
@TargetApi(11)
public void moveViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY();
float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY();
Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f,
getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration);
Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler, xValue, yValue + yInView / 2f,
getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration);
addViewportJob(job);
addViewportJob(job);
MPPointD.recycleInstance(bounds);
} else {
Log.e(LOG_TAG, "Unable to execute moveViewToAnimated(...) on API level < 11");
}
MPPointD.recycleInstance(bounds);
}
/**
@ -941,23 +939,18 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
@TargetApi(11)
public void centerViewToAnimated(float xValue, float yValue, AxisDependency axis, long duration) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
MPPointD bounds = getValuesByTouchPoint(mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), axis);
float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY();
float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX();
float yInView = getAxisRange(axis) / mViewPortHandler.getScaleY();
float xInView = getXAxis().mAxisRange / mViewPortHandler.getScaleX();
Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler,
xValue - xInView / 2f, yValue + yInView / 2f,
getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration);
Runnable job = AnimatedMoveViewJob.getInstance(mViewPortHandler,
xValue - xInView / 2f, yValue + yInView / 2f,
getTransformer(axis), this, (float) bounds.x, (float) bounds.y, duration);
addViewportJob(job);
addViewportJob(job);
MPPointD.recycleInstance(bounds);
} else {
Log.e(LOG_TAG, "Unable to execute centerViewToAnimated(...) on API level < 11");
}
MPPointD.recycleInstance(bounds);
}
/**
@ -1240,6 +1233,17 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
mClipValuesToContent = enabled;
}
/**
* When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can
* be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines)
* that there is unwanted clipping.
*
* @param enabled
*/
public void setClipDataToContent(boolean enabled) {
mClipDataToContent = enabled;
}
/**
* When enabled, the values will be clipped to contentRect,
* otherwise they can bleed outside the content rect.
@ -1250,6 +1254,17 @@ public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<
return mClipValuesToContent;
}
/**
* When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can
* be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines)
* that there is unwanted clipping.
*
* @return
*/
public boolean isClipDataToContentEnabled() {
return mClipDataToContent;
}
/**
* Sets the width of the border lines in dp.
*

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.charts;
import android.animation.ValueAnimator;
@ -14,7 +13,6 @@ import android.graphics.Paint.Align;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore.Images;
import androidx.annotation.RequiresApi;
@ -26,7 +24,6 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.animation.Easing.EasingFunction;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.IMarker;
@ -35,7 +32,7 @@ import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.ChartHighlighter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.highlight.IHighlighter;
@ -55,6 +52,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Baseclass of all Chart-Views.
@ -209,18 +208,14 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
setWillNotDraw(false);
// setLayerType(View.LAYER_TYPE_HARDWARE, null);
if (Build.VERSION.SDK_INT < 11) {
mAnimator = new ChartAnimator();
} else {
mAnimator = new ChartAnimator(new AnimatorUpdateListener() {
mAnimator = new ChartAnimator(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// ViewCompat.postInvalidateOnAnimation(Chart.this);
postInvalidate();
}
});
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// ViewCompat.postInvalidateOnAnimation(Chart.this);
postInvalidate();
}
});
// initialize the utils
Utils.init(getContext());
@ -403,8 +398,23 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
boolean hasText = !TextUtils.isEmpty(mNoDataText);
if (hasText) {
MPPointF c = getCenter();
canvas.drawText(mNoDataText, c.x, c.y, mInfoPaint);
MPPointF pt = getCenter();
switch (mInfoPaint.getTextAlign()) {
case LEFT:
pt.x = 0;
canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint);
break;
case RIGHT:
pt.x *= 2.0;
canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint);
break;
default:
canvas.drawText(mNoDataText, pt.x, pt.y, mInfoPaint);
break;
}
}
return;
@ -553,6 +563,24 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
invalidate();
}
public void highlightValues(List<Highlight> highs, List<IMarker> markers) {
if (highs.size() != markers.size()) throw new IllegalArgumentException("Markers and highs must be mutually corresponding. High size = " + highs.size() + " Markers size = " + markers.size());
setMarkers(markers);
highlightValues(highs.toArray(new Highlight[0]));
}
/**
* Highlights any y-value at the given x-value in the given DataSet.
* Provide -1 as the dataSetIndex to undo all highlighting.
* This method will call the listener.
* @param x The x-value to highlight
* @param dataSetIndex The dataset index to search in
* @param dataIndex The data index to search in (only used in CombinedChartView currently)
*/
public void highlightValue(float x, int dataSetIndex, int dataIndex) {
highlightValue(x, dataSetIndex, dataIndex, true);
}
/**
* Highlights any y-value at the given x-value in the given DataSet.
* Provide -1 as the dataSetIndex to undo all highlighting.
@ -561,7 +589,20 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
* @param dataSetIndex The dataset index to search in
*/
public void highlightValue(float x, int dataSetIndex) {
highlightValue(x, dataSetIndex, true);
highlightValue(x, dataSetIndex, -1, true);
}
/**
* Highlights the value at the given x-value and y-value in the given DataSet.
* Provide -1 as the dataSetIndex to undo all highlighting.
* This method will call the listener.
* @param x The x-value to highlight
* @param y The y-value to highlight. Supply `NaN` for "any"
* @param dataSetIndex The dataset index to search in
* @param dataIndex The data index to search in (only used in CombinedChartView currently)
*/
public void highlightValue(float x, float y, int dataSetIndex, int dataIndex) {
highlightValue(x, y, dataSetIndex, dataIndex, true);
}
/**
@ -573,7 +614,19 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
* @param dataSetIndex The dataset index to search in
*/
public void highlightValue(float x, float y, int dataSetIndex) {
highlightValue(x, y, dataSetIndex, true);
highlightValue(x, y, dataSetIndex, -1, true);
}
/**
* Highlights any y-value at the given x-value in the given DataSet.
* Provide -1 as the dataSetIndex to undo all highlighting.
* @param x The x-value to highlight
* @param dataSetIndex The dataset index to search in
* @param dataIndex The data index to search in (only used in CombinedChartView currently)
* @param callListener Should the listener be called for this change
*/
public void highlightValue(float x, int dataSetIndex, int dataIndex, boolean callListener) {
highlightValue(x, Float.NaN, dataSetIndex, dataIndex, callListener);
}
/**
@ -584,7 +637,25 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
* @param callListener Should the listener be called for this change
*/
public void highlightValue(float x, int dataSetIndex, boolean callListener) {
highlightValue(x, Float.NaN, dataSetIndex, callListener);
highlightValue(x, Float.NaN, dataSetIndex, -1, callListener);
}
/**
* Highlights any y-value at the given x-value in the given DataSet.
* Provide -1 as the dataSetIndex to undo all highlighting.
* @param x The x-value to highlight
* @param y The y-value to highlight. Supply `NaN` for "any"
* @param dataSetIndex The dataset index to search in
* @param dataIndex The data index to search in (only used in CombinedChartView currently)
* @param callListener Should the listener be called for this change
*/
public void highlightValue(float x, float y, int dataSetIndex, int dataIndex, boolean callListener) {
if (dataSetIndex < 0 || dataSetIndex >= mData.getDataSetCount()) {
highlightValue(null, callListener);
} else {
highlightValue(new Highlight(x, y, dataSetIndex, dataIndex), callListener);
}
}
/**
@ -596,12 +667,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
* @param callListener Should the listener be called for this change
*/
public void highlightValue(float x, float y, int dataSetIndex, boolean callListener) {
if (dataSetIndex < 0 || dataSetIndex >= mData.getDataSetCount()) {
highlightValue(null, callListener);
} else {
highlightValue(new Highlight(x, y, dataSetIndex), callListener);
}
highlightValue(x, y, dataSetIndex, -1, callListener);
}
/**
@ -712,7 +778,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
/**
* the view that represents the marker
*/
protected IMarker mMarker;
protected List<IMarker> mMarkers;
/**
* draws all MarkerViews on the highlighted positions
@ -720,7 +786,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
protected void drawMarkers(Canvas canvas) {
// if there is no marker view or drawing marker is disabled
if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
if (mMarkers == null || !isDrawMarkersEnabled() || !valuesToHighlight())
return;
for (int i = 0; i < mIndicesToHighlight.length; i++) {
@ -743,10 +809,12 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
continue;
// callbacks to update the content
mMarker.refreshContent(e, highlight);
int markerIndex = i % mMarkers.size();
IMarker markerItem = mMarkers.get(markerIndex);
markerItem.refreshContent(e, highlight);
// draw the marker
mMarker.draw(canvas, pos[0], pos[1]);
markerItem.draw(canvas, pos[0], pos[1]);
}
}
@ -892,60 +960,6 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
*/
/** CODE BELOW FOR PREDEFINED EASING OPTIONS */
/**
* Animates the drawing / rendering of the chart on both x- and y-axis with
* the specified animation time. If animate(...) is called, no further
* calling of invalidate() is necessary to refresh the chart. ANIMATIONS
* ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER.
*
* @param durationMillisX
* @param durationMillisY
* @param easingX a predefined easing option
* @param easingY a predefined easing option
*
* @deprecated Use {@link #animateXY(int, int, EasingFunction, EasingFunction)}
* @see #animateXY(int, int, EasingFunction, EasingFunction)
*/
@Deprecated
public void animateXY(int durationMillisX, int durationMillisY, Easing.EasingOption easingX,
Easing.EasingOption easingY) {
mAnimator.animateXY(durationMillisX, durationMillisY, easingX, easingY);
}
/**
* Animates the rendering of the chart on the x-axis with the specified
* animation time. If animate(...) is called, no further calling of
* invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR
* API LEVEL 11 (Android 3.0.x) AND HIGHER.
*
* @param durationMillis
* @param easing a predefined easing option
*
* @deprecated Use {@link #animateX(int, EasingFunction)}
* @see #animateX(int, EasingFunction)
*/
@Deprecated
public void animateX(int durationMillis, Easing.EasingOption easing) {
mAnimator.animateX(durationMillis, easing);
}
/**
* Animates the rendering of the chart on the y-axis with the specified
* animation time. If animate(...) is called, no further calling of
* invalidate() is necessary to refresh the chart. ANIMATIONS ONLY WORK FOR
* API LEVEL 11 (Android 3.0.x) AND HIGHER.
*
* @param durationMillis
* @param easing a predefined easing option
*
* @deprecated Use {@link #animateY(int, EasingFunction)}
* @see #animateY(int, EasingFunction)
*/
@Deprecated
public void animateY(int durationMillis, Easing.EasingOption easing) {
mAnimator.animateY(durationMillis, easing);
}
/**
* ################ ################ ################ ################
* ANIMATIONS ONLY WORK FOR API LEVEL 11 (Android 3.0.x) AND HIGHER.
@ -1015,7 +1029,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
*
* @return
*/
public IValueFormatter getDefaultValueFormatter() {
public ValueFormatter getDefaultValueFormatter() {
return mDefaultValueFormatter;
}
@ -1221,6 +1235,15 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
mInfoPaint.setTypeface(tf);
}
/**
* alignment of the no data text
*
* @param align
*/
public void setNoDataTextAlignment(Align align) {
mInfoPaint.setTextAlign(align);
}
/**
* Set this to false to disable all gestures and touches on the chart,
* default: true
@ -1231,22 +1254,25 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
this.mTouchEnabled = enabled;
}
public void setMarkers(List<IMarker> marker) {
mMarkers = marker;
}
/**
* sets the marker that is displayed when a value is clicked on the chart
*
* @param marker
*/
public void setMarker(IMarker marker) {
mMarker = marker;
setMarkers(Collections.unmodifiableList(Collections.singletonList(marker)));
}
/**
* returns the marker that is set as a marker view for the chart
*
* @return
*/
public IMarker getMarker() {
return mMarker;
public List<IMarker> getMarker() {
return mMarkers;
}
@Deprecated
@ -1255,7 +1281,7 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
}
@Deprecated
public IMarker getMarkerView() {
public List<IMarker> getMarkerView() {
return getMarker();
}
@ -1752,16 +1778,10 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
*/
public void setHardwareAccelerationEnabled(boolean enabled) {
if (android.os.Build.VERSION.SDK_INT >= 11) {
if (enabled)
setLayerType(View.LAYER_TYPE_HARDWARE, null);
else
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} else {
Log.e(LOG_TAG,
"Cannot enable/disable hardware acceleration for devices below API level 11.");
}
if (enabled)
setLayerType(View.LAYER_TYPE_HARDWARE, null);
else
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
@Override

View file

@ -6,6 +6,7 @@ import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import com.github.mikephil.charting.components.IMarker;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BubbleData;
import com.github.mikephil.charting.data.CandleData;
@ -236,7 +237,7 @@ public class CombinedChart extends BarLineChartBase<CombinedData> implements Com
protected void drawMarkers(Canvas canvas) {
// if there is no marker view or drawing marker is disabled
if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
if (mMarkers == null || !isDrawMarkersEnabled() || !valuesToHighlight())
return;
for (int i = 0; i < mIndicesToHighlight.length; i++) {
@ -262,10 +263,11 @@ public class CombinedChart extends BarLineChartBase<CombinedData> implements Com
continue;
// callbacks to update the content
mMarker.refreshContent(e, highlight);
IMarker markerItem = mMarkers.get(i % mMarkers.size());
markerItem.refreshContent(e, highlight);
// draw the marker
mMarker.draw(canvas, pos[0], pos[1]);
markerItem.draw(canvas, pos[0], pos[1]);
}
}

View file

@ -60,6 +60,84 @@ public class HorizontalBarChart extends BarChart {
private RectF mOffsetsBuffer = new RectF();
protected void calculateLegendOffsets(RectF offsets) {
offsets.left = 0.f;
offsets.right = 0.f;
offsets.top = 0.f;
offsets.bottom = 0.f;
if (mLegend == null || !mLegend.isEnabled() || mLegend.isDrawInsideEnabled())
return;
switch (mLegend.getOrientation()) {
case VERTICAL:
switch (mLegend.getHorizontalAlignment()) {
case LEFT:
offsets.left += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
case RIGHT:
offsets.right += Math.min(mLegend.mNeededWidth,
mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent())
+ mLegend.getXOffset();
break;
case CENTER:
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
break;
default:
break;
}
}
break;
case HORIZONTAL:
switch (mLegend.getVerticalAlignment()) {
case TOP:
offsets.top += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
if (mAxisLeft.isEnabled() && mAxisLeft.isDrawLabelsEnabled())
offsets.top += mAxisLeft.getRequiredHeightSpace(
mAxisRendererLeft.getPaintAxisLabels());
break;
case BOTTOM:
offsets.bottom += Math.min(mLegend.mNeededHeight,
mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent())
+ mLegend.getYOffset();
if (mAxisRight.isEnabled() && mAxisRight.isDrawLabelsEnabled())
offsets.bottom += mAxisRight.getRequiredHeightSpace(
mAxisRendererRight.getPaintAxisLabels());
break;
default:
break;
}
break;
}
}
@Override
public void calculateOffsets() {

View file

@ -94,6 +94,12 @@ public class PieChart extends PieRadarChartBase<PieData> {
protected float mMaxAngle = 360f;
/**
* Minimum angle to draw slices, this only works if there is enough room for all slices to have
* the minimum angle, default 0f.
*/
private float mMinAngleForSlices = 0f;
public PieChart(Context context) {
super(context);
}
@ -228,7 +234,12 @@ public class PieChart extends PieRadarChartBase<PieData> {
List<IPieDataSet> dataSets = mData.getDataSets();
boolean hasMinAngle = mMinAngleForSlices != 0f && entryCount * mMinAngleForSlices <= mMaxAngle;
float[] minAngles = new float[entryCount];
int cnt = 0;
float offset = 0f;
float diff = 0f;
for (int i = 0; i < mData.getDataSetCount(); i++) {
@ -236,7 +247,20 @@ public class PieChart extends PieRadarChartBase<PieData> {
for (int j = 0; j < set.getEntryCount(); j++) {
mDrawAngles[cnt] = calcAngle(Math.abs(set.getEntryForIndex(j).getY()), yValueSum);
float drawAngle = calcAngle(Math.abs(set.getEntryForIndex(j).getY()), yValueSum);
if (hasMinAngle) {
float temp = drawAngle - mMinAngleForSlices;
if (temp <= 0) {
minAngles[cnt] = mMinAngleForSlices;
offset += -temp;
} else {
minAngles[cnt] = drawAngle;
diff += temp;
}
}
mDrawAngles[cnt] = drawAngle;
if (cnt == 0) {
mAbsoluteAngles[cnt] = mDrawAngles[cnt];
@ -248,6 +272,20 @@ public class PieChart extends PieRadarChartBase<PieData> {
}
}
if (hasMinAngle) {
// Correct bigger slices by relatively reducing their angles based on the total angle needed to subtract
// This requires that `entryCount * mMinAngleForSlices <= mMaxAngle` be true to properly work!
for (int i = 0; i < entryCount; i++) {
minAngles[i] -= (minAngles[i] - mMinAngleForSlices) / diff * offset;
if (i == 0) {
mAbsoluteAngles[0] = minAngles[0];
} else {
mAbsoluteAngles[i] = mAbsoluteAngles[i - 1] + minAngles[i];
}
}
mDrawAngles = minAngles;
}
}
/**
@ -650,6 +688,16 @@ public class PieChart extends PieRadarChartBase<PieData> {
((PieChartRenderer) mRenderer).getPaintEntryLabels().setTextSize(Utils.convertDpToPixel(size));
}
/**
* Sets whether to draw slices in a curved fashion, only works if drawing the hole is enabled
* and if the slices are not drawn under the hole.
*
* @param enabled draw curved ends of slices
*/
public void setDrawRoundedSlices(boolean enabled) {
mDrawRoundedSlices = enabled;
}
/**
* Returns true if the chart is set to draw each end of a pie-slice
* "rounded".
@ -719,6 +767,32 @@ public class PieChart extends PieRadarChartBase<PieData> {
this.mMaxAngle = maxangle;
}
/**
* The minimum angle slices on the chart are rendered with, default is 0f.
*
* @return minimum angle for slices
*/
public float getMinAngleForSlices() {
return mMinAngleForSlices;
}
/**
* Set the angle to set minimum size for slices, you must call {@link #notifyDataSetChanged()}
* and {@link #invalidate()} when changing this, only works if there is enough room for all
* slices to have the minimum angle.
*
* @param minAngle minimum 0, maximum is half of {@link #setMaxAngle(float)}
*/
public void setMinAngleForSlices(float minAngle) {
if (minAngle > (mMaxAngle / 2f))
minAngle = mMaxAngle / 2f;
else if (minAngle < 0)
minAngle = 0f;
this.mMinAngleForSlices = minAngle;
}
@Override
protected void onDetachedFromWindow() {
// releases the bitmap in the renderer to avoid oom error

View file

@ -480,9 +480,6 @@ public abstract class PieRadarChartBase<T extends ChartData<? extends IDataSet<?
@SuppressLint("NewApi")
public void spin(int durationmillis, float fromangle, float toangle, EasingFunction easing) {
if (android.os.Build.VERSION.SDK_INT < 11)
return;
setRotationAngle(fromangle);
ObjectAnimator spinAnimator = ObjectAnimator.ofFloat(this, "rotationAngle", fromangle,

View file

@ -84,6 +84,7 @@ public class RadarChart extends PieRadarChartBase<RadarData> {
super.init();
mYAxis = new YAxis(AxisDependency.LEFT);
mYAxis.setLabelXOffset(10f);
mWebLineWidth = Utils.convertDpToPixel(1.5f);
mInnerWebLineWidth = Utils.convertDpToPixel(0.75f);

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.components;
import android.graphics.Color;
@ -6,7 +5,7 @@ import android.graphics.DashPathEffect;
import android.util.Log;
import com.github.mikephil.charting.formatter.DefaultAxisValueFormatter;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.Utils;
import java.util.ArrayList;
@ -22,7 +21,7 @@ public abstract class AxisBase extends ComponentBase {
/**
* custom formatter that is used instead of the auto-formatter if set
*/
protected IAxisValueFormatter mAxisValueFormatter;
protected ValueFormatter mAxisValueFormatter;
private int mGridColor = Color.GRAY;
@ -152,6 +151,39 @@ public abstract class AxisBase extends ComponentBase {
*/
public float mAxisRange = 0f;
private int mAxisMinLabels = 2;
private int mAxisMaxLabels = 25;
/**
* The minumum number of labels on the axis
*/
public int getAxisMinLabels() {
return mAxisMinLabels;
}
/**
* The minumum number of labels on the axis
*/
public void setAxisMinLabels(int labels) {
if (labels > 0)
mAxisMinLabels = labels;
}
/**
* The maximum number of labels on the axis
*/
public int getAxisMaxLabels() {
return mAxisMaxLabels;
}
/**
* The maximum number of labels on the axis
*/
public void setAxisMaxLabels(int labels) {
if (labels > 0)
mAxisMaxLabels = labels;
}
/**
* default constructor
*/
@ -315,10 +347,10 @@ public abstract class AxisBase extends ComponentBase {
*/
public void setLabelCount(int count) {
if (count > 25)
count = 25;
if (count < 2)
count = 2;
if (count > getAxisMaxLabels())
count = getAxisMaxLabels();
if (count < getAxisMinLabels())
count = getAxisMinLabels();
mLabelCount = count;
mForceLabels = false;
@ -486,7 +518,7 @@ public abstract class AxisBase extends ComponentBase {
if (index < 0 || index >= mEntries.length)
return "";
else
return getValueFormatter().getFormattedValue(mEntries[index], this);
return getValueFormatter().getAxisLabel(mEntries[index], this);
}
/**
@ -498,7 +530,7 @@ public abstract class AxisBase extends ComponentBase {
*
* @param f
*/
public void setValueFormatter(IAxisValueFormatter f) {
public void setValueFormatter(ValueFormatter f) {
if (f == null)
mAxisValueFormatter = new DefaultAxisValueFormatter(mDecimals);
@ -511,7 +543,7 @@ public abstract class AxisBase extends ComponentBase {
*
* @return
*/
public IAxisValueFormatter getValueFormatter() {
public ValueFormatter getValueFormatter() {
if (mAxisValueFormatter == null ||
(mAxisValueFormatter instanceof DefaultAxisValueFormatter &&

View file

@ -1,10 +1,8 @@
package com.github.mikephil.charting.components;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.utils.FSize;
import com.github.mikephil.charting.utils.Utils;
@ -22,19 +20,6 @@ import java.util.List;
*/
public class Legend extends ComponentBase {
/**
* This property is deprecated - Use `horizontalAlignment`, `verticalAlignment`, `orientation`, `drawInside`,
* `direction`.
*/
@Deprecated
public enum LegendPosition {
RIGHT_OF_CHART, RIGHT_OF_CHART_CENTER, RIGHT_OF_CHART_INSIDE,
LEFT_OF_CHART, LEFT_OF_CHART_CENTER, LEFT_OF_CHART_INSIDE,
BELOW_CHART_LEFT, BELOW_CHART_RIGHT, BELOW_CHART_CENTER,
ABOVE_CHART_LEFT, ABOVE_CHART_RIGHT, ABOVE_CHART_CENTER,
PIECHART_CENTER
}
public enum LegendForm {
/**
* Avoid drawing a form
@ -182,43 +167,6 @@ public class Legend extends ComponentBase {
this.mEntries = entries;
}
@Deprecated
public Legend(int[] colors, String[] labels) {
this();
if (colors == null || labels == null) {
throw new IllegalArgumentException("colors array or labels array is NULL");
}
if (colors.length != labels.length) {
throw new IllegalArgumentException(
"colors array and labels array need to be of same size");
}
List<LegendEntry> entries = new ArrayList<>();
for (int i = 0; i < Math.min(colors.length, labels.length); i++) {
final LegendEntry entry = new LegendEntry();
entry.formColor = colors[i];
entry.label = labels[i];
if (entry.formColor == ColorTemplate.COLOR_SKIP)
entry.form = LegendForm.NONE;
else if (entry.formColor == ColorTemplate.COLOR_NONE ||
entry.formColor == 0)
entry.form = LegendForm.EMPTY;
entries.add(entry);
}
mEntries = entries.toArray(new LegendEntry[entries.size()]);
}
@Deprecated
public Legend(List<Integer> colors, List<String> labels) {
this(Utils.convertIntegers(colors), Utils.convertStrings(labels));
}
/**
* This method sets the automatically computed colors for the legend. Use setCustom(...) to set custom colors.
*
@ -287,50 +235,6 @@ public class Legend extends ComponentBase {
return max;
}
@Deprecated
public int[] getColors() {
int[] old = new int[mEntries.length];
for (int i = 0; i < mEntries.length; i++) {
old[i] = mEntries[i].form == LegendForm.NONE ? ColorTemplate.COLOR_SKIP :
(mEntries[i].form == LegendForm.EMPTY ? ColorTemplate.COLOR_NONE :
mEntries[i].formColor);
}
return old;
}
@Deprecated
public String[] getLabels() {
String[] old = new String[mEntries.length];
for (int i = 0; i < mEntries.length; i++) {
old[i] = mEntries[i].label;
}
return old;
}
@Deprecated
public int[] getExtraColors() {
int[] old = new int[mExtraEntries.length];
for (int i = 0; i < mExtraEntries.length; i++) {
old[i] = mExtraEntries[i].form == LegendForm.NONE ? ColorTemplate.COLOR_SKIP :
(mExtraEntries[i].form == LegendForm.EMPTY ? ColorTemplate.COLOR_NONE :
mExtraEntries[i].formColor);
}
return old;
}
@Deprecated
public String[] getExtraLabels() {
String[] old = new String[mExtraEntries.length];
for (int i = 0; i < mExtraEntries.length; i++) {
old[i] = mExtraEntries[i].label;
}
return old;
}
public LegendEntry[] getExtraEntries() {
return mExtraEntries;
@ -346,11 +250,6 @@ public class Legend extends ComponentBase {
mExtraEntries = entries;
}
@Deprecated
public void setExtra(List<Integer> colors, List<String> labels) {
setExtra(Utils.convertIntegers(colors), Utils.convertStrings(labels));
}
/**
* Entries that will be appended to the end of the auto calculated
* entries after calculating the legend.
@ -423,109 +322,6 @@ public class Legend extends ComponentBase {
return mIsLegendCustom;
}
/**
* This property is deprecated - Use `horizontalAlignment`, `verticalAlignment`, `orientation`, `drawInside`,
* `direction`.
*/
@Deprecated
public LegendPosition getPosition() {
if (mOrientation == LegendOrientation.VERTICAL
&& mHorizontalAlignment == LegendHorizontalAlignment.CENTER
&& mVerticalAlignment == LegendVerticalAlignment.CENTER) {
return LegendPosition.PIECHART_CENTER;
} else if (mOrientation == LegendOrientation.HORIZONTAL) {
if (mVerticalAlignment == LegendVerticalAlignment.TOP)
return mHorizontalAlignment == LegendHorizontalAlignment.LEFT
? LegendPosition.ABOVE_CHART_LEFT
: (mHorizontalAlignment == LegendHorizontalAlignment.RIGHT
? LegendPosition.ABOVE_CHART_RIGHT
: LegendPosition.ABOVE_CHART_CENTER);
else
return mHorizontalAlignment == LegendHorizontalAlignment.LEFT
? LegendPosition.BELOW_CHART_LEFT
: (mHorizontalAlignment == LegendHorizontalAlignment.RIGHT
? LegendPosition.BELOW_CHART_RIGHT
: LegendPosition.BELOW_CHART_CENTER);
} else {
if (mHorizontalAlignment == LegendHorizontalAlignment.LEFT)
return mVerticalAlignment == LegendVerticalAlignment.TOP && mDrawInside
? LegendPosition.LEFT_OF_CHART_INSIDE
: (mVerticalAlignment == LegendVerticalAlignment.CENTER
? LegendPosition.LEFT_OF_CHART_CENTER
: LegendPosition.LEFT_OF_CHART);
else
return mVerticalAlignment == LegendVerticalAlignment.TOP && mDrawInside
? LegendPosition.RIGHT_OF_CHART_INSIDE
: (mVerticalAlignment == LegendVerticalAlignment.CENTER
? LegendPosition.RIGHT_OF_CHART_CENTER
: LegendPosition.RIGHT_OF_CHART);
}
}
/**
* This property is deprecated - Use `horizontalAlignment`, `verticalAlignment`, `orientation`, `drawInside`,
* `direction`.
*/
@Deprecated
public void setPosition(LegendPosition newValue) {
switch (newValue) {
case LEFT_OF_CHART:
case LEFT_OF_CHART_INSIDE:
case LEFT_OF_CHART_CENTER:
mHorizontalAlignment = LegendHorizontalAlignment.LEFT;
mVerticalAlignment = newValue == LegendPosition.LEFT_OF_CHART_CENTER
? LegendVerticalAlignment.CENTER
: LegendVerticalAlignment.TOP;
mOrientation = LegendOrientation.VERTICAL;
break;
case RIGHT_OF_CHART:
case RIGHT_OF_CHART_INSIDE:
case RIGHT_OF_CHART_CENTER:
mHorizontalAlignment = LegendHorizontalAlignment.RIGHT;
mVerticalAlignment = newValue == LegendPosition.RIGHT_OF_CHART_CENTER
? LegendVerticalAlignment.CENTER
: LegendVerticalAlignment.TOP;
mOrientation = LegendOrientation.VERTICAL;
break;
case ABOVE_CHART_LEFT:
case ABOVE_CHART_CENTER:
case ABOVE_CHART_RIGHT:
mHorizontalAlignment = newValue == LegendPosition.ABOVE_CHART_LEFT
? LegendHorizontalAlignment.LEFT
: (newValue == LegendPosition.ABOVE_CHART_RIGHT
? LegendHorizontalAlignment.RIGHT
: LegendHorizontalAlignment.CENTER);
mVerticalAlignment = LegendVerticalAlignment.TOP;
mOrientation = LegendOrientation.HORIZONTAL;
break;
case BELOW_CHART_LEFT:
case BELOW_CHART_CENTER:
case BELOW_CHART_RIGHT:
mHorizontalAlignment = newValue == LegendPosition.BELOW_CHART_LEFT
? LegendHorizontalAlignment.LEFT
: (newValue == LegendPosition.BELOW_CHART_RIGHT
? LegendHorizontalAlignment.RIGHT
: LegendHorizontalAlignment.CENTER);
mVerticalAlignment = LegendVerticalAlignment.BOTTOM;
mOrientation = LegendOrientation.HORIZONTAL;
break;
case PIECHART_CENTER:
mHorizontalAlignment = LegendHorizontalAlignment.CENTER;
mVerticalAlignment = LegendVerticalAlignment.CENTER;
mOrientation = LegendOrientation.VERTICAL;
break;
}
mDrawInside = newValue == LegendPosition.LEFT_OF_CHART_INSIDE
|| newValue == LegendPosition.RIGHT_OF_CHART_INSIDE;
}
/**
* returns the horizontal alignment of the legend
*
@ -907,8 +703,7 @@ public class Legend extends ComponentBase {
width += Utils.calcTextWidth(labelpaint, label);
if (i < entryCount - 1)
maxHeight += labelLineHeight + yEntrySpace;
maxHeight += labelLineHeight + yEntrySpace;
} else {
wasStacked = true;
width += formSize;

View file

@ -73,6 +73,11 @@ public class YAxis extends AxisBase {
*/
private YAxisLabelPosition mPosition = YAxisLabelPosition.OUTSIDE_CHART;
/**
* the horizontal offset of the y-label
*/
private float mXLabelOffset = 0.0f;
/**
* enum for the position of the y-labels relative to the chart
*/
@ -174,6 +179,22 @@ public class YAxis extends AxisBase {
mPosition = pos;
}
/**
* returns the horizontal offset of the y-label
*/
public float getLabelXOffset() {
return mXLabelOffset;
}
/**
* sets the horizontal offset of the y-label
*
* @param xOffset
*/
public void setLabelXOffset(float xOffset) {
mXLabelOffset = xOffset;
}
/**
* returns true if drawing the top y-axis label entry is enabled
*
@ -406,6 +427,26 @@ public class YAxis extends AxisBase {
float min = dataMin;
float max = dataMax;
// Make sure max is greater than min
// Discussion: https://github.com/danielgindi/Charts/pull/3650#discussion_r221409991
if (min > max)
{
if (mCustomAxisMax && mCustomAxisMin)
{
float t = min;
min = max;
max = t;
}
else if (mCustomAxisMax)
{
min = max < 0f ? max * 1.5f : max * 0.5f;
}
else if (mCustomAxisMin)
{
max = min < 0f ? min * 0.5f : min * 1.5f;
}
}
float range = Math.abs(max - min);
// in case all values are equal

View file

@ -4,6 +4,7 @@ package com.github.mikephil.charting.data;
import android.graphics.Color;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.utils.Fill;
import java.util.ArrayList;
import java.util.List;
@ -38,9 +39,9 @@ public class BarDataSet extends BarLineScatterCandleBubbleDataSet<BarEntry> impl
/**
* array of labels used to describe the different values of the stacked bars
*/
private String[] mStackLabels = new String[]{
"Stack"
};
private String[] mStackLabels = new String[]{};
protected List<Fill> mFills = null;
public BarDataSet(List<BarEntry> yVals, String label) {
super(yVals, label);
@ -54,8 +55,8 @@ public class BarDataSet extends BarLineScatterCandleBubbleDataSet<BarEntry> impl
@Override
public DataSet<BarEntry> copy() {
List<BarEntry> entries = new ArrayList<BarEntry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
BarDataSet copied = new BarDataSet(entries, getLabel());
copy(copied);
@ -71,6 +72,67 @@ public class BarDataSet extends BarLineScatterCandleBubbleDataSet<BarEntry> impl
barDataSet.mHighLightAlpha = mHighLightAlpha;
}
@Override
public List<Fill> getFills() {
return mFills;
}
@Override
public Fill getFill(int index) {
return mFills.get(index % mFills.size());
}
/**
* This method is deprecated.
* Use getFills() instead.
*/
@Deprecated
public List<Fill> getGradients() {
return mFills;
}
/**
* This method is deprecated.
* Use getFill(...) instead.
*
* @param index
*/
@Deprecated
public Fill getGradient(int index) {
return getFill(index);
}
/**
* Sets the start and end color for gradient color, ONLY color that should be used for this DataSet.
*
* @param startColor
* @param endColor
*/
public void setGradientColor(int startColor, int endColor) {
mFills.clear();
mFills.add(new Fill(startColor, endColor));
}
/**
* This method is deprecated.
* Use setFills(...) instead.
*
* @param gradientColors
*/
@Deprecated
public void setGradientColors(List<Fill> gradientColors) {
this.mFills = gradientColors;
}
/**
* Sets the fills for the bars in this dataset.
*
* @param fills
*/
public void setFills(List<Fill> fills) {
this.mFills = fills;
}
/**
* Calculates the total number of entries this DataSet represents, including
* stacks. All values belonging to a stack are calculated separately.

View file

@ -7,9 +7,8 @@ import android.graphics.Typeface;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.model.GradientColor;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.utils.Utils;
@ -29,10 +28,6 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
*/
protected List<Integer> mColors = null;
protected GradientColor mGradientColor = null;
protected List<GradientColor> mGradientColors = null;
/**
* List representing all colors that are used for drawing the actual values for this DataSet
*/
@ -56,7 +51,7 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
/**
* custom formatter that is used instead of the auto-formatter if set
*/
protected transient IValueFormatter mValueFormatter;
protected transient ValueFormatter mValueFormatter;
/**
* the typeface used for the value text
@ -146,21 +141,6 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
return mColors.get(index % mColors.size());
}
@Override
public GradientColor getGradientColor() {
return mGradientColor;
}
@Override
public List<GradientColor> getGradientColors() {
return mGradientColors;
}
@Override
public GradientColor getGradientColor(int index) {
return mGradientColors.get(index % mGradientColors.size());
}
/**
* ###### ###### COLOR SETTING RELATED METHODS ##### ######
*/
@ -236,25 +216,6 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
mColors.add(color);
}
/**
* Sets the start and end color for gradient color, ONLY color that should be used for this DataSet.
*
* @param startColor
* @param endColor
*/
public void setGradientColor(int startColor, int endColor) {
mGradientColor = new GradientColor(startColor, endColor);
}
/**
* Sets the start and end color for gradient colors, ONLY color that should be used for this DataSet.
*
* @param gradientColors
*/
public void setGradientColors(List<GradientColor> gradientColors) {
this.mGradientColors = gradientColors;
}
/**
* Sets a color with a specific alpha value.
*
@ -313,7 +274,7 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
}
@Override
public void setValueFormatter(IValueFormatter f) {
public void setValueFormatter(ValueFormatter f) {
if (f == null)
return;
@ -322,7 +283,7 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
}
@Override
public IValueFormatter getValueFormatter() {
public ValueFormatter getValueFormatter() {
if (needsFormatter())
return Utils.getDefaultValueFormatter();
return mValueFormatter;
@ -534,8 +495,6 @@ public abstract class BaseDataSet<T extends Entry> implements IDataSet<T> {
baseDataSet.mFormLineDashEffect = mFormLineDashEffect;
baseDataSet.mFormLineWidth = mFormLineWidth;
baseDataSet.mFormSize = mFormSize;
baseDataSet.mGradientColor = mGradientColor;
baseDataSet.mGradientColors = mGradientColors;
baseDataSet.mHighlightEnabled = mHighlightEnabled;
baseDataSet.mIconsOffset = mIconsOffset;
baseDataSet.mValueColors = mValueColors;

View file

@ -42,8 +42,8 @@ public class BubbleDataSet extends BarLineScatterCandleBubbleDataSet<BubbleEntry
@Override
public DataSet<BubbleEntry> copy() {
List<BubbleEntry> entries = new ArrayList<BubbleEntry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
BubbleDataSet copied = new BubbleDataSet(entries, getLabel());
copy(copied);

View file

@ -80,8 +80,8 @@ public class CandleDataSet extends LineScatterCandleRadarDataSet<CandleEntry> im
@Override
public DataSet<CandleEntry> copy() {
List<CandleEntry> entries = new ArrayList<CandleEntry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
CandleDataSet copied = new CandleDataSet(entries, getLabel());
copy(copied);

View file

@ -1,11 +1,10 @@
package com.github.mikephil.charting.data;
import android.graphics.Typeface;
import android.util.Log;
import com.github.mikephil.charting.components.YAxis.AxisDependency;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
@ -400,7 +399,7 @@ public abstract class ChartData<T extends IDataSet<? extends Entry>> {
// if a DataSet was removed
if (removed) {
calcMinMax();
notifyDataChanged();
}
return removed;
@ -527,7 +526,7 @@ public abstract class ChartData<T extends IDataSet<? extends Entry>> {
boolean removed = set.removeEntry(e);
if (removed) {
calcMinMax();
notifyDataChanged();
}
return removed;
@ -659,7 +658,7 @@ public abstract class ChartData<T extends IDataSet<? extends Entry>> {
*
* @param f
*/
public void setValueFormatter(IValueFormatter f) {
public void setValueFormatter(ValueFormatter f) {
if (f == null)
return;
else {

View file

@ -3,6 +3,7 @@ package com.github.mikephil.charting.data;
import android.util.Log;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IBarLineScatterCandleBubbleDataSet;
@ -91,18 +92,26 @@ public class CombinedData extends BarLineScatterCandleBubbleData<IBarLineScatter
if (data.getXMin() < mXMin)
mXMin = data.getXMin();
if (data.mLeftAxisMax > mLeftAxisMax)
mLeftAxisMax = data.mLeftAxisMax;
for (IBarLineScatterCandleBubbleDataSet<? extends Entry> dataset : sets) {
if (dataset.getAxisDependency() == YAxis.AxisDependency.LEFT) {
if (dataset.getYMax() > mLeftAxisMax) {
mLeftAxisMax = dataset.getYMax();
}
if (data.mLeftAxisMin < mLeftAxisMin)
mLeftAxisMin = data.mLeftAxisMin;
if (data.mRightAxisMax > mRightAxisMax)
mRightAxisMax = data.mRightAxisMax;
if (data.mRightAxisMin < mRightAxisMin)
mRightAxisMin = data.mRightAxisMin;
if (dataset.getYMin() < mLeftAxisMin) {
mLeftAxisMin = dataset.getYMin();
}
}
else {
if (dataset.getYMax() > mRightAxisMax) {
mRightAxisMax = dataset.getYMax();
}
if (dataset.getYMin() < mRightAxisMin) {
mRightAxisMin = dataset.getYMin();
}
}
}
}
}

View file

@ -17,7 +17,7 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
/**
* the entries that this DataSet represents / holds together
*/
protected List<T> mValues = null;
protected List<T> mEntries;
/**
* maximum y-value in the value array
@ -45,15 +45,15 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
* label that describes the DataSet can be specified. The label can also be
* used to retrieve the DataSet from a ChartData object.
*
* @param values
* @param entries
* @param label
*/
public DataSet(List<T> values, String label) {
public DataSet(List<T> entries, String label) {
super(label);
this.mValues = values;
this.mEntries = entries;
if (mValues == null)
mValues = new ArrayList<T>();
if (mEntries == null)
mEntries = new ArrayList<T>();
calcMinMax();
}
@ -61,35 +61,36 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
@Override
public void calcMinMax() {
if (mValues == null || mValues.isEmpty())
return;
mYMax = -Float.MAX_VALUE;
mYMin = Float.MAX_VALUE;
mXMax = -Float.MAX_VALUE;
mXMin = Float.MAX_VALUE;
for (T e : mValues) {
if (mEntries == null || mEntries.isEmpty())
return;
for (T e : mEntries) {
calcMinMax(e);
}
}
@Override
public void calcMinMaxY(float fromX, float toX) {
if (mValues == null || mValues.isEmpty())
return;
mYMax = -Float.MAX_VALUE;
mYMin = Float.MAX_VALUE;
if (mEntries == null || mEntries.isEmpty())
return;
int indexFrom = getEntryIndex(fromX, Float.NaN, Rounding.DOWN);
int indexTo = getEntryIndex(toX, Float.NaN, Rounding.UP);
if (indexTo < indexFrom) return;
for (int i = indexFrom; i <= indexTo; i++) {
// only recalculate y
calcMinMaxY(mValues.get(i));
calcMinMaxY(mEntries.get(i));
}
}
@ -128,7 +129,18 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
@Override
public int getEntryCount() {
return mValues.size();
return mEntries.size();
}
/**
* This method is deprecated.
* Use getEntries() instead.
*
* @return
*/
@Deprecated
public List<T> getValues() {
return mEntries;
}
/**
@ -136,8 +148,19 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
*
* @return
*/
public List<T> getValues() {
return mValues;
public List<T> getEntries() {
return mEntries;
}
/**
* This method is deprecated.
* Use setEntries(...) instead.
*
* @param values
*/
@Deprecated
public void setValues(List<T> values) {
setEntries(values);
}
/**
@ -145,8 +168,8 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
*
* @return
*/
public void setValues(List<T> values) {
mValues = values;
public void setEntries(List<T> entries) {
mEntries = entries;
notifyDataSetChanged();
}
@ -169,8 +192,8 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(toSimpleString());
for (int i = 0; i < mValues.size(); i++) {
buffer.append(mValues.get(i).toString() + " ");
for (int i = 0; i < mEntries.size(); i++) {
buffer.append(mEntries.get(i).toString() + " ");
}
return buffer.toString();
}
@ -183,7 +206,7 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
*/
public String toSimpleString() {
StringBuffer buffer = new StringBuffer();
buffer.append("DataSet, label: " + (getLabel() == null ? "" : getLabel()) + ", entries: " + mValues.size() +
buffer.append("DataSet, label: " + (getLabel() == null ? "" : getLabel()) + ", entries: " + mEntries.size() +
"\n");
return buffer.toString();
}
@ -214,23 +237,23 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
if (e == null)
return;
if (mValues == null) {
mValues = new ArrayList<T>();
if (mEntries == null) {
mEntries = new ArrayList<T>();
}
calcMinMax(e);
if (mValues.size() > 0 && mValues.get(mValues.size() - 1).getX() > e.getX()) {
if (mEntries.size() > 0 && mEntries.get(mEntries.size() - 1).getX() > e.getX()) {
int closestIndex = getEntryIndex(e.getX(), e.getY(), Rounding.UP);
mValues.add(closestIndex, e);
mEntries.add(closestIndex, e);
} else {
mValues.add(e);
mEntries.add(e);
}
}
@Override
public void clear() {
mValues.clear();
mEntries.clear();
notifyDataSetChanged();
}
@ -240,9 +263,9 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
if (e == null)
return false;
List<T> values = getValues();
List<T> values = getEntries();
if (values == null) {
values = new ArrayList<T>();
values = new ArrayList<>();
}
calcMinMax(e);
@ -257,11 +280,11 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
if (e == null)
return false;
if (mValues == null)
if (mEntries == null)
return false;
// remove the entry
boolean removed = mValues.remove(e);
boolean removed = mEntries.remove(e);
if (removed) {
calcMinMax();
@ -272,7 +295,7 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
@Override
public int getEntryIndex(Entry e) {
return mValues.indexOf(e);
return mEntries.indexOf(e);
}
@Override
@ -280,7 +303,7 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
int index = getEntryIndex(xValue, closestToY, rounding);
if (index > -1)
return mValues.get(index);
return mEntries.get(index);
return null;
}
@ -291,24 +314,24 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
@Override
public T getEntryForIndex(int index) {
return mValues.get(index);
return mEntries.get(index);
}
@Override
public int getEntryIndex(float xValue, float closestToY, Rounding rounding) {
if (mValues == null || mValues.isEmpty())
if (mEntries == null || mEntries.isEmpty())
return -1;
int low = 0;
int high = mValues.size() - 1;
int high = mEntries.size() - 1;
int closest = high;
while (low < high) {
int m = (low + high) / 2;
final float d1 = mValues.get(m).getX() - xValue,
d2 = mValues.get(m + 1).getX() - xValue,
final float d1 = mEntries.get(m).getX() - xValue,
d2 = mEntries.get(m + 1).getX() - xValue,
ad1 = Math.abs(d1), ad2 = Math.abs(d2);
if (ad2 < ad1) {
@ -335,10 +358,10 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
}
if (closest != -1) {
float closestXValue = mValues.get(closest).getX();
float closestXValue = mEntries.get(closest).getX();
if (rounding == Rounding.UP) {
// If rounding up, and found x-value is lower than specified x, and we can go upper...
if (closestXValue < xValue && closest < mValues.size() - 1) {
if (closestXValue < xValue && closest < mEntries.size() - 1) {
++closest;
}
} else if (rounding == Rounding.DOWN) {
@ -350,23 +373,23 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
// Search by closest to y-value
if (!Float.isNaN(closestToY)) {
while (closest > 0 && mValues.get(closest - 1).getX() == closestXValue)
while (closest > 0 && mEntries.get(closest - 1).getX() == closestXValue)
closest -= 1;
float closestYValue = mValues.get(closest).getY();
float closestYValue = mEntries.get(closest).getY();
int closestYIndex = closest;
while (true) {
closest += 1;
if (closest >= mValues.size())
if (closest >= mEntries.size())
break;
final Entry value = mValues.get(closest);
final Entry value = mEntries.get(closest);
if (value.getX() != closestXValue)
break;
if (Math.abs(value.getY() - closestToY) < Math.abs(closestYValue - closestToY)) {
if (Math.abs(value.getY() - closestToY) <= Math.abs(closestYValue - closestToY)) {
closestYValue = closestToY;
closestYIndex = closest;
}
@ -385,22 +408,22 @@ public abstract class DataSet<T extends Entry> extends BaseDataSet<T> {
List<T> entries = new ArrayList<T>();
int low = 0;
int high = mValues.size() - 1;
int high = mEntries.size() - 1;
while (low <= high) {
int m = (high + low) / 2;
T entry = mValues.get(m);
T entry = mEntries.get(m);
// if we have a match
if (xValue == entry.getX()) {
while (m > 0 && mValues.get(m - 1).getX() == xValue)
while (m > 0 && mEntries.get(m - 1).getX() == xValue)
m--;
high = mValues.size();
high = mEntries.size();
// loop over all "equal" entries
for (; m < high; m++) {
entry = mValues.get(m);
entry = mEntries.get(m);
if (entry.getX() == xValue) {
entries.add(entry);
} else {

View file

@ -85,8 +85,8 @@ public class LineDataSet extends LineRadarDataSet<Entry> implements ILineDataSet
@Override
public DataSet<Entry> copy() {
List<Entry> entries = new ArrayList<Entry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
LineDataSet copied = new LineDataSet(entries, getLabel());
copy(copied);

View file

@ -17,6 +17,7 @@ import java.util.List;
*/
public abstract class LineRadarDataSet<T extends Entry> extends LineScatterCandleRadarDataSet<T> implements ILineRadarDataSet<T> {
// TODO: Move to using `Fill` class
/**
* the color that is used for filling the line surface
*/

View file

@ -1,6 +1,8 @@
package com.github.mikephil.charting.data;
import android.util.Log;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
@ -46,6 +48,18 @@ public class PieData extends ChartData<IPieDataSet> {
return mDataSets.get(0);
}
@Override
public List<IPieDataSet> getDataSets() {
List<IPieDataSet> dataSets = super.getDataSets();
if (dataSets.size() < 1) {
Log.e("MPAndroidChart",
"Found multiple data sets while pie chart only allows one");
}
return dataSets;
}
/**
* The PieData object can only have one DataSet. Use getDataSet() method instead.
*

View file

@ -3,6 +3,7 @@ package com.github.mikephil.charting.data;
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
import com.github.mikephil.charting.utils.Utils;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
@ -22,13 +23,14 @@ public class PieDataSet extends DataSet<PieEntry> implements IPieDataSet {
private ValuePosition mXValuePosition = ValuePosition.INSIDE_SLICE;
private ValuePosition mYValuePosition = ValuePosition.INSIDE_SLICE;
private boolean mUsingSliceColorAsValueLineColor = false;
private int mValueLineColor = 0xff000000;
private boolean mUseValueColorForLine = false;
private float mValueLineWidth = 1.0f;
private float mValueLinePart1OffsetPercentage = 75.f;
private float mValueLinePart1Length = 0.3f;
private float mValueLinePart2Length = 0.4f;
private boolean mValueLineVariableLength = true;
private Integer mHighlightColor = null;
public PieDataSet(List<PieEntry> yVals, String label) {
super(yVals, label);
@ -38,8 +40,8 @@ public class PieDataSet extends DataSet<PieEntry> implements IPieDataSet {
@Override
public DataSet<PieEntry> copy() {
List<PieEntry> entries = new ArrayList<>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
PieDataSet copied = new PieDataSet(entries, getLabel());
copy(copied);
@ -135,15 +137,23 @@ public class PieDataSet extends DataSet<PieEntry> implements IPieDataSet {
}
/**
* When valuePosition is OutsideSlice, use slice colors as line color if true
* This method is deprecated.
* Use isUseValueColorForLineEnabled() instead.
*/
@Override
@Deprecated
public boolean isUsingSliceColorAsValueLineColor() {
return mUsingSliceColorAsValueLineColor;
return isUseValueColorForLineEnabled();
}
public void setUsingSliceColorAsValueLineColor(boolean usingSliceColorAsValueLineColor) {
this.mUsingSliceColorAsValueLineColor = usingSliceColorAsValueLineColor;
/**
* This method is deprecated.
* Use setUseValueColorForLine(...) instead.
*
* @param enabled
*/
@Deprecated
public void setUsingSliceColorAsValueLineColor(boolean enabled) {
setUseValueColorForLine(enabled);
}
/**
@ -158,6 +168,17 @@ public class PieDataSet extends DataSet<PieEntry> implements IPieDataSet {
this.mValueLineColor = valueLineColor;
}
@Override
public boolean isUseValueColorForLineEnabled()
{
return mUseValueColorForLine;
}
public void setUseValueColorForLine(boolean enabled)
{
mUseValueColorForLine = enabled;
}
/**
* When valuePosition is OutsideSlice, indicates line width
*/
@ -218,6 +239,21 @@ public class PieDataSet extends DataSet<PieEntry> implements IPieDataSet {
this.mValueLineVariableLength = valueLineVariableLength;
}
/** Gets the color for the highlighted sector */
@Override
@Nullable
public Integer getHighlightColor()
{
return mHighlightColor;
}
/** Sets the color for the highlighted sector (null for using entry color) */
public void setHighlightColor(@Nullable Integer color)
{
this.mHighlightColor = color;
}
public enum ValuePosition {
INSIDE_SLICE,
OUTSIDE_SLICE

View file

@ -102,8 +102,8 @@ public class RadarDataSet extends LineRadarDataSet<RadarEntry> implements IRadar
@Override
public DataSet<RadarEntry> copy() {
List<RadarEntry> entries = new ArrayList<RadarEntry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
RadarDataSet copied = new RadarDataSet(entries, getLabel());
copy(copied);

View file

@ -48,8 +48,8 @@ public class ScatterDataSet extends LineScatterCandleRadarDataSet<Entry> impleme
@Override
public DataSet<Entry> copy() {
List<Entry> entries = new ArrayList<Entry>();
for (int i = 0; i < mValues.size(); i++) {
entries.add(mValues.get(i).copy());
for (int i = 0; i < mEntries.size(); i++) {
entries.add(mEntries.get(i).copy());
}
ScatterDataSet copied = new ScatterDataSet(entries, getLabel());
copy(copied);

View file

@ -0,0 +1,146 @@
package com.github.mikephil.charting.data.filter;
import java.util.ArrayList;
/**
* Implemented according to modified Douglas Peucker {@link}
* http://psimpl.sourceforge.net/douglas-peucker.html
*/
public class ApproximatorN
{
public float[] reduceWithDouglasPeucker(float[] points, float resultCount) {
int pointCount = points.length / 2;
// if a shape has 2 or less points it cannot be reduced
if (resultCount <= 2 || resultCount >= pointCount)
return points;
boolean[] keep = new boolean[pointCount];
// first and last always stay
keep[0] = true;
keep[pointCount - 1] = true;
int currentStoredPoints = 2;
ArrayList<Line> queue = new ArrayList<>();
Line line = new Line(0, pointCount - 1, points);
queue.add(line);
do {
line = queue.remove(queue.size() - 1);
// store the key
keep[line.index] = true;
// check point count tolerance
currentStoredPoints += 1;
if (currentStoredPoints == resultCount)
break;
// split the polyline at the key and recurse
Line left = new Line(line.start, line.index, points);
if (left.index > 0) {
int insertionIndex = insertionIndex(left, queue);
queue.add(insertionIndex, left);
}
Line right = new Line(line.index, line.end, points);
if (right.index > 0) {
int insertionIndex = insertionIndex(right, queue);
queue.add(insertionIndex, right);
}
} while (queue.isEmpty());
float[] reducedEntries = new float[currentStoredPoints * 2];
for (int i = 0, i2 = 0, r2 = 0; i < currentStoredPoints; i++, r2 += 2) {
if (keep[i]) {
reducedEntries[i2++] = points[r2];
reducedEntries[i2++] = points[r2 + 1];
}
}
return reducedEntries;
}
private static float distanceToLine(
float ptX, float ptY, float[]
fromLinePoint1, float[] fromLinePoint2) {
float dx = fromLinePoint2[0] - fromLinePoint1[0];
float dy = fromLinePoint2[1] - fromLinePoint1[1];
float dividend = Math.abs(
dy * ptX -
dx * ptY -
fromLinePoint1[0] * fromLinePoint2[1] +
fromLinePoint2[0] * fromLinePoint1[1]);
double divisor = Math.sqrt(dx * dx + dy * dy);
return (float)(dividend / divisor);
}
private static class Line {
int start;
int end;
float distance = 0;
int index = 0;
Line(int start, int end, float[] points) {
this.start = start;
this.end = end;
float[] startPoint = new float[]{points[start * 2], points[start * 2 + 1]};
float[] endPoint = new float[]{points[end * 2], points[end * 2 + 1]};
if (end <= start + 1) return;
for (int i = start + 1, i2 = i * 2; i < end; i++, i2 += 2) {
float distance = distanceToLine(
points[i2], points[i2 + 1],
startPoint, endPoint);
if (distance > this.distance) {
this.index = i;
this.distance = distance;
}
}
}
boolean equals(final Line rhs) {
return (start == rhs.start) && (end == rhs.end) && index == rhs.index;
}
boolean lessThan(final Line rhs) {
return distance < rhs.distance;
}
}
private static int insertionIndex(Line line, ArrayList<Line> queue) {
int min = 0;
int max = queue.size();
while (!queue.isEmpty()) {
int midIndex = min + (max - min) / 2;
Line midLine = queue.get(midIndex);
if (midLine.equals(line)) {
return midIndex;
}
else if (line.lessThan(midLine)) {
// perform search in left half
max = midIndex;
}
else {
// perform search in right half
min = midIndex + 1;
}
}
return min;
}
}

View file

@ -1,13 +1,11 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.components.AxisBase;
import java.text.DecimalFormat;
/**
* Created by philipp on 02/06/16.
*/
public class DefaultAxisValueFormatter implements IAxisValueFormatter
public class DefaultAxisValueFormatter extends ValueFormatter
{
/**
@ -18,7 +16,7 @@ public class DefaultAxisValueFormatter implements IAxisValueFormatter
/**
* the number of decimal digits this formatter uses
*/
protected int digits = 0;
protected int digits;
/**
* Constructor that specifies to how many digits the value should be
@ -40,7 +38,7 @@ public class DefaultAxisValueFormatter implements IAxisValueFormatter
}
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
// avoid memory allocations here (for performance)
return mFormat.format(value);
}

View file

@ -1,9 +1,5 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
/**
@ -12,7 +8,7 @@ import java.text.DecimalFormat;
*
* @author Philipp Jahoda
*/
public class DefaultValueFormatter implements IValueFormatter
public class DefaultValueFormatter extends ValueFormatter
{
/**
@ -52,7 +48,7 @@ public class DefaultValueFormatter implements IValueFormatter
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
public String getFormattedValue(float value) {
// put more logic here ...
// avoid memory allocations here (for performance reasons)

View file

@ -6,7 +6,10 @@ import com.github.mikephil.charting.components.AxisBase;
* Created by Philipp Jahoda on 20/09/15.
* Custom formatter interface that allows formatting of
* axis labels before they are being drawn.
*
* @deprecated Extend {@link ValueFormatter} instead
*/
@Deprecated
public interface IAxisValueFormatter
{
@ -18,6 +21,9 @@ public interface IAxisValueFormatter
* @param value the value to be formatted
* @param axis the axis the value belongs to
* @return
*
* @deprecated Extend {@link ValueFormatter} and use {@link ValueFormatter#getAxisLabel(float, AxisBase)}
*/
@Deprecated
String getFormattedValue(float value, AxisBase axis);
}

View file

@ -4,13 +4,12 @@ import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
/**
* Interface that allows custom formatting of all values inside the chart before they are
* being drawn to the screen. Simply create your own formatting class and let
* it implement IValueFormatter. Then override the getFormattedValue(...) method
* and return whatever you want.
* Interface to format all values before they are drawn as labels.
*
* @author Philipp Jahoda
* @deprecated Extend {@link ValueFormatter} instead
*/
@Deprecated
public interface IValueFormatter
{
@ -24,6 +23,9 @@ public interface IValueFormatter
* @param dataSetIndex the index of the DataSet the entry in focus belongs to
* @param viewPortHandler provides information about the current chart state (scale, translation, ...)
* @return the formatted label ready for being drawn
*
* @deprecated Extend {@link ValueFormatter} and override an appropriate method
*/
@Deprecated
String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler);
}

View file

@ -1,18 +1,11 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.Collection;
/**
* This formatter is used for passing an array of x-axis labels, on whole x steps.
*/
public class IndexAxisValueFormatter implements IAxisValueFormatter
public class IndexAxisValueFormatter extends ValueFormatter
{
private String[] mValues = new String[] {};
private int mValueCount = 0;
@ -44,7 +37,8 @@ public class IndexAxisValueFormatter implements IAxisValueFormatter
setValues(values.toArray(new String[values.size()]));
}
public String getFormattedValue(float value, AxisBase axis) {
@Override
public String getFormattedValue(float value) {
int index = Math.round(value);
if (index < 0 || index >= mValueCount || index != (int)value)

View file

@ -1,10 +1,5 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
/**
@ -17,7 +12,7 @@ import java.text.DecimalFormat;
* @author Philipp Jahoda
* @author Oleksandr Tyshkovets <olexandr.tyshkovets@gmail.com>
*/
public class LargeValueFormatter implements IValueFormatter, IAxisValueFormatter
public class LargeValueFormatter extends ValueFormatter
{
private String[] mSuffix = new String[]{
@ -41,15 +36,8 @@ public class LargeValueFormatter implements IValueFormatter, IAxisValueFormatter
mText = appendix;
}
// IValueFormatter
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return makePretty(value) + mText;
}
// IAxisValueFormatter
@Override
public String getFormattedValue(float value, AxisBase axis) {
public String getFormattedValue(float value) {
return makePretty(value) + mText;
}

View file

@ -1,49 +1,54 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.data.PieEntry;
import java.text.DecimalFormat;
/**
* This IValueFormatter is just for convenience and simply puts a "%" sign after
* each value. (Recommeded for PieChart)
* each value. (Recommended for PieChart)
*
* @author Philipp Jahoda
*/
public class PercentFormatter implements IValueFormatter, IAxisValueFormatter
public class PercentFormatter extends ValueFormatter
{
protected DecimalFormat mFormat;
public DecimalFormat mFormat;
private PieChart pieChart;
private boolean percentSignSeparated;
public PercentFormatter() {
mFormat = new DecimalFormat("###,###,##0.0");
percentSignSeparated = true;
}
/**
* Allow a custom decimalformat
*
* @param format
*/
public PercentFormatter(DecimalFormat format) {
this.mFormat = format;
// Can be used to remove percent signs if the chart isn't in percent mode
public PercentFormatter(PieChart pieChart) {
this();
this.pieChart = pieChart;
}
// Can be used to remove percent signs if the chart isn't in percent mode
public PercentFormatter(PieChart pieChart, boolean percentSignSeparated) {
this(pieChart);
this.percentSignSeparated = percentSignSeparated;
}
// IValueFormatter
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return mFormat.format(value) + " %";
public String getFormattedValue(float value) {
return mFormat.format(value) + (percentSignSeparated ? " %" : "%");
}
// IAxisValueFormatter
@Override
public String getFormattedValue(float value, AxisBase axis) {
return mFormat.format(value) + " %";
public String getPieLabel(float value, PieEntry pieEntry) {
if (pieChart != null && pieChart.isUsePercentValuesEnabled()) {
// Converted to percent
return getFormattedValue(value);
} else {
// raw value, skip percent sign
return mFormat.format(value);
}
}
public int getDecimalDigits() {
return 1;
}
}

View file

@ -1,8 +1,6 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.text.DecimalFormat;
@ -12,7 +10,7 @@ import java.text.DecimalFormat;
* A formatter specifically for stacked BarChart that allows to specify whether the all stack values
* or just the top value should be drawn.
*/
public class StackedValueFormatter implements IValueFormatter
public class StackedValueFormatter extends ValueFormatter
{
/**
@ -23,7 +21,7 @@ public class StackedValueFormatter implements IValueFormatter
/**
* a string that should be appended behind the value
*/
private String mAppendix;
private String mSuffix;
private DecimalFormat mFormat;
@ -31,12 +29,12 @@ public class StackedValueFormatter implements IValueFormatter
* Constructor.
*
* @param drawWholeStack if true, all stack values of the stacked bar entry are drawn, else only top
* @param appendix a string that should be appended behind the value
* @param suffix a string that should be appended behind the value
* @param decimals the number of decimal digits to use
*/
public StackedValueFormatter(boolean drawWholeStack, String appendix, int decimals) {
public StackedValueFormatter(boolean drawWholeStack, String suffix, int decimals) {
this.mDrawWholeStack = drawWholeStack;
this.mAppendix = appendix;
this.mSuffix = suffix;
StringBuffer b = new StringBuffer();
for (int i = 0; i < decimals; i++) {
@ -49,12 +47,10 @@ public class StackedValueFormatter implements IValueFormatter
}
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
public String getBarStackedLabel(float value, BarEntry entry) {
if (!mDrawWholeStack) {
if (!mDrawWholeStack && entry instanceof BarEntry) {
BarEntry barEntry = (BarEntry) entry;
float[] vals = barEntry.getYVals();
float[] vals = entry.getYVals();
if (vals != null) {
@ -62,7 +58,7 @@ public class StackedValueFormatter implements IValueFormatter
if (vals[vals.length - 1] == value) {
// return the "sum" across all stack values
return mFormat.format(barEntry.getY()) + mAppendix;
return mFormat.format(entry.getY()) + mSuffix;
} else {
return ""; // return empty
}
@ -70,6 +66,6 @@ public class StackedValueFormatter implements IValueFormatter
}
// return the "proposed" value
return mFormat.format(value) + mAppendix;
return mFormat.format(value) + mSuffix;
}
}

View file

@ -0,0 +1,137 @@
package com.github.mikephil.charting.formatter;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.BubbleEntry;
import com.github.mikephil.charting.data.CandleEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.data.RadarEntry;
import com.github.mikephil.charting.utils.ViewPortHandler;
/**
* Class to format all values before they are drawn as labels.
*/
public abstract class ValueFormatter implements IAxisValueFormatter, IValueFormatter{
/**
* <b>DO NOT USE</b>, only for backwards compatibility and will be removed in future versions.
*
* @param value the value to be formatted
* @param axis the axis the value belongs to
* @return formatted string label
*/
@Override
@Deprecated
public String getFormattedValue(float value, AxisBase axis) {
return getFormattedValue(value);
}
/**
* <b>DO NOT USE</b>, only for backwards compatibility and will be removed in future versions.
* @param value the value to be formatted
* @param entry the entry the value belongs to - in e.g. BarChart, this is of class BarEntry
* @param dataSetIndex the index of the DataSet the entry in focus belongs to
* @param viewPortHandler provides information about the current chart state (scale, translation, ...)
* @return formatted string label
*/
@Override
@Deprecated
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return getFormattedValue(value);
}
/**
* Called when drawing any label, used to change numbers into formatted strings.
*
* @param value float to be formatted
* @return formatted string label
*/
public String getFormattedValue(float value) {
return String.valueOf(value);
}
/**
* Used to draw axis labels, calls {@link #getFormattedValue(float)} by default.
*
* @param value float to be formatted
* @param axis axis being labeled
* @return formatted string label
*/
public String getAxisLabel(float value, AxisBase axis) {
return getFormattedValue(value);
}
/**
* Used to draw bar labels, calls {@link #getFormattedValue(float)} by default.
*
* @param barEntry bar being labeled
* @return formatted string label
*/
public String getBarLabel(BarEntry barEntry) {
return getFormattedValue(barEntry.getY());
}
/**
* Used to draw stacked bar labels, calls {@link #getFormattedValue(float)} by default.
*
* @param value current value to be formatted
* @param stackedEntry stacked entry being labeled, contains all Y values
* @return formatted string label
*/
public String getBarStackedLabel(float value, BarEntry stackedEntry) {
return getFormattedValue(value);
}
/**
* Used to draw line and scatter labels, calls {@link #getFormattedValue(float)} by default.
*
* @param entry point being labeled, contains X value
* @return formatted string label
*/
public String getPointLabel(Entry entry) {
return getFormattedValue(entry.getY());
}
/**
* Used to draw pie value labels, calls {@link #getFormattedValue(float)} by default.
*
* @param value float to be formatted, may have been converted to percentage
* @param pieEntry slice being labeled, contains original, non-percentage Y value
* @return formatted string label
*/
public String getPieLabel(float value, PieEntry pieEntry) {
return getFormattedValue(value);
}
/**
* Used to draw radar value labels, calls {@link #getFormattedValue(float)} by default.
*
* @param radarEntry entry being labeled
* @return formatted string label
*/
public String getRadarLabel(RadarEntry radarEntry) {
return getFormattedValue(radarEntry.getY());
}
/**
* Used to draw bubble size labels, calls {@link #getFormattedValue(float)} by default.
*
* @param bubbleEntry bubble being labeled, also contains X and Y values
* @return formatted string label
*/
public String getBubbleLabel(BubbleEntry bubbleEntry) {
return getFormattedValue(bubbleEntry.getSize());
}
/**
* Used to draw high labels, calls {@link #getFormattedValue(float)} by default.
*
* @param candleEntry candlestick being labeled
* @return formatted string label
*/
public String getCandleLabel(CandleEntry candleEntry) {
return getFormattedValue(candleEntry.getHigh());
}
}

View file

@ -60,10 +60,18 @@ public class Highlight {
*/
private float mDrawY;
public Highlight(float x, float y, int dataSetIndex, int dataIndex) {
this.mX = x;
this.mY = y;
this.mDataSetIndex = dataSetIndex;
this.mDataIndex = dataIndex;
}
public Highlight(float x, float y, int dataSetIndex) {
this.mX = x;
this.mY = y;
this.mDataSetIndex = dataSetIndex;
this.mDataIndex = -1;
}
public Highlight(float x, int dataSetIndex, int stackIndex) {

View file

@ -3,7 +3,7 @@ package com.github.mikephil.charting.interfaces.dataprovider;
import android.graphics.RectF;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.MPPointF;
/**
@ -61,7 +61,7 @@ public interface ChartInterface {
RectF getContentRect();
IValueFormatter getDefaultValueFormatter();
ValueFormatter getDefaultValueFormatter();
ChartData getData();

View file

@ -1,12 +1,19 @@
package com.github.mikephil.charting.interfaces.datasets;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.utils.Fill;
import java.util.List;
/**
* Created by philipp on 21/10/15.
*/
public interface IBarDataSet extends IBarLineScatterCandleBubbleDataSet<BarEntry> {
List<Fill> getFills();
Fill getFill(int index);
/**
* Returns true if this DataSet is stacked (stacksize > 1) or not.
*

View file

@ -1,16 +1,14 @@
package com.github.mikephil.charting.interfaces.datasets;
import android.graphics.DashPathEffect;
import android.graphics.PointF;
import android.graphics.Typeface;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.DataSet;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.model.GradientColor;
import java.util.List;
@ -286,28 +284,6 @@ public interface IDataSet<T extends Entry> {
*/
int getColor();
/**
* Returns the Gradient color model
*
* @return
*/
GradientColor getGradientColor();
/**
* Returns the Gradient colors
*
* @return
*/
List<GradientColor> getGradientColors();
/**
* Returns the Gradient colors
*
* @param index
* @return
*/
GradientColor getGradientColor(int index);
/**
* Returns the color at the given index of the DataSet's color array.
* Performs a IndexOutOfBounds check by modulus.
@ -341,14 +317,14 @@ public interface IDataSet<T extends Entry> {
*
* @param f
*/
void setValueFormatter(IValueFormatter f);
void setValueFormatter(ValueFormatter f);
/**
* Returns the formatter used for drawing the values inside the chart.
*
* @return
*/
IValueFormatter getValueFormatter();
ValueFormatter getValueFormatter();
/**
* Returns true if the valueFormatter object of this DataSet is null.

View file

@ -1,5 +1,7 @@
package com.github.mikephil.charting.interfaces.datasets;
import androidx.annotation.Nullable;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
@ -35,16 +37,16 @@ public interface IPieDataSet extends IDataSet<PieEntry> {
PieDataSet.ValuePosition getXValuePosition();
PieDataSet.ValuePosition getYValuePosition();
/**
* When valuePosition is OutsideSlice, use slice colors as line color if true
* */
boolean isUsingSliceColorAsValueLineColor();
/**
* When valuePosition is OutsideSlice, indicates line color
* */
int getValueLineColor();
/**
* When valuePosition is OutsideSlice and enabled, line will have the same color as the slice
* */
boolean isUseValueColorForLineEnabled();
/**
* When valuePosition is OutsideSlice, indicates line width
* */
@ -70,5 +72,11 @@ public interface IPieDataSet extends IDataSet<PieEntry> {
* */
boolean isValueLineVariableLength();
/**
* Gets the color for the highlighted sector
* */
@Nullable
Integer getHighlightColor();
}

View file

@ -580,12 +580,19 @@ public class BarLineChartTouchListener extends ChartTouchListener<BarLineChartBa
MPPointF trans = getTrans(e.getX(), e.getY());
mChart.zoom(mChart.isScaleXEnabled() ? 1.4f : 1f, mChart.isScaleYEnabled() ? 1.4f : 1f, trans.x, trans.y);
float scaleX = mChart.isScaleXEnabled() ? 1.4f : 1f;
float scaleY = mChart.isScaleYEnabled() ? 1.4f : 1f;
mChart.zoom(scaleX, scaleY, trans.x, trans.y);
if (mChart.isLogEnabled())
Log.i("BarlineChartTouch", "Double-Tap, Zooming In, x: " + trans.x + ", y: "
+ trans.y);
if (l != null) {
l.onChartScale(e, scaleX, scaleY);
}
MPPointF.recycleInstance(trans);
}

View file

@ -57,7 +57,7 @@ public interface OnChartGestureListener {
void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY);
/**
* Callbacks when the chart is scaled / zoomed via pinch zoom gesture.
* Callbacks when the chart is scaled / zoomed via pinch zoom / double-tap gesture.
*
* @param me
* @param scaleX scalefactor on the x-axis

View file

@ -1,28 +1,69 @@
package com.github.mikephil.charting.model;
public class GradientColor {
import com.github.mikephil.charting.utils.Fill;
private int startColor;
private int endColor;
public GradientColor(int startColor, int endColor) {
this.startColor = startColor;
this.endColor = endColor;
/**
* Deprecated. Use `Fill`
*/
@Deprecated
public class GradientColor extends Fill
{
/**
* Deprecated. Use `Fill.getGradientColors()`
*/
@Deprecated
public int getStartColor()
{
return getGradientColors()[0];
}
public int getStartColor() {
return startColor;
/**
* Deprecated. Use `Fill.setGradientColors(...)`
*/
@Deprecated
public void setStartColor(int startColor)
{
if (getGradientColors() == null || getGradientColors().length != 2)
{
setGradientColors(new int[]{
startColor,
getGradientColors() != null && getGradientColors().length > 1
? getGradientColors()[1]
: 0
});
} else
{
getGradientColors()[0] = startColor;
}
}
public void setStartColor(int startColor) {
this.startColor = startColor;
/**
* Deprecated. Use `Fill.getGradientColors()`
*/
@Deprecated
public int getEndColor()
{
return getGradientColors()[1];
}
public int getEndColor() {
return endColor;
/**
* Deprecated. Use `Fill.setGradientColors(...)`
*/
@Deprecated
public void setEndColor(int endColor)
{
if (getGradientColors() == null || getGradientColors().length != 2)
{
setGradientColors(new int[]{
getGradientColors() != null && getGradientColors().length > 0
? getGradientColors()[0]
: 0,
endColor
});
} else
{
getGradientColors()[1] = endColor;
}
}
public void setEndColor(int endColor) {
this.endColor = endColor;
}
}

View file

@ -174,9 +174,12 @@ public abstract class AxisRenderer extends Renderer {
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or
// 90
interval = Math.floor(10 * intervalMagnitude);
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
// if it's 0.0 after floor(), we use the old value
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
? interval
: Math.floor(10.0 * intervalMagnitude);
}
int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;
@ -214,11 +217,14 @@ public abstract class AxisRenderer extends Renderer {
double f;
int i;
if (interval != 0.0) {
if (interval != 0.0 && last != first) {
for (f = first; f <= last; f += interval) {
++n;
}
}
else if (last == first && n == 0) {
n = 1;
}
mAxis.mEntryCount = n;

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -11,16 +10,16 @@ import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.highlight.Range;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.utils.Fill;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
import android.graphics.LinearGradient;
import com.github.mikephil.charting.model.GradientColor;
import java.util.List;
@ -145,13 +144,15 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
trans.pointValuesToPixel(buffer.buffer);
final boolean isCustomFill = dataSet.getFills() != null && !dataSet.getFills().isEmpty();
final boolean isSingleColor = dataSet.getColors().size() == 1;
final boolean isInverted = mChart.isInverted(dataSet.getAxisDependency());
if (isSingleColor) {
mRenderPaint.setColor(dataSet.getColor());
}
for (int j = 0; j < buffer.size(); j += 4) {
for (int j = 0, pos = 0; j < buffer.size(); j += 4, pos++) {
if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
continue;
@ -162,38 +163,24 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
if (!isSingleColor) {
// Set the color for the currently drawn value. If the index
// is out of bounds, reuse colors.
mRenderPaint.setColor(dataSet.getColor(j / 4));
mRenderPaint.setColor(dataSet.getColor(pos));
}
if (dataSet.getGradientColor() != null) {
GradientColor gradientColor = dataSet.getGradientColor();
mRenderPaint.setShader(
new LinearGradient(
buffer.buffer[j],
buffer.buffer[j + 3],
buffer.buffer[j],
buffer.buffer[j + 1],
gradientColor.getStartColor(),
gradientColor.getEndColor(),
android.graphics.Shader.TileMode.MIRROR));
if (isCustomFill) {
dataSet.getFill(pos)
.fillRect(
c, mRenderPaint,
buffer.buffer[j],
buffer.buffer[j + 1],
buffer.buffer[j + 2],
buffer.buffer[j + 3],
isInverted ? Fill.Direction.DOWN : Fill.Direction.UP);
}
if (dataSet.getGradientColors() != null) {
mRenderPaint.setShader(
new LinearGradient(
buffer.buffer[j],
buffer.buffer[j + 3],
buffer.buffer[j],
buffer.buffer[j + 1],
dataSet.getGradientColor(j / 4).getStartColor(),
dataSet.getGradientColor(j / 4).getEndColor(),
android.graphics.Shader.TileMode.MIRROR));
else {
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
}
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
if (drawBorder) {
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mBarBorderPaint);
@ -254,6 +241,8 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
final float phaseY = mAnimator.getPhaseY();
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
@ -276,8 +265,7 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
float val = entry.getY();
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), val, entry, i, x,
val >= 0 ?
drawValue(c, formatter.getBarLabel(entry), x, val >= 0 ?
(buffer.buffer[j + 1] + posOffset) :
(buffer.buffer[j + 3] + negOffset),
dataSet.getValueTextColor(j / 4));
@ -335,8 +323,7 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
continue;
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
buffer.buffer[bufferIndex + 1] +
drawValue(c, formatter.getBarLabel(entry), x, buffer.buffer[bufferIndex + 1] +
(entry.getY() >= 0 ? posOffset : negOffset),
color);
}
@ -407,14 +394,7 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
continue;
if (dataSet.isDrawValuesEnabled()) {
drawValue(c,
dataSet.getValueFormatter(),
vals[k / 2],
entry,
i,
x,
y,
color);
drawValue(c, formatter.getBarStackedLabel(val, entry), x, y, color);
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -442,6 +422,12 @@ public class BarChartRenderer extends BarLineScatterCandleBubbleRenderer {
}
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawHighlighted(Canvas c, Highlight[] indices) {

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -9,6 +8,7 @@ import android.graphics.drawable.Drawable;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.data.BubbleData;
import com.github.mikephil.charting.data.BubbleEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BubbleDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IBubbleDataSet;
@ -108,7 +108,7 @@ public class BubbleChartRenderer extends BarLineScatterCandleBubbleRenderer {
if (!mViewPortHandler.isInBoundsRight(pointBuffer[0] - shapeHalf))
break;
final int color = dataSet.getColor((int) entry.getX());
final int color = dataSet.getColor(j);
mRenderPaint.setColor(color);
c.drawCircle(pointBuffer[0], pointBuffer[1], shapeHalf, mRenderPaint);
@ -150,6 +150,8 @@ public class BubbleChartRenderer extends BarLineScatterCandleBubbleRenderer {
final float alpha = phaseX == 1 ? phaseY : phaseX;
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
@ -172,8 +174,7 @@ public class BubbleChartRenderer extends BarLineScatterCandleBubbleRenderer {
BubbleEntry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), entry.getSize(), entry, i, x,
y + (0.5f * lineHeight), valueTextColor);
drawValue(c, formatter.getBubbleLabel(entry), x, y + (0.5f * lineHeight), valueTextColor);
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -195,6 +196,12 @@ public class BubbleChartRenderer extends BarLineScatterCandleBubbleRenderer {
}
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawExtras(Canvas c) {
}

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -8,6 +7,7 @@ import android.graphics.drawable.Drawable;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.data.CandleData;
import com.github.mikephil.charting.data.CandleEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.CandleDataProvider;
import com.github.mikephil.charting.interfaces.datasets.ICandleDataSet;
@ -279,6 +279,8 @@ public class CandleStickChartRenderer extends LineScatterCandleRadarRenderer {
float yOffset = Utils.convertDpToPixel(5f);
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
@ -297,15 +299,7 @@ public class CandleStickChartRenderer extends LineScatterCandleRadarRenderer {
CandleEntry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);
if (dataSet.isDrawValuesEnabled()) {
drawValue(c,
dataSet.getValueFormatter(),
entry.getHigh(),
entry,
i,
x,
y - yOffset,
dataSet
.getValueTextColor(j / 2));
drawValue(c, formatter.getCandleLabel(entry), x, y - yOffset, dataSet.getValueTextColor(j / 2));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -327,6 +321,12 @@ public class CandleStickChartRenderer extends LineScatterCandleRadarRenderer {
}
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawExtras(Canvas c) {
}

View file

@ -1,6 +1,7 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
import android.util.Log;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.charts.Chart;
@ -9,7 +10,6 @@ import com.github.mikephil.charting.charts.CombinedChart.DrawOrder;
import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.CombinedData;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarLineScatterCandleBubbleDataProvider;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.lang.ref.WeakReference;
@ -89,6 +89,11 @@ public class CombinedChartRenderer extends DataRenderer {
renderer.drawData(c);
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
Log.e("MPAndroidChart", "Erroneous call to drawValue() in CombinedChartRenderer!");
}
@Override
public void drawValues(Canvas c) {

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -6,15 +5,11 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.ChartInterface;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
@ -138,19 +133,13 @@ public abstract class DataRenderer extends Renderer {
/**
* Draws the value of the given entry by using the provided IValueFormatter.
*
* @param c canvas
* @param formatter formatter for custom value-formatting
* @param value the value to be drawn
* @param entry the entry the value belongs to
* @param dataSetIndex the index of the DataSet the drawn Entry belongs to
* @param x position
* @param y position
* @param c canvas
* @param valueText label to draw
* @param x position
* @param y position
* @param color
*/
public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x, y, mValuePaint);
}
public abstract void drawValue(Canvas c, String valueText, float x, float y, int color);
/**
* Draws any kind of additional information (e.g. line-circles).

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -11,11 +10,12 @@ import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.buffer.HorizontalBarBuffer;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
import com.github.mikephil.charting.interfaces.dataprovider.ChartInterface;
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
import com.github.mikephil.charting.utils.Fill;
import com.github.mikephil.charting.utils.MPPointF;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
@ -112,13 +112,15 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
trans.pointValuesToPixel(buffer.buffer);
final boolean isCustomFill = dataSet.getFills() != null && !dataSet.getFills().isEmpty();
final boolean isSingleColor = dataSet.getColors().size() == 1;
final boolean isInverted = mChart.isInverted(dataSet.getAxisDependency());
if (isSingleColor) {
mRenderPaint.setColor(dataSet.getColor());
}
for (int j = 0; j < buffer.size(); j += 4) {
for (int j = 0, pos = 0; j < buffer.size(); j += 4, pos++) {
if (!mViewPortHandler.isInBoundsTop(buffer.buffer[j + 3]))
break;
@ -132,8 +134,20 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
mRenderPaint.setColor(dataSet.getColor(j / 4));
}
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
if (isCustomFill) {
dataSet.getFill(pos)
.fillRect(
c, mRenderPaint,
buffer.buffer[j],
buffer.buffer[j + 1],
buffer.buffer[j + 2],
buffer.buffer[j + 3],
isInverted ? Fill.Direction.LEFT : Fill.Direction.RIGHT);
}
else {
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
}
if (drawBorder) {
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
@ -167,7 +181,7 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
applyValueTextStyle(dataSet);
final float halfTextHeight = Utils.calcTextHeight(mValuePaint, "10") / 2f;
IValueFormatter formatter = dataSet.getValueFormatter();
ValueFormatter formatter = dataSet.getValueFormatter();
// get the buffer
BarBuffer buffer = mBarBuffers[i];
@ -196,12 +210,13 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
BarEntry entry = dataSet.getEntryForIndex(j / 4);
float val = entry.getY();
String formattedValue = formatter.getFormattedValue(val, entry, i, mViewPortHandler);
String formattedValue = formatter.getBarLabel(entry);
// calculate the correct offset depending on the draw position of the value
float valueTextWidth = Utils.calcTextWidth(mValuePaint, formattedValue);
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus));
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus);
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
- (buffer.buffer[j + 2] - buffer.buffer[j]);
if (isInverted) {
posOffset = -posOffset - valueTextWidth;
@ -265,9 +280,7 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
if (!mViewPortHandler.isInBoundsBottom(buffer.buffer[bufferIndex + 1]))
continue;
float val = entry.getY();
String formattedValue = formatter.getFormattedValue(val,
entry, i, mViewPortHandler);
String formattedValue = formatter.getBarLabel(entry);
// calculate the correct offset depending on the draw position of the value
float valueTextWidth = Utils.calcTextWidth(mValuePaint, formattedValue);
@ -337,8 +350,7 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
for (int k = 0; k < transformed.length; k += 2) {
final float val = vals[k / 2];
String formattedValue = formatter.getFormattedValue(val,
entry, i, mViewPortHandler);
String formattedValue = formatter.getBarStackedLabel(val, entry);
// calculate the correct offset depending on the draw position of the value
float valueTextWidth = Utils.calcTextWidth(mValuePaint, formattedValue);
@ -396,7 +408,8 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
}
}
protected void drawValue(Canvas c, String valueText, float x, float y, int color) {
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}

View file

@ -90,6 +90,7 @@ public class LegendRenderer extends Renderer {
for (int i = 0; i < data.getDataSetCount(); i++) {
IDataSet dataSet = data.getDataSetByIndex(i);
if (dataSet == null) continue;
List<Integer> clrs = dataSet.getColors();
int entryCount = dataSet.getEntryCount();
@ -100,10 +101,19 @@ public class LegendRenderer extends Renderer {
IBarDataSet bds = (IBarDataSet) dataSet;
String[] sLabels = bds.getStackLabels();
for (int j = 0; j < clrs.size() && j < bds.getStackSize(); j++) {
int minEntries = Math.min(clrs.size(), bds.getStackSize());
for (int j = 0; j < minEntries; j++) {
String label;
if (sLabels.length > 0) {
int labelIndex = j % minEntries;
label = labelIndex < sLabels.length ? sLabels[labelIndex] : null;
} else {
label = null;
}
computedEntries.add(new LegendEntry(
sLabels[j % sLabels.length],
label,
dataSet.getForm(),
dataSet.getFormSize(),
dataSet.getFormLineWidth(),

View file

@ -12,6 +12,7 @@ import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IDataSet;
@ -294,7 +295,7 @@ public class LineChartRenderer extends LineRadarRenderer {
int entryCount = dataSet.getEntryCount();
final boolean isDrawSteppedEnabled = dataSet.isDrawSteppedEnabled();
final boolean isDrawSteppedEnabled = dataSet.getMode() == LineDataSet.Mode.STEPPED;
final int pointsPerEntryPair = isDrawSteppedEnabled ? 4 : 2;
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
@ -322,10 +323,14 @@ public class LineChartRenderer extends LineRadarRenderer {
// more than 1 color
if (dataSet.getColors().size() > 1) {
if (mLineBuffer.length <= pointsPerEntryPair * 2)
mLineBuffer = new float[pointsPerEntryPair * 4];
int numberOfFloats = pointsPerEntryPair * 2;
for (int j = mXBounds.min; j <= mXBounds.range + mXBounds.min; j++) {
if (mLineBuffer.length <= numberOfFloats)
mLineBuffer = new float[numberOfFloats * 2];
int max = mXBounds.min + mXBounds.range;
for (int j = mXBounds.min; j < max; j++) {
Entry e = dataSet.getEntryForIndex(j);
if (e == null) continue;
@ -356,16 +361,26 @@ public class LineChartRenderer extends LineRadarRenderer {
mLineBuffer[3] = mLineBuffer[1];
}
// Determine the start and end coordinates of the line, and make sure they differ.
float firstCoordinateX = mLineBuffer[0];
float firstCoordinateY = mLineBuffer[1];
float lastCoordinateX = mLineBuffer[numberOfFloats - 2];
float lastCoordinateY = mLineBuffer[numberOfFloats - 1];
if (firstCoordinateX == lastCoordinateX &&
firstCoordinateY == lastCoordinateY)
continue;
trans.pointValuesToPixel(mLineBuffer);
if (!mViewPortHandler.isInBoundsRight(mLineBuffer[0]))
if (!mViewPortHandler.isInBoundsRight(firstCoordinateX))
break;
// make sure the lines don't do shitty things outside
// bounds
if (!mViewPortHandler.isInBoundsLeft(mLineBuffer[2])
|| (!mViewPortHandler.isInBoundsTop(mLineBuffer[1]) && !mViewPortHandler
.isInBoundsBottom(mLineBuffer[3])))
if (!mViewPortHandler.isInBoundsLeft(lastCoordinateX) ||
!mViewPortHandler.isInBoundsTop(Math.max(firstCoordinateY, lastCoordinateY)) ||
!mViewPortHandler.isInBoundsBottom(Math.min(firstCoordinateY, lastCoordinateY)))
continue;
// get the color that is set for this line-segment
@ -547,6 +562,7 @@ public class LineChartRenderer extends LineRadarRenderer {
float[] positions = trans.generateTransformedValuesLine(dataSet, mAnimator.getPhaseX(), mAnimator
.getPhaseY(), mXBounds.min, mXBounds.max);
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
@ -566,8 +582,7 @@ public class LineChartRenderer extends LineRadarRenderer {
Entry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);
if (dataSet.isDrawValuesEnabled()) {
drawValue(c, dataSet.getValueFormatter(), entry.getY(), entry, i, x,
y - valOffset, dataSet.getValueTextColor(j / 2));
drawValue(c, formatter.getPointLabel(entry), x, y - valOffset, dataSet.getValueTextColor(j / 2));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -589,6 +604,12 @@ public class LineChartRenderer extends LineRadarRenderer {
}
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawExtras(Canvas c) {
drawCircles(c);

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Bitmap;
@ -22,7 +21,7 @@ import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
@ -231,6 +230,9 @@ public class PieChartRenderer extends DataRenderer {
final float userInnerRadius = drawInnerArc
? radius * (mChart.getHoleRadius() / 100.f)
: 0.f;
final float roundedRadius = (radius - (radius * mChart.getHoleRadius() / 100f)) / 2f;
final RectF roundedCircleBox = new RectF();
final boolean drawRoundedSlices = drawInnerArc && mChart.isDrawRoundedSlicesEnabled();
int visibleAngleCount = 0;
for (int j = 0; j < entryCount; j++) {
@ -250,133 +252,151 @@ public class PieChartRenderer extends DataRenderer {
Entry e = dataSet.getEntryForIndex(j);
// draw only if the value is greater than zero
if ((Math.abs(e.getY()) > Utils.FLOAT_EPSILON)) {
if (!mChart.needsHighlight(j)) {
final boolean accountForSliceSpacing = sliceSpace > 0.f && sliceAngle <= 180.f;
mRenderPaint.setColor(dataSet.getColor(j));
final float sliceSpaceAngleOuter = visibleAngleCount == 1 ?
0.f :
sliceSpace / (Utils.FDEG2RAD * radius);
final float startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
float sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY;
if (sweepAngleOuter < 0.f) {
sweepAngleOuter = 0.f;
}
mPathBuffer.reset();
float arcStartPointX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
float arcStartPointY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
// Android is doing "mod 360"
mPathBuffer.addCircle(center.x, center.y, radius, Path.Direction.CW);
} else {
mPathBuffer.moveTo(arcStartPointX, arcStartPointY);
mPathBuffer.arcTo(
circleBox,
startAngleOuter,
sweepAngleOuter
);
}
// API < 21 does not receive floats in addArc, but a RectF
mInnerRectBuffer.set(
center.x - innerRadius,
center.y - innerRadius,
center.x + innerRadius,
center.y + innerRadius);
if (drawInnerArc &&
(innerRadius > 0.f || accountForSliceSpacing)) {
if (accountForSliceSpacing) {
float minSpacedRadius =
calculateMinimumRadiusForSpacedSlice(
center, radius,
sliceAngle * phaseY,
arcStartPointX, arcStartPointY,
startAngleOuter,
sweepAngleOuter);
if (minSpacedRadius < 0.f)
minSpacedRadius = -minSpacedRadius;
innerRadius = Math.max(innerRadius, minSpacedRadius);
}
final float sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.f ?
0.f :
sliceSpace / (Utils.FDEG2RAD * innerRadius);
final float startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.f) * phaseY;
float sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY;
if (sweepAngleInner < 0.f) {
sweepAngleInner = 0.f;
}
final float endAngleInner = startAngleInner + sweepAngleInner;
if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
// Android is doing "mod 360"
mPathBuffer.addCircle(center.x, center.y, innerRadius, Path.Direction.CCW);
} else {
mPathBuffer.lineTo(
center.x + innerRadius * (float) Math.cos(endAngleInner * Utils.FDEG2RAD),
center.y + innerRadius * (float) Math.sin(endAngleInner * Utils.FDEG2RAD));
mPathBuffer.arcTo(
mInnerRectBuffer,
endAngleInner,
-sweepAngleInner
);
}
} else {
if (sweepAngleOuter % 360f > Utils.FLOAT_EPSILON) {
if (accountForSliceSpacing) {
float angleMiddle = startAngleOuter + sweepAngleOuter / 2.f;
float sliceSpaceOffset =
calculateMinimumRadiusForSpacedSlice(
center,
radius,
sliceAngle * phaseY,
arcStartPointX,
arcStartPointY,
startAngleOuter,
sweepAngleOuter);
float arcEndPointX = center.x +
sliceSpaceOffset * (float) Math.cos(angleMiddle * Utils.FDEG2RAD);
float arcEndPointY = center.y +
sliceSpaceOffset * (float) Math.sin(angleMiddle * Utils.FDEG2RAD);
mPathBuffer.lineTo(
arcEndPointX,
arcEndPointY);
} else {
mPathBuffer.lineTo(
center.x,
center.y);
}
}
}
mPathBuffer.close();
mBitmapCanvas.drawPath(mPathBuffer, mRenderPaint);
}
if (!(Math.abs(e.getY()) > Utils.FLOAT_EPSILON)) {
angle += sliceAngle * phaseX;
continue;
}
// Don't draw if it's highlighted, unless the chart uses rounded slices
if (dataSet.isHighlightEnabled() && mChart.needsHighlight(j) && !drawRoundedSlices) {
angle += sliceAngle * phaseX;
continue;
}
final boolean accountForSliceSpacing = sliceSpace > 0.f && sliceAngle <= 180.f;
mRenderPaint.setColor(dataSet.getColor(j));
final float sliceSpaceAngleOuter = visibleAngleCount == 1 ?
0.f :
sliceSpace / (Utils.FDEG2RAD * radius);
final float startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
float sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY;
if (sweepAngleOuter < 0.f) {
sweepAngleOuter = 0.f;
}
mPathBuffer.reset();
if (drawRoundedSlices) {
float x = center.x + (radius - roundedRadius) * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
float y = center.y + (radius - roundedRadius) * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
}
float arcStartPointX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
float arcStartPointY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
// Android is doing "mod 360"
mPathBuffer.addCircle(center.x, center.y, radius, Path.Direction.CW);
} else {
if (drawRoundedSlices) {
mPathBuffer.arcTo(roundedCircleBox, startAngleOuter + 180, -180);
}
mPathBuffer.arcTo(
circleBox,
startAngleOuter,
sweepAngleOuter
);
}
// API < 21 does not receive floats in addArc, but a RectF
mInnerRectBuffer.set(
center.x - innerRadius,
center.y - innerRadius,
center.x + innerRadius,
center.y + innerRadius);
if (drawInnerArc && (innerRadius > 0.f || accountForSliceSpacing)) {
if (accountForSliceSpacing) {
float minSpacedRadius =
calculateMinimumRadiusForSpacedSlice(
center, radius,
sliceAngle * phaseY,
arcStartPointX, arcStartPointY,
startAngleOuter,
sweepAngleOuter);
if (minSpacedRadius < 0.f)
minSpacedRadius = -minSpacedRadius;
innerRadius = Math.max(innerRadius, minSpacedRadius);
}
final float sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.f ?
0.f :
sliceSpace / (Utils.FDEG2RAD * innerRadius);
final float startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.f) * phaseY;
float sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY;
if (sweepAngleInner < 0.f) {
sweepAngleInner = 0.f;
}
final float endAngleInner = startAngleInner + sweepAngleInner;
if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
// Android is doing "mod 360"
mPathBuffer.addCircle(center.x, center.y, innerRadius, Path.Direction.CCW);
} else {
if (drawRoundedSlices) {
float x = center.x + (radius - roundedRadius) * (float) Math.cos(endAngleInner * Utils.FDEG2RAD);
float y = center.y + (radius - roundedRadius) * (float) Math.sin(endAngleInner * Utils.FDEG2RAD);
roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
mPathBuffer.arcTo(roundedCircleBox, endAngleInner, 180);
} else
mPathBuffer.lineTo(
center.x + innerRadius * (float) Math.cos(endAngleInner * Utils.FDEG2RAD),
center.y + innerRadius * (float) Math.sin(endAngleInner * Utils.FDEG2RAD));
mPathBuffer.arcTo(
mInnerRectBuffer,
endAngleInner,
-sweepAngleInner
);
}
} else {
if (sweepAngleOuter % 360f > Utils.FLOAT_EPSILON) {
if (accountForSliceSpacing) {
float angleMiddle = startAngleOuter + sweepAngleOuter / 2.f;
float sliceSpaceOffset =
calculateMinimumRadiusForSpacedSlice(
center,
radius,
sliceAngle * phaseY,
arcStartPointX,
arcStartPointY,
startAngleOuter,
sweepAngleOuter);
float arcEndPointX = center.x +
sliceSpaceOffset * (float) Math.cos(angleMiddle * Utils.FDEG2RAD);
float arcEndPointY = center.y +
sliceSpaceOffset * (float) Math.sin(angleMiddle * Utils.FDEG2RAD);
mPathBuffer.lineTo(
arcEndPointX,
arcEndPointY);
} else {
mPathBuffer.lineTo(
center.x,
center.y);
}
}
}
mPathBuffer.close();
mBitmapCanvas.drawPath(mPathBuffer, mRenderPaint);
angle += sliceAngle * phaseX;
}
@ -397,11 +417,17 @@ public class PieChartRenderer extends DataRenderer {
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
final float roundedRadius = (radius - (radius * mChart.getHoleRadius() / 100f)) / 2f;
final float holeRadiusPercent = mChart.getHoleRadius() / 100.f;
float labelRadiusOffset = radius / 10f * 3.6f;
if (mChart.isDrawHoleEnabled()) {
labelRadiusOffset = (radius - (radius * holeRadiusPercent)) / 2f;
if (!mChart.isDrawSlicesUnderHoleEnabled() && mChart.isDrawRoundedSlicesEnabled()) {
// Add curved circle slice and spacing to rotation angle, so that it sits nicely inside
rotationAngle += roundedRadius * 360 / (Math.PI * 2 * radius);
}
}
final float labelRadius = radius - labelRadiusOffset;
@ -438,11 +464,13 @@ public class PieChartRenderer extends DataRenderer {
float lineHeight = Utils.calcTextHeight(mValuePaint, "Q")
+ Utils.convertDpToPixel(4f);
IValueFormatter formatter = dataSet.getValueFormatter();
ValueFormatter formatter = dataSet.getValueFormatter();
int entryCount = dataSet.getEntryCount();
mValueLinePaint.setColor(dataSet.getValueLineColor());
boolean isUseValueColorForLineEnabled = dataSet.isUseValueColorForLineEnabled();
int valueLineColor = dataSet.getValueLineColor();
mValueLinePaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getValueLineWidth()));
final float sliceSpace = getSliceSpace(dataSet);
@ -472,6 +500,8 @@ public class PieChartRenderer extends DataRenderer {
float value = mChart.isUsePercentValuesEnabled() ? entry.getY()
/ yValueSum * 100f : entry.getY();
String formattedValue = formatter.getPieLabel(value, entry);
String entryLabel = entry.getLabel();
final float sliceXBase = (float) Math.cos(transformedAngle * Utils.FDEG2RAD);
final float sliceYBase = (float) Math.sin(transformedAngle * Utils.FDEG2RAD);
@ -537,12 +567,15 @@ public class PieChartRenderer extends DataRenderer {
labelPty = pt2y;
}
if (dataSet.getValueLineColor() != ColorTemplate.COLOR_NONE) {
int lineColor = ColorTemplate.COLOR_NONE;
if (dataSet.isUsingSliceColorAsValueLineColor()) {
mValueLinePaint.setColor(dataSet.getColor(j));
}
if (isUseValueColorForLineEnabled)
lineColor = dataSet.getColor(j);
else if (valueLineColor != ColorTemplate.COLOR_NONE)
lineColor = valueLineColor;
if (lineColor != ColorTemplate.COLOR_NONE) {
mValueLinePaint.setColor(lineColor);
c.drawLine(pt0x, pt0y, pt1x, pt1y, mValueLinePaint);
c.drawLine(pt1x, pt1y, pt2x, pt2y, mValueLinePaint);
}
@ -550,27 +583,19 @@ public class PieChartRenderer extends DataRenderer {
// draw everything, depending on settings
if (drawXOutside && drawYOutside) {
drawValue(c,
formatter,
value,
entry,
0,
labelPtx,
labelPty,
dataSet.getValueTextColor(j));
drawValue(c, formattedValue, labelPtx, labelPty, dataSet.getValueTextColor(j));
if (j < data.getEntryCount() && entry.getLabel() != null) {
drawEntryLabel(c, entry.getLabel(), labelPtx, labelPty + lineHeight);
if (j < data.getEntryCount() && entryLabel != null) {
drawEntryLabel(c, entryLabel, labelPtx, labelPty + lineHeight);
}
} else if (drawXOutside) {
if (j < data.getEntryCount() && entry.getLabel() != null) {
drawEntryLabel(c, entry.getLabel(), labelPtx, labelPty + lineHeight / 2.f);
if (j < data.getEntryCount() && entryLabel != null) {
drawEntryLabel(c, entryLabel, labelPtx, labelPty + lineHeight / 2.f);
}
} else if (drawYOutside) {
drawValue(c, formatter, value, entry, 0, labelPtx, labelPty + lineHeight / 2.f, dataSet
.getValueTextColor(j));
drawValue(c, formattedValue, labelPtx, labelPty + lineHeight / 2.f, dataSet.getValueTextColor(j));
}
}
@ -584,19 +609,18 @@ public class PieChartRenderer extends DataRenderer {
// draw everything, depending on settings
if (drawXInside && drawYInside) {
drawValue(c, formatter, value, entry, 0, x, y, dataSet.getValueTextColor(j));
drawValue(c, formattedValue, x, y, dataSet.getValueTextColor(j));
if (j < data.getEntryCount() && entry.getLabel() != null) {
drawEntryLabel(c, entry.getLabel(), x, y + lineHeight);
if (j < data.getEntryCount() && entryLabel != null) {
drawEntryLabel(c, entryLabel, x, y + lineHeight);
}
} else if (drawXInside) {
if (j < data.getEntryCount() && entry.getLabel() != null) {
drawEntryLabel(c, entry.getLabel(), x, y + lineHeight / 2f);
if (j < data.getEntryCount() && entryLabel != null) {
drawEntryLabel(c, entryLabel, x, y + lineHeight / 2f);
}
} else if (drawYInside) {
drawValue(c, formatter, value, entry, 0, x, y + lineHeight / 2f, dataSet.getValueTextColor(j));
drawValue(c, formattedValue, x, y + lineHeight / 2f, dataSet.getValueTextColor(j));
}
}
@ -626,6 +650,12 @@ public class PieChartRenderer extends DataRenderer {
c.restore();
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
/**
* Draws an entry label at the specified position.
*
@ -640,7 +670,6 @@ public class PieChartRenderer extends DataRenderer {
@Override
public void drawExtras(Canvas c) {
// drawCircles(c);
drawHole(c);
c.drawBitmap(mDrawBitmap.get(), 0, 0, null);
drawCenterText(c);
@ -766,6 +795,15 @@ public class PieChartRenderer extends DataRenderer {
@Override
public void drawHighlighted(Canvas c, Highlight[] indices) {
/* Skip entirely if using rounded circle slices, because it doesn't make sense to highlight
* in this way.
* TODO: add support for changing slice color with highlighting rather than only shifting the slice
*/
final boolean drawInnerArc = mChart.isDrawHoleEnabled() && !mChart.isDrawSlicesUnderHoleEnabled();
if (drawInnerArc && mChart.isDrawRoundedSlicesEnabled())
return;
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
@ -776,7 +814,6 @@ public class PieChartRenderer extends DataRenderer {
float[] absoluteAngles = mChart.getAbsoluteAngles();
final MPPointF center = mChart.getCenterCircleBox();
final float radius = mChart.getRadius();
final boolean drawInnerArc = mChart.isDrawHoleEnabled() && !mChart.isDrawSlicesUnderHoleEnabled();
final float userInnerRadius = drawInnerArc
? radius * (mChart.getHoleRadius() / 100.f)
: 0.f;
@ -793,8 +830,7 @@ public class PieChartRenderer extends DataRenderer {
continue;
IPieDataSet set = mChart.getData()
.getDataSetByIndex(indices[i]
.getDataSetIndex());
.getDataSetByIndex(indices[i].getDataSetIndex());
if (set == null || !set.isHighlightEnabled())
continue;
@ -825,7 +861,10 @@ public class PieChartRenderer extends DataRenderer {
final boolean accountForSliceSpacing = sliceSpace > 0.f && sliceAngle <= 180.f;
mRenderPaint.setColor(set.getColor(index));
Integer highlightColor = set.getHighlightColor();
if (highlightColor == null)
highlightColor = set.getColor(index);
mRenderPaint.setColor(highlightColor);
final float sliceSpaceAngleOuter = visibleAngleCount == 1 ?
0.f :

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -11,6 +10,7 @@ import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.charts.RadarChart;
import com.github.mikephil.charting.data.RadarData;
import com.github.mikephil.charting.data.RadarEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.IRadarDataSet;
import com.github.mikephil.charting.utils.ColorTemplate;
@ -174,6 +174,8 @@ public class RadarChartRenderer extends LineRadarRenderer {
// apply the text-styling defined by the DataSet
applyValueTextStyle(dataSet);
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
@ -189,15 +191,7 @@ public class RadarChartRenderer extends LineRadarRenderer {
pOut);
if (dataSet.isDrawValuesEnabled()) {
drawValue(c,
dataSet.getValueFormatter(),
entry.getY(),
entry,
i,
pOut.x,
pOut.y - yoffset,
dataSet.getValueTextColor
(j));
drawValue(c, formatter.getRadarLabel(entry), pOut.x, pOut.y - yoffset, dataSet.getValueTextColor(j));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -231,6 +225,12 @@ public class RadarChartRenderer extends LineRadarRenderer {
MPPointF.recycleInstance(pIcon);
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawExtras(Canvas c) {
drawWeb(c);

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -8,6 +7,7 @@ import android.util.Log;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.ScatterData;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.dataprovider.ScatterDataProvider;
import com.github.mikephil.charting.interfaces.datasets.IScatterDataSet;
@ -118,6 +118,8 @@ public class ScatterChartRenderer extends LineScatterCandleRadarRenderer {
float shapeSize = Utils.convertDpToPixel(dataSet.getScatterShapeSize());
ValueFormatter formatter = dataSet.getValueFormatter();
MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
@ -135,14 +137,7 @@ public class ScatterChartRenderer extends LineScatterCandleRadarRenderer {
Entry entry = dataSet.getEntryForIndex(j / 2 + mXBounds.min);
if (dataSet.isDrawValuesEnabled()) {
drawValue(c,
dataSet.getValueFormatter(),
entry.getY(),
entry,
i,
positions[j],
positions[j + 1] - shapeSize,
dataSet.getValueTextColor(j / 2 + mXBounds.min));
drawValue(c, formatter.getPointLabel(entry), positions[j], positions[j + 1] - shapeSize, dataSet.getValueTextColor(j / 2 + mXBounds.min));
}
if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {
@ -164,6 +159,12 @@ public class ScatterChartRenderer extends LineScatterCandleRadarRenderer {
}
}
@Override
public void drawValue(Canvas c, String valueText, float x, float y, int color) {
mValuePaint.setColor(color);
c.drawText(valueText, x, y, mValuePaint);
}
@Override
public void drawExtras(Canvas c) {
}

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -202,7 +201,7 @@ public class XAxisRenderer extends AxisRenderer {
if (mViewPortHandler.isInBoundsX(x)) {
String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis);
String label = mXAxis.getValueFormatter().getAxisLabel(mXAxis.mEntries[i / 2], mXAxis);
if (mXAxis.isAvoidFirstLastClippingEnabled()) {

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
@ -57,10 +56,10 @@ public class XAxisRendererHorizontalBarChart extends XAxisRenderer {
computeAxisValues(min, max);
}
@Override
protected void computeSize() {
mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
@ -156,7 +155,7 @@ public class XAxisRendererHorizontalBarChart extends XAxisRenderer {
if (mViewPortHandler.isInBoundsY(y)) {
String label = mXAxis.getValueFormatter().getFormattedValue(mXAxis.mEntries[i / 2], mXAxis);
String label = mXAxis.getValueFormatter().getAxisLabel(mXAxis.mEntries[i / 2], mXAxis);
drawLabel(c, label, pos, y, anchor, labelRotationAngleDegrees);
}
}

View file

@ -1,8 +1,6 @@
package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
import android.graphics.PointF;
import com.github.mikephil.charting.charts.RadarChart;
import com.github.mikephil.charting.components.XAxis;
@ -43,7 +41,7 @@ public class XAxisRendererRadarChart extends XAxisRenderer {
MPPointF pOut = MPPointF.getInstance(0,0);
for (int i = 0; i < mChart.getData().getMaxEntryCountSet().getEntryCount(); i++) {
String label = mXAxis.getValueFormatter().getFormattedValue(i, mXAxis);
String label = mXAxis.getValueFormatter().getAxisLabel(i, mXAxis);
float angle = (sliceangle * i + mChart.getRotationAngle()) % 360f;

View file

@ -119,12 +119,17 @@ public class YAxisRenderer extends AxisRenderer {
? mYAxis.mEntryCount
: (mYAxis.mEntryCount - 1);
float xOffset = mYAxis.getLabelXOffset();
// draw
for (int i = from; i < to; i++) {
String text = mYAxis.getFormattedLabel(i);
c.drawText(text, fixedPosition, positions[i * 2 + 1] + offset, mAxisLabelPaint);
c.drawText(text,
fixedPosition + xOffset,
positions[i * 2 + 1] + offset,
mAxisLabelPaint);
}
}

View file

@ -142,11 +142,16 @@ public class YAxisRendererHorizontalBarChart extends YAxisRenderer {
? mYAxis.mEntryCount
: (mYAxis.mEntryCount - 1);
float xOffset = mYAxis.getLabelXOffset();
for (int i = from; i < to; i++) {
String text = mYAxis.getFormattedLabel(i);
c.drawText(text, positions[i * 2], fixedPosition - offset, mAxisLabelPaint);
c.drawText(text,
positions[i * 2],
fixedPosition - offset + xOffset,
mAxisLabelPaint);
}
}

View file

@ -52,9 +52,11 @@ public class YAxisRendererRadarChart extends YAxisRenderer {
double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
int intervalSigDigit = (int) (interval / intervalMagnitude);
if (intervalSigDigit > 5) {
// Use one order of magnitude higher, to avoid intervals like 0.9 or
// 90
interval = Math.floor(10 * intervalMagnitude);
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
// if it's 0.0 after floor(), we use the old value
interval = Math.floor(10.0 * intervalMagnitude) == 0.0
? interval
: Math.floor(10.0 * intervalMagnitude);
}
boolean centeringEnabled = mAxis.isCenterAxisLabelsEnabled();
@ -161,6 +163,8 @@ public class YAxisRendererRadarChart extends YAxisRenderer {
? mYAxis.mEntryCount
: (mYAxis.mEntryCount - 1);
float xOffset = mYAxis.getLabelXOffset();
for (int j = from; j < to; j++) {
float r = (mYAxis.mEntries[j] - mYAxis.mAxisMinimum) * factor;
@ -169,7 +173,7 @@ public class YAxisRendererRadarChart extends YAxisRenderer {
String label = mYAxis.getFormattedLabel(j);
c.drawText(label, pOut.x + 10, pOut.y, mAxisLabelPaint);
c.drawText(label, pOut.x + xOffset, pOut.y, mAxisLabelPaint);
}
MPPointF.recycleInstance(center);
MPPointF.recycleInstance(pOut);

View file

@ -0,0 +1,342 @@
package com.github.mikephil.charting.utils;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class Fill
{
public enum Type
{
EMPTY, COLOR, LINEAR_GRADIENT, DRAWABLE
}
public enum Direction
{
DOWN, UP, RIGHT, LEFT
}
/**
* the type of fill
*/
private Type mType = Type.EMPTY;
/**
* the color that is used for filling
*/
@Nullable
private Integer mColor = null;
private Integer mFinalColor = null;
/**
* the drawable to be used for filling
*/
@Nullable
protected Drawable mDrawable;
@Nullable
private int[] mGradientColors;
@Nullable
private float[] mGradientPositions;
/**
* transparency used for filling
*/
private int mAlpha = 255;
public Fill()
{
}
public Fill(int color)
{
this.mType = Type.COLOR;
this.mColor = color;
calculateFinalColor();
}
public Fill(int startColor, int endColor)
{
this.mType = Type.LINEAR_GRADIENT;
this.mGradientColors = new int[]{startColor, endColor};
}
public Fill(@NonNull int[] gradientColors)
{
this.mType = Type.LINEAR_GRADIENT;
this.mGradientColors = gradientColors;
}
public Fill(@NonNull int[] gradientColors, @NonNull float[] gradientPositions)
{
this.mType = Type.LINEAR_GRADIENT;
this.mGradientColors = gradientColors;
this.mGradientPositions = gradientPositions;
}
public Fill(@NonNull Drawable drawable)
{
this.mType = Type.DRAWABLE;
this.mDrawable = drawable;
}
public Type getType()
{
return mType;
}
public void setType(Type type)
{
this.mType = type;
}
@Nullable
public Integer getColor()
{
return mColor;
}
public void setColor(int color)
{
this.mColor = color;
calculateFinalColor();
}
public int[] getGradientColors()
{
return mGradientColors;
}
public void setGradientColors(int[] colors)
{
this.mGradientColors = colors;
}
public float[] getGradientPositions()
{
return mGradientPositions;
}
public void setGradientPositions(float[] positions)
{
this.mGradientPositions = positions;
}
public void setGradientColors(int startColor, int endColor)
{
this.mGradientColors = new int[]{startColor, endColor};
}
public int getAlpha()
{
return mAlpha;
}
public void setAlpha(int alpha)
{
this.mAlpha = alpha;
calculateFinalColor();
}
private void calculateFinalColor()
{
if (mColor == null)
{
mFinalColor = null;
} else
{
int alpha = (int) Math.floor(((mColor >> 24) / 255.0) * (mAlpha / 255.0) * 255.0);
mFinalColor = (alpha << 24) | (mColor & 0xffffff);
}
}
public void fillRect(Canvas c, Paint paint,
float left, float top, float right, float bottom,
Direction gradientDirection)
{
switch (mType)
{
case EMPTY:
return;
case COLOR:
{
if (mFinalColor == null) return;
if (isClipPathSupported())
{
int save = c.save();
c.clipRect(left, top, right, bottom);
c.drawColor(mFinalColor);
c.restoreToCount(save);
}
else
{
// save
Paint.Style previous = paint.getStyle();
int previousColor = paint.getColor();
// set
paint.setStyle(Paint.Style.FILL);
paint.setColor(mFinalColor);
c.drawRect(left, top, right, bottom, paint);
// restore
paint.setColor(previousColor);
paint.setStyle(previous);
}
}
break;
case LINEAR_GRADIENT:
{
if (mGradientColors == null) return;
LinearGradient gradient = new LinearGradient(
(int) (gradientDirection == Direction.RIGHT
? right
: gradientDirection == Direction.LEFT
? left
: left),
(int) (gradientDirection == Direction.UP
? bottom
: gradientDirection == Direction.DOWN
? top
: top),
(int) (gradientDirection == Direction.RIGHT
? left
: gradientDirection == Direction.LEFT
? right
: left),
(int) (gradientDirection == Direction.UP
? top
: gradientDirection == Direction.DOWN
? bottom
: top),
mGradientColors,
mGradientPositions,
android.graphics.Shader.TileMode.MIRROR);
paint.setShader(gradient);
c.drawRect(left, top, right, bottom, paint);
}
break;
case DRAWABLE:
{
if (mDrawable == null) return;
mDrawable.setBounds((int) left, (int) top, (int) right, (int) bottom);
mDrawable.draw(c);
}
break;
}
}
public void fillPath(Canvas c, Path path, Paint paint,
@Nullable RectF clipRect)
{
switch (mType)
{
case EMPTY:
return;
case COLOR:
{
if (mFinalColor == null) return;
if (clipRect != null && isClipPathSupported())
{
int save = c.save();
c.clipPath(path);
c.drawColor(mFinalColor);
c.restoreToCount(save);
}
else
{
// save
Paint.Style previous = paint.getStyle();
int previousColor = paint.getColor();
// set
paint.setStyle(Paint.Style.FILL);
paint.setColor(mFinalColor);
c.drawPath(path, paint);
// restore
paint.setColor(previousColor);
paint.setStyle(previous);
}
}
break;
case LINEAR_GRADIENT:
{
if (mGradientColors == null) return;
LinearGradient gradient = new LinearGradient(
0,
0,
c.getWidth(),
c.getHeight(),
mGradientColors,
mGradientPositions,
android.graphics.Shader.TileMode.MIRROR);
paint.setShader(gradient);
c.drawPath(path, paint);
}
break;
case DRAWABLE:
{
if (mDrawable == null) return;
ensureClipPathSupported();
int save = c.save();
c.clipPath(path);
mDrawable.setBounds(
clipRect == null ? 0 : (int) clipRect.left,
clipRect == null ? 0 : (int) clipRect.top,
clipRect == null ? c.getWidth() : (int) clipRect.right,
clipRect == null ? c.getHeight() : (int) clipRect.bottom);
mDrawable.draw(c);
c.restoreToCount(save);
}
break;
}
}
private boolean isClipPathSupported()
{
return Utils.getSDKInt() >= 18;
}
private void ensureClipPathSupported()
{
if (Utils.getSDKInt() < 18)
{
throw new RuntimeException("Fill-drawables not (yet) supported below API level 18, " +
"this code was run on API level " + Utils.getSDKInt() + ".");
}
}
}

View file

@ -1,4 +1,3 @@
package com.github.mikephil.charting.utils;
import android.annotation.SuppressLint;
@ -7,7 +6,6 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Layout;
@ -15,14 +13,13 @@ import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SizeF;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import com.github.mikephil.charting.formatter.DefaultValueFormatter;
import com.github.mikephil.charting.formatter.IValueFormatter;
import com.github.mikephil.charting.formatter.ValueFormatter;
import java.util.List;
@ -229,15 +226,14 @@ public abstract class Utils {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
};
private static IValueFormatter mDefaultValueFormatter = generateDefaultValueFormatter();
private static ValueFormatter mDefaultValueFormatter = generateDefaultValueFormatter();
private static IValueFormatter generateDefaultValueFormatter() {
final DefaultValueFormatter formatter = new DefaultValueFormatter(1);
return formatter;
private static ValueFormatter generateDefaultValueFormatter() {
return new DefaultValueFormatter(1);
}
/// - returns: The default value formatter used for all chart components that needs a default
public static IValueFormatter getDefaultValueFormatter()
public static ValueFormatter getDefaultValueFormatter()
{
return mDefaultValueFormatter;
}
@ -353,11 +349,11 @@ public abstract class Utils {
* @return
*/
public static float roundToNextSignificant(double number) {
if (Double.isInfinite(number) ||
Double.isNaN(number) ||
if (Double.isInfinite(number) ||
Double.isNaN(number) ||
number == 0.0)
return 0;
final float d = (float) Math.ceil((float) Math.log10(number < 0 ? -number : number));
final int pw = 1 - (int) d;
final float magnitude = (float) Math.pow(10, pw);
@ -375,10 +371,10 @@ public abstract class Utils {
public static int getDecimals(float number) {
float i = roundToNextSignificant(number);
if (Float.isInfinite(i))
return 0;
return (int) Math.ceil(-Math.log10(i)) + 2;
}

View file

@ -16,80 +16,80 @@ public class LargeValueFormatterTest {
LargeValueFormatter formatter = new LargeValueFormatter();
String result = formatter.getFormattedValue(5f, null);
String result = formatter.getFormattedValue(5f);
assertEquals("5", result);
result = formatter.getFormattedValue(5.5f, null);
result = formatter.getFormattedValue(5.5f);
assertEquals("5.5", result);
result = formatter.getFormattedValue(50f, null);
result = formatter.getFormattedValue(50f);
assertEquals("50", result);
result = formatter.getFormattedValue(50.5f, null);
result = formatter.getFormattedValue(50.5f);
assertEquals("50.5", result);
result = formatter.getFormattedValue(500f, null);
result = formatter.getFormattedValue(500f);
assertEquals("500", result);
result = formatter.getFormattedValue(1100f, null);
result = formatter.getFormattedValue(1100f);
assertEquals("1.1k", result);
result = formatter.getFormattedValue(10000f, null);
result = formatter.getFormattedValue(10000f);
assertEquals("10k", result);
result = formatter.getFormattedValue(10500f, null);
result = formatter.getFormattedValue(10500f);
assertEquals("10.5k", result);
result = formatter.getFormattedValue(100000f, null);
result = formatter.getFormattedValue(100000f);
assertEquals("100k", result);
result = formatter.getFormattedValue(1000000f, null);
result = formatter.getFormattedValue(1000000f);
assertEquals("1m", result);
result = formatter.getFormattedValue(1500000f, null);
result = formatter.getFormattedValue(1500000f);
assertEquals("1.5m", result);
result = formatter.getFormattedValue(9500000f, null);
result = formatter.getFormattedValue(9500000f);
assertEquals("9.5m", result);
result = formatter.getFormattedValue(22200000f, null);
result = formatter.getFormattedValue(22200000f);
assertEquals("22.2m", result);
result = formatter.getFormattedValue(222000000f, null);
result = formatter.getFormattedValue(222000000f);
assertEquals("222m", result);
result = formatter.getFormattedValue(1000000000f, null);
result = formatter.getFormattedValue(1000000000f);
assertEquals("1b", result);
result = formatter.getFormattedValue(9900000000f, null);
result = formatter.getFormattedValue(9900000000f);
assertEquals("9.9b", result);
result = formatter.getFormattedValue(99000000000f, null);
result = formatter.getFormattedValue(99000000000f);
assertEquals("99b", result);
result = formatter.getFormattedValue(99500000000f, null);
result = formatter.getFormattedValue(99500000000f);
assertEquals("99.5b", result);
result = formatter.getFormattedValue(999000000000f, null);
result = formatter.getFormattedValue(999000000000f);
assertEquals("999b", result);
result = formatter.getFormattedValue(1000000000000f, null);
result = formatter.getFormattedValue(1000000000000f);
assertEquals("1t", result);
formatter.setSuffix(new String[]{"", "k", "m", "b", "t", "q"}); // quadrillion support
result = formatter.getFormattedValue(1000000000000000f, null);
result = formatter.getFormattedValue(1000000000000000f);
assertEquals("1q", result);
result = formatter.getFormattedValue(1100000000000000f, null);
result = formatter.getFormattedValue(1100000000000000f);
assertEquals("1.1q", result);
result = formatter.getFormattedValue(10000000000000000f, null);
result = formatter.getFormattedValue(10000000000000000f);
assertEquals("10q", result);
result = formatter.getFormattedValue(13300000000000000f, null);
result = formatter.getFormattedValue(13300000000000000f);
assertEquals("13.3q", result);
result = formatter.getFormattedValue(100000000000000000f, null);
result = formatter.getFormattedValue(100000000000000000f);
assertEquals("100q", result);
}
}

View file

@ -2,7 +2,7 @@ package com.github.mikephil.charting.test;
import com.github.mikephil.charting.utils.ObjectPool;
import junit.framework.Assert;
import org.junit.Assert;
import org.junit.Test;

View file

@ -23,23 +23,9 @@
1. [License](#licence)
1. [Creators](#creators)
## [Realtime Graphing Solution | SciChart](https://scichart.com/android-chart-features?source=MPAndroidChart)
## [Coding Newsletter](https://weeklycoding.com)
<img align="left" width="190" height="190" style="margin:0px 15px 0px 0px" src="https://raw.github.com/PhilJay/MPChart/master/design/other/left.png">
<img align="right" width="90" height="90" style="margin:0px 15px 0px 0px" src="https://raw.github.com/PhilJay/MPChart/master/design/other/right.png">
MPAndroidChart is free software, as a result **dynamic & realtime data is not officially supported**. If you are looking for an enterprise-grade chart solution with extreme realtime performance and tech support, we recommend
<a href="https://scichart.com/android-chart-features?source=MPAndroidChart" target="_blank">SciChart Android</a>.
<img align="right" width="270" height="60" style="margin:0px 0px 0px 0px" src="https://raw.github.com/PhilJay/MPChart/master/design/other/bottom.png">
All MPAndroidChart users are entitled to a special **discount of 5%** off the <a href="https://store.scichart.com?productTab=Android&CouponCode=MPANDROIDCHART&source=MPAndroidChart" target="_blank">SciChart store</a>, using the following discount code: **MPANDROIDCHART**
<br/>
## [Daily Coding Newsletter](https://philjay.substack.com/subscribe)
Sign up for my [daily coding newsletter](https://philjay.substack.com/subscribe) to get quick updates on Kotlin and Android development related topics.
Sign up for my [coding newsletter](https://weeklycoding.com) to get quick updates on Kotlin and Android development related topics.
<h2 id="quick-start">Quick Start :chart_with_upwards_trend:</h2>
@ -53,7 +39,7 @@ repositories {
}
dependencies {
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}
```
@ -70,7 +56,7 @@ dependencies {
<dependency>
<groupId>com.github.PhilJay</groupId>
<artifactId>MPAndroidChart</artifactId>
<version>v3.0.3</version>
<version>v3.1.0</version>
</dependency>
```
@ -78,13 +64,14 @@ dependencies {
<h2 id="documentation">Documentation :notebook_with_decorative_cover:</h2>
See the [**documentation**](https://github.com/PhilJay/MPAndroidChart/wiki) for examples and general use of MPAndroidChart.
See the [**documentation**](https://weeklycoding.com/mpandroidchart/) for examples and general use of MPAndroidChart.
See the [**javadocs**](https://jitpack.io/com/github/PhilJay/MPAndroidChart/v3.0.3/javadoc/) for more advanced documentation.
See the [**javadocs**](https://jitpack.io/com/github/PhilJay/MPAndroidChart/v3.1.0/javadoc/) for more advanced documentation.
<br/>
<h2 id="examples">Examples :eyes:</h2>
Download the [MPAndroidChart Example App](https://play.google.com/store/apps/details?id=com.xxmassdeveloper.mpchartexample) or look at the [source code](https://github.com/PhilJay/MPAndroidChart/tree/master/MPChartExample).
[![ScreenShot](https://github.com/PhilJay/MPAndroidChart/blob/master/design/video_thumbnail.png)](https://www.youtube.com/watch?v=ufaK_Hd6BpI)
@ -95,7 +82,7 @@ Download the [MPAndroidChart Example App](https://play.google.com/store/apps/det
This repository's issue tracker is only for bugs and feature requests. The maintainers ask that you refrain from asking questions about how to use MPAndroidChart through the issue tracker.
Please read the [**documentation**](https://github.com/PhilJay/MPAndroidChart/wiki) first, then ask all your questions on [stackoverflow.com](https://stackoverflow.com/questions/tagged/mpandroidchart) for the fastest answer.
Please read the [**documentation**](https://weeklycoding.com/mpandroidchart/) first, then ask all your questions on [stackoverflow.com](https://stackoverflow.com/questions/tagged/mpandroidchart) for the fastest answer.
<br/>
@ -111,6 +98,9 @@ Please read the [**documentation**](https://github.com/PhilJay/MPAndroidChart/wi
0x04ef098bf9f91871391363e3caf791afa3adc39b
[**Lightning Network (tippin.me)**](https://tippin.me/@PhilippJahoda)
**PayPal**
- [**Donate 5 $**](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7G52RA87ED8NY): Thank's for creating this project, here's a coffee (or some beer) for you!
@ -129,7 +119,7 @@ If you like this library, please tell others about it :two_hearts: :two_hearts:
[![Share on Google+](https://github.com/PhilJay/MPAndroidChart/blob/master/design/googleplus_icon.png)](https://plus.google.com/share?url=https://github.com/PhilJay/MPAndroidChart)
[![Share on Facebook](https://github.com/PhilJay/MPAndroidChart/blob/master/design/facebook_icon.png)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/PhilJay/MPAndroidChart)
You can follow me on Twitter [**@PhilippJahoda**](https://twitter.com/PhilippJahoda) or sign up for my [**daily coding newsletter**](https://philjay.substack.com/subscribe).
You can follow me on Twitter [**@PhilippJahoda**](https://twitter.com/PhilippJahoda) or sign up for my [**coding newsletter**](https://weeklycoding.com).
<br/>
@ -205,7 +195,7 @@ You can follow me on Twitter [**@PhilippJahoda**](https://twitter.com/PhilippJah
<h1 id="license">License :page_facing_up:</h1>
Copyright 2018 Philipp Jahoda
Copyright 2019 Philipp Jahoda
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View file

@ -2,9 +2,10 @@ buildscript {
repositories {
jcenter()
google()
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
}
}

Some files were not shown because too many files have changed in this diff Show more