package com.github.mikephil.charting.data; import com.github.mikephil.charting.exception.DrawingDataSetNotCreatedException; import com.github.mikephil.charting.interfaces.OnDrawListener; import java.util.ArrayList; public class DrawingContext { /** holds a DataSet that can be manipulated on the go, to allow users to draw into the chart */ private LineDataSet mCurrentDrawingDataSet; private int mLastDrawnDataSetIndex = 0; private boolean mAutoFinishDrawing = false; private ArrayList<Entry> mCurrentDrawingEntries; private Entry mMovingEntry; private OnDrawListener mListener; /** * Call this method to create a new drawing DataSet * * @param type * the type of the new DataSet */ public void createNewDrawingDataSet(ChartData<? extends DataSet<? extends Entry>> data) { if (mCurrentDrawingDataSet != null && mCurrentDrawingEntries != null) { // if an old one exist, finish the other one first finishNewDrawingEntry(data); } mCurrentDrawingEntries = new ArrayList<Entry>(); this.mCurrentDrawingDataSet = new LineDataSet(mCurrentDrawingEntries, "DS " + mLastDrawnDataSetIndex); mCurrentDrawingDataSet.setLineWidth(2.5f); mCurrentDrawingDataSet.setCircleSize(4f); ArrayList<LineDataSet> dataSets = (ArrayList<LineDataSet>) data.getDataSets(); dataSets.add((LineDataSet) mCurrentDrawingDataSet); } /** * 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, ChartData<? extends DataSet<? extends Entry>> data) { if (mCurrentDrawingDataSet != null && mCurrentDrawingEntries != null) { if (mCurrentDrawingEntries.size() > 0 && mCurrentDrawingEntries.get(mCurrentDrawingEntries.size() - 1).getXIndex() == entry.getXIndex()) { return false; } if (mCurrentDrawingEntries.size() > 0) { Entry prevEntry = mCurrentDrawingEntries.get(mCurrentDrawingEntries.size() - 1); fillData(prevEntry, entry); } // add new entry last to have correct order mCurrentDrawingEntries.add(entry); data.notifyDataForNewEntry(entry); if (mListener != null) { mListener.onEntryAdded(entry); } mCurrentDrawingDataSet.notifyDataSetChanged(); return true; } else { // new data set has to be created first throw new DrawingDataSetNotCreatedException(); } } /** * Call this method to notify the drawing context about the entry being moved * * @param data */ public void notifyEntryMoved(ChartData<? extends DataSet<? extends Entry>> data) { data.notifyDataForNewEntry(mMovingEntry); if (mListener != null) { mListener.onEntryMoved(mMovingEntry); } } private void fillData(Entry prevEntry, Entry newEntry) { int skippedIndexes = newEntry.getXIndex() - prevEntry.getXIndex(); int startIndex = prevEntry.getXIndex(); if (skippedIndexes == -1 || skippedIndexes == 1) { // no index skipped return; } skippedIndexes--; // get real number of skipped indexes if (skippedIndexes < 0) { // new entry before prev entry skippedIndexes *= -1; // make positive for (int i = 1; i < skippedIndexes; i++) { // we do not need to correct data because same as new entry Entry entry = new Entry(newEntry.getVal(), startIndex - i); mCurrentDrawingEntries.add(entry); if (mListener != null) { mListener.onEntryAdded(entry); } } } else { // new entry after prev entry for (int i = 1; i <= skippedIndexes; i++) { Entry entry = new Entry(newEntry.getVal(), startIndex + i); mCurrentDrawingEntries.add(entry); if (mListener != null) { mListener.onEntryAdded(entry); } } } } /** * Finishes a drawing entry and adds values at the beginning and the end to fill up the line */ public void finishNewDrawingEntry(ChartData<? extends DataSet<? extends Entry>> data) { if (mAutoFinishDrawing && mCurrentDrawingEntries.size() > 0) { Entry firstEntry = mCurrentDrawingEntries.get(0); int xIndex = 0; while (xIndex < firstEntry.getXIndex()) { Entry entry = new Entry(firstEntry.getVal(), xIndex); mCurrentDrawingEntries.add(xIndex, entry); data.notifyDataForNewEntry(entry); xIndex++; } Entry lastEntry = mCurrentDrawingEntries.get(mCurrentDrawingEntries.size() - 1); xIndex = lastEntry.getXIndex(); while (xIndex < data.getXValCount()) { Entry entry = new Entry(lastEntry.getVal(), xIndex); mCurrentDrawingEntries.add(entry); data.notifyDataForNewEntry(entry); xIndex++; } } else if (mCurrentDrawingEntries.size() == 0) { // do not save a dataset with no entries deleteLastDrawingEntry(data); return; } mLastDrawnDataSetIndex++; mCurrentDrawingDataSet.notifyDataSetChanged(); if (mListener != null) { mListener.onDrawFinished(mCurrentDrawingDataSet); } mCurrentDrawingDataSet = null; mCurrentDrawingEntries = null; } public void deleteLastDrawingEntry(ChartData<? extends DataSet<? extends Entry>> data) { if(data == null) return; data.getDataSets().remove(mCurrentDrawingDataSet); mCurrentDrawingDataSet = null; mCurrentDrawingEntries = null; } public void init(OnDrawListener mListener, boolean autoFinish) { this.mListener = mListener; this.mAutoFinishDrawing = autoFinish; } /** * Sets an entry that can be moved later by calling moveEntry() * * @param entry */ public void setMovingEntry(Entry entry) { mMovingEntry = entry; } public Entry getMovingEntry() { return mMovingEntry; } }