diff options
author | Daniel Cohen Gindi <danielgindi@gmail.com> | 2020-01-22 16:01:42 +0200 |
---|---|---|
committer | Daniel Cohen Gindi <danielgindi@gmail.com> | 2020-01-22 16:01:42 +0200 |
commit | 45240c3723387a0980074a5b4a72e1d2166192a4 (patch) | |
tree | 0351b91e18284091cf99a3b068b4fb995f3384b4 | |
parent | 14456f475fcfab0875e3f81604c4c7d69eea5fe0 (diff) | |
download | MPAndroidChart-45240c3723387a0980074a5b4a72e1d2166192a4.tar.gz |
Improved negative offset for horz bar chart
https://github.com/danielgindi/Charts/pull/3854
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; |