package com.github.mikephil.charting.renderer;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import com.github.mikephil.charting.animation.ChartAnimator;
import com.github.mikephil.charting.buffer.BarBuffer;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.BarDataProvider;
import com.github.mikephil.charting.utils.Transformer;
import com.github.mikephil.charting.utils.Utils;
import com.github.mikephil.charting.utils.ViewPortHandler;
import java.util.List;
public class BarChartRenderer extends DataRenderer {
protected BarDataProvider mChart;
/**
* the rect object that is used for drawing the bars
*/
protected RectF mBarRect = new RectF();
protected BarBuffer[] mBarBuffers;
protected Paint mShadowPaint;
public BarChartRenderer(BarDataProvider chart, ChartAnimator animator,
ViewPortHandler viewPortHandler) {
super(animator, viewPortHandler);
this.mChart = chart;
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mHighlightPaint.setStyle(Paint.Style.FILL);
mHighlightPaint.setColor(Color.rgb(0, 0, 0));
// set alpha after color
mHighlightPaint.setAlpha(120);
mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mShadowPaint.setStyle(Paint.Style.FILL);
}
@Override
public void initBuffers() {
BarData barData = mChart.getBarData();
mBarBuffers = new BarBuffer[barData.getDataSetCount()];
for (int i = 0; i < mBarBuffers.length; i++) {
BarDataSet set = barData.getDataSetByIndex(i);
mBarBuffers[i] = new BarBuffer(set.getValueCount() * 4 * set.getStackSize(),
barData.getGroupSpace(),
barData.getDataSetCount(), set.isStacked());
}
}
@Override
public void drawData(Canvas c) {
BarData barData = mChart.getBarData();
for (int i = 0; i < barData.getDataSetCount(); i++) {
BarDataSet set = barData.getDataSetByIndex(i);
if (set.isVisible() && set.getEntryCount() > 0) {
drawDataSet(c, set, i);
}
}
}
protected void drawDataSet(Canvas c, BarDataSet dataSet, int index) {
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
mShadowPaint.setColor(dataSet.getBarShadowColor());
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
List<BarEntry> entries = dataSet.getYVals();
// initialize the buffer
BarBuffer buffer = mBarBuffers[index];
buffer.setPhases(phaseX, phaseY);
buffer.setBarSpace(dataSet.getBarSpace());
buffer.setDataSet(index);
buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
buffer.feed(entries);
trans.pointValuesToPixel(buffer.buffer);
// if multiple colors
if (dataSet.getColors().size() > 1) {
for (int j = 0; j < buffer.size(); j += 4) {
if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
continue;
if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
break;
if (mChart.isDrawBarShadowEnabled()) {
c.drawRect(buffer.buffer[j], mViewPortHandler.contentTop(),
buffer.buffer[j + 2],
mViewPortHandler.contentBottom(), mShadowPaint);
}
// Set the color for the currently drawn value. If the index
// is
// out of bounds, reuse colors.
int entryIndex = j / 4;
BarEntry entry = entries.get(entryIndex);
float val = entry.getVal();
if (val >= 0 && val < 10) {
mRenderPaint.setColor(dataSet.getColor(0));
} else if (val >= 10 && val < 20) {
mRenderPaint.setColor(dataSet.getColor(1));
} else if (val >= 20 && val < 30) {
mRenderPaint.setColor(dataSet.getColor(2));
} else if (val >= 30 && val < 40) {
mRenderPaint.setColor(dataSet.getColor(3));
} else {
mRenderPaint.setColor(dataSet.getColor(4));
}
// mRenderPaint.setColor(dataSet.getColor(j / 4));
if (null != mFixSet) {
String xValue = mChart.getBarData().getXVals().get(j / 4);
if (null != xValue && !"".equals(xValue) && !mFixSet.contains(Integer.valueOf(xValue))) {
mRenderPaint.setColor(Color.GRAY);
}
}
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
}
} else {
mRenderPaint.setColor(dataSet.getColor());
for (int j = 0; j < buffer.size(); j += 4) {
if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
continue;
if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
break;
if (mChart.isDrawBarShadowEnabled()) {
c.drawRect(buffer.buffer[j], mViewPortHandler.contentTop(),
buffer.buffer[j + 2],
mViewPortHandler.contentBottom(), mShadowPaint);
}
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
}
}
}
/**
* Prepares a bar for being highlighted.
*
* @param x the x-position
* @param y1 the y1-position
* @param y2 the y2-position
* @param barspaceHalf the space between bars
* @param trans
*/
protected void prepareBarHighlight(float x, float y1, float y2, float barspaceHalf,
Transformer trans) {
float barWidth = 0.5f;
float left = x - barWidth + barspaceHalf;
float right = x + barWidth - barspaceHalf;
float top = y1;
float bottom = y2;
mBarRect.set(left, top, right, bottom);
trans.rectValueToPixel(mBarRect, mAnimator.getPhaseY());
}
@Override
public void drawValues(Canvas c) {
// if values are drawn
if (passesCheck()) {
List<BarDataSet> dataSets = mChart.getBarData().getDataSets();
final float valueOffsetPlus = Utils.convertDpToPixel(4.5f);
float posOffset = 0f;
float negOffset = 0f;
boolean drawValueAboveBar = mChart.isDrawValueAboveBarEnabled();
for (int i = 0; i < mChart.getBarData().getDataSetCount(); i++) {
BarDataSet dataSet = dataSets.get(i);
if (!dataSet.isDrawValuesEnabled() || dataSet.getEntryCount() == 0)
continue;
// apply the text-styling defined by the DataSet
applyValueTextStyle(dataSet);
boolean isInverted = mChart.isInverted(dataSet.getAxisDependency());
// calculate the correct offset depending on the draw position of
// the value
float valueTextHeight = Utils.calcTextHeight(mValuePaint, "8");
posOffset = (drawValueAboveBar ? -valueOffsetPlus : valueTextHeight + valueOffsetPlus);
negOffset = (drawValueAboveBar ? valueTextHeight + valueOffsetPlus : -valueOffsetPlus);
if (isInverted) {
posOffset = -posOffset - valueTextHeight;
negOffset = -negOffset - valueTextHeight;
}
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
List<BarEntry> entries = dataSet.getYVals();
float[] valuePoints = getTransformedValues(trans, entries, i);
// if only single values are drawn (sum)
if (!dataSet.isStacked()) {
for (int j = 0; j < valuePoints.length * mAnimator.getPhaseX(); j += 2) {
if (!mViewPortHandler.isInBoundsRight(valuePoints[j]))
break;
if (!mViewPortHandler.isInBoundsY(valuePoints[j + 1])
|| !mViewPortHandler.isInBoundsLeft(valuePoints[j]))
continue;
BarEntry entry = entries.get(j / 2);
float val = entry.getVal();
float x = valuePoints[j];
float y = valuePoints[j + 1] + (val >= 0 ? posOffset : negOffset);
String xValue = mChart.getBarData().getXVals().get(j / 2);
drawValue(c, dataSet.getValueFormatter(), val, entry, i, x, y);
drawIcon(c, xValue, x, y);
}
// if we have stacks
} else {
for (int j = 0; j < (valuePoints.length - 1) * mAnimator.getPhaseX(); j += 2) {
BarEntry entry = entries.get(j / 2);
float[] vals = entry.getVals();
// we still draw stacked bars, but there is one
// non-stacked
// in between
if (vals == null) {
if (!mViewPortHandler.isInBoundsRight(valuePoints[j]))
break;
if (!mViewPortHandler.isInBoundsY(valuePoints[j + 1])
|| !mViewPortHandler.isInBoundsLeft(valuePoints[j]))
continue;
drawValue(c, dataSet.getValueFormatter(), entry.getVal(), entry, i, valuePoints[j],
valuePoints[j + 1] + (entry.getVal() >= 0 ? posOffset : negOffset));
// draw stack values
} else {
float[] transformed = new float[vals.length * 2];
float posY = 0f;
float negY = -entry.getNegativeSum();
for (int k = 0, idx = 0; k < transformed.length; k += 2, idx++) {
float value = vals[idx];
float y;
if (value >= 0f) {
posY += value;
y = posY;
} else {
y = negY;
negY -= value;
}
transformed[k + 1] = y * mAnimator.getPhaseY();
}
trans.pointValuesToPixel(transformed);
for (int k = 0; k < transformed.length; k += 2) {
float x = valuePoints[j];
float y = transformed[k + 1]
+ (vals[k / 2] >= 0 ? posOffset : negOffset);
if (!mViewPortHandler.isInBoundsRight(x))
break;
if (!mViewPortHandler.isInBoundsY(y)
|| !mViewPortHandler.isInBoundsLeft(x))
continue;
drawValue(c, dataSet.getValueFormatter(), vals[k / 2], entry, i, x, y);
}
}
}
}
}
}
}
@Override
public void drawHighlighted(Canvas c, Highlight[] indices) {
int setCount = mChart.getBarData().getDataSetCount();
for (int i = 0; i < indices.length; i++) {
Highlight h = indices[i];
int index = h.getXIndex();
int dataSetIndex = h.getDataSetIndex();
BarDataSet set = mChart.getBarData().getDataSetByIndex(dataSetIndex);
if (set == null || !set.isHighlightEnabled())
continue;
float barspaceHalf = set.getBarSpace() / 2f;
Transformer trans = mChart.getTransformer(set.getAxisDependency());
mHighlightPaint.setColor(set.getHighLightColor());
mHighlightPaint.setAlpha(set.getHighLightAlpha());
// check outofbounds
if (index >= 0
&& index < (mChart.getXChartMax() * mAnimator.getPhaseX()) / setCount) {
BarEntry e = set.getEntryForXIndex(index);
if (e == null || e.getXIndex() != index)
continue;
float groupspace = mChart.getBarData().getGroupSpace();
boolean isStack = h.getStackIndex() < 0 ? false : true;
// calculate the correct x-position
float x = index * setCount + dataSetIndex + groupspace / 2f
+ groupspace * index;
final float y1;
final float y2;
if (isStack) {
y1 = h.getRange().from;
y2 = h.getRange().to;
} else {
y1 = e.getVal();
y2 = 0.f;
}
prepareBarHighlight(x, y1, y2, barspaceHalf, trans);
c.drawRect(mBarRect, mHighlightPaint);
if (mChart.isDrawHighlightArrowEnabled()) {
mHighlightPaint.setAlpha(255);
// distance between highlight arrow and bar
float offsetY = mAnimator.getPhaseY() * 0.07f;
float[] values = new float[9];
trans.getPixelToValueMatrix().getValues(values);
final float xToYRel = Math.abs(values[Matrix.MSCALE_Y] / values[Matrix.MSCALE_X]);
final float arrowWidth = set.getBarSpace() / 2.f;
final float arrowHeight = arrowWidth * xToYRel;
final float yArrow = (y1 > -y2 ? y1 : y1) * mAnimator.getPhaseY();
Path arrow = new Path();
arrow.moveTo(x + 0.4f, yArrow + offsetY);
arrow.lineTo(x + 0.4f + arrowWidth, yArrow + offsetY - arrowHeight);
arrow.lineTo(x + 0.4f + arrowWidth, yArrow + offsetY + arrowHeight);
trans.pathValueToPixel(arrow);
c.drawPath(arrow, mHighlightPaint);
}
}
}
}
public float[] getTransformedValues(Transformer trans, List<BarEntry> entries,
int dataSetIndex) {
return trans.generateTransformedValuesBarChart(entries, dataSetIndex,
mChart.getBarData(),
mAnimator.getPhaseY());
}
protected boolean passesCheck() {
return mChart.getBarData().getYValCount() < mChart.getMaxVisibleCount()
* mViewPortHandler.getScaleX();
}
@Override
public void drawExtras(Canvas c) {
}
}