1 2 package com.xxmassdeveloper.mpchartexample; 3 4 import android.Manifest; 5 import android.content.Intent; 6 import android.content.pm.PackageManager; 7 import android.graphics.Color; 8 import android.graphics.DashPathEffect; 9 import android.graphics.drawable.Drawable; 10 import android.net.Uri; 11 import android.os.Bundle; 12 import androidx.core.content.ContextCompat; 13 import android.util.Log; 14 import android.view.Menu; 15 import android.view.MenuItem; 16 import android.view.WindowManager; 17 import android.widget.SeekBar; 18 import android.widget.SeekBar.OnSeekBarChangeListener; 19 import android.widget.TextView; 20 21 import com.github.mikephil.charting.animation.Easing; 22 import com.github.mikephil.charting.charts.LineChart; 23 import com.github.mikephil.charting.components.Legend; 24 import com.github.mikephil.charting.components.Legend.LegendForm; 25 import com.github.mikephil.charting.components.LimitLine; 26 import com.github.mikephil.charting.components.LimitLine.LimitLabelPosition; 27 import com.github.mikephil.charting.components.XAxis; 28 import com.github.mikephil.charting.components.YAxis; 29 import com.github.mikephil.charting.data.Entry; 30 import com.github.mikephil.charting.data.LineData; 31 import com.github.mikephil.charting.data.LineDataSet; 32 import com.github.mikephil.charting.formatter.IFillFormatter; 33 import com.github.mikephil.charting.highlight.Highlight; 34 import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider; 35 import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; 36 import com.github.mikephil.charting.listener.OnChartValueSelectedListener; 37 import com.github.mikephil.charting.utils.Utils; 38 import com.xxmassdeveloper.mpchartexample.custom.MyMarkerView; 39 import com.xxmassdeveloper.mpchartexample.notimportant.DemoBase; 40 41 import java.util.ArrayList; 42 import java.util.List; 43 44 /** 45 * Example of a heavily customized {@link LineChart} with limit lines, custom line shapes, etc. 46 * 47 * @since 1.7.4 48 * @version 3.1.0 49 */ 50 public class LineChartActivity1 extends DemoBase implements OnSeekBarChangeListener, 51 OnChartValueSelectedListener { 52 53 private LineChart chart; 54 private SeekBar seekBarX, seekBarY; 55 private TextView tvX, tvY; 56 57 @Override onCreate(Bundle savedInstanceState)58 protected void onCreate(Bundle savedInstanceState) { 59 super.onCreate(savedInstanceState); 60 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 61 WindowManager.LayoutParams.FLAG_FULLSCREEN); 62 setContentView(R.layout.activity_linechart); 63 64 setTitle("LineChartActivity1"); 65 66 tvX = findViewById(R.id.tvXMax); 67 tvY = findViewById(R.id.tvYMax); 68 69 seekBarX = findViewById(R.id.seekBar1); 70 seekBarX.setOnSeekBarChangeListener(this); 71 72 seekBarY = findViewById(R.id.seekBar2); 73 seekBarY.setMax(180); 74 seekBarY.setOnSeekBarChangeListener(this); 75 76 77 { // // Chart Style // // 78 chart = findViewById(R.id.chart1); 79 80 // background color 81 chart.setBackgroundColor(Color.WHITE); 82 83 // disable description text 84 chart.getDescription().setEnabled(false); 85 86 // enable touch gestures 87 chart.setTouchEnabled(true); 88 89 // set listeners 90 chart.setOnChartValueSelectedListener(this); 91 chart.setDrawGridBackground(false); 92 93 // create marker to display box when values are selected 94 MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view); 95 96 // Set the marker to the chart 97 mv.setChartView(chart); 98 chart.setMarker(mv); 99 100 // enable scaling and dragging 101 chart.setDragEnabled(true); 102 chart.setScaleEnabled(true); 103 // chart.setScaleXEnabled(true); 104 // chart.setScaleYEnabled(true); 105 106 // force pinch zoom along both axis 107 chart.setPinchZoom(true); 108 } 109 110 XAxis xAxis; 111 { // // X-Axis Style // // 112 xAxis = chart.getXAxis(); 113 114 // vertical grid lines 115 xAxis.enableGridDashedLine(10f, 10f, 0f); 116 } 117 118 YAxis yAxis; 119 { // // Y-Axis Style // // 120 yAxis = chart.getAxisLeft(); 121 122 // disable dual axis (only use LEFT axis) 123 chart.getAxisRight().setEnabled(false); 124 125 // horizontal grid lines 126 yAxis.enableGridDashedLine(10f, 10f, 0f); 127 128 // axis range 129 yAxis.setAxisMaximum(200f); 130 yAxis.setAxisMinimum(-50f); 131 } 132 133 134 { // // Create Limit Lines // // 135 LimitLine llXAxis = new LimitLine(9f, "Index 10"); 136 llXAxis.setLineWidth(4f); 137 llXAxis.enableDashedLine(10f, 10f, 0f); 138 llXAxis.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM); 139 llXAxis.setTextSize(10f); 140 llXAxis.setTypeface(tfRegular); 141 142 LimitLine ll1 = new LimitLine(150f, "Upper Limit"); 143 ll1.setLineWidth(4f); 144 ll1.enableDashedLine(10f, 10f, 0f); 145 ll1.setLabelPosition(LimitLabelPosition.RIGHT_TOP); 146 ll1.setTextSize(10f); 147 ll1.setTypeface(tfRegular); 148 149 LimitLine ll2 = new LimitLine(-30f, "Lower Limit"); 150 ll2.setLineWidth(4f); 151 ll2.enableDashedLine(10f, 10f, 0f); 152 ll2.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM); 153 ll2.setTextSize(10f); 154 ll2.setTypeface(tfRegular); 155 156 // draw limit lines behind data instead of on top 157 yAxis.setDrawLimitLinesBehindData(true); 158 xAxis.setDrawLimitLinesBehindData(true); 159 160 // add limit lines 161 yAxis.addLimitLine(ll1); 162 yAxis.addLimitLine(ll2); 163 //xAxis.addLimitLine(llXAxis); 164 } 165 166 // add data 167 seekBarX.setProgress(45); 168 seekBarY.setProgress(180); 169 setData(45, 180); 170 171 // draw points over time 172 chart.animateX(1500); 173 174 // get the legend (only possible after setting data) 175 Legend l = chart.getLegend(); 176 177 // draw legend entries as lines 178 l.setForm(LegendForm.LINE); 179 } 180 setData(int count, float range)181 private void setData(int count, float range) { 182 183 ArrayList<Entry> values = new ArrayList<>(); 184 185 for (int i = 0; i < count; i++) { 186 187 float val = (float) (Math.random() * range) - 30; 188 values.add(new Entry(i, val, getResources().getDrawable(R.drawable.star))); 189 } 190 191 LineDataSet set1; 192 193 if (chart.getData() != null && 194 chart.getData().getDataSetCount() > 0) { 195 set1 = (LineDataSet) chart.getData().getDataSetByIndex(0); 196 set1.setValues(values); 197 set1.notifyDataSetChanged(); 198 chart.getData().notifyDataChanged(); 199 chart.notifyDataSetChanged(); 200 } else { 201 // create a dataset and give it a type 202 set1 = new LineDataSet(values, "DataSet 1"); 203 204 set1.setDrawIcons(false); 205 206 // draw dashed line 207 set1.enableDashedLine(10f, 5f, 0f); 208 209 // black lines and points 210 set1.setColor(Color.BLACK); 211 set1.setCircleColor(Color.BLACK); 212 213 // line thickness and point size 214 set1.setLineWidth(1f); 215 set1.setCircleRadius(3f); 216 217 // draw points as solid circles 218 set1.setDrawCircleHole(false); 219 220 // customize legend entry 221 set1.setFormLineWidth(1f); 222 set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f)); 223 set1.setFormSize(15.f); 224 225 // text size of values 226 set1.setValueTextSize(9f); 227 228 // draw selection line as dashed 229 set1.enableDashedHighlightLine(10f, 5f, 0f); 230 231 // set the filled area 232 set1.setDrawFilled(true); 233 set1.setFillFormatter(new IFillFormatter() { 234 @Override 235 public float getFillLinePosition(ILineDataSet dataSet, LineDataProvider dataProvider) { 236 return chart.getAxisLeft().getAxisMinimum(); 237 } 238 }); 239 240 // set color of filled area 241 if (Utils.getSDKInt() >= 18) { 242 // drawables only supported on api level 18 and above 243 Drawable drawable = ContextCompat.getDrawable(this, R.drawable.fade_red); 244 set1.setFillDrawable(drawable); 245 } else { 246 set1.setFillColor(Color.BLACK); 247 } 248 249 ArrayList<ILineDataSet> dataSets = new ArrayList<>(); 250 dataSets.add(set1); // add the data sets 251 252 // create a data object with the data sets 253 LineData data = new LineData(dataSets); 254 255 // set data 256 chart.setData(data); 257 } 258 } 259 260 @Override onCreateOptionsMenu(Menu menu)261 public boolean onCreateOptionsMenu(Menu menu) { 262 getMenuInflater().inflate(R.menu.line, menu); 263 return true; 264 } 265 266 @Override onOptionsItemSelected(MenuItem item)267 public boolean onOptionsItemSelected(MenuItem item) { 268 269 switch (item.getItemId()) { 270 case R.id.viewGithub: { 271 Intent i = new Intent(Intent.ACTION_VIEW); 272 i.setData(Uri.parse("https://github.com/PhilJay/MPAndroidChart/blob/master/MPChartExample/src/com/xxmassdeveloper/mpchartexample/LineChartActivity1.java")); 273 startActivity(i); 274 break; 275 } 276 case R.id.actionToggleValues: { 277 List<ILineDataSet> sets = chart.getData() 278 .getDataSets(); 279 280 for (ILineDataSet iSet : sets) { 281 282 LineDataSet set = (LineDataSet) iSet; 283 set.setDrawValues(!set.isDrawValuesEnabled()); 284 } 285 286 chart.invalidate(); 287 break; 288 } 289 case R.id.actionToggleIcons: { 290 List<ILineDataSet> sets = chart.getData() 291 .getDataSets(); 292 293 for (ILineDataSet iSet : sets) { 294 295 LineDataSet set = (LineDataSet) iSet; 296 set.setDrawIcons(!set.isDrawIconsEnabled()); 297 } 298 299 chart.invalidate(); 300 break; 301 } 302 case R.id.actionToggleHighlight: { 303 if(chart.getData() != null) { 304 chart.getData().setHighlightEnabled(!chart.getData().isHighlightEnabled()); 305 chart.invalidate(); 306 } 307 break; 308 } 309 case R.id.actionToggleFilled: { 310 311 List<ILineDataSet> sets = chart.getData() 312 .getDataSets(); 313 314 for (ILineDataSet iSet : sets) { 315 316 LineDataSet set = (LineDataSet) iSet; 317 if (set.isDrawFilledEnabled()) 318 set.setDrawFilled(false); 319 else 320 set.setDrawFilled(true); 321 } 322 chart.invalidate(); 323 break; 324 } 325 case R.id.actionToggleCircles: { 326 List<ILineDataSet> sets = chart.getData() 327 .getDataSets(); 328 329 for (ILineDataSet iSet : sets) { 330 331 LineDataSet set = (LineDataSet) iSet; 332 if (set.isDrawCirclesEnabled()) 333 set.setDrawCircles(false); 334 else 335 set.setDrawCircles(true); 336 } 337 chart.invalidate(); 338 break; 339 } 340 case R.id.actionToggleCubic: { 341 List<ILineDataSet> sets = chart.getData() 342 .getDataSets(); 343 344 for (ILineDataSet iSet : sets) { 345 346 LineDataSet set = (LineDataSet) iSet; 347 set.setMode(set.getMode() == LineDataSet.Mode.CUBIC_BEZIER 348 ? LineDataSet.Mode.LINEAR 349 : LineDataSet.Mode.CUBIC_BEZIER); 350 } 351 chart.invalidate(); 352 break; 353 } 354 case R.id.actionToggleStepped: { 355 List<ILineDataSet> sets = chart.getData() 356 .getDataSets(); 357 358 for (ILineDataSet iSet : sets) { 359 360 LineDataSet set = (LineDataSet) iSet; 361 set.setMode(set.getMode() == LineDataSet.Mode.STEPPED 362 ? LineDataSet.Mode.LINEAR 363 : LineDataSet.Mode.STEPPED); 364 } 365 chart.invalidate(); 366 break; 367 } 368 case R.id.actionToggleHorizontalCubic: { 369 List<ILineDataSet> sets = chart.getData() 370 .getDataSets(); 371 372 for (ILineDataSet iSet : sets) { 373 374 LineDataSet set = (LineDataSet) iSet; 375 set.setMode(set.getMode() == LineDataSet.Mode.HORIZONTAL_BEZIER 376 ? LineDataSet.Mode.LINEAR 377 : LineDataSet.Mode.HORIZONTAL_BEZIER); 378 } 379 chart.invalidate(); 380 break; 381 } 382 case R.id.actionTogglePinch: { 383 if (chart.isPinchZoomEnabled()) 384 chart.setPinchZoom(false); 385 else 386 chart.setPinchZoom(true); 387 388 chart.invalidate(); 389 break; 390 } 391 case R.id.actionToggleAutoScaleMinMax: { 392 chart.setAutoScaleMinMaxEnabled(!chart.isAutoScaleMinMaxEnabled()); 393 chart.notifyDataSetChanged(); 394 break; 395 } 396 case R.id.animateX: { 397 chart.animateX(2000); 398 break; 399 } 400 case R.id.animateY: { 401 chart.animateY(2000, Easing.EaseInCubic); 402 break; 403 } 404 case R.id.animateXY: { 405 chart.animateXY(2000, 2000); 406 break; 407 } 408 case R.id.actionSave: { 409 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { 410 saveToGallery(); 411 } else { 412 requestStoragePermission(chart); 413 } 414 break; 415 } 416 } 417 return true; 418 } 419 420 @Override onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)421 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 422 423 tvX.setText(String.valueOf(seekBarX.getProgress())); 424 tvY.setText(String.valueOf(seekBarY.getProgress())); 425 426 setData(seekBarX.getProgress(), seekBarY.getProgress()); 427 428 // redraw 429 chart.invalidate(); 430 } 431 432 @Override saveToGallery()433 protected void saveToGallery() { 434 saveToGallery(chart, "LineChartActivity1"); 435 } 436 437 @Override onStartTrackingTouch(SeekBar seekBar)438 public void onStartTrackingTouch(SeekBar seekBar) {} 439 440 @Override onStopTrackingTouch(SeekBar seekBar)441 public void onStopTrackingTouch(SeekBar seekBar) {} 442 443 @Override onValueSelected(Entry e, Highlight h)444 public void onValueSelected(Entry e, Highlight h) { 445 Log.i("Entry selected", e.toString()); 446 Log.i("LOW HIGH", "low: " + chart.getLowestVisibleX() + ", high: " + chart.getHighestVisibleX()); 447 Log.i("MIN MAX", "xMin: " + chart.getXChartMin() + ", xMax: " + chart.getXChartMax() + ", yMin: " + chart.getYChartMin() + ", yMax: " + chart.getYChartMax()); 448 } 449 450 @Override onNothingSelected()451 public void onNothingSelected() { 452 Log.i("Nothing selected", "Nothing selected."); 453 } 454 } 455