@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int size = (int) Utils.convertDpToPixel(50f); setMeasuredDimension( Math.max(getSuggestedMinimumWidth(), resolveSize(size, widthMeasureSpec)), Math.max(getSuggestedMinimumHeight(), resolveSize(size, heightMeasureSpec))); }
@Override protected void init() { super.init(); mWebLineWidth = Utils.convertDpToPixel(1.5f); mInnerWebLineWidth = Utils.convertDpToPixel(0.75f); mWebPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mWebPaint.setStyle(Paint.Style.STROKE); mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mHighlightPaint.setStyle(Paint.Style.STROKE); mHighlightPaint.setStrokeWidth(2f); mHighlightPaint.setColor(Color.rgb(255, 187, 115)); }
/** * sets the size of the description text in pixels, min 6f, max 16f * * @param size */ public void setDescriptionTextSize(float size) { if (size > 16f) size = 16f; if (size < 6f) size = 6f; mDescPaint.setTextSize(Utils.convertDpToPixel(size)); }
public XAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) { super(viewPortHandler, trans); this.mXAxis = xAxis; mAxisLabelPaint.setColor(Color.WHITE); mAxisLabelPaint.setTextAlign(Align.CENTER); mAxisLabelPaint.setTextSize(Utils.convertDpToPixel(10f)); }
/** * Draws the LimitLines associated with this axis to the screen. * * @param c */ @Override public void renderLimitLines(Canvas c) { List<LimitLine> limitLines = mXAxis.getLimitLines(); if (limitLines == null || limitLines.size() <= 0) return; float[] pts = new float[4]; Path limitLinePath = new Path(); for (int i = 0; i < limitLines.size(); i++) { LimitLine l = limitLines.get(i); pts[0] = l.getLimit(); pts[2] = l.getLimit(); mTrans.pointValuesToPixel(pts); pts[1] = mViewPortHandler.contentTop(); pts[3] = mViewPortHandler.contentBottom(); limitLinePath.moveTo(pts[0], pts[1]); limitLinePath.lineTo(pts[2], pts[3]); mLimitLinePaint.setStyle(Paint.Style.STROKE); mLimitLinePaint.setColor(l.getLineColor()); mLimitLinePaint.setStrokeWidth(l.getLineWidth()); mLimitLinePaint.setPathEffect(l.getDashPathEffect()); c.drawPath(limitLinePath, mLimitLinePaint); limitLinePath.reset(); String label = l.getLabel(); // if drawing the limit-value label is enabled if (label != null && !label.equals("")) { float xOffset = l.getLineWidth(); float add = Utils.convertDpToPixel(4f); mLimitLinePaint.setStyle(l.getTextStyle()); mLimitLinePaint.setPathEffect(null); mLimitLinePaint.setColor(l.getTextColor()); mLimitLinePaint.setStrokeWidth(0.5f); mLimitLinePaint.setTextSize(l.getTextSize()); float yOffset = Utils.calcTextHeight(mLimitLinePaint, label) + add / 2f; if (l.getLabelPosition() == LimitLine.LimitLabelPosition.POS_RIGHT) { c.drawText( label, pts[0] + xOffset, mViewPortHandler.contentBottom() - add, mLimitLinePaint); } else { c.drawText( label, pts[0] + xOffset, mViewPortHandler.contentTop() + yOffset, mLimitLinePaint); } } } }
/** initialize all paints and stuff */ protected void init() { setWillNotDraw(false); // setLayerType(View.LAYER_TYPE_HARDWARE, null); if (android.os.Build.VERSION.SDK_INT < 11) mAnimator = new ChartAnimator(); else mAnimator = new ChartAnimator( new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // ViewCompat.postInvalidateOnAnimation(Chart.this); postInvalidate(); } }); // initialize the utils Utils.init(getContext()); mDefaultFormatter = new DefaultValueFormatter(1); mViewPortHandler = new ViewPortHandler(); mLegend = new Legend(); mLegendRenderer = new LegendRenderer(mViewPortHandler, mLegend); mXAxis = new XAxis(); mDescPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mDescPaint.setColor(Color.BLACK); mDescPaint.setTextAlign(Align.RIGHT); mDescPaint.setTextSize(Utils.convertDpToPixel(9f)); mInfoPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mInfoPaint.setColor(Color.rgb(247, 189, 51)); // orange mInfoPaint.setTextAlign(Align.CENTER); mInfoPaint.setTextSize(Utils.convertDpToPixel(12f)); mDrawPaint = new Paint(Paint.DITHER_FLAG); if (mLogEnabled) Log.i("", "Chart.init()"); }
/** default constructor */ public Legend() { mFormSize = Utils.convertDpToPixel(8f); mXEntrySpace = Utils.convertDpToPixel(6f); mYEntrySpace = Utils.convertDpToPixel(0f); mFormToTextSpace = Utils.convertDpToPixel(5f); mTextSize = Utils.convertDpToPixel(10f); mStackSpace = Utils.convertDpToPixel(3f); this.mXOffset = Utils.convertDpToPixel(5f); this.mYOffset = Utils.convertDpToPixel(3f); // 2 }
public BubbleChartRenderer( BubbleDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) { super(animator, viewPortHandler); mChart = chart; mRenderPaint.setStyle(Style.FILL); mHighlightPaint.setStyle(Style.STROKE); mHighlightPaint.setStrokeWidth(Utils.convertDpToPixel(1.5f)); }
public PieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) { super(animator, viewPortHandler); mChart = chart; mHolePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mHolePaint.setColor(Color.WHITE); mHolePaint.setStyle(Style.FILL); mTransparentCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTransparentCirclePaint.setColor(Color.WHITE); mTransparentCirclePaint.setStyle(Style.FILL); mTransparentCirclePaint.setAlpha(105); mCenterTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); mCenterTextPaint.setColor(Color.BLACK); mCenterTextPaint.setTextSize(Utils.convertDpToPixel(12f)); // mCenterTextPaint.setTextAlign(Align.CENTER); mValuePaint.setTextSize(Utils.convertDpToPixel(13f)); mValuePaint.setColor(Color.WHITE); mValuePaint.setTextAlign(Align.CENTER); }
@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 = Math.max(dataSet.getEntryPosition(entryFrom), 0); 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 renderAxisLine(Canvas c) { if (!mXAxis.isDrawAxisLineEnabled() || !mXAxis.isEnabled()) return; mAxisLinePaint.setColor(mXAxis.getAxisLineColor()); mAxisLinePaint.setStrokeWidth(mXAxis.getAxisLineWidth()); // if (mXAxis.getPosition() == XAxisPosition.TOP // || mXAxis.getPosition() == XAxisPosition.TOP_INSIDE // || mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { c.drawLine( mViewPortHandler.contentLeft(), mViewPortHandler.contentTop(), mViewPortHandler.contentRight(), mViewPortHandler.contentTop(), mAxisLinePaint); // } // if (mXAxis.getPosition() == XAxisPosition.BOTTOM // || mXAxis.getPosition() == XAxisPosition.BOTTOM_INSIDE // || mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { c.drawLine( mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom() * topchartScale, mViewPortHandler.contentRight(), mViewPortHandler.contentBottom() * topchartScale, mAxisLinePaint); float yoffset = mViewPortHandler.contentBottom() * 0.08f - Utils.convertDpToPixel(1); c.drawLine( mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom() * topchartScale + yoffset, mViewPortHandler.contentRight(), mViewPortHandler.contentBottom() * topchartScale + yoffset, mAxisLinePaint); c.drawLine( mViewPortHandler.contentLeft(), mViewPortHandler.contentBottom() - 1, mViewPortHandler.contentRight(), mViewPortHandler.contentBottom() - 1, mAxisLinePaint); // } }
@Override protected void drawValues() { // if values are drawn if (mDrawYValues) { float sliceangle = getSliceAngle(); // calculate the factor that is needed for transforming the value to // pixels float factor = getFactor(); PointF c = getCenterOffsets(); float yoffset = Utils.convertDpToPixel(5f); for (int i = 0; i < mCurrentData.getDataSetCount(); i++) { RadarDataSet dataSet = mCurrentData.getDataSetByIndex(i); ArrayList<Entry> entries = dataSet.getYVals(); for (int j = 0; j < entries.size(); j++) { Entry e = entries.get(j); PointF p = getPosition(c, e.getVal() * factor, sliceangle * j + mRotationAngle); if (mDrawUnitInChart) mDrawCanvas.drawText( mValueFormatter.getFormattedValue(e.getVal()) + mUnit, p.x, p.y - yoffset, mValuePaint); else mDrawCanvas.drawText( mValueFormatter.getFormattedValue(e.getVal()), p.x, p.y - yoffset, mValuePaint); } } } }
@Override public void renderAxisLabels(Canvas c) { if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled()) return; float yoffset = Utils.convertDpToPixel(4f); mAxisLabelPaint.setTypeface(mXAxis.getTypeface()); mAxisLabelPaint.setTextSize(mXAxis.getTextSize()); mAxisLabelPaint.setColor(mXAxis.getTextColor()); if (mXAxis.getPosition() == XAxisPosition.TOP) { drawLabels(c, mViewPortHandler.offsetTop() - yoffset); } else if (mXAxis.getPosition() == XAxisPosition.BOTTOM) { drawLabels( c, mViewPortHandler.contentBottom() * topchartScale + (mViewPortHandler.contentBottom() * 0.04f) + mXAxis.mLabelHeight / 2); } else if (mXAxis.getPosition() == XAxisPosition.BOTTOM_INSIDE) { drawLabels(c, mViewPortHandler.contentBottom() - yoffset); } else if (mXAxis.getPosition() == XAxisPosition.TOP_INSIDE) { drawLabels(c, mViewPortHandler.offsetTop() + yoffset + mXAxis.mLabelHeight); } else { // BOTH SIDED drawLabels(c, mViewPortHandler.offsetTop() - yoffset); drawLabels(c, mViewPortHandler.contentBottom() + mXAxis.mLabelHeight + yoffset * 1.6f); } }
/** * Sets the size of the center text of the PieChart in dp. * * @param sizeDp */ public void setCenterTextSize(float sizeDp) { ((PieChartRenderer) mRenderer).getPaintCenterText().setTextSize(Utils.convertDpToPixel(sizeDp)); }
@Override public void setHighlightCircleWidth(float width) { mHighlightCircleWidth = Utils.convertDpToPixel(width); }
@Override public void drawValues(Canvas c) { PointF center = mChart.getCenterCircleBox(); // get whole the radius float r = mChart.getRadius(); float rotationAngle = mChart.getRotationAngle(); float[] drawAngles = mChart.getDrawAngles(); float[] absoluteAngles = mChart.getAbsoluteAngles(); float phaseX = mAnimator.getPhaseX(); float phaseY = mAnimator.getPhaseY(); float off = r / 10f * 3.6f; if (mChart.isDrawHoleEnabled()) { off = (r - (r / 100f * mChart.getHoleRadius())) / 2f; } r -= off; // offset to keep things inside the chart PieData data = mChart.getData(); List<IPieDataSet> dataSets = data.getDataSets(); float yValueSum = data.getYValueSum(); boolean drawXVals = mChart.isDrawSliceTextEnabled(); float angle; int xIndex = 0; for (int i = 0; i < dataSets.size(); i++) { IPieDataSet dataSet = dataSets.get(i); if (!dataSet.isDrawValuesEnabled() && !drawXVals) continue; // apply the text-styling defined by the DataSet applyValueTextStyle(dataSet); float lineHeight = Utils.calcTextHeight(mValuePaint, "Q") + Utils.convertDpToPixel(4f); int entryCount = dataSet.getEntryCount(); for (int j = 0, maxEntry = Math.min((int) Math.ceil(entryCount * phaseX), entryCount); j < maxEntry; j++) { Entry entry = dataSet.getEntryForIndex(j); if (xIndex == 0) angle = 0.f; else angle = absoluteAngles[xIndex - 1] * phaseX; final float sliceAngle = drawAngles[xIndex]; final float sliceSpace = dataSet.getSliceSpace(); // offset needed to center the drawn text in the slice final float offset = (sliceAngle - sliceSpace / 2.f) / 2.f; angle = angle + offset; // calculate the text position float x = (float) (r * Math.cos(Math.toRadians(rotationAngle + angle)) + center.x); float y = (float) (r * Math.sin(Math.toRadians(rotationAngle + angle)) + center.y); float value = mChart.isUsePercentValuesEnabled() ? entry.getVal() / yValueSum * 100f : entry.getVal(); ValueFormatter formatter = dataSet.getValueFormatter(); boolean drawYVals = dataSet.isDrawValuesEnabled(); // draw everything, depending on settings if (drawXVals && drawYVals) { drawValue(c, formatter, value, entry, 0, x, y); if (j < data.getXValCount()) c.drawText(data.getXVals().get(j), x, y + lineHeight, mValuePaint); } else if (drawXVals) { if (j < data.getXValCount()) c.drawText(data.getXVals().get(j), x, y + lineHeight / 2f, mValuePaint); } else if (drawYVals) { drawValue(c, formatter, value, entry, 0, x, y + lineHeight / 2f); } xIndex++; } } }
/** * Sets the width of the candle-shadow-line in pixels. Default 3f. * * @param width */ public void setShadowWidth(float width) { mShadowWidth = Utils.convertDpToPixel(width); }
@Override protected void calculateOffsets() { float offsetLeft = 0f, offsetRight = 0f, offsetTop = 0f, offsetBottom = 0f; // setup offsets for legend if (mLegend != null && mLegend.isEnabled()) { if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART || mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART_CENTER) { offsetRight += Math.min( mLegend.mNeededWidth, mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) + mLegend.getXOffset() * 2f; } else if (mLegend.getPosition() == LegendPosition.LEFT_OF_CHART || mLegend.getPosition() == LegendPosition.LEFT_OF_CHART_CENTER) { offsetLeft += Math.min( mLegend.mNeededWidth, mViewPortHandler.getChartWidth() * mLegend.getMaxSizePercent()) + mLegend.getXOffset() * 2f; } else if (mLegend.getPosition() == LegendPosition.BELOW_CHART_LEFT || mLegend.getPosition() == LegendPosition.BELOW_CHART_RIGHT || mLegend.getPosition() == LegendPosition.BELOW_CHART_CENTER) { float yOffset = mLegend.mTextHeightMax * 2.f; // It's possible that we do not need this offset anymore as it is available // through the extraOffsets offsetBottom += Math.min( mLegend.mNeededHeight + yOffset, mViewPortHandler.getChartHeight() * mLegend.getMaxSizePercent()); } } // offsets for y-labels if (mAxisLeft.needsOffset()) { offsetTop += mAxisLeft.getRequiredHeightSpace(mAxisRendererLeft.getPaintAxisLabels()); } if (mAxisRight.needsOffset()) { offsetBottom += mAxisRight.getRequiredHeightSpace(mAxisRendererRight.getPaintAxisLabels()); } float xlabelwidth = mXAxis.mLabelWidth; if (mXAxis.isEnabled()) { // offsets for x-labels if (mXAxis.getPosition() == XAxisPosition.BOTTOM) { offsetLeft += xlabelwidth; } else if (mXAxis.getPosition() == XAxisPosition.TOP) { offsetRight += xlabelwidth; } else if (mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { offsetLeft += xlabelwidth; offsetRight += xlabelwidth; } } offsetTop += getExtraTopOffset(); offsetRight += getExtraRightOffset(); offsetBottom += getExtraBottomOffset(); offsetLeft += getExtraLeftOffset(); float min = Utils.convertDpToPixel(10f); mViewPortHandler.restrainViewPort( Math.max(min, offsetLeft), Math.max(min, offsetTop), Math.max(min, offsetRight), Math.max(min, offsetBottom)); if (mLogEnabled) { Log.i( LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); Log.i(LOG_TAG, "Content: " + mViewPortHandler.getContentRect().toString()); } prepareOffsetMatrix(); prepareValuePxMatrix(); }
/** * sets the space between the form and the actual label/text, converts to dp internally * * @param space */ public void setFormToTextSpace(float space) { this.mFormToTextSpace = Utils.convertDpToPixel(space); }
/** * 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); }
/** * Set an offset in dp that allows the user to drag the chart over it's bounds on the y-axis. * * @param offset */ public void setDragOffsetY(float offset) { mTransOffsetY = Utils.convertDpToPixel(offset); }
/** * Sets the width of the web lines that are in between the lines coming from the center. * * @param width */ public void setWebLineWidthInner(float width) { mInnerWebLineWidth = Utils.convertDpToPixel(width); }
/** * 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); }
/** Set an extra offset to be appended to the viewport's left */ public void setExtraLeftOffset(float offset) { mExtraLeftOffset = Utils.convertDpToPixel(offset); }
@Override protected void calculateOffsets() { float legendLeft = 0f, legendRight = 0f, legendBottom = 0f, legendTop = 0f; if (mLegend != null && mLegend.isEnabled()) { if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART_CENTER) { // this is the space between the legend and the chart float spacing = Utils.convertDpToPixel(13f); legendRight = getFullLegendWidth() + spacing; } else if (mLegend.getPosition() == LegendPosition.RIGHT_OF_CHART) { // this is the space between the legend and the chart float spacing = Utils.convertDpToPixel(8f); float legendWidth = getFullLegendWidth() + spacing; float legendHeight = mLegend.mNeededHeight + mLegend.mTextHeightMax; PointF c = getCenter(); PointF bottomRight = new PointF(getWidth() - legendWidth + 15, legendHeight + 15); float distLegend = distanceToCenter(bottomRight.x, bottomRight.y); PointF reference = getPosition(c, getRadius(), getAngleForPoint(bottomRight.x, bottomRight.y)); float distReference = distanceToCenter(reference.x, reference.y); float min = Utils.convertDpToPixel(5f); if (distLegend < distReference) { float diff = distReference - distLegend; legendRight = min + diff; } if (bottomRight.y >= c.y && getHeight() - legendWidth > getWidth()) { legendRight = legendWidth; } } else if (mLegend.getPosition() == LegendPosition.LEFT_OF_CHART_CENTER) { // this is the space between the legend and the chart float spacing = Utils.convertDpToPixel(13f); legendLeft = getFullLegendWidth() + spacing; } else if (mLegend.getPosition() == LegendPosition.LEFT_OF_CHART) { // this is the space between the legend and the chart float spacing = Utils.convertDpToPixel(8f); float legendWidth = getFullLegendWidth() + spacing; float legendHeight = mLegend.mNeededHeight + mLegend.mTextHeightMax; PointF c = getCenter(); PointF bottomLeft = new PointF(legendWidth - 15, legendHeight + 15); float distLegend = distanceToCenter(bottomLeft.x, bottomLeft.y); PointF reference = getPosition(c, getRadius(), getAngleForPoint(bottomLeft.x, bottomLeft.y)); float distReference = distanceToCenter(reference.x, reference.y); float min = Utils.convertDpToPixel(5f); if (distLegend < distReference) { float diff = distReference - distLegend; legendLeft = min + diff; } if (bottomLeft.y >= c.y && getHeight() - legendWidth > getWidth()) { legendLeft = legendWidth; } } else if (mLegend.getPosition() == LegendPosition.BELOW_CHART_LEFT || mLegend.getPosition() == LegendPosition.BELOW_CHART_RIGHT || mLegend.getPosition() == LegendPosition.BELOW_CHART_CENTER) { legendBottom = getRequiredBottomOffset(); } legendLeft += getRequiredBaseOffset(); legendRight += getRequiredBaseOffset(); legendTop += getRequiredBaseOffset(); } float min = Utils.convertDpToPixel(10f); float offsetLeft = Math.max(min, legendLeft); float offsetTop = Math.max(min, legendTop); float offsetRight = Math.max(min, legendRight); float offsetBottom = Math.max(min, Math.max(getRequiredBaseOffset(), legendBottom)); mViewPortHandler.restrainViewPort(offsetLeft, offsetTop, offsetRight, offsetBottom); if (mLogEnabled) Log.i( LOG_TAG, "offsetLeft: " + offsetLeft + ", offsetTop: " + offsetTop + ", offsetRight: " + offsetRight + ", offsetBottom: " + offsetBottom); }
/** * set the line width of the chart (min = 0.2f, max = 10f); default 1f NOTE: thinner line == * better performance, thicker line == worse performance * * @param width */ public void setLineWidth(float width) { if (width < 0.2f) width = 0.2f; if (width > 10.0f) width = 10.0f; mLineWidth = Utils.convertDpToPixel(width); }