aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Cohen Gindi <danielgindi@gmail.com>2020-01-22 16:01:42 +0200
committerDaniel Cohen Gindi <danielgindi@gmail.com>2020-01-22 16:01:42 +0200
commit45240c3723387a0980074a5b4a72e1d2166192a4 (patch)
tree0351b91e18284091cf99a3b068b4fb995f3384b4
parent14456f475fcfab0875e3f81604c4c7d69eea5fe0 (diff)
downloadMPAndroidChart-45240c3723387a0980074a5b4a72e1d2166192a4.tar.gz
Improved negative offset for horz bar chart
https://github.com/danielgindi/Charts/pull/3854
-rw-r--r--MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarNegativeChartActivity.java288
-rw-r--r--MPChartExample/src/main/AndroidManifest.xml1
-rw-r--r--MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/notimportant/MainActivity.java83
-rw-r--r--MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.java3
4 files changed, 335 insertions, 40 deletions
diff --git a/MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarNegativeChartActivity.java b/MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarNegativeChartActivity.java
new file mode 100644
index 00000000..c3de5fa6
--- /dev/null
+++ b/MPChartExample/src/com/xxmassdeveloper/mpchartexample/HorizontalBarNegativeChartActivity.java
@@ -0,0 +1,288 @@
+
+package com.xxmassdeveloper.mpchartexample;
+
+import android.annotation.SuppressLint;
+import android.graphics.RectF;
+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 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 {
+
+ protected HorizontalBarChart mChart;
+ private SeekBar mSeekBarX, mSeekBarY;
+ 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);
+
+ tvX = findViewById(R.id.tvXMax);
+ tvY = (TextView) findViewById(R.id.tvYMax);
+
+ mSeekBarX = (SeekBar) findViewById(R.id.seekBar1);
+ mSeekBarY = (SeekBar) findViewById(R.id.seekBar2);
+
+ mChart = (HorizontalBarChart) findViewById(R.id.chart1);
+ mChart.setOnChartValueSelectedListener(this);
+ // mChart.setHighlightEnabled(false);
+
+ mChart.setDrawBarShadow(false);
+
+ mChart.setDrawValueAboveBar(true);
+
+ mChart.getDescription().setEnabled(false);
+
+ // if more than 60 entries are displayed in the chart, no values will be
+ // drawn
+ mChart.setMaxVisibleValueCount(60);
+
+ // scaling can now only be done on x- and y-axis separately
+ mChart.setPinchZoom(false);
+
+ // draw shadows for each bar that show the maximum value
+ // mChart.setDrawBarShadow(true);
+
+ mChart.setDrawGridBackground(false);
+
+ XAxis xl = mChart.getXAxis();
+ xl.setPosition(XAxisPosition.BOTTOM);
+ xl.setTypeface(mTfLight);
+ xl.setDrawAxisLine(true);
+ xl.setDrawGridLines(false);
+ xl.setGranularity(10f);
+
+ YAxis yl = mChart.getAxisLeft();
+ yl.setTypeface(mTfLight);
+ yl.setDrawAxisLine(true);
+ yl.setDrawGridLines(true);
+ yl.setDrawZeroLine(true); // draw a zero line
+// yl.setInverted(true);
+
+ YAxis yr = mChart.getAxisRight();
+ yr.setTypeface(mTfLight);
+ yr.setDrawAxisLine(true);
+ yr.setDrawGridLines(false);
+// yr.setInverted(true);
+
+ setData(12, 50);
+ mChart.setFitBars(true);
+ mChart.animateY(2500);
+
+ // setting data
+ mSeekBarY.setProgress(50);
+ mSeekBarX.setProgress(12);
+
+ mSeekBarY.setOnSeekBarChangeListener(this);
+ mSeekBarX.setOnSeekBarChangeListener(this);
+
+ Legend l = mChart.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);
+ }
+
+ @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.actionToggleValues: {
+ List<IBarDataSet> sets = mChart.getData()
+ .getDataSets();
+
+ for (IBarDataSet iSet : sets) {
+
+ IBarDataSet set = (BarDataSet) iSet;
+ set.setDrawValues(!set.isDrawValuesEnabled());
+ }
+
+ mChart.invalidate();
+ break;
+ }
+ case R.id.actionToggleIcons: {
+ List<IBarDataSet> sets = mChart.getData()
+ .getDataSets();
+
+ for (IBarDataSet iSet : sets) {
+
+ IBarDataSet set = (BarDataSet) iSet;
+ set.setDrawIcons(!set.isDrawIconsEnabled());
+ }
+
+ mChart.invalidate();
+ break;
+ }
+ case R.id.actionToggleHighlight: {
+ if(mChart.getData() != null) {
+ mChart.getData().setHighlightEnabled(!mChart.getData().isHighlightEnabled());
+ mChart.invalidate();
+ }
+ break;
+ }
+ case R.id.actionTogglePinch: {
+ if (mChart.isPinchZoomEnabled())
+ mChart.setPinchZoom(false);
+ else
+ mChart.setPinchZoom(true);
+
+ mChart.invalidate();
+ break;
+ }
+ case R.id.actionToggleAutoScaleMinMax: {
+ mChart.setAutoScaleMinMaxEnabled(!mChart.isAutoScaleMinMaxEnabled());
+ mChart.notifyDataSetChanged();
+ break;
+ }
+ case R.id.actionToggleBarBorders: {
+ for (IBarDataSet set : mChart.getData().getDataSets())
+ ((BarDataSet)set).setBarBorderWidth(set.getBarBorderWidth() == 1.f ? 0.f : 1.f);
+
+ mChart.invalidate();
+ break;
+ }
+ case R.id.animateX: {
+ mChart.animateX(3000);
+ break;
+ }
+ case R.id.animateY: {
+ mChart.animateY(3000);
+ break;
+ }
+ case R.id.animateXY: {
+
+ mChart.animateXY(3000, 3000);
+ break;
+ }
+ case R.id.actionSave: {
+ if (mChart.saveToGallery("title" + System.currentTimeMillis(), 50)) {
+ Toast.makeText(getApplicationContext(), "Saving SUCCESSFUL!",
+ Toast.LENGTH_SHORT).show();
+ } else
+ Toast.makeText(getApplicationContext(), "Saving FAILED!", Toast.LENGTH_SHORT)
+ .show();
+ break;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+
+ tvX.setText("" + (mSeekBarX.getProgress() + 1));
+ tvY.setText("" + (mSeekBarY.getProgress()));
+
+ setData(mSeekBarX.getProgress() + 1, mSeekBarY.getProgress());
+ mChart.setFitBars(true);
+ mChart.invalidate();
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ private void setData(int count, float range) {
+
+ float barWidth = 9f;
+ float spaceForBar = 10f;
+ ArrayList<BarEntry> yVals1 = new ArrayList<BarEntry>();
+
+ for (int i = 0; i < count; i++) {
+ float val = (float) (Math.random() * range - range / 2);
+ yVals1.add(new BarEntry(i * spaceForBar, val,
+ getResources().getDrawable(R.drawable.star)));
+ }
+
+ BarDataSet set1;
+
+ if (mChart.getData() != null &&
+ mChart.getData().getDataSetCount() > 0) {
+ set1 = (BarDataSet)mChart.getData().getDataSetByIndex(0);
+ set1.setValues(yVals1);
+ mChart.getData().notifyDataChanged();
+ mChart.notifyDataSetChanged();
+ } else {
+ set1 = new BarDataSet(yVals1, "DataSet 1");
+
+ set1.setDrawIcons(false);
+
+ ArrayList<IBarDataSet> dataSets = new ArrayList<IBarDataSet>();
+ dataSets.add(set1);
+
+ BarData data = new BarData(dataSets);
+ data.setValueTextSize(10f);
+ data.setValueTypeface(mTfLight);
+ data.setBarWidth(barWidth);
+ mChart.setData(data);
+ }
+ }
+
+ protected RectF mOnValueSelectedRectF = new RectF();
+ @SuppressLint("NewApi")
+ @Override
+ public void onValueSelected(Entry e, Highlight h) {
+
+ if (e == null)
+ return;
+
+ RectF bounds = mOnValueSelectedRectF;
+ mChart.getBarBounds((BarEntry) e, bounds);
+
+ MPPointF position = mChart.getPosition(e, mChart.getData().getDataSetByIndex(h.getDataSetIndex())
+ .getAxisDependency());
+
+ Log.i("bounds", bounds.toString());
+ Log.i("position", position.toString());
+
+ MPPointF.recycleInstance(position);
+ }
+
+ @Override
+ public void onNothingSelected() {
+ };
+}
diff --git a/MPChartExample/src/main/AndroidManifest.xml b/MPChartExample/src/main/AndroidManifest.xml
index 28c55b89..99334e60 100644
--- a/MPChartExample/src/main/AndroidManifest.xml
+++ b/MPChartExample/src/main/AndroidManifest.xml
@@ -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" />
diff --git a/MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/notimportant/MainActivity.java b/MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/notimportant/MainActivity.java
index 67749e74..88e5dc8d 100644
--- a/MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/notimportant/MainActivity.java
+++ b/MPChartExample/src/main/java/com/xxmassdeveloper/mpchartexample/notimportant/MainActivity.java
@@ -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;*/
}
diff --git a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.java b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.java
index 7607abdd..b692a1f9 100644
--- a/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.java
+++ b/MPChartLib/src/main/java/com/github/mikephil/charting/renderer/HorizontalBarChartRenderer.java
@@ -200,7 +200,8 @@ public class HorizontalBarChartRenderer extends BarChartRenderer {
// 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;