Merge pull request #4787 from danielgindi/feature/catching_up_to_ios
Feature/catching up to ios
This commit is contained in:
commit
f8d068d377
36 changed files with 1083 additions and 232 deletions
|
@ -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() {
|
||||
};
|
||||
}
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;*/
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1224,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.
|
||||
|
@ -1234,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.
|
||||
*
|
||||
|
|
|
@ -398,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;
|
||||
|
@ -548,6 +563,18 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
|
|||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -556,7 +583,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -568,7 +608,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,7 +631,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -591,12 +661,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1162,6 +1227,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
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -151,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
|
||||
*/
|
||||
|
@ -314,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;
|
||||
|
|
|
@ -703,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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -38,9 +38,7 @@ 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[]{};
|
||||
|
||||
public BarDataSet(List<BarEntry> yVals, String label) {
|
||||
super(yVals, label);
|
||||
|
@ -54,8 +52,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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -399,7 +399,7 @@ public abstract class ChartData<T extends IDataSet<? extends Entry>> {
|
|||
|
||||
// if a DataSet was removed
|
||||
if (removed) {
|
||||
calcMinMax();
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
return removed;
|
||||
|
@ -526,7 +526,7 @@ public abstract class ChartData<T extends IDataSet<? extends Entry>> {
|
|||
boolean removed = set.removeEntry(e);
|
||||
|
||||
if (removed) {
|
||||
calcMinMax();
|
||||
notifyDataChanged();
|
||||
}
|
||||
|
||||
return removed;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 android.support.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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.github.mikephil.charting.interfaces.datasets;
|
||||
|
||||
import android.support.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();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -323,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;
|
||||
|
@ -357,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(lastCoordinateY) ||
|
||||
!mViewPortHandler.isInBoundsBottom(firstCoordinateY))
|
||||
continue;
|
||||
|
||||
// get the color that is set for this line-segment
|
||||
|
|
|
@ -258,7 +258,7 @@ public class PieChartRenderer extends DataRenderer {
|
|||
}
|
||||
|
||||
// Don't draw if it's highlighted, unless the chart uses rounded slices
|
||||
if (mChart.needsHighlight(j) && !drawRoundedSlices) {
|
||||
if (dataSet.isHighlightEnabled() && mChart.needsHighlight(j) && !drawRoundedSlices) {
|
||||
angle += sliceAngle * phaseX;
|
||||
continue;
|
||||
}
|
||||
|
@ -468,7 +468,9 @@ public class PieChartRenderer extends DataRenderer {
|
|||
|
||||
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);
|
||||
|
@ -565,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);
|
||||
}
|
||||
|
@ -825,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;
|
||||
|
@ -857,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 :
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue