| |
| package com.github.mikephil.charting.renderer; |
| |
| import android.graphics.Canvas; |
| import android.graphics.Color; |
| import android.graphics.Paint; |
| |
| import com.github.mikephil.charting.animation.ChartAnimator; |
| import com.github.mikephil.charting.buffer.CandleBodyBuffer; |
| import com.github.mikephil.charting.buffer.CandleShadowBuffer; |
| import com.github.mikephil.charting.data.CandleData; |
| import com.github.mikephil.charting.data.CandleDataSet; |
| import com.github.mikephil.charting.data.CandleEntry; |
| import com.github.mikephil.charting.data.Entry; |
| import com.github.mikephil.charting.interfaces.CandleDataProvider; |
| import com.github.mikephil.charting.utils.ColorTemplate; |
| import com.github.mikephil.charting.utils.Highlight; |
| 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 CandleStickChartRenderer extends DataRenderer { |
| |
| protected CandleDataProvider mChart; |
| |
| private CandleShadowBuffer[] mShadowBuffers; |
| private CandleBodyBuffer[] mBodyBuffers; |
| |
| public CandleStickChartRenderer(CandleDataProvider chart, ChartAnimator animator, |
| ViewPortHandler viewPortHandler) { |
| super(animator, viewPortHandler); |
| mChart = chart; |
| } |
| |
| @Override |
| public void initBuffers() { |
| CandleData candleData = mChart.getCandleData(); |
| mShadowBuffers = new CandleShadowBuffer[candleData.getDataSetCount()]; |
| mBodyBuffers = new CandleBodyBuffer[candleData.getDataSetCount()]; |
| |
| for (int i = 0; i < mShadowBuffers.length; i++) { |
| CandleDataSet set = candleData.getDataSetByIndex(i); |
| mShadowBuffers[i] = new CandleShadowBuffer(set.getValueCount() * 4); |
| mBodyBuffers[i] = new CandleBodyBuffer(set.getValueCount() * 4); |
| } |
| } |
| |
| @Override |
| public void drawData(Canvas c) { |
| |
| CandleData candleData = mChart.getCandleData(); |
| |
| for (CandleDataSet set : candleData.getDataSets()) { |
| |
| if (set.isVisible()) |
| drawDataSet(c, set); |
| } |
| } |
| |
| protected void drawDataSet(Canvas c, CandleDataSet dataSet) { |
| |
| Transformer trans = mChart.getTransformer(dataSet.getAxisDependency()); |
| calcXBounds(trans); |
| |
| float phaseX = mAnimator.getPhaseX(); |
| float phaseY = mAnimator.getPhaseY(); |
| |
| int dataSetIndex = mChart.getCandleData().getIndexOfDataSet(dataSet); |
| |
| List<CandleEntry> entries = dataSet.getYVals(); |
| |
| Entry entryFrom = dataSet.getEntryForXIndex(mMinX); |
| Entry entryTo = dataSet.getEntryForXIndex(mMaxX); |
| |
| int minx = dataSet.getEntryPosition(entryFrom); |
| int maxx = Math.min(dataSet.getEntryPosition(entryTo) + 1, entries.size()); |
| |
| int range = (maxx - minx) * 4; |
| int to = (int)Math.ceil((maxx - minx) * phaseX + minx); |
| |
| CandleShadowBuffer shadowBuffer = mShadowBuffers[dataSetIndex]; |
| shadowBuffer.setPhases(phaseX, phaseY); |
| shadowBuffer.limitFrom(minx); |
| shadowBuffer.limitTo(maxx); |
| shadowBuffer.feed(entries); |
| |
| trans.pointValuesToPixel(shadowBuffer.buffer); |
| |
| mRenderPaint.setStyle(Paint.Style.STROKE); |
| |
| // If not set, use default functionality for backward compatibility |
| if (dataSet.getShadowColor() == ColorTemplate.COLOR_NONE) { |
| mRenderPaint.setColor(dataSet.getColor()); |
| } else { |
| mRenderPaint.setColor(dataSet.getShadowColor()); |
| } |
| |
| mRenderPaint.setStrokeWidth(dataSet.getShadowWidth()); |
| |
| // draw the shadow |
| c.drawLines(shadowBuffer.buffer, 0, range, mRenderPaint); |
| |
| CandleBodyBuffer bodyBuffer = mBodyBuffers[dataSetIndex]; |
| bodyBuffer.setBodySpace(dataSet.getBodySpace()); |
| bodyBuffer.setPhases(phaseX, phaseY); |
| bodyBuffer.limitFrom(minx); |
| bodyBuffer.limitTo(maxx); |
| bodyBuffer.feed(entries); |
| |
| trans.pointValuesToPixel(bodyBuffer.buffer); |
| |
| // draw the body |
| for (int j = 0; j < range; j += 4) { |
| |
| // get the entry |
| CandleEntry e = entries.get(j / 4 + minx); |
| |
| if (!fitsBounds(e.getXIndex(), mMinX, to)) |
| continue; |
| |
| float leftBody = bodyBuffer.buffer[j]; |
| float open = bodyBuffer.buffer[j + 1]; |
| float rightBody = bodyBuffer.buffer[j + 2]; |
| float close = bodyBuffer.buffer[j + 3]; |
| |
| // draw body differently for increasing and decreasing entry |
| if (open > close) { // decreasing |
| |
| if (dataSet.getDecreasingColor() == ColorTemplate.COLOR_NONE) { |
| mRenderPaint.setColor(dataSet.getColor(j / 4 + minx)); |
| } else { |
| mRenderPaint.setColor(dataSet.getDecreasingColor()); |
| } |
| |
| mRenderPaint.setStyle(dataSet.getDecreasingPaintStyle()); |
| // draw the body |
| c.drawRect(leftBody, close, rightBody, open, mRenderPaint); |
| |
| } else if(open < close) { |
| |
| if (dataSet.getIncreasingColor() == ColorTemplate.COLOR_NONE) { |
| mRenderPaint.setColor(dataSet.getColor(j / 4 + minx)); |
| } else { |
| mRenderPaint.setColor(dataSet.getIncreasingColor()); |
| } |
| |
| mRenderPaint.setStyle(dataSet.getIncreasingPaintStyle()); |
| // draw the body |
| c.drawRect(leftBody, open, rightBody, close, mRenderPaint); |
| } else { // equal values |
| |
| mRenderPaint.setColor(Color.BLACK); |
| mRenderPaint.setStyle(Paint.Style.STROKE); |
| c.drawLine(leftBody, open, rightBody, close, mRenderPaint); |
| } |
| } |
| } |
| |
| // /** |
| // * Transforms the values of an entry in order to draw the candle-body. |
| // * |
| // * @param bodyPoints |
| // * @param e |
| // * @param bodySpace |
| // */ |
| // private void transformBody(float[] bodyPoints, CandleEntry e, float |
| // bodySpace, Transformer trans) { |
| // |
| // float phase = mAnimator.getPhaseY(); |
| // |
| // bodyPoints[0] = e.getXIndex() - 0.5f + bodySpace; |
| // bodyPoints[1] = e.getClose() * phase; |
| // bodyPoints[2] = e.getXIndex() + 0.5f - bodySpace; |
| // bodyPoints[3] = e.getOpen() * phase; |
| // |
| // trans.pointValuesToPixel(bodyPoints); |
| // } |
| // |
| // /** |
| // * Transforms the values of an entry in order to draw the candle-shadow. |
| // * |
| // * @param shadowPoints |
| // * @param e |
| // */ |
| // private void transformShadow(float[] shadowPoints, CandleEntry e, |
| // Transformer trans) { |
| // |
| // float phase = mAnimator.getPhaseY(); |
| // |
| // shadowPoints[0] = e.getXIndex(); |
| // shadowPoints[1] = e.getHigh() * phase; |
| // shadowPoints[2] = e.getXIndex(); |
| // shadowPoints[3] = e.getLow() * phase; |
| // |
| // trans.pointValuesToPixel(shadowPoints); |
| // } |
| |
| @Override |
| public void drawValues(Canvas c) { |
| |
| // if values are drawn |
| if (mChart.getCandleData().getYValCount() < mChart.getMaxVisibleCount() |
| * mViewPortHandler.getScaleX()) { |
| |
| List<CandleDataSet> dataSets = mChart.getCandleData().getDataSets(); |
| |
| for (int i = 0; i < dataSets.size(); i++) { |
| |
| CandleDataSet dataSet = dataSets.get(i); |
| |
| if (!dataSet.isDrawValuesEnabled()) |
| continue; |
| |
| // apply the text-styling defined by the DataSet |
| applyValueTextStyle(dataSet); |
| |
| Transformer trans = mChart.getTransformer(dataSet.getAxisDependency()); |
| |
| List<CandleEntry> entries = dataSet.getYVals(); |
| |
| Entry entryFrom = dataSet.getEntryForXIndex(mMinX); |
| Entry entryTo = dataSet.getEntryForXIndex(mMaxX); |
| |
| int minx = dataSet.getEntryPosition(entryFrom); |
| int maxx = Math.min(dataSet.getEntryPosition(entryTo) + 1, entries.size()); |
| |
| float[] positions = trans.generateTransformedValuesCandle( |
| entries, mAnimator.getPhaseX(), mAnimator.getPhaseY(), minx, maxx); |
| |
| float yOffset = Utils.convertDpToPixel(5f); |
| |
| for (int j = 0; j < positions.length; j += 2) { |
| |
| float x = positions[j]; |
| float y = positions[j + 1]; |
| |
| if (!mViewPortHandler.isInBoundsRight(x)) |
| break; |
| |
| if (!mViewPortHandler.isInBoundsLeft(x) || !mViewPortHandler.isInBoundsY(y)) |
| continue; |
| |
| float val = entries.get(j / 2 + minx).getHigh(); |
| |
| c.drawText(dataSet.getValueFormatter().getFormattedValue(val), x, y - yOffset, |
| mValuePaint); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void drawExtras(Canvas c) { |
| } |
| |
| @Override |
| public void drawHighlighted(Canvas c, Highlight[] indices) { |
| |
| for (int i = 0; i < indices.length; i++) { |
| |
| int xIndex = indices[i].getXIndex(); // get the |
| // x-position |
| |
| CandleDataSet set = mChart.getCandleData().getDataSetByIndex( |
| indices[i].getDataSetIndex()); |
| |
| if (set == null) |
| continue; |
| |
| mHighlightPaint.setColor(set.getHighLightColor()); |
| |
| CandleEntry e = set.getEntryForXIndex(xIndex); |
| |
| if (e == null) |
| continue; |
| |
| float low = e.getLow() * mAnimator.getPhaseY(); |
| float high = e.getHigh() * mAnimator.getPhaseY(); |
| |
| float min = mChart.getYChartMin(); |
| float max = mChart.getYChartMax(); |
| |
| float[] vertPts = new float[] { |
| xIndex - 0.5f, max, xIndex - 0.5f, min, xIndex + 0.5f, max, xIndex + 0.5f, |
| min |
| }; |
| |
| float[] horPts = new float[] { |
| 0, low, mChart.getXChartMax(), low, 0, high, mChart.getXChartMax(), high |
| }; |
| |
| mChart.getTransformer(set.getAxisDependency()).pointValuesToPixel(vertPts); |
| mChart.getTransformer(set.getAxisDependency()).pointValuesToPixel(horPts); |
| |
| // draw the vertical highlight lines |
| c.drawLines(vertPts, mHighlightPaint); |
| |
| // draw the horizontal highlight lines |
| c.drawLines(horPts, mHighlightPaint); |
| } |
| } |
| |
| } |