Started implementing drawable line chart that allows the user to draw into the chart
This commit is contained in:
parent
3ec5abf750
commit
f21692312d
12 changed files with 2383 additions and 2005 deletions
|
@ -29,6 +29,7 @@
|
|||
<activity android:name="PieChartActivity"></activity>
|
||||
<activity android:name="MultiLineChartActivity"></activity>
|
||||
<activity android:name="BarChartActivityMultiDataset"></activity>
|
||||
<activity android:name="DrawChartActivity"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -10,62 +10,69 @@
|
|||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" >
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/button1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="LineChart" />
|
||||
<Button
|
||||
android:id="@+id/button1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="LineChart" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="BarChart" />
|
||||
<Button
|
||||
android:id="@+id/button3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="PieChart" />
|
||||
<Button
|
||||
android:id="@+id/button2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="BarChart" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="LineChart (more datasets)" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="BarChart (more datasets)" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button6"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="MultipleCharts" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button7"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="View on GitHub" />
|
||||
<Button
|
||||
android:id="@+id/button3"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="PieChart" />
|
||||
|
||||
</LinearLayout>
|
||||
<Button
|
||||
android:id="@+id/button4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="LineChart (more datasets)" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button5"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="BarChart (more datasets)" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button6"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="MultipleCharts" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button7"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="Draw Chart" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button8"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="4dp"
|
||||
android:text="View on GitHub" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
</RelativeLayout>
|
|
@ -0,0 +1,180 @@
|
|||
package com.example.mpchartexample;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.mikephil.charting.ChartData;
|
||||
import com.github.mikephil.charting.ColorTemplate;
|
||||
import com.github.mikephil.charting.DataSet;
|
||||
import com.github.mikephil.charting.Entry;
|
||||
import com.github.mikephil.charting.Highlight;
|
||||
import com.github.mikephil.charting.LineChart;
|
||||
import com.github.mikephil.charting.OnChartValueSelectedListener;
|
||||
|
||||
public class DrawChartActivity extends Activity implements OnChartValueSelectedListener {
|
||||
|
||||
private LineChart mChart;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
setContentView(R.layout.activity_linechart);
|
||||
|
||||
// create a color template for one dataset with only one color
|
||||
ColorTemplate ct = new ColorTemplate();
|
||||
ct.addColorsForDataSets(new int[] { R.color.colorful_1 }, this);
|
||||
|
||||
mChart = (LineChart) findViewById(R.id.chart1);
|
||||
mChart.setOnChartValueSelectedListener(this);
|
||||
mChart.setColorTemplate(ct);
|
||||
mChart.setDrawingEnabled(true);
|
||||
|
||||
// mChart.setDrawFilled(true);
|
||||
// mChart.setRoundedYLegend(false);
|
||||
// mChart.setStartAtZero(true);
|
||||
mChart.setDrawYValues(false);
|
||||
mChart.setLineWidth(5f);
|
||||
mChart.setCircleSize(5f);
|
||||
// mChart.setSpacePercent(20, 10);
|
||||
mChart.setYLegendCount(6);
|
||||
mChart.setTouchEnabled(true);
|
||||
mChart.setHighlightEnabled(true);
|
||||
|
||||
// highlight index 2 and 6 in dataset 0
|
||||
// mChart.highlightValues(new Highlight[] {new Highlight(2, 0), new
|
||||
// Highlight(6, 0)});
|
||||
mChart.setDragEnabled(true);
|
||||
mChart.setTouchEnabled(true);
|
||||
|
||||
TextView textView = new TextView(this);
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setBackgroundColor(Color.WHITE);
|
||||
textView.setPadding(15, 15, 15, 15);
|
||||
textView.setText("Marker View");
|
||||
|
||||
mChart.setDrawMarkerView(true);
|
||||
mChart.setMarkerView(textView);
|
||||
|
||||
initWithDummyData();
|
||||
}
|
||||
|
||||
private void initWithDummyData() {
|
||||
ArrayList<String> xVals = new ArrayList<String>();
|
||||
for (int i = 0; i < 25; i++) {
|
||||
xVals.add((i) + ":00");
|
||||
}
|
||||
|
||||
ArrayList<Entry> yVals = new ArrayList<Entry>();
|
||||
|
||||
// create a dataset and give it a type (0)
|
||||
DataSet set1 = new DataSet(yVals, 0);
|
||||
|
||||
ArrayList<DataSet> dataSets = new ArrayList<DataSet>();
|
||||
dataSets.add(set1); // add the datasets
|
||||
|
||||
// create a data object with the datasets
|
||||
ChartData data = new ChartData(xVals, dataSets);
|
||||
|
||||
mChart.setData(data);
|
||||
mChart.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.line, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.actionToggleRound: {
|
||||
if (mChart.isYLegendRounded())
|
||||
mChart.setRoundedYLegend(false);
|
||||
else
|
||||
mChart.setRoundedYLegend(true);
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleValues: {
|
||||
if (mChart.isDrawYValuesEnabled())
|
||||
mChart.setDrawYValues(false);
|
||||
else
|
||||
mChart.setDrawYValues(true);
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleHighlight: {
|
||||
if (mChart.isHighlightEnabled())
|
||||
mChart.setHighlightEnabled(false);
|
||||
else
|
||||
mChart.setHighlightEnabled(true);
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleFilled: {
|
||||
if (mChart.isDrawFilledEnabled())
|
||||
mChart.setDrawFilled(false);
|
||||
else
|
||||
mChart.setDrawFilled(true);
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleCircles: {
|
||||
if (mChart.isDrawCirclesEnabled())
|
||||
mChart.setDrawCircles(false);
|
||||
else
|
||||
mChart.setDrawCircles(true);
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleStartzero: {
|
||||
if (mChart.isStartAtZeroEnabled())
|
||||
mChart.setStartAtZero(false);
|
||||
else
|
||||
mChart.setStartAtZero(true);
|
||||
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionToggleAdjustXLegend: {
|
||||
if (mChart.isAdjustXLegendEnabled())
|
||||
mChart.setAdjustXLegend(false);
|
||||
else
|
||||
mChart.setAdjustXLegend(true);
|
||||
|
||||
mChart.invalidate();
|
||||
break;
|
||||
}
|
||||
case R.id.actionSave: {
|
||||
// mChart.saveToGallery("title"+System.currentTimeMillis());
|
||||
mChart.saveToPath("title" + System.currentTimeMillis(), "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValuesSelected(Entry[] values, Highlight[] highlights) {
|
||||
Log.i("VALS SELECTED", "Value: " + values[0].getVal() + ", xIndex: " + highlights[0].getXIndex()
|
||||
+ ", DataSet index: " + highlights[0].getDataSetIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package com.example.mpchartexample;
|
||||
|
||||
import android.app.Activity;
|
||||
|
@ -11,64 +10,69 @@ import android.view.WindowManager;
|
|||
import android.widget.Button;
|
||||
|
||||
public class MainActivity extends Activity implements OnClickListener {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Button btn1 = (Button) findViewById(R.id.button1);
|
||||
Button btn2 = (Button) findViewById(R.id.button2);
|
||||
Button btn3 = (Button) findViewById(R.id.button3);
|
||||
Button btn4 = (Button) findViewById(R.id.button4);
|
||||
Button btn5 = (Button) findViewById(R.id.button5);
|
||||
Button btn6 = (Button) findViewById(R.id.button6);
|
||||
Button btn7 = (Button) findViewById(R.id.button7);
|
||||
btn1.setOnClickListener(this);
|
||||
btn2.setOnClickListener(this);
|
||||
btn3.setOnClickListener(this);
|
||||
btn4.setOnClickListener(this);
|
||||
btn5.setOnClickListener(this);
|
||||
btn6.setOnClickListener(this);
|
||||
btn7.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
Intent i;
|
||||
|
||||
switch(v.getId()) {
|
||||
case R.id.button1:
|
||||
i = new Intent(this, LineChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button2:
|
||||
i = new Intent(this, BarChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button3:
|
||||
i = new Intent(this, PieChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button4:
|
||||
i = new Intent(this, MultiLineChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button5:
|
||||
i = new Intent(this, BarChartActivityMultiDataset.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button6:
|
||||
i = new Intent(this, MultipleChartsActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button7:
|
||||
i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/PhilJay/MPAndroidChart"));
|
||||
startActivity(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Button btn1 = (Button) findViewById(R.id.button1);
|
||||
Button btn2 = (Button) findViewById(R.id.button2);
|
||||
Button btn3 = (Button) findViewById(R.id.button3);
|
||||
Button btn4 = (Button) findViewById(R.id.button4);
|
||||
Button btn5 = (Button) findViewById(R.id.button5);
|
||||
Button btn6 = (Button) findViewById(R.id.button6);
|
||||
Button btn7 = (Button) findViewById(R.id.button7);
|
||||
Button btn8 = (Button) findViewById(R.id.button8);
|
||||
btn1.setOnClickListener(this);
|
||||
btn2.setOnClickListener(this);
|
||||
btn3.setOnClickListener(this);
|
||||
btn4.setOnClickListener(this);
|
||||
btn5.setOnClickListener(this);
|
||||
btn6.setOnClickListener(this);
|
||||
btn7.setOnClickListener(this);
|
||||
btn8.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
Intent i;
|
||||
|
||||
switch (v.getId()) {
|
||||
case R.id.button1:
|
||||
i = new Intent(this, LineChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button2:
|
||||
i = new Intent(this, BarChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button3:
|
||||
i = new Intent(this, PieChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button4:
|
||||
i = new Intent(this, MultiLineChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button5:
|
||||
i = new Intent(this, BarChartActivityMultiDataset.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button6:
|
||||
i = new Intent(this, MultipleChartsActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button7:
|
||||
i = new Intent(this, DrawChartActivity.class);
|
||||
startActivity(i);
|
||||
break;
|
||||
case R.id.button8:
|
||||
i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/PhilJay/MPAndroidChart"));
|
||||
startActivity(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,3 @@
|
|||
|
||||
package com.github.mikephil.charting;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
|
@ -14,261 +13,307 @@ import android.widget.ImageView;
|
|||
|
||||
public class BarLineChartTouchListener extends SimpleOnGestureListener implements OnTouchListener {
|
||||
|
||||
private static final float MAX_SCALE = Float.MAX_VALUE; // 10f;
|
||||
private static final float MIN_SCALE = 0.5f;
|
||||
private static final float MAX_SCALE = Float.MAX_VALUE; // 10f;
|
||||
private static final float MIN_SCALE = 0.5f;
|
||||
|
||||
Matrix matrix = new Matrix();
|
||||
Matrix savedMatrix = new Matrix();
|
||||
Matrix matrix = new Matrix();
|
||||
Matrix savedMatrix = new Matrix();
|
||||
|
||||
PointF start = new PointF();
|
||||
PointF mid = new PointF();
|
||||
PointF start = new PointF();
|
||||
PointF mid = new PointF();
|
||||
|
||||
// We can be in one of these 3 states
|
||||
private static final int NONE = 0;
|
||||
private static final int DRAG = 1;
|
||||
private static final int ZOOM = 2;
|
||||
private static final int POSTZOOM = 3;
|
||||
private static final int LONGPRESS = 4;
|
||||
// We can be in one of these 3 states
|
||||
private static final int NONE = 0;
|
||||
private static final int DRAG = 1;
|
||||
private static final int ZOOM = 2;
|
||||
private static final int POSTZOOM = 3;
|
||||
private static final int LONGPRESS = 4;
|
||||
private static final int DRAWING = 5;
|
||||
|
||||
private int mode = NONE;
|
||||
private float oldDist = 1f;
|
||||
private BarLineChartBase mChart;
|
||||
|
||||
private GestureDetector mGestureDetector;
|
||||
/** if ture, user can draw on the chart */
|
||||
private boolean mDrawingEnabled = false;
|
||||
|
||||
public BarLineChartTouchListener(BarLineChartBase chart, Matrix start) {
|
||||
this.mChart = chart;
|
||||
this.matrix = start;
|
||||
|
||||
mGestureDetector = new GestureDetector(chart.getContext(), this);
|
||||
}
|
||||
private int mode = NONE;
|
||||
private float oldDist = 1f;
|
||||
private BarLineChartBase mChart;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
|
||||
if(mode == NONE) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
if(!mChart.isDragEnabled()) return true;
|
||||
private GestureDetector mGestureDetector;
|
||||
|
||||
// Handle touch events here...
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
savedMatrix.set(matrix);
|
||||
start.set(event.getX(), event.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
oldDist = spacing(event);
|
||||
Log.d("TouchListener", "oldDist=" + oldDist);
|
||||
if (oldDist > 10f) {
|
||||
savedMatrix.set(matrix);
|
||||
midPoint(mid, event);
|
||||
mode = ZOOM;
|
||||
mChart.disableScroll();
|
||||
Log.d("TouchListener","mode=ZOOM");
|
||||
}
|
||||
break;
|
||||
public BarLineChartTouchListener(BarLineChartBase chart, Matrix start) {
|
||||
this.mChart = chart;
|
||||
this.matrix = start;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mode == NONE) {
|
||||
}
|
||||
Log.d("TouchListener","mode=NONE");
|
||||
mode = NONE;
|
||||
mChart.enableScroll();
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
Log.d("TouchListener","mode=POSTZOOM");
|
||||
mode = POSTZOOM;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mode == NONE && distance(event.getX(), start.x, event.getY(), start.y) > 25f) {
|
||||
savedMatrix.set(matrix);
|
||||
start.set(event.getX(), event.getY());
|
||||
Log.d("TouchListener","mode=DRAG");
|
||||
mode = DRAG;
|
||||
mChart.disableScroll();
|
||||
} else if (mode == DRAG) {
|
||||
matrix.set(savedMatrix);
|
||||
matrix.postTranslate(event.getX() - start.x, 0);
|
||||
} else if (mode == ZOOM) {
|
||||
float newDist = spacing(event);
|
||||
Log.d("TouchListener","newDist=" + newDist);
|
||||
if (newDist > 10f) {
|
||||
float scale = newDist / oldDist;
|
||||
float[] values = new float[9];
|
||||
matrix.getValues(values);
|
||||
float oldScale = values[0];
|
||||
if ((scale < 1 || oldScale < mChart.getMaxScale())
|
||||
&& (scale > 1 || oldScale > MIN_SCALE)) {
|
||||
matrix.set(savedMatrix);
|
||||
matrix.postScale(scale, 1, mid.x, mid.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (mode == LONGPRESS) {
|
||||
mChart.disableScroll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
mGestureDetector = new GestureDetector(chart.getContext(), this);
|
||||
}
|
||||
|
||||
// Perform the transformation
|
||||
matrix = mChart.refreshTouch(matrix);
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
|
||||
return true; // indicate event was handled
|
||||
}
|
||||
if (mode == NONE) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private PointF calcImagePosition(PointF klick) {
|
||||
PointF point = new PointF();
|
||||
Matrix inverse = new Matrix();
|
||||
matrix.invert(inverse);
|
||||
float[] pts = new float[2];
|
||||
float[] values = new float[9];
|
||||
pts[0] = klick.x;
|
||||
pts[1] = klick.y;
|
||||
inverse.mapPoints(pts);
|
||||
matrix.getValues(values);
|
||||
Log.d("TouchListener","Pts 0: " + pts[0] + ", Pts 1: " + pts[1]);
|
||||
point.x = (klick.x - values[Matrix.MTRANS_X]) / values[Matrix.MSCALE_X];
|
||||
point.y = (klick.y - values[Matrix.MTRANS_Y]) / values[Matrix.MSCALE_Y];
|
||||
Log.d("TouchListener","Pts X: " + point.x + ", Pts 1: " + point.y);
|
||||
return point;
|
||||
}
|
||||
if (mDrawingEnabled) {
|
||||
if (mChart instanceof LineChart) {
|
||||
ChartData data = mChart.getData();
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mode == NONE) {
|
||||
mode = DRAWING;
|
||||
data.createNewDrawingDataSet(1);
|
||||
Log.i("Drawing", "New drawing data set created");
|
||||
}
|
||||
break;
|
||||
|
||||
public void resetMatrix(ImageView view) {
|
||||
matrix.reset();
|
||||
view.setImageMatrix(matrix);
|
||||
}
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mode == DRAWING) {
|
||||
int xIndex = ((LineChart) mChart).getXIndexByTouchPoint(event.getX(), event.getY());
|
||||
// TODO feed the right y value
|
||||
Entry entry = new Entry(event.getY(), xIndex);
|
||||
boolean added = data.addNewDrawingEntry(entry);
|
||||
if (added) {
|
||||
Log.i("Drawing", "Added entry " + entry.toString());
|
||||
// TODO it is bad to call prepare all the time
|
||||
mChart.prepare();
|
||||
mChart.invalidate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mode == DRAWING) {
|
||||
data.finishNewDrawingEntry();
|
||||
mode = NONE;
|
||||
mChart.prepare();
|
||||
mChart.invalidate();
|
||||
Log.i("Drawing", "Drawing finished");
|
||||
}
|
||||
break;
|
||||
|
||||
private void limitScale() {
|
||||
// float[] values = new float[9];
|
||||
// matrix.getValues(values);
|
||||
// float sX = values[Matrix.MSCALE_X];
|
||||
//
|
||||
// float minScale = Math.max(minScale(), sX);
|
||||
// values[Matrix.MSCALE_X] = minScale;
|
||||
// values[Matrix.MSCALE_Y] = minScale;
|
||||
// matrix.setValues(values);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// currently no dragging when drawing
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
// public void moveTo(float x, float y) {
|
||||
// matrix.postTranslate(x, y);
|
||||
// limitPan();
|
||||
// view.setImageMatrix(matrix);
|
||||
// view.invalidate();
|
||||
// }
|
||||
//
|
||||
// private float minScale() {
|
||||
// return Math.max(view.getWidth() / PlanModel.imageWidth, view.getHeight()
|
||||
// / PlanModel.imageHeight);
|
||||
// }
|
||||
if (!mChart.isDragEnabled())
|
||||
return true;
|
||||
|
||||
// public void setMatrixMinScale() {
|
||||
// DisplayMetrics metrics = new DisplayMetrics();
|
||||
// ctx.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
//
|
||||
// float minScale = Math.max(metrics.widthPixels / PlanModel.imageWidth,
|
||||
// (metrics.heightPixels - (50 + 25) * metrics.density)
|
||||
// / PlanModel.imageHeight);
|
||||
// matrix.setScale(minScale, minScale);
|
||||
// view.setImageMatrix(matrix);
|
||||
// }
|
||||
// Handle touch events here...
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
savedMatrix.set(matrix);
|
||||
start.set(event.getX(), event.getY());
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
oldDist = spacing(event);
|
||||
Log.d("TouchListener", "oldDist=" + oldDist);
|
||||
if (oldDist > 10f) {
|
||||
savedMatrix.set(matrix);
|
||||
midPoint(mid, event);
|
||||
mode = ZOOM;
|
||||
mChart.disableScroll();
|
||||
Log.d("TouchListener", "mode=ZOOM");
|
||||
}
|
||||
break;
|
||||
|
||||
private static float distance(float eventX, float startX, float eventY, float startY) {
|
||||
float dx = eventX - startX;
|
||||
float dy = eventY - startY;
|
||||
return (float) Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mode == NONE) {
|
||||
}
|
||||
Log.d("TouchListener", "mode=NONE");
|
||||
mode = NONE;
|
||||
mChart.enableScroll();
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
Log.d("TouchListener", "mode=POSTZOOM");
|
||||
mode = POSTZOOM;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mode == NONE && distance(event.getX(), start.x, event.getY(), start.y) > 25f) {
|
||||
savedMatrix.set(matrix);
|
||||
start.set(event.getX(), event.getY());
|
||||
Log.d("TouchListener", "mode=DRAG");
|
||||
mode = DRAG;
|
||||
mChart.disableScroll();
|
||||
} else if (mode == DRAG) {
|
||||
matrix.set(savedMatrix);
|
||||
matrix.postTranslate(event.getX() - start.x, 0);
|
||||
} else if (mode == ZOOM) {
|
||||
float newDist = spacing(event);
|
||||
Log.d("TouchListener", "newDist=" + newDist);
|
||||
if (newDist > 10f) {
|
||||
float scale = newDist / oldDist;
|
||||
float[] values = new float[9];
|
||||
matrix.getValues(values);
|
||||
float oldScale = values[0];
|
||||
if ((scale < 1 || oldScale < mChart.getMaxScale()) && (scale > 1 || oldScale > MIN_SCALE)) {
|
||||
matrix.set(savedMatrix);
|
||||
matrix.postScale(scale, 1, mid.x, mid.y);
|
||||
}
|
||||
}
|
||||
} else if (mode == LONGPRESS) {
|
||||
mChart.disableScroll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void midPoint(PointF point, MotionEvent event) {
|
||||
float x = event.getX(0) + event.getX(1);
|
||||
float y = event.getY(0) + event.getY(1);
|
||||
point.set(x / 2, y / 2);
|
||||
}
|
||||
// Perform the transformation
|
||||
matrix = mChart.refreshTouch(matrix);
|
||||
|
||||
private static float spacing(MotionEvent event) {
|
||||
float x = event.getX(0) - event.getX(1);
|
||||
float y = event.getY(0) - event.getY(1);
|
||||
return FloatMath.sqrt(x * x + y * y);
|
||||
}
|
||||
return true; // indicate event was handled
|
||||
}
|
||||
|
||||
/** Show an event in the LogCat view, for debugging */
|
||||
private void dumpEvent(MotionEvent event) {
|
||||
String names[] = {
|
||||
"DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE",
|
||||
"POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?"
|
||||
};
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int action = event.getAction();
|
||||
int actionCode = action & MotionEvent.ACTION_MASK;
|
||||
sb.append("event ACTION_").append(names[actionCode]);
|
||||
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|
||||
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||
sb.append("(pid ").append(
|
||||
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append("[");
|
||||
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||
sb.append("#").append(i);
|
||||
sb.append("(pid ").append(event.getPointerId(i));
|
||||
sb.append(")=").append((int) event.getX(i));
|
||||
sb.append(",").append((int) event.getY(i));
|
||||
if (i + 1 < event.getPointerCount())
|
||||
sb.append(";");
|
||||
}
|
||||
sb.append(", dist: " + distance(event.getX(), start.x, event.getY(), start.y) + "]");
|
||||
Log.d("TouchListener",sb.toString());
|
||||
}
|
||||
public void setDrawingEnabled(boolean mDrawingEnabled) {
|
||||
this.mDrawingEnabled = mDrawingEnabled;
|
||||
}
|
||||
|
||||
public Matrix getMatrix() {
|
||||
return matrix;
|
||||
}
|
||||
private PointF calcImagePosition(PointF klick) {
|
||||
PointF point = new PointF();
|
||||
Matrix inverse = new Matrix();
|
||||
matrix.invert(inverse);
|
||||
float[] pts = new float[2];
|
||||
float[] values = new float[9];
|
||||
pts[0] = klick.x;
|
||||
pts[1] = klick.y;
|
||||
inverse.mapPoints(pts);
|
||||
matrix.getValues(values);
|
||||
Log.d("TouchListener", "Pts 0: " + pts[0] + ", Pts 1: " + pts[1]);
|
||||
point.x = (klick.x - values[Matrix.MTRANS_X]) / values[Matrix.MSCALE_X];
|
||||
point.y = (klick.y - values[Matrix.MTRANS_Y]) / values[Matrix.MSCALE_Y];
|
||||
Log.d("TouchListener", "Pts X: " + point.x + ", Pts 1: " + point.y);
|
||||
return point;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean onDoubleTap(MotionEvent e) {
|
||||
//
|
||||
// float[] values = new float[9];
|
||||
// matrix.getValues(values);
|
||||
// float sX = values[Matrix.MSCALE_X];
|
||||
// float minScale = minScale();
|
||||
//
|
||||
// if (sX > minScale * 1.5f) {
|
||||
// matrix.postScale(0.5f, 0.5f, e.getX(), e.getY());
|
||||
// } else {
|
||||
// matrix.postScale(2, 2, e.getX(), e.getY());
|
||||
// }
|
||||
// limitScale();
|
||||
// limitPan();
|
||||
// ctx.update();
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
public void resetMatrix(ImageView view) {
|
||||
matrix.reset();
|
||||
view.setImageMatrix(matrix);
|
||||
}
|
||||
|
||||
Highlight h = mChart.getIndexByTouchPoint(e.getX(), e.getY());
|
||||
|
||||
mChart.highlightValues(new Highlight[] { h });
|
||||
private void limitScale() {
|
||||
// float[] values = new float[9];
|
||||
// matrix.getValues(values);
|
||||
// float sX = values[Matrix.MSCALE_X];
|
||||
//
|
||||
// float minScale = Math.max(minScale(), sX);
|
||||
// values[Matrix.MSCALE_X] = minScale;
|
||||
// values[Matrix.MSCALE_Y] = minScale;
|
||||
// matrix.setValues(values);
|
||||
}
|
||||
|
||||
return super.onSingleTapConfirmed(e);
|
||||
}
|
||||
|
||||
|
||||
// public void moveTo(float x, float y) {
|
||||
// matrix.postTranslate(x, y);
|
||||
// limitPan();
|
||||
// view.setImageMatrix(matrix);
|
||||
// view.invalidate();
|
||||
// }
|
||||
//
|
||||
// private float minScale() {
|
||||
// return Math.max(view.getWidth() / PlanModel.imageWidth, view.getHeight()
|
||||
// / PlanModel.imageHeight);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent arg0) {
|
||||
if (mode == NONE) {
|
||||
mode = LONGPRESS;
|
||||
// ctx.showValue(arg0, matrix);
|
||||
}
|
||||
};
|
||||
// public void setMatrixMinScale() {
|
||||
// DisplayMetrics metrics = new DisplayMetrics();
|
||||
// ctx.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||
//
|
||||
// float minScale = Math.max(metrics.widthPixels / PlanModel.imageWidth,
|
||||
// (metrics.heightPixels - (50 + 25) * metrics.density)
|
||||
// / PlanModel.imageHeight);
|
||||
// matrix.setScale(minScale, minScale);
|
||||
// view.setImageMatrix(matrix);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
// ctx.showValue(e, matrix);
|
||||
return true;
|
||||
}
|
||||
private static float distance(float eventX, float startX, float eventY, float startY) {
|
||||
float dx = eventX - startX;
|
||||
float dy = eventY - startY;
|
||||
return (float) Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
private static void midPoint(PointF point, MotionEvent event) {
|
||||
float x = event.getX(0) + event.getX(1);
|
||||
float y = event.getY(0) + event.getY(1);
|
||||
point.set(x / 2, y / 2);
|
||||
}
|
||||
|
||||
private static float spacing(MotionEvent event) {
|
||||
float x = event.getX(0) - event.getX(1);
|
||||
float y = event.getY(0) - event.getY(1);
|
||||
return FloatMath.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
/** Show an event in the LogCat view, for debugging */
|
||||
private void dumpEvent(MotionEvent event) {
|
||||
String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int action = event.getAction();
|
||||
int actionCode = action & MotionEvent.ACTION_MASK;
|
||||
sb.append("event ACTION_").append(names[actionCode]);
|
||||
if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||
sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
|
||||
sb.append(")");
|
||||
}
|
||||
sb.append("[");
|
||||
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||
sb.append("#").append(i);
|
||||
sb.append("(pid ").append(event.getPointerId(i));
|
||||
sb.append(")=").append((int) event.getX(i));
|
||||
sb.append(",").append((int) event.getY(i));
|
||||
if (i + 1 < event.getPointerCount())
|
||||
sb.append(";");
|
||||
}
|
||||
sb.append(", dist: " + distance(event.getX(), start.x, event.getY(), start.y) + "]");
|
||||
Log.d("TouchListener", sb.toString());
|
||||
}
|
||||
|
||||
public Matrix getMatrix() {
|
||||
return matrix;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean onDoubleTap(MotionEvent e) {
|
||||
//
|
||||
// float[] values = new float[9];
|
||||
// matrix.getValues(values);
|
||||
// float sX = values[Matrix.MSCALE_X];
|
||||
// float minScale = minScale();
|
||||
//
|
||||
// if (sX > minScale * 1.5f) {
|
||||
// matrix.postScale(0.5f, 0.5f, e.getX(), e.getY());
|
||||
// } else {
|
||||
// matrix.postScale(2, 2, e.getX(), e.getY());
|
||||
// }
|
||||
// limitScale();
|
||||
// limitPan();
|
||||
// ctx.update();
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
|
||||
Highlight h = mChart.getHighlightByTouchPoint(e.getX(), e.getY());
|
||||
|
||||
mChart.highlightValues(new Highlight[] { h });
|
||||
|
||||
return super.onSingleTapConfirmed(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent arg0) {
|
||||
if (mode == NONE) {
|
||||
mode = LONGPRESS;
|
||||
// ctx.showValue(arg0, matrix);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
// ctx.showValue(e, matrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
|
||||
package com.github.mikephil.charting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.github.mikephil.charting.exception.DrawingDataSetNotCreatedException;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Class that holds all relevant data that represents the chart
|
||||
*
|
||||
|
@ -10,215 +13,312 @@ import java.util.ArrayList;
|
|||
*/
|
||||
public class ChartData {
|
||||
|
||||
/** maximum y-value in the y-value array */
|
||||
private float mYMax = 0.0f;
|
||||
/** maximum y-value in the y-value array */
|
||||
private float mYMax = 0.0f;
|
||||
|
||||
/** the minimum y-value in the y-value array */
|
||||
private float mYMin = 0.0f;
|
||||
/** the minimum y-value in the y-value array */
|
||||
private float mYMin = 0.0f;
|
||||
|
||||
/** the total sum of all y-values */
|
||||
private float mYValueSum = 0f;
|
||||
/** the total sum of all y-values */
|
||||
private float mYValueSum = 0f;
|
||||
|
||||
/** holds all x-values the chart represents */
|
||||
private ArrayList<String> mXVals;
|
||||
/** holds all x-values the chart represents */
|
||||
private ArrayList<String> mXVals;
|
||||
|
||||
/** holds all the datasets (e.g. different lines) the chart represents */
|
||||
private ArrayList<DataSet> mDataSets;
|
||||
/** holds all the datasets (e.g. different lines) the chart represents */
|
||||
private ArrayList<DataSet> mDataSets;
|
||||
|
||||
/** array that holds all the different type ids that are in the series array */
|
||||
private ArrayList<Integer> mDiffTypes;
|
||||
/** holds a DataSet that can be manipulated on the go, to allow users to draw into the chart */
|
||||
private DataSet mCurrentDrawingDataSet;
|
||||
|
||||
/**
|
||||
* constructor for chart data
|
||||
*
|
||||
* @param xVals must be at least as long as the highest xIndex in the Series
|
||||
* objects across all DataSets
|
||||
* @param dataSets all DataSet objects the chart needs to represent
|
||||
*/
|
||||
public ChartData(ArrayList<String> xVals, ArrayList<DataSet> dataSets) {
|
||||
this.mXVals = xVals;
|
||||
this.mDataSets = dataSets;
|
||||
private ArrayList<Entry> mCurrentDrawingEntries;
|
||||
|
||||
calcTypes();
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
/** array that holds all the different type ids that are in the series array */
|
||||
private ArrayList<Integer> mDiffTypes;
|
||||
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
if (mDataSets.get(i).getYVals().size() > xVals.size()) {
|
||||
throw new IllegalArgumentException(
|
||||
"x values are smaller than the largest y series array of one type");
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* constructor for chart data
|
||||
*
|
||||
* @param xVals
|
||||
* must be at least as long as the highest xIndex in the Series objects across all DataSets
|
||||
* @param dataSets
|
||||
* all DataSet objects the chart needs to represent
|
||||
*/
|
||||
public ChartData(ArrayList<String> xVals, ArrayList<DataSet> dataSets) {
|
||||
this.mXVals = xVals;
|
||||
this.mDataSets = dataSets;
|
||||
|
||||
/**
|
||||
* calculates all different types that occur in the datasets and stores them
|
||||
* for fast access
|
||||
*/
|
||||
private void calcTypes() {
|
||||
mDiffTypes = new ArrayList<Integer>();
|
||||
calcTypes();
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
if (mDataSets.get(i).getYVals().size() > xVals.size()) {
|
||||
throw new IllegalArgumentException("x values are smaller than the largest y series array of one type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int type = mDataSets.get(i).getType();
|
||||
/**
|
||||
* Call this method to let the CartData know that the underlying data has changed
|
||||
*/
|
||||
public void notifyDataChanged() {
|
||||
calcTypes();
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
}
|
||||
|
||||
if (!alreadyCounted(mDiffTypes, type)) {
|
||||
mDiffTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* calculates all different types that occur in the datasets and stores them for fast access
|
||||
*/
|
||||
private void calcTypes() {
|
||||
mDiffTypes = new ArrayList<Integer>();
|
||||
|
||||
/**
|
||||
* calc minimum and maximum y value over all datasets
|
||||
*/
|
||||
private void calcMinMax() {
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
|
||||
mYMin = mDataSets.get(0).getYMin();
|
||||
mYMax = mDataSets.get(0).getYMax();
|
||||
int type = mDataSets.get(i).getType();
|
||||
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
if (mDataSets.get(i).getYMin() < mYMin)
|
||||
mYMin = mDataSets.get(i).getYMin();
|
||||
if (!alreadyCounted(mDiffTypes, type)) {
|
||||
mDiffTypes.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mDataSets.get(i).getYMax() > mYMax)
|
||||
mYMax = mDataSets.get(i).getYMax();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* calc minimum and maximum y value over all datasets
|
||||
*/
|
||||
private void calcMinMax() {
|
||||
|
||||
/**
|
||||
* calculates the sum of all y-values in all datasets
|
||||
*/
|
||||
private void calcYValueSum() {
|
||||
mYMin = mDataSets.get(0).getYMin();
|
||||
mYMax = mDataSets.get(0).getYMax();
|
||||
|
||||
mYValueSum = 0;
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
if (mDataSets.get(i).getYMin() < mYMin)
|
||||
mYMin = mDataSets.get(i).getYMin();
|
||||
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
mYValueSum += Math.abs(mDataSets.get(i).getYValueSum());
|
||||
}
|
||||
}
|
||||
if (mDataSets.get(i).getYMax() > mYMax)
|
||||
mYMax = mDataSets.get(i).getYMax();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean alreadyCounted(ArrayList<Integer> countedTypes, int type) {
|
||||
for (int i = 0; i < countedTypes.size(); i++) {
|
||||
if (countedTypes.get(i) == type)
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* calculates the sum of all y-values in all datasets
|
||||
*/
|
||||
private void calcYValueSum() {
|
||||
|
||||
return false;
|
||||
}
|
||||
mYValueSum = 0;
|
||||
|
||||
public int getDataSetCount() {
|
||||
return mDataSets.size();
|
||||
}
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
mYValueSum += Math.abs(mDataSets.get(i).getYValueSum());
|
||||
}
|
||||
}
|
||||
|
||||
public float getYMin() {
|
||||
return mYMin;
|
||||
}
|
||||
/**
|
||||
* Call this method to create a new drawing DataSet
|
||||
*
|
||||
* @param type
|
||||
* the type of the new DataSet
|
||||
*/
|
||||
public void createNewDrawingDataSet(int type) {
|
||||
if (mCurrentDrawingDataSet != null && mCurrentDrawingEntries != null) {
|
||||
// if an old one exist, finish the other one first
|
||||
finishNewDrawingEntry();
|
||||
}
|
||||
// keep type count correct
|
||||
if (!mDiffTypes.contains(type)) {
|
||||
mDiffTypes.add(type);
|
||||
}
|
||||
mCurrentDrawingEntries = new ArrayList<Entry>();
|
||||
this.mCurrentDrawingDataSet = new DataSet(mCurrentDrawingEntries, type);
|
||||
mDataSets.add(mCurrentDrawingDataSet);
|
||||
}
|
||||
|
||||
public float getYMax() {
|
||||
return mYMax;
|
||||
}
|
||||
/**
|
||||
* Add a new entry.
|
||||
*
|
||||
* @param entry
|
||||
* @return true if entry added, false if an entry on this x index already existed
|
||||
*/
|
||||
public boolean addNewDrawingEntry(Entry entry) {
|
||||
if (mCurrentDrawingDataSet != null && mCurrentDrawingEntries != null) {
|
||||
// only add if no value for this x already exist
|
||||
for (int i = 0; i < mCurrentDrawingEntries.size(); i++) {
|
||||
if (mCurrentDrawingEntries.get(i).getXIndex() == entry.getXIndex()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mCurrentDrawingEntries.add(entry);
|
||||
correctDataForNewEntry(entry);
|
||||
mCurrentDrawingDataSet.notifyDataSetChanged();
|
||||
return true;
|
||||
} else {
|
||||
// new data set has to be created first
|
||||
throw new DrawingDataSetNotCreatedException();
|
||||
}
|
||||
}
|
||||
|
||||
public float getYValueSum() {
|
||||
return mYValueSum;
|
||||
}
|
||||
/**
|
||||
* Finishes a drawing entry and adds values at the beginning and the end to fill up the line
|
||||
*/
|
||||
public void finishNewDrawingEntry() {
|
||||
Entry firstEntry = mCurrentDrawingEntries.get(0);
|
||||
int xIndex = 0;
|
||||
while (xIndex < firstEntry.getXIndex()) {
|
||||
Entry entry = new Entry(firstEntry.getVal(), xIndex);
|
||||
mCurrentDrawingEntries.add(xIndex, entry);
|
||||
correctDataForNewEntry(entry);
|
||||
xIndex++;
|
||||
}
|
||||
Entry lastEntry = mCurrentDrawingEntries.get(mCurrentDrawingEntries.size() - 1);
|
||||
xIndex = lastEntry.getXIndex();
|
||||
while (xIndex < getXValCount()) {
|
||||
Entry entry = new Entry(lastEntry.getVal(), xIndex);
|
||||
mCurrentDrawingEntries.add(entry);
|
||||
correctDataForNewEntry(entry);
|
||||
xIndex++;
|
||||
}
|
||||
mCurrentDrawingDataSet.notifyDataSetChanged();
|
||||
mCurrentDrawingDataSet = null;
|
||||
mCurrentDrawingEntries = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the ChartData object contains valid data
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid() {
|
||||
private boolean alreadyCounted(ArrayList<Integer> countedTypes, int type) {
|
||||
for (int i = 0; i < countedTypes.size(); i++) {
|
||||
if (countedTypes.get(i) == type)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mXVals == null || mXVals.size() <= 1 || mDataSets == null || mDataSets.size() < 1
|
||||
|| mDataSets.get(0).getYVals().size() <= 1)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the x-values the chart represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<String> getXVals() {
|
||||
return mXVals;
|
||||
}
|
||||
/**
|
||||
* Corrects all values that are kept as member variables after a new entry was added. This saves recalculating all
|
||||
* values.
|
||||
*
|
||||
* @param entry
|
||||
* the new entry
|
||||
*/
|
||||
private void correctDataForNewEntry(Entry entry) {
|
||||
mYValueSum += Math.abs(entry.getVal());
|
||||
if (mYMin > entry.getVal()) {
|
||||
mYMin = entry.getVal();
|
||||
}
|
||||
if (mYMax < entry.getVal()) {
|
||||
mYMax = entry.getVal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the Entries array from the DataSet at the given index
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Entry> getYVals(int index) {
|
||||
return mDataSets.get(index).getYVals();
|
||||
}
|
||||
public int getDataSetCount() {
|
||||
return mDataSets.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the dataset at the given index
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public DataSet getDataSetByIndex(int index) {
|
||||
return mDataSets.get(index);
|
||||
}
|
||||
public float getYMin() {
|
||||
return mYMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve a dataset with a specific type from the chartdata
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public DataSet getDataSetByType(int type) {
|
||||
for (int i = 0; i < mDataSets.size(); i++)
|
||||
if (type == mDataSets.get(i).getType())
|
||||
return mDataSets.get(i);
|
||||
public float getYMax() {
|
||||
return mYMax;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public float getYValueSum() {
|
||||
return mYValueSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all DataSet objects the ChartData represents.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<DataSet> getDataSets() {
|
||||
return mDataSets;
|
||||
}
|
||||
/**
|
||||
* Checks if the ChartData object contains valid data
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid() {
|
||||
|
||||
/**
|
||||
* returns all the different DataSet types the chartdata represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Integer> getTypes() {
|
||||
return mDiffTypes;
|
||||
}
|
||||
if (mXVals == null || mXVals.size() <= 1 || mDataSets == null || mDataSets.size() < 1)
|
||||
// || mDataSets.get(0).getYVals().size() <= 1)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the total number of x-values this chartdata represents (the size
|
||||
* of the xvals array)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getXValCount() {
|
||||
return mXVals.size();
|
||||
}
|
||||
/**
|
||||
* returns the x-values the chart represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<String> getXVals() {
|
||||
return mXVals;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the total number of y-values across all DataSets the chartdata
|
||||
* represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getYValCount() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
count += mDataSets.get(i).getEntryCount();
|
||||
}
|
||||
/**
|
||||
* returns the Entries array from the DataSet at the given index
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Entry> getYVals(int index) {
|
||||
return mDataSets.get(index).getYVals();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
/**
|
||||
* returns the dataset at the given index
|
||||
*
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public DataSet getDataSetByIndex(int index) {
|
||||
return mDataSets.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve a dataset with a specific type from the chartdata
|
||||
*
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public DataSet getDataSetByType(int type) {
|
||||
for (int i = 0; i < mDataSets.size(); i++)
|
||||
if (type == mDataSets.get(i).getType())
|
||||
return mDataSets.get(i);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all DataSet objects the ChartData represents.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<DataSet> getDataSets() {
|
||||
return mDataSets;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all the different DataSet types the chartdata represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Integer> getTypes() {
|
||||
return mDiffTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the total number of x-values this chartdata represents (the size of the xvals array)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getXValCount() {
|
||||
return mXVals.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the total number of y-values across all DataSets the chartdata represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getYValCount() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < mDataSets.size(); i++) {
|
||||
count += mDataSets.get(i).getEntryCount();
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,218 +1,215 @@
|
|||
|
||||
package com.github.mikephil.charting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The DataSet class represents one group or type of entries (Entry) in the
|
||||
* Chart that belong together. It is designed to logically separate different
|
||||
* groups of values inside the Chart (e.g. the values for a specific line in the
|
||||
* The DataSet class represents one group or type of entries (Entry) in the Chart that belong together. It is designed
|
||||
* to logically separate different groups of values inside the Chart (e.g. the values for a specific line in the
|
||||
* LineChart, or the values of a specific group of bars in the BarChart).
|
||||
*
|
||||
* @author Philipp Jahoda
|
||||
*/
|
||||
public class DataSet {
|
||||
|
||||
/** the entries that this dataset represents / holds together */
|
||||
private ArrayList<Entry> mYVals;
|
||||
/** the entries that this dataset represents / holds together */
|
||||
private ArrayList<Entry> mYVals;
|
||||
|
||||
/** maximum y-value in the y-value array */
|
||||
private float mYMax = 0.0f;
|
||||
/** maximum y-value in the y-value array */
|
||||
private float mYMax = 0.0f;
|
||||
|
||||
/** the minimum y-value in the y-value array */
|
||||
private float mYMin = 0.0f;
|
||||
/** the minimum y-value in the y-value array */
|
||||
private float mYMin = 0.0f;
|
||||
|
||||
/** the total sum of all y-values */
|
||||
private float mYValueSum = 0f;
|
||||
/** the total sum of all y-values */
|
||||
private float mYValueSum = 0f;
|
||||
|
||||
/** type, used for identification amongst other DataSets */
|
||||
private int mType = 0;
|
||||
/** type, used for identification amongst other DataSets */
|
||||
private int mType = 0;
|
||||
|
||||
/**
|
||||
* Creates a new DataSet object with the given values it represents and a
|
||||
* type for identification amongst other DataSet objects (the type can be
|
||||
* chosen freely and must not be equal to another type in the ChartData
|
||||
* object).
|
||||
*
|
||||
* @param yVals
|
||||
* @param type
|
||||
*/
|
||||
public DataSet(ArrayList<Entry> yVals, int type) {
|
||||
this.mType = type;
|
||||
this.mYVals = yVals;
|
||||
/**
|
||||
* Creates a new DataSet object with the given values it represents and a type for identification amongst other
|
||||
* DataSet objects (the type can be chosen freely and must not be equal to another type in the ChartData object).
|
||||
*
|
||||
* @param yVals
|
||||
* @param type
|
||||
*/
|
||||
public DataSet(ArrayList<Entry> yVals, int type) {
|
||||
this.mType = type;
|
||||
this.mYVals = yVals;
|
||||
|
||||
if (yVals == null || yVals.size() <= 0)
|
||||
return;
|
||||
if (yVals == null || yVals.size() <= 0)
|
||||
return;
|
||||
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
}
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
}
|
||||
|
||||
/**
|
||||
* calc minimum and maximum y value
|
||||
*/
|
||||
private void calcMinMax() {
|
||||
/**
|
||||
* Use this method to tell the data set that the underlying data has changed
|
||||
*/
|
||||
public void notifyDataSetChanged() {
|
||||
calcMinMax();
|
||||
calcYValueSum();
|
||||
}
|
||||
|
||||
mYMin = mYVals.get(0).getVal();
|
||||
mYMax = mYVals.get(0).getVal();
|
||||
/**
|
||||
* calc minimum and maximum y value
|
||||
*/
|
||||
private void calcMinMax() {
|
||||
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (mYVals.get(i).getVal() < mYMin)
|
||||
mYMin = mYVals.get(i).getVal();
|
||||
mYMin = mYVals.get(0).getVal();
|
||||
mYMax = mYVals.get(0).getVal();
|
||||
|
||||
if (mYVals.get(i).getVal() > mYMax)
|
||||
mYMax = mYVals.get(i).getVal();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (mYVals.get(i).getVal() < mYMin)
|
||||
mYMin = mYVals.get(i).getVal();
|
||||
|
||||
/**
|
||||
* calculates the sum of all y-values
|
||||
*/
|
||||
private void calcYValueSum() {
|
||||
if (mYVals.get(i).getVal() > mYMax)
|
||||
mYMax = mYVals.get(i).getVal();
|
||||
}
|
||||
}
|
||||
|
||||
mYValueSum = 0;
|
||||
/**
|
||||
* calculates the sum of all y-values
|
||||
*/
|
||||
private void calcYValueSum() {
|
||||
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
mYValueSum += Math.abs(mYVals.get(i).getVal());
|
||||
}
|
||||
}
|
||||
mYValueSum = 0;
|
||||
|
||||
/**
|
||||
* returns the number of y-values this DataSet represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getEntryCount() {
|
||||
return mYVals.size();
|
||||
}
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
mYValueSum += Math.abs(mYVals.get(i).getVal());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the Entry object at the given xIndex. Returns
|
||||
* Float.NaN if no value is at the given x-index. INFORMATION: This method
|
||||
* does calculations at runtime. Do not over-use in performance critical
|
||||
* situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public float getYValForXIndex(int xIndex) {
|
||||
/**
|
||||
* returns the number of y-values this DataSet represents
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getEntryCount() {
|
||||
return mYVals.size();
|
||||
}
|
||||
|
||||
Entry s = getEntryForXIndex(xIndex);
|
||||
/**
|
||||
* Returns the value of the Entry object at the given xIndex. Returns Float.NaN if no value is at the given x-index.
|
||||
* INFORMATION: This method does calculations at runtime. Do not over-use in performance critical situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public float getYValForXIndex(int xIndex) {
|
||||
|
||||
if (s != null)
|
||||
return s.getVal();
|
||||
else
|
||||
return Float.NaN;
|
||||
}
|
||||
Entry s = getEntryForXIndex(xIndex);
|
||||
|
||||
/**
|
||||
* Returns the Entry object at the given xIndex. Returns null if no Entry
|
||||
* object at that index. INFORMATION: This method does calculations at
|
||||
* runtime. Do not over-use in performance critical situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public Entry getEntryForXIndex(int xIndex) {
|
||||
if (s != null)
|
||||
return s.getVal();
|
||||
else
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (xIndex == mYVals.get(i).getXIndex())
|
||||
return mYVals.get(i);
|
||||
}
|
||||
/**
|
||||
* Returns the Entry object at the given xIndex. Returns null if no Entry object at that index. INFORMATION: This
|
||||
* method does calculations at runtime. Do not over-use in performance critical situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public Entry getEntryForXIndex(int xIndex) {
|
||||
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (xIndex == mYVals.get(i).getXIndex())
|
||||
return mYVals.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the DataSets Entry array
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Entry> getYVals() {
|
||||
return mYVals;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the sum of all y-values
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYValueSum() {
|
||||
return mYValueSum;
|
||||
}
|
||||
/**
|
||||
* returns the DataSets Entry array
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<Entry> getYVals() {
|
||||
return mYVals;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the minimum y-value this DataSet holds
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYMin() {
|
||||
return mYMin;
|
||||
}
|
||||
/**
|
||||
* gets the sum of all y-values
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYValueSum() {
|
||||
return mYValueSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the maximum y-value this DataSet holds
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYMax() {
|
||||
return mYMax;
|
||||
}
|
||||
/**
|
||||
* returns the minimum y-value this DataSet holds
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYMin() {
|
||||
return mYMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the type of the DataSet, specified via constructor
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
/**
|
||||
* returns the maximum y-value this DataSet holds
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getYMax() {
|
||||
return mYMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* The xIndex of an Entry object is provided. This method returns the actual
|
||||
* index in the Entry array of the DataSet. IMPORTANT: This method does
|
||||
* calculations at runtime, do not over-use in performance critical
|
||||
* situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public int getIndexInEntries(int xIndex) {
|
||||
/**
|
||||
* returns the type of the DataSet, specified via constructor
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (xIndex == mYVals.get(i).getXIndex())
|
||||
return i;
|
||||
}
|
||||
/**
|
||||
* The xIndex of an Entry object is provided. This method returns the actual index in the Entry array of the
|
||||
* DataSet. IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.
|
||||
*
|
||||
* @param xIndex
|
||||
* @return
|
||||
*/
|
||||
public int getIndexInEntries(int xIndex) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < mYVals.size(); i++) {
|
||||
if (xIndex == mYVals.get(i).getXIndex())
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to create multiple DataSets of different types with
|
||||
* various double value arrays. Each double array represents the data of one
|
||||
* DataSet with a type created by this method, starting at 0 (and
|
||||
* incremented).
|
||||
*
|
||||
* @param yValues
|
||||
* @return
|
||||
*/
|
||||
public static ArrayList<DataSet> makeDataSets(ArrayList<Double[]> yValues) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ArrayList<DataSet> dataSets = new ArrayList<DataSet>();
|
||||
/**
|
||||
* Convenience method to create multiple DataSets of different types with various double value arrays. Each double
|
||||
* array represents the data of one DataSet with a type created by this method, starting at 0 (and incremented).
|
||||
*
|
||||
* @param yValues
|
||||
* @return
|
||||
*/
|
||||
public static ArrayList<DataSet> makeDataSets(ArrayList<Double[]> yValues) {
|
||||
|
||||
for (int i = 0; i < yValues.size(); i++) {
|
||||
ArrayList<DataSet> dataSets = new ArrayList<DataSet>();
|
||||
|
||||
Double[] curValues = yValues.get(i);
|
||||
for (int i = 0; i < yValues.size(); i++) {
|
||||
|
||||
ArrayList<Entry> entries = new ArrayList<Entry>();
|
||||
Double[] curValues = yValues.get(i);
|
||||
|
||||
for (int j = 0; j < curValues.length; j++) {
|
||||
entries.add(new Entry(curValues[j].floatValue(), j));
|
||||
}
|
||||
ArrayList<Entry> entries = new ArrayList<Entry>();
|
||||
|
||||
dataSets.add(new DataSet(entries, i));
|
||||
}
|
||||
for (int j = 0; j < curValues.length; j++) {
|
||||
entries.add(new Entry(curValues[j].floatValue(), j));
|
||||
}
|
||||
|
||||
return dataSets;
|
||||
}
|
||||
dataSets.add(new DataSet(entries, i));
|
||||
}
|
||||
|
||||
return dataSets;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.github.mikephil.charting;
|
||||
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnTouchListener;
|
||||
|
||||
public class DrawLineChartTouchListener extends SimpleOnGestureListener implements OnTouchListener {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.github.mikephil.charting;
|
||||
|
||||
|
||||
public class Entry {
|
||||
|
||||
private float mVal = 0f;
|
||||
|
@ -21,66 +20,74 @@ public class Entry {
|
|||
|
||||
/**
|
||||
* returns the x-index the value of this object is mapped to
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getXIndex() {
|
||||
return mXIndex;
|
||||
}
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to create a series of double values
|
||||
// *
|
||||
// * @param yValues
|
||||
// * @return
|
||||
// */
|
||||
// public static ArrayList<Series> makeSeries(double[] yValues) {
|
||||
// ArrayList<Series> series = new ArrayList<Series>();
|
||||
// for (int i = 0; i < yValues.length; i++) {
|
||||
// series.add(new Series((float) yValues[i], 0, i));
|
||||
// }
|
||||
// return series;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to create multiple series of different types of various double value arrays. Each double array
|
||||
// * represents one type starting at 0.
|
||||
// *
|
||||
// * @param yValues
|
||||
// * @return
|
||||
// */
|
||||
// public static ArrayList<Series> makeMultipleSeries(ArrayList<Double[]> yValues) {
|
||||
// ArrayList<Series> series = new ArrayList<Series>();
|
||||
//
|
||||
// int sizeOfFirst = yValues.get(0).length;
|
||||
//
|
||||
// for (int i = 0; i < yValues.size(); i++) {
|
||||
// Double[] curValues = yValues.get(i);
|
||||
// if (curValues.length != sizeOfFirst) {
|
||||
// throw new IllegalArgumentException("Array sizes do not match");
|
||||
// }
|
||||
// for (int j = 0; j < curValues.length; j++) {
|
||||
// series.add(new Series(curValues[j].floatValue(), i, j));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return series;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to add a series. The new series has to be the same size as the old. If you want to create a
|
||||
// * different sized series, please add manually.
|
||||
// *
|
||||
// * @param series
|
||||
// * @param yValues
|
||||
// * @param type
|
||||
// */
|
||||
// public static void addSeries(ArrayList<Series> series, double[] yValues, int type) {
|
||||
// for (int i = 0; i < yValues.length; i++) {
|
||||
// series.add(new Series((float) yValues[i], type, i));
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to create a series of double values
|
||||
// *
|
||||
// * @param yValues
|
||||
// * @return
|
||||
// */
|
||||
// public static ArrayList<Series> makeSeries(double[] yValues) {
|
||||
// ArrayList<Series> series = new ArrayList<Series>();
|
||||
// for (int i = 0; i < yValues.length; i++) {
|
||||
// series.add(new Series((float) yValues[i], 0, i));
|
||||
// }
|
||||
// return series;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to create multiple series of different types of various double value arrays. Each double
|
||||
// array
|
||||
// * represents one type starting at 0.
|
||||
// *
|
||||
// * @param yValues
|
||||
// * @return
|
||||
// */
|
||||
// public static ArrayList<Series> makeMultipleSeries(ArrayList<Double[]> yValues) {
|
||||
// ArrayList<Series> series = new ArrayList<Series>();
|
||||
//
|
||||
// int sizeOfFirst = yValues.get(0).length;
|
||||
//
|
||||
// for (int i = 0; i < yValues.size(); i++) {
|
||||
// Double[] curValues = yValues.get(i);
|
||||
// if (curValues.length != sizeOfFirst) {
|
||||
// throw new IllegalArgumentException("Array sizes do not match");
|
||||
// }
|
||||
// for (int j = 0; j < curValues.length; j++) {
|
||||
// series.add(new Series(curValues[j].floatValue(), i, j));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return series;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Convenience method to add a series. The new series has to be the same size as the old. If you want to create a
|
||||
// * different sized series, please add manually.
|
||||
// *
|
||||
// * @param series
|
||||
// * @param yValues
|
||||
// * @param type
|
||||
// */
|
||||
// public static void addSeries(ArrayList<Series> series, double[] yValues, int type) {
|
||||
// for (int i = 0; i < yValues.length; i++) {
|
||||
// series.add(new Series((float) yValues[i], type, i));
|
||||
// }
|
||||
// }
|
||||
|
||||
public float getVal() {
|
||||
return mVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "xIndex: " + mXIndex + " yVal: " + mVal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,378 +1,423 @@
|
|||
|
||||
package com.github.mikephil.charting;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
public class LineChart extends BarLineChartBase {
|
||||
|
||||
/** the radius of the circle-shaped value indicators */
|
||||
protected float mCircleSize = 4f;
|
||||
/** the radius of the circle-shaped value indicators */
|
||||
protected float mCircleSize = 4f;
|
||||
|
||||
/** the width of the drawn data lines */
|
||||
protected float mLineWidth = 1f;
|
||||
/** the width of the drawn data lines */
|
||||
protected float mLineWidth = 1f;
|
||||
|
||||
/** the width of the highlighning line */
|
||||
protected float mHighlightWidth = 3f;
|
||||
/** the width of the highlighning line */
|
||||
protected float mHighlightWidth = 3f;
|
||||
|
||||
/** if true, the data will also be drawn filled */
|
||||
protected boolean mDrawFilled = false;
|
||||
/** if true, the data will also be drawn filled */
|
||||
protected boolean mDrawFilled = false;
|
||||
|
||||
/** if true, drawing circles is enabled */
|
||||
protected boolean mDrawCircles = true;
|
||||
/** if true, drawing circles is enabled */
|
||||
protected boolean mDrawCircles = true;
|
||||
|
||||
/** paint for the filled are (if enabled) below the chart line */
|
||||
protected Paint mFilledPaint;
|
||||
/** paint for the filled are (if enabled) below the chart line */
|
||||
protected Paint mFilledPaint;
|
||||
|
||||
/** paint for the inner circle of the value indicators */
|
||||
protected Paint mCirclePaintInner;
|
||||
/** paint for the inner circle of the value indicators */
|
||||
protected Paint mCirclePaintInner;
|
||||
|
||||
public LineChart(Context context) {
|
||||
super(context);
|
||||
}
|
||||
public LineChart(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public LineChart(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
public LineChart(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public LineChart(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
public LineChart(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
mCircleSize = Utils.convertDpToPixel(mCircleSize);
|
||||
mCircleSize = Utils.convertDpToPixel(mCircleSize);
|
||||
|
||||
mFilledPaint = new Paint();
|
||||
mFilledPaint.setStyle(Paint.Style.FILL);
|
||||
mFilledPaint.setColor(mColorDarkBlue);
|
||||
mFilledPaint.setAlpha(130); // alpha ~55%
|
||||
mFilledPaint = new Paint();
|
||||
mFilledPaint.setStyle(Paint.Style.FILL);
|
||||
mFilledPaint.setColor(mColorDarkBlue);
|
||||
mFilledPaint.setAlpha(130); // alpha ~55%
|
||||
|
||||
mCirclePaintInner = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mCirclePaintInner.setStyle(Paint.Style.FILL);
|
||||
mCirclePaintInner.setColor(Color.WHITE);
|
||||
mCirclePaintInner = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mCirclePaintInner.setStyle(Paint.Style.FILL);
|
||||
mCirclePaintInner.setColor(Color.WHITE);
|
||||
|
||||
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mHighlightPaint.setStyle(Paint.Style.STROKE);
|
||||
mHighlightPaint.setStrokeWidth(2f);
|
||||
mHighlightPaint.setColor(Color.rgb(255, 187, 115));
|
||||
}
|
||||
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mHighlightPaint.setStyle(Paint.Style.STROKE);
|
||||
mHighlightPaint.setStrokeWidth(2f);
|
||||
mHighlightPaint.setColor(Color.rgb(255, 187, 115));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawHighlights() {
|
||||
@Override
|
||||
protected void drawHighlights() {
|
||||
|
||||
// if there are values to highlight and highlighnting is enabled, do it
|
||||
if (mHighlightEnabled && valuesToHighlight()) {
|
||||
// if there are values to highlight and highlighnting is enabled, do it
|
||||
if (mHighlightEnabled && valuesToHighlight()) {
|
||||
|
||||
for (int i = 0; i < mIndicesToHightlight.length; i++) {
|
||||
for (int i = 0; i < mIndicesToHightlight.length; i++) {
|
||||
|
||||
DataSet set = getDataSetByIndex(mIndicesToHightlight[i].getDataSetIndex());
|
||||
DataSet set = getDataSetByIndex(mIndicesToHightlight[i].getDataSetIndex());
|
||||
|
||||
int xIndex = mIndicesToHightlight[i].getXIndex(); // get the
|
||||
// x-position
|
||||
float y = set.getYValForXIndex(xIndex); // get the y-position
|
||||
int xIndex = mIndicesToHightlight[i].getXIndex(); // get the
|
||||
// x-position
|
||||
float y = set.getYValForXIndex(xIndex); // get the y-position
|
||||
|
||||
float[] pts = new float[] {
|
||||
xIndex, mYChartMax, xIndex, mYChartMin, 0,
|
||||
y, mDeltaX, y
|
||||
};
|
||||
float[] pts = new float[] { xIndex, mYChartMax, xIndex, mYChartMin, 0, y, mDeltaX, y };
|
||||
|
||||
transformPointArray(pts);
|
||||
// draw the highlight lines
|
||||
mDrawCanvas.drawLines(pts, mHighlightPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
transformPointArray(pts);
|
||||
// draw the highlight lines
|
||||
mDrawCanvas.drawLines(pts, mHighlightPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draws the given y values to the screen
|
||||
*/
|
||||
@Override
|
||||
protected void drawData() {
|
||||
/**
|
||||
* draws the given y values to the screen
|
||||
*/
|
||||
@Override
|
||||
protected void drawData() {
|
||||
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
|
||||
float[] valuePoints = generateTransformedValues(entries, 0f);
|
||||
float[] valuePoints = generateTransformedValues(entries, 0f);
|
||||
|
||||
// Get the colors for the DataSet at the current index. If the index
|
||||
// is out of bounds, reuse DataSet colors.
|
||||
ArrayList<Integer> colors = mCt.getDataSetColors(i % mCt.getColors().size());
|
||||
// Get the colors for the DataSet at the current index. If the index
|
||||
// is out of bounds, reuse DataSet colors.
|
||||
ArrayList<Integer> colors = mCt.getDataSetColors(i % mCt.getColors().size());
|
||||
|
||||
Paint paint = mRenderPaint;
|
||||
Paint paint = mRenderPaint;
|
||||
|
||||
for (int j = 0; j < valuePoints.length - 2; j += 2) {
|
||||
for (int j = 0; j < valuePoints.length - 2; j += 2) {
|
||||
|
||||
// Set the color for the currently drawn value. If the index is
|
||||
// out of bounds, reuse colors.
|
||||
paint.setColor(colors.get(j % colors.size()));
|
||||
// Set the color for the currently drawn value. If the index is
|
||||
// out of bounds, reuse colors.
|
||||
paint.setColor(colors.get(j % colors.size()));
|
||||
|
||||
if (isOffContentRight(valuePoints[j]))
|
||||
break;
|
||||
if (isOffContentRight(valuePoints[j]))
|
||||
break;
|
||||
|
||||
// make sure the lines don't do shitty things outside bounds
|
||||
if (j != 0 && isOffContentLeft(valuePoints[j - 1]))
|
||||
continue;
|
||||
// make sure the lines don't do shitty things outside bounds
|
||||
if (j != 0 && isOffContentLeft(valuePoints[j - 1]))
|
||||
continue;
|
||||
|
||||
mDrawCanvas.drawLine(valuePoints[j], valuePoints[j + 1], valuePoints[j + 2],
|
||||
valuePoints[j + 3], paint);
|
||||
}
|
||||
mDrawCanvas.drawLine(valuePoints[j], valuePoints[j + 1], valuePoints[j + 2], valuePoints[j + 3], paint);
|
||||
}
|
||||
|
||||
// if drawing filled is enabled
|
||||
if (mDrawFilled) {
|
||||
// mDrawCanvas.drawVertices(VertexMode.TRIANGLE_STRIP,
|
||||
// valuePoints.length, valuePoints, 0,
|
||||
// null, 0, null, 0, null, 0, 0, paint);
|
||||
// if drawing filled is enabled
|
||||
if (mDrawFilled) {
|
||||
// mDrawCanvas.drawVertices(VertexMode.TRIANGLE_STRIP,
|
||||
// valuePoints.length, valuePoints, 0,
|
||||
// null, 0, null, 0, null, 0, 0, paint);
|
||||
|
||||
// filled is drawn with less alpha
|
||||
paint.setAlpha(85);
|
||||
// filled is drawn with less alpha
|
||||
paint.setAlpha(85);
|
||||
|
||||
Path filled = new Path();
|
||||
filled.moveTo(0, entries.get(0).getVal());
|
||||
Path filled = new Path();
|
||||
filled.moveTo(0, entries.get(0).getVal());
|
||||
|
||||
// create a new path
|
||||
for (int x = 1; x < entries.size(); x++) {
|
||||
// create a new path
|
||||
for (int x = 1; x < entries.size(); x++) {
|
||||
|
||||
filled.lineTo(x, entries.get(x).getVal());
|
||||
}
|
||||
filled.lineTo(x, entries.get(x).getVal());
|
||||
}
|
||||
|
||||
// close up
|
||||
filled.lineTo(entries.size() - 1, mYChartMin);
|
||||
filled.lineTo(0f, mYChartMin);
|
||||
filled.close();
|
||||
// close up
|
||||
filled.lineTo(entries.size() - 1, mYChartMin);
|
||||
filled.lineTo(0f, mYChartMin);
|
||||
filled.close();
|
||||
|
||||
transformPath(filled);
|
||||
transformPath(filled);
|
||||
|
||||
mDrawCanvas.drawPath(filled, paint);
|
||||
mDrawCanvas.drawPath(filled, paint);
|
||||
|
||||
// restore alpha
|
||||
paint.setAlpha(255);
|
||||
}
|
||||
}
|
||||
}
|
||||
// restore alpha
|
||||
paint.setAlpha(255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawValues() {
|
||||
@Override
|
||||
protected void drawValues() {
|
||||
|
||||
// if values are drawn
|
||||
if (mDrawYValues && mData.getYValCount() < mMaxVisibleCount * mScaleX) {
|
||||
// if values are drawn
|
||||
if (mDrawYValues && mData.getYValCount() < mMaxVisibleCount * mScaleX) {
|
||||
|
||||
// make sure the values do not interfear with the circles
|
||||
int valOffset = (int) (mCircleSize * 1.7f);
|
||||
// make sure the values do not interfear with the circles
|
||||
int valOffset = (int) (mCircleSize * 1.7f);
|
||||
|
||||
if (!mDrawCircles)
|
||||
valOffset = valOffset / 2;
|
||||
if (!mDrawCircles)
|
||||
valOffset = valOffset / 2;
|
||||
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
|
||||
float[] positions = generateTransformedValues(entries, 0f);
|
||||
float[] positions = generateTransformedValues(entries, 0f);
|
||||
|
||||
for (int j = 0; j < positions.length; j += 2) {
|
||||
|
||||
if (isOffContentRight(positions[j]))
|
||||
break;
|
||||
|
||||
if (isOffContentLeft(positions[j]))
|
||||
continue;
|
||||
for (int j = 0; j < positions.length; j += 2) {
|
||||
|
||||
float val = entries.get(j / 2).getVal();
|
||||
|
||||
if (mDrawUnitInChart) {
|
||||
|
||||
mDrawCanvas.drawText(mFormatValue.format(val) + mUnit,
|
||||
positions[j], positions[j + 1] - valOffset, mValuePaint);
|
||||
} else {
|
||||
|
||||
mDrawCanvas.drawText(mFormatValue.format(val), positions[j],
|
||||
positions[j + 1] - valOffset, mValuePaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draws the circle value indicators
|
||||
*/
|
||||
@Override
|
||||
protected void drawAdditional() {
|
||||
// if drawing circles is enabled
|
||||
if (mDrawCircles) {
|
||||
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
|
||||
// Get the colors for the DataSet at the current index. If the
|
||||
// index
|
||||
// is out of bounds, reuse DataSet colors.
|
||||
ArrayList<Integer> colors = mCt.getDataSetColors(i % mCt.getColors().size());
|
||||
|
||||
float[] positions = generateTransformedValues(entries, 0f);
|
||||
|
||||
for (int j = 0; j < positions.length; j += 2) {
|
||||
|
||||
// Set the color for the currently drawn value. If the index is
|
||||
// out of bounds, reuse colors.
|
||||
mRenderPaint.setColor(colors.get(j % colors.size()));
|
||||
|
||||
if (isOffContentRight(positions[j]))
|
||||
break;
|
||||
|
||||
// make sure the circles don't do shitty things outside
|
||||
// bounds
|
||||
if (isOffContentLeft(positions[j]))
|
||||
continue;
|
||||
|
||||
mDrawCanvas.drawCircle(positions[j], positions[j + 1], mCircleSize,
|
||||
mRenderPaint);
|
||||
mDrawCanvas.drawCircle(positions[j], positions[j + 1], mCircleSize / 2,
|
||||
mCirclePaintInner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set this to true to enable the drawing of circle indicators
|
||||
*
|
||||
* @param enabled
|
||||
*/
|
||||
public void setDrawCircles(boolean enabled) {
|
||||
this.mDrawCircles = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if drawing circles is enabled, false if not
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDrawCirclesEnabled() {
|
||||
return mDrawCircles;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the size (radius) of the circle shpaed value indicators, default
|
||||
* size = 4f
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
public void setCircleSize(float size) {
|
||||
mCircleSize = Utils.convertDpToPixel(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the circlesize
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
public float getCircleSize(float size) {
|
||||
return Utils.convertPixelsToDp(mCircleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* set if the chartdata should be drawn as a line or filled default = line /
|
||||
* default = false, disabling this will give up to 20% performance boost on
|
||||
* large datasets
|
||||
*
|
||||
* @param filled
|
||||
*/
|
||||
public void setDrawFilled(boolean filled) {
|
||||
mDrawFilled = filled;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if filled drawing is enabled, false if not
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDrawFilledEnabled() {
|
||||
return mDrawFilled;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the line width of the chart (min = 0.5f, max = 10f); default 1f NOTE:
|
||||
* thinner line == better performance, thicker line == worse performance
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
|
||||
if (width < 0.5f)
|
||||
width = 0.5f;
|
||||
if (width > 10.0f)
|
||||
width = 10.0f;
|
||||
mLineWidth = width;
|
||||
|
||||
mRenderPaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the width of the drawn chart line
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getLineWidth() {
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the color for the fill-paint
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setFillColor(int color) {
|
||||
mFilledPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the width of the highlightning lines, default 3f
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void setHighlightLineWidth(float width) {
|
||||
mHighlightWidth = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the width of the highlightning line, default 3f
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getHighlightLineWidth() {
|
||||
return mHighlightWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaint(Paint p, int which) {
|
||||
super.setPaint(p, which);
|
||||
|
||||
switch (which) {
|
||||
case PAINT_CIRCLES_INNER:
|
||||
mCirclePaintInner = p;
|
||||
break;
|
||||
case PAINT_HIGHLIGHT_LINE:
|
||||
mHighlightPaint = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isOffContentRight(positions[j]))
|
||||
break;
|
||||
|
||||
if (isOffContentLeft(positions[j]))
|
||||
continue;
|
||||
|
||||
float val = entries.get(j / 2).getVal();
|
||||
|
||||
if (mDrawUnitInChart) {
|
||||
|
||||
mDrawCanvas.drawText(mFormatValue.format(val) + mUnit, positions[j], positions[j + 1]
|
||||
- valOffset, mValuePaint);
|
||||
} else {
|
||||
|
||||
mDrawCanvas.drawText(mFormatValue.format(val), positions[j], positions[j + 1] - valOffset,
|
||||
mValuePaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* draws the circle value indicators
|
||||
*/
|
||||
@Override
|
||||
protected void drawAdditional() {
|
||||
// if drawing circles is enabled
|
||||
if (mDrawCircles) {
|
||||
|
||||
ArrayList<DataSet> dataSets = mData.getDataSets();
|
||||
|
||||
for (int i = 0; i < mData.getDataSetCount(); i++) {
|
||||
|
||||
DataSet dataSet = dataSets.get(i);
|
||||
ArrayList<Entry> entries = dataSet.getYVals();
|
||||
|
||||
// Get the colors for the DataSet at the current index. If the
|
||||
// index
|
||||
// is out of bounds, reuse DataSet colors.
|
||||
ArrayList<Integer> colors = mCt.getDataSetColors(i % mCt.getColors().size());
|
||||
|
||||
float[] positions = generateTransformedValues(entries, 0f);
|
||||
|
||||
for (int j = 0; j < positions.length; j += 2) {
|
||||
|
||||
// Set the color for the currently drawn value. If the index is
|
||||
// out of bounds, reuse colors.
|
||||
mRenderPaint.setColor(colors.get(j % colors.size()));
|
||||
|
||||
if (isOffContentRight(positions[j]))
|
||||
break;
|
||||
|
||||
// make sure the circles don't do shitty things outside
|
||||
// bounds
|
||||
if (isOffContentLeft(positions[j]))
|
||||
continue;
|
||||
|
||||
mDrawCanvas.drawCircle(positions[j], positions[j + 1], mCircleSize, mRenderPaint);
|
||||
mDrawCanvas.drawCircle(positions[j], positions[j + 1], mCircleSize / 2, mCirclePaintInner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the x index of the touch. If touch is out of the chart, the first or last index will be returned
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public int getXIndexByTouchPoint(float x, float y) {
|
||||
// create an array of the touch-point
|
||||
float[] pts = new float[2];
|
||||
pts[0] = x;
|
||||
pts[1] = y;
|
||||
|
||||
Matrix tmp = new Matrix();
|
||||
|
||||
// invert all matrixes to convert back to the original value
|
||||
mMatrixOffset.invert(tmp);
|
||||
tmp.mapPoints(pts);
|
||||
|
||||
mMatrixTouch.invert(tmp);
|
||||
tmp.mapPoints(pts);
|
||||
|
||||
mMatrixValueToPx.invert(tmp);
|
||||
tmp.mapPoints(pts);
|
||||
|
||||
double xTouchVal = pts[0];
|
||||
double yTouchVal = pts[1];
|
||||
double base = Math.floor(xTouchVal);
|
||||
|
||||
Log.i(LOG_TAG, "touchindex x: " + xTouchVal + ", touchindex y: " + yTouchVal);
|
||||
|
||||
// touch out of chart
|
||||
if (xTouchVal < 0)
|
||||
return 0;
|
||||
if (xTouchVal > mDeltaX) {
|
||||
return mData.getXValCount() - 1;
|
||||
}
|
||||
|
||||
return (int) base;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this to true to enable the drawing of circle indicators
|
||||
*
|
||||
* @param enabled
|
||||
*/
|
||||
public void setDrawCircles(boolean enabled) {
|
||||
this.mDrawCircles = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if drawing circles is enabled, false if not
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDrawCirclesEnabled() {
|
||||
return mDrawCircles;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the size (radius) of the circle shpaed value indicators, default size = 4f
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
public void setCircleSize(float size) {
|
||||
mCircleSize = Utils.convertDpToPixel(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the circlesize
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
public float getCircleSize(float size) {
|
||||
return Utils.convertPixelsToDp(mCircleSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* set if the chartdata should be drawn as a line or filled default = line / default = false, disabling this will
|
||||
* give up to 20% performance boost on large datasets
|
||||
*
|
||||
* @param filled
|
||||
*/
|
||||
public void setDrawFilled(boolean filled) {
|
||||
mDrawFilled = filled;
|
||||
}
|
||||
|
||||
/**
|
||||
* set if the user should be allowed to draw onto the chart
|
||||
*
|
||||
* @param drawingEnabled
|
||||
*/
|
||||
public void setDrawingEnabled(boolean drawingEnabled) {
|
||||
if (mListener instanceof BarLineChartTouchListener) {
|
||||
((BarLineChartTouchListener) mListener).setDrawingEnabled(drawingEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if filled drawing is enabled, false if not
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDrawFilledEnabled() {
|
||||
return mDrawFilled;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the line width of the chart (min = 0.5f, max = 10f); default 1f NOTE: thinner line == better performance,
|
||||
* thicker line == worse performance
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void setLineWidth(float width) {
|
||||
|
||||
if (width < 0.5f)
|
||||
width = 0.5f;
|
||||
if (width > 10.0f)
|
||||
width = 10.0f;
|
||||
mLineWidth = width;
|
||||
|
||||
mRenderPaint.setStrokeWidth(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the width of the drawn chart line
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getLineWidth() {
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the color for the fill-paint
|
||||
*
|
||||
* @param color
|
||||
*/
|
||||
public void setFillColor(int color) {
|
||||
mFilledPaint.setColor(color);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the width of the highlightning lines, default 3f
|
||||
*
|
||||
* @param width
|
||||
*/
|
||||
public void setHighlightLineWidth(float width) {
|
||||
mHighlightWidth = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the width of the highlightning line, default 3f
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public float getHighlightLineWidth() {
|
||||
return mHighlightWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaint(Paint p, int which) {
|
||||
super.setPaint(p, which);
|
||||
|
||||
switch (which) {
|
||||
case PAINT_CIRCLES_INNER:
|
||||
mCirclePaintInner = p;
|
||||
break;
|
||||
case PAINT_HIGHLIGHT_LINE:
|
||||
mHighlightPaint = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package com.github.mikephil.charting.exception;
|
||||
|
||||
public class DrawingDataSetNotCreatedException extends RuntimeException {
|
||||
|
||||
public DrawingDataSetNotCreatedException() {
|
||||
super("Have to create a new drawing set first. Call ChartData's createNewDrawingDataSet() method");
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue