content: 
  package com.github.mikephil.charting.charts;
  
  import android.content.Context;
  import android.graphics.Path;
  import android.util.AttributeSet;
  
  import com.github.mikephil.charting.data.Entry;
  import com.github.mikephil.charting.data.ScatterData;
  import com.github.mikephil.charting.data.ScatterDataSet;
  
  import java.util.ArrayList;
  
  /**
   * The ScatterChart. Draws dots, triangles, squares and custom shapes into the
   * chartview.
   * 
   * @author Philipp Jahoda
   */
  public class ScatterChart extends BarLineChartBase<ScatterData> {
  
      /** enum that defines the shape that is drawn where the values are */
      public enum ScatterShape {
          CROSS, TRIANGLE, CIRCLE, SQUARE, CUSTOM
      }
  
      public ScatterChart(Context context) {
          super(context);
      }
  
      public ScatterChart(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
  
      public ScatterChart(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
      }
      
      @Override
      protected void prepareContentRect() {
          if(isEmpty()) {
              super.prepareContentRect();
          } else {
              
              float offset = mData.getGreatestShapeSize() / 2f;
              
              mContentRect.set(mOffsetLeft - offset,
                      mOffsetTop,
                      getWidth() - mOffsetRight + offset,
                      getHeight() - mOffsetBottom);
          }
      }
  
      @Override
      protected void calcMinMax(boolean fixedValues) {
          super.calcMinMax(fixedValues);
  
          if (mDeltaX == 0 && mData.getYValCount() > 0)
              mDeltaX = 1;
      }
  
      @Override
      protected void drawData() {
  
          ArrayList<ScatterDataSet> dataSets = mData.getDataSets();
  
          for (int i = 0; i < mData.getDataSetCount(); i++) {
  
              ScatterDataSet dataSet = dataSets.get(i);
              ArrayList<Entry> entries = dataSet.getYVals();
  
              float shapeHalf = dataSet.getScatterShapeSize() / 2f;
  
              float[] valuePoints = mTrans.generateTransformedValuesLineScatter(entries, mPhaseY);
  
              ScatterShape shape = dataSet.getScatterShape();
  
              for (int j = 0; j < valuePoints.length * mPhaseX; j += 2) {
  
                  if (isOffContentRight(valuePoints[j]))
                      break;
  
                  // make sure the lines don't do shitty things outside bounds
                  if (j != 0 && isOffContentLeft(valuePoints[j - 1])
                          && isOffContentTop(valuePoints[j + 1])
                          && isOffContentBottom(valuePoints[j + 1]))
                      continue;
  
                  // Set the color for the currently drawn value. If the index is
                  // out of bounds, reuse colors.
                  mRenderPaint.setColor(dataSet.getColor(j));
  
                  if (shape == ScatterShape.SQUARE) {
  
                      mDrawCanvas.drawRect(valuePoints[j] - shapeHalf,
                              valuePoints[j + 1] - shapeHalf, valuePoints[j]
                                      + shapeHalf, valuePoints[j + 1]
                                      + shapeHalf, mRenderPaint);
  
                  } else if (shape == ScatterShape.CIRCLE) {
  
                      mDrawCanvas.drawCircle(valuePoints[j], valuePoints[j + 1], shapeHalf,
                              mRenderPaint);
  
                  } else if (shape == ScatterShape.CROSS) {
  
                      mDrawCanvas.drawLine(valuePoints[j] - shapeHalf, valuePoints[j + 1],
                              valuePoints[j] + shapeHalf,
                              valuePoints[j + 1], mRenderPaint);
                      mDrawCanvas.drawLine(valuePoints[j], valuePoints[j + 1] - shapeHalf,
                              valuePoints[j], valuePoints[j + 1]
                                      + shapeHalf, mRenderPaint);
  
                  } else if (shape == ScatterShape.TRIANGLE) {
  
                      // create a triangle path
                      Path tri = new Path();
                      tri.moveTo(valuePoints[j], valuePoints[j + 1] - shapeHalf);
                      tri.lineTo(valuePoints[j] + shapeHalf, valuePoints[j + 1] + shapeHalf);
                      tri.lineTo(valuePoints[j] - shapeHalf, valuePoints[j + 1] + shapeHalf);
                      tri.close();
  
                      mDrawCanvas.drawPath(tri, mRenderPaint);
  
                  } else if (shape == ScatterShape.CUSTOM) {
  
                      Path customShape = dataSet.getCustomScatterShape();
  
                      if (customShape == null)
                          return;
  
                      // transform the provided custom path
                      mTrans.pathValueToPixel(customShape);
                      mDrawCanvas.drawPath(customShape, mRenderPaint);
                  }
              }
          }
      }
  
      @Override
      protected void drawValues() {
          // if values are drawn
          if (mDrawYValues && mData.getYValCount() < mMaxVisibleCount * mTrans.getScaleX()) {
  
              ArrayList<ScatterDataSet> dataSets = mData
                      .getDataSets();
  
              for (int i = 0; i < mData.getDataSetCount(); i++) {
  
                  ScatterDataSet dataSet = dataSets.get(i);
                  ArrayList<Entry> entries = dataSet.getYVals();
  
                  float[] positions = mTrans.generateTransformedValuesLineScatter(entries, mPhaseY);
  
                  float shapeSize = dataSet.getScatterShapeSize();
  
                  for (int j = 0; j < positions.length * mPhaseX; j += 2) {
  
                      if (isOffContentRight(positions[j]))
                          break;
  
                      if (isOffContentLeft(positions[j]) || isOffContentTop(positions[j + 1])
                              || isOffContentBottom(positions[j + 1]))
                          continue;
  
                      float val = entries.get(j / 2).getVal();
  
                      if (mDrawUnitInChart) {
  
                          mDrawCanvas.drawText(mValueFormatter.getFormattedValue(val) + mUnit,
                                  positions[j],
                                  positions[j + 1] - shapeSize, mValuePaint);
                      } else {
  
                          mDrawCanvas.drawText(mValueFormatter.getFormattedValue(val), positions[j],
                                  positions[j + 1] - shapeSize,
                                  mValuePaint);
                      }
                  }
              }
          }
      }
  
      @Override
      protected void drawHighlights() {
  
          for (int i = 0; i < mIndicesToHightlight.length; i++) {
  
              ScatterDataSet set = mData.getDataSetByIndex(mIndicesToHightlight[i]
                      .getDataSetIndex());
              
              if (set == null)
                  continue;
  
              mHighlightPaint.setColor(set.getHighLightColor());
  
              int xIndex = mIndicesToHightlight[i].getXIndex(); // get the
                                                                // x-position
  
              if (xIndex > mDeltaX * mPhaseX)
                  continue;
  
              float y = set.getYValForXIndex(xIndex) * mPhaseY; // get the
                                                                // y-position
  
              float[] pts = new float[] {
                      xIndex, mYChartMax, xIndex, mYChartMin, 0, y, mDeltaX, y
              };
  
              mTrans.pointValuesToPixel(pts);
              // draw the highlight lines
              mDrawCanvas.drawLines(pts, mHighlightPaint);
          }
      }
  
      @Override
      protected void drawAdditional() {
  
      }
  
      /**
       * Returns all possible predefined scattershapes.
       * 
       * @return
       */
      public static ScatterShape[] getAllPossibleShapes() {
          return new ScatterShape[] {
                  ScatterShape.SQUARE, ScatterShape.CIRCLE, ScatterShape.TRIANGLE, ScatterShape.CROSS
          };
      }
  }
  