package com.github.mikephil.charting.utils;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import java.util.ArrayList;
/**
* Class representing the legend of the chart. The legend will contain one entry
* per color and DataSet. Multiple colors in one DataSet are grouped together.
* The legend object is NOT available before setting data to the chart.
*
* @author Philipp Jahoda
*/
public class Legend {
public enum LegendPosition {
RIGHT_OF_CHART, RIGHT_OF_CHART_CENTER, RIGHT_OF_CHART_INSIDE, BELOW_CHART_LEFT, BELOW_CHART_RIGHT, BELOW_CHART_CENTER, PIECHART_CENTER, NONE
}
public enum LegendForm {
SQUARE, CIRCLE, LINE
}
/** offsets for the legend */
private float mLegendOffsetBottom = 12f, mLegendOffsetRight = 12f, mLegendOffsetLeft = 12f,
mLegendOffsetTop = 12f;
/** the legend colors */
private int[] mColors;
/** the legend labels */
private String[] mLegendLabels;
/** the position relative to the chart the legend is drawn on */
private LegendPosition mPosition = LegendPosition.BELOW_CHART_LEFT;
/** the shape/form the legend colors are drawn in */
private LegendForm mShape = LegendForm.SQUARE;
/** the typeface used for the legend labels */
private Typeface mTypeface = null;
/** the text size of the legend labels */
private float mTextSize = 9f;
/** the text color to use */
private int mTextColor = Color.BLACK;
/** the size of the legend forms/shapes */
private float mFormSize = 8f;
/**
* the space between the legend entries on a horizontal axis, default 6f
*/
private float mXEntrySpace = 6f;
/**
* the space between the legend entries on a vertical axis, default 5f
*/
private float mYEntrySpace = 5f;
/**
* the space between the legend entries on a vertical axis, default 2f
* private float mYEntrySpace = 2f; /** the space between the form and the
* actual label/text
*/
private float mFormToTextSpace = 5f;
/** the space that should be left between stacked forms */
private float mStackSpace = 3f;
/** default constructor */
public Legend() {
mFormSize = Utils.convertDpToPixel(8f);
mXEntrySpace = Utils.convertDpToPixel(6f);
mYEntrySpace = Utils.convertDpToPixel(5f);
mFormToTextSpace = Utils.convertDpToPixel(5f);
mTextSize = Utils.convertDpToPixel(9f);
mStackSpace = Utils.convertDpToPixel(3f);
}
/**
* Constructor. Provide colors and labels for the legend.
*
* @param colors
* @param labels
*/
public Legend(int[] colors, String[] labels) {
this();
if (colors == null || labels == null) {
throw new IllegalArgumentException("colors array or labels array is NULL");
}
if (colors.length != labels.length) {
throw new IllegalArgumentException(
"colors array and labels array need to be of same size");
}
this.mColors = colors;
this.mLegendLabels = labels;
}
/**
* Constructor. Provide colors and labels for the legend.
*
* @param colors
* @param labels
*/
public Legend(ArrayList<Integer> colors, ArrayList<String> labels) {
this();
if (colors == null || labels == null) {
throw new IllegalArgumentException("colors array or labels array is NULL");
}
if (colors.size() != labels.size()) {
throw new IllegalArgumentException(
"colors array and labels array need to be of same size");
}
this.mColors = Utils.convertIntegers(colors);
this.mLegendLabels = Utils.convertStrings(labels);
}
/**
* returns the maximum length in pixels over all legend labels + their forms
*
* @param p the paint object used for rendering the text
* @return
*/
public int getMaximumEntryLength(Paint p) {
int max = 0;
for (int i = 0; i < mLegendLabels.length; i++) {
if (mLegendLabels[i] != null) {
int length = Utils.calcTextWidth(p, mLegendLabels[i]);
if (length > max)
max = length;
}
}
return max + (int) mFormSize;
}
/**
* returns all the colors the legend uses
*
* @return
*/
public int[] getColors() {
return mColors;
}
/**
* returns all the labels the legend uses
*
* @return
*/
public String[] getLegendLabels() {
return mLegendLabels;
}
/**
* Sets a custom array of labels for the legend. Make sure the labels array
* has the same length as the colors array.
*
* @param labels
*/
public void setLegendLabels(String[] labels) {
if (mColors.length != labels.length) {
throw new IllegalArgumentException(
"colors array and labels array need to be of same size");
}
this.mLegendLabels = labels;
}
/**
* returns the position of the legend relative to the chart
*
* @return
*/
public LegendPosition getPosition() {
return mPosition;
}
/**
* sets the position of the legend relative to the whole chart
*
* @param pos
*/
public void setPosition(LegendPosition pos) {
mPosition = pos;
}
/**
* returns the current form/shape that is set for the legend
*
* @return
*/
public LegendForm getForm() {
return mShape;
}
/**
* sets the form/shape of the legend forms
*
* @param shape
*/
public void setForm(LegendForm shape) {
mShape = shape;
}
/**
* returns the typeface used for the legend labels, returns null if none is
* set
*
* @return
*/
public Typeface getTypeface() {
return mTypeface;
}
/**
* sets a specific typeface for the legend labels
*
* @param tf
*/
public void setTypeface(Typeface tf) {
mTypeface = tf;
}
/**
* sets the size in pixels of the legend forms, this is internally converted
* in dp, default 8f
*
* @param size
*/
public void setFormSize(float size) {
mFormSize = Utils.convertDpToPixel(size);
}
/**
* returns the size in dp of the legend forms
*
* @return
*/
public float getFormSize() {
return mFormSize;
}
/**
* returns the space between the legend entries on a horizontal axis in
* pixels
*
* @return
*/
public float getXEntrySpace() {
return mXEntrySpace;
}
/**
* sets the space between the legend entries on a horizontal axis in pixels,
* converts to dp internally
*
* @param space
*/
public void setXEntrySpace(float space) {
mXEntrySpace = Utils.convertDpToPixel(space);
}
/**
* returns the space between the legend entries on a vertical axis in pixels
*
* @return
*/
public float getYEntrySpace() {
return mYEntrySpace;
}
/**
* sets the space between the legend entries on a vertical axis in pixels,
* converts to dp internally
*
* @param space
*/
public void setYEntrySpace(float space) {
mYEntrySpace = Utils.convertDpToPixel(space);
}
/**
* returns the space between the form and the actual label/text
*
* @return
*/
public float getFormToTextSpace() {
return mFormToTextSpace;
}
/**
* sets the space between the form and the actual label/text, converts to dp
* internally
*
* @param mFormToTextSpace
*/
public void setFormToTextSpace(float space) {
this.mFormToTextSpace = Utils.convertDpToPixel(space);
}
/**
* draws the form at the given position with the color at the given index
*
* @param c canvas to draw with
* @param x
* @param y
* @param p paint to use for drawing
* @param index the index of the color to use (in the colors array)
*/
public void drawForm(Canvas c, float x, float y, Paint p, int index) {
if (mColors[index] == -2)
return;
p.setColor(mColors[index]);
float half = mFormSize / 2f;
switch (getForm()) {
case CIRCLE:
c.drawCircle(x + half, y + half, half, p);
break;
case SQUARE:
c.drawRect(x, y, x + mFormSize, y + mFormSize, p);
break;
case LINE:
c.drawLine(x - half, y + half, x + half, y + half, p);
break;
}
}
/**
* draws the label at the given index in the labels array at the given
* position
*
* @param c canvas to draw with
* @param x
* @param y
* @param p paint to use for drawing
* @param index index in the labels-array
*/
public void drawLabel(Canvas c, float x, float y, Paint p, int index) {
c.drawText(mLegendLabels[index], x, y, p);
}
/**
* applies the state from the legend in the parameter to this legend (except
* colors, labels and offsets)
*
* @param l
*/
public void apply(Legend l) {
mPosition = l.mPosition;
mShape = l.mShape;
mTypeface = l.mTypeface;
mFormSize = l.mFormSize;
mXEntrySpace = l.mXEntrySpace;
mYEntrySpace = l.mYEntrySpace;
mFormToTextSpace = l.mFormToTextSpace;
mTextSize = l.mTextSize;
mStackSpace = l.mStackSpace;
mTextColor = l.mTextColor;
// apply offsets
mLegendOffsetBottom = l.mLegendOffsetBottom;
mLegendOffsetLeft = l.mLegendOffsetLeft;
mLegendOffsetRight = l.mLegendOffsetRight;
mLegendOffsetTop = l.mLegendOffsetTop;
}
/**
* returns the bottom offset
*
* @return
*/
public float getOffsetBottom() {
return mLegendOffsetBottom;
}
/**
* returns the right offset
*
* @return
*/
public float getOffsetRight() {
return mLegendOffsetRight;
}
/**
* sets the bottom offset
*
* @param off
*/
public void setOffsetBottom(float off) {
mLegendOffsetBottom = off;
}
/**
* sets the right offset
*
* @param off
*/
public void setOffsetRight(float off) {
mLegendOffsetRight = off;
}
/**
* returns the bottom offset
*
* @return
*/
public float getOffsetTop() {
return mLegendOffsetTop;
}
/**
* returns the left offset
*
* @return
*/
public float getOffsetLeft() {
return mLegendOffsetLeft;
}
/**
* sets the bottom offset
*
* @param off
*/
public void setOffsetTop(float off) {
mLegendOffsetTop = off;
}
/**
* sets the left offset
*
* @param off
*/
public void setOffsetLeft(float off) {
mLegendOffsetLeft = off;
}
/**
* sets the text size of the legend labels, default 9f
*
* @param size
*/
public void setTextSize(float size) {
mTextSize = Utils.convertDpToPixel(size);
}
/**
* returns the text size of the legend labels
*
* @return
*/
public float getTextSize() {
return mTextSize;
}
/**
* returns the space that is left out between stacked forms (with no label)
*
* @return
*/
public float getStackSpace() {
return mStackSpace;
}
/**
* sets the space that is left out between stacked forms (with no label)
*
* @param space
*/
public void setStackSpace(float space) {
mStackSpace = space;
}
/**
* calculates the full width the fully drawn legend will use in pixels
*
* @return
*/
public float getFullWidth(Paint labelpaint) {
float width = 0f;
for (int i = 0; i < mLegendLabels.length; i++) {
// grouped forms have null labels
if (mLegendLabels[i] != null) {
// make a step to the left
if (mColors[i] != -2)
width += mFormSize + mFormToTextSpace;
width += Utils.calcTextWidth(labelpaint, mLegendLabels[i])
+ mXEntrySpace;
} else {
width += mFormSize + mStackSpace;
}
}
return width;
}
/**
* Calculates the full height of the drawn legend.
*
* @param mLegendLabelPaint
* @return
*/
public float getFullHeight(Paint labelpaint) {
float height = 0f;
for (int i = 0; i < mLegendLabels.length; i++) {
// grouped forms have null labels
if (mLegendLabels[i] != null) {
height += Utils.calcTextHeight(labelpaint, mLegendLabels[i])
+ mYEntrySpace;
}
}
return height;
}
/**
* Sets the text color to use for the legend labels. Make sure to use
* getResources().getColor(...) when using a color from the resources.
*
* @param color
*/
public void setTextColor(int color) {
mTextColor = color;
}
/**
* Returns the text color that is set for the legend labels.
*
* @return
*/
public int getTextColor() {
return mTextColor;
}
}