@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))); }
/** * draws the x-labels on the specified y-position * * @param pos */ protected void drawLabels(Canvas c, float pos) { // pre allocate to save performance (dont allocate in loop) float[] position = new float[] {0f, 0f}; for (int i = mMinX; i <= mMaxX; i += mXAxis.mAxisLabelModulus) { position[0] = i; mTrans.pointValuesToPixel(position); if (mViewPortHandler.isInBoundsX(position[0])) { String label = mXAxis.getValues().get(i); if (mXAxis.isAvoidFirstLastClippingEnabled()) { // avoid clipping of the last if (i == mXAxis.getValues().size() - 1 && mXAxis.getValues().size() > 1) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); if (width > mViewPortHandler.offsetRight() * 2 && position[0] + width > mViewPortHandler.getChartWidth()) position[0] -= width / 2; // avoid clipping of the first } else if (i == 0) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); position[0] += width / 2; } } c.drawText(label, position[0], pos, mAxisLabelPaint); } } }
/** * This method sets the automatically computed colors for the legend. Use setCustom(...) to set * custom colors. * * @param colors */ public void setComputedColors(List<Integer> colors) { if (mColors != null && colors.size() == mColors.length) { Utils.copyIntegers(colors, mColors); } else { mColors = Utils.convertIntegers(colors); } }
/*设置量表对齐*/ private void setOffset() { float lineLeft = combinedchart.getViewPortHandler().offsetLeft(); float barLeft = barChart.getViewPortHandler().offsetLeft(); float lineRight = combinedchart.getViewPortHandler().offsetRight(); float barRight = barChart.getViewPortHandler().offsetRight(); float barBottom = barChart.getViewPortHandler().offsetBottom(); float offsetLeft, offsetRight; float transLeft = 0, transRight = 0; /*注:setExtraLeft...函数是针对图表相对位置计算,比如A表offLeftA=20dp,B表offLeftB=30dp,则A.setExtraLeftOffset(10),并不是30,还有注意单位转换*/ if (barLeft < lineLeft) { /* offsetLeft = Utils.convertPixelsToDp(lineLeft - barLeft); barChart.setExtraLeftOffset(offsetLeft);*/ transLeft = lineLeft; } else { offsetLeft = Utils.convertPixelsToDp(barLeft - lineLeft); combinedchart.setExtraLeftOffset(offsetLeft); transLeft = barLeft; } /*注:setExtraRight...函数是针对图表绝对位置计算,比如A表offRightA=20dp,B表offRightB=30dp,则A.setExtraLeftOffset(30),并不是10,还有注意单位转换*/ if (barRight < lineRight) { /* offsetRight = Utils.convertPixelsToDp(lineRight); barChart.setExtraRightOffset(offsetRight);*/ transRight = lineRight; } else { offsetRight = Utils.convertPixelsToDp(barRight); combinedchart.setExtraRightOffset(offsetRight); transRight = barRight; } barChart.setViewPortOffsets(transLeft, 15, transRight, barBottom); }
/** * This method sets the automatically computed labels for the legend. Use setCustom(...) to set * custom labels. * * @param labels */ public void setComputedLabels(List<String> labels) { if (mLabels != null && mLabels.length == labels.size()) { Utils.copyStrings(labels, mLabels); } else { mLabels = Utils.convertStrings(labels); } }
/** * Calculates the required maximum y-value in order to be able to provide the desired number of * label entries and rounded label values. */ private void prepareYLabels() { int labelCount = mYLabels.getLabelCount(); double range = mCurrentData.getYMax() - mYChartMin; double rawInterval = range / labelCount; double interval = Utils.roundToNextSignificant(rawInterval); double intervalMagnitude = Math.pow(10, (int) Math.log10(interval)); int intervalSigDigit = (int) (interval / intervalMagnitude); if (intervalSigDigit > 5) { // Use one order of magnitude higher, to avoid intervals like 0.9 or // 90 interval = Math.floor(10 * intervalMagnitude); } double first = Math.ceil(mYChartMin / interval) * interval; double last = Utils.nextUp(Math.floor(mCurrentData.getYMax() / interval) * interval); double f; int n = 0; for (f = first; f <= last; f += interval) { ++n; } mYLabels.mEntryCount = n; mYChartMax = (float) interval * n; // calc delta mDeltaY = Math.abs(mYChartMax - mYChartMin); }
/** * 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); } } } }
/** * Sets a custom legend's labels and colors arrays. The colors count should match the labels * count. * Each color is for the form drawn at the same index. * A null label will start a group. * * A ColorTemplate.COLOR_SKIP color will avoid drawing a form This will disable the feature that * automatically calculates the legend labels and colors from the datasets. Call resetCustom() to * re-enable automatic calculation (and then notifyDataSetChanged() is needed to auto-calculate * the legend again) */ public void setCustom(List<Integer> colors, List<String> labels) { if (colors.size() != labels.size()) { throw new IllegalArgumentException("colors array and labels array need to be of same size"); } mColors = Utils.convertIntegers(colors); mLabels = Utils.convertStrings(labels); mIsLegendCustom = true; }
/** * Colors and labels that will be appended to the end of the auto calculated colors and labels * arrays after calculating the legend. (if the legend has already been calculated, you will need * to call notifyDataSetChanged() to let the changes take effect) */ public void setExtra(List<Integer> colors, List<String> labels) { if (mExtraColors != null && mExtraColors.length == colors.size()) { Utils.copyIntegers(colors, mExtraColors); } else { this.mExtraColors = Utils.convertIntegers(colors); } if (mExtraLabels != null && mExtraLabels.length == labels.size()) { Utils.copyStrings(labels, mExtraLabels); } else { this.mExtraLabels = Utils.convertStrings(labels); } }
/** setup the x-axis labels */ private void prepareXLabels() { StringBuffer a = new StringBuffer(); int max = (int) Math.round(mCurrentData.getXValAverageLength()); for (int i = 0; i < max; i++) { a.append("h"); } mXLabels.mLabelWidth = Utils.calcTextWidth(mXLabelPaint, a.toString()); mXLabels.mLabelHeight = Utils.calcTextWidth(mXLabelPaint, "Q"); }
// callbacks everytime the MarkerView is redrawn, can be used to update the // content (user-interface) @Override public void refreshContent(Entry e, int dataSetIndex) { if (e instanceof CandleEntry) { CandleEntry ce = (CandleEntry) e; tvContent.setText("" + Utils.formatNumber(ce.getHigh(), 0, true)); } else { tvContent.setText("" + Utils.formatNumber(e.getVal(), 0, true)); } }
/** * Constructor. Provide colors and labels for the legend. * * @param colors * @param labels */ public Legend(List<Integer> colors, List<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.mLabels = Utils.convertStrings(labels); }
// callbacks everytime the MarkerView is redrawn, can be used to update the // content (user-interface) @Override public void refreshContent(Entry e, Highlight highlight) { if (e instanceof CandleEntry) { CandleEntry ce = (CandleEntry) e; tvContent.setText("" + Utils.formatNumber(ce.getHigh(), 0, true)); } else { tvContent.setText("" + Utils.formatNumber(e.getY(), 0, true)); } super.refreshContent(e, highlight); }
@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)); }
/** Draws the y-labels of the RadarChart. */ private void drawYLabels() { if (!mDrawYLabels) return; mYLabelPaint.setTypeface(mYLabels.getTypeface()); mYLabelPaint.setTextSize(mYLabels.getTextSize()); mYLabelPaint.setColor(mYLabels.getTextColor()); PointF c = getCenterOffsets(); float factor = getFactor(); int labelCount = mYLabels.mEntryCount; for (int j = 0; j < labelCount; j++) { if (j == labelCount - 1 && mYLabels.isDrawTopYLabelEntryEnabled() == false) break; float r = ((mYChartMax / labelCount) * j) * factor; PointF p = getPosition(c, r, mRotationAngle); float val = r / factor; String label = Utils.formatNumber(val, mYLabels.mDecimals, mYLabels.isSeparateThousandsEnabled()); if (mYLabels.isDrawUnitsInYLabelEnabled()) mDrawCanvas.drawText(label + mUnit, p.x + 10, p.y - 5, mYLabelPaint); else { mDrawCanvas.drawText(label, p.x + 10, p.y - 5, mYLabelPaint); } } }
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)); }
@Override public void renderAxisLabels(Canvas c) { if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled()) return; mAxisPaint.setTypeface(mXAxis.getTypeface()); mAxisPaint.setTextSize(mXAxis.getTextSize()); mAxisPaint.setColor(mXAxis.getTextColor()); float sliceangle = mChart.getSliceAngle(); // calculate the factor that is needed for transforming the value to // pixels float factor = mChart.getFactor(); PointF center = mChart.getCenterOffsets(); for (int i = 0; i < mXAxis.getValues().size(); i++) { String text = mXAxis.getValues().get(i); float angle = (sliceangle * i + mChart.getRotationAngle()) % 360f; PointF p = Utils.getPosition(center, mChart.getYRange() * factor + mXAxis.mLabelWidth / 2f, angle); c.drawText(text, p.x, p.y + mXAxis.mLabelHeight / 2f, mAxisPaint); } }
/** * 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)); }
/** * draws the x-labels on the specified y-position * * @param pos */ @Override protected void drawLabels(Canvas c, float pos) { // pre allocate to save performance (dont allocate in loop) float[] position = new float[] {0f, 0f}; BarData bd = mChart.getData(); int step = bd.getDataSetCount(); for (int i = mMinX; i <= mMaxX; i += mXAxis.mAxisLabelModulus) { position[0] = i * step + i * bd.getGroupSpace() + bd.getGroupSpace() / 2f; // consider groups (center label for each group) if (step > 1) { position[0] += ((float) step - 1f) / 2f; } mTrans.pointValuesToPixel(position); if (mViewPortHandler.isInBoundsX(position[0]) && i >= 0 && i < mXAxis.getValues().size()) { String label = mXAxis.getValues().get(i); int color = mXAxis.getTextColor(i); mAxisLabelPaint.setColor(color); if (mXAxis.isAvoidFirstLastClippingEnabled()) { // avoid clipping of the last if (i == mXAxis.getValues().size() - 1) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); if (width > mViewPortHandler.offsetRight() * 2 && position[0] + width > mViewPortHandler.getChartWidth()) position[0] -= width / 2; // avoid clipping of the first } else if (i == 0) { float width = Utils.calcTextWidth(mAxisLabelPaint, label); position[0] += width / 2; } } c.drawText(label, position[0], pos, mAxisLabelPaint); } } }
public void computeAxis(float xValAverageLength, List<String> xValues) { mAxisLabelPaint.setTypeface(mXAxis.getTypeface()); mAxisLabelPaint.setTextSize(mXAxis.getTextSize()); StringBuffer a = new StringBuffer(); int max = (int) Math.round(xValAverageLength + mXAxis.getSpaceBetweenLabels()); for (int i = 0; i < max; i++) { a.append("h"); } mXAxis.mLabelWidth = Utils.calcTextWidth(mAxisLabelPaint, a.toString()); mXAxis.mLabelHeight = Utils.calcTextHeight(mAxisLabelPaint, "Q"); mXAxis.setValues(xValues); }
/** 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)); }
@Override public int getIndexForAngle(float angle) { // take the current angle of the chart into consideration float a = Utils.getNormalizedAngle(angle - getRotationAngle()); for (int i = 0; i < mAbsoluteAngles.length; i++) { if (mAbsoluteAngles[i] > a) return i; } return -1; // return -1 if no index found }
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 protected void onDraw(Canvas canvas) { // super.onDraw(canvas); if (mData == null) { boolean hasText = !TextUtils.isEmpty(mNoDataText); boolean hasDescription = !TextUtils.isEmpty(mNoDataTextDescription); float line1height = hasText ? Utils.calcTextHeight(mInfoPaint, mNoDataText) : 0.f; float line2height = hasDescription ? Utils.calcTextHeight(mInfoPaint, mNoDataTextDescription) : 0.f; float lineSpacing = (hasText && hasDescription) ? (mInfoPaint.getFontSpacing() - line1height) : 0.f; // if no data, inform the user float y = (getHeight() - (line1height + lineSpacing + line2height)) / 2.f + line1height; if (hasText) { canvas.drawText(mNoDataText, getWidth() / 2, y, mInfoPaint); if (hasDescription) { y = y + line1height + lineSpacing; } } if (hasDescription) { canvas.drawText(mNoDataTextDescription, getWidth() / 2, y, mInfoPaint); } return; } if (!mOffsetsCalculated) { calculateOffsets(); mOffsetsCalculated = true; } }
/** * calculates the required number of digits for the values that might be drawn in the chart (if * enabled), and creates the default-value-formatter */ protected void calculateFormatter(float min, float max) { float reference = 0f; if (mData == null || mData.getXValCount() < 2) { reference = Math.max(Math.abs(min), Math.abs(max)); } else { reference = Math.abs(max - min); } int digits = Utils.getDecimals(reference); mDefaultFormatter = new DefaultValueFormatter(digits); }
/** * returns the maximum height in pixels across all legend labels * * @param p the paint object used for rendering the text * @return */ public float getMaximumEntryHeight(Paint p) { float max = 0f; for (int i = 0; i < mLabels.length; i++) { if (mLabels[i] != null) { float length = (float) Utils.calcTextHeight(p, mLabels[i]); if (length > max) max = length; } } return max; }
/** * returns the maximum length in pixels across all legend labels + formsize + formtotextspace * * @param p the paint object used for rendering the text * @return */ public float getMaximumEntryWidth(Paint p) { float max = 0f; for (int i = 0; i < mLabels.length; i++) { if (mLabels[i] != null) { float length = (float) Utils.calcTextWidth(p, mLabels[i]); if (length > max) max = length; } } return max + mFormSize + mFormToTextSpace; }