介绍一中比较简单实现多区间多颜色折线图实现方式

介绍一中比较简单实现多区间多颜色折线图实现方式

首页休闲益智one color更新时间:2024-06-23

前面介绍过一种实现不同区间不同颜色的方案,在手机上使用看不出什么问题,但是在大平板上使用的时候在颜色变换点的位置有一个断口。现在分享另一种实现方式,相对更简单一些。主要思路是将不同颜色区间的画板进行拆分。

废话不多说,直接上代码,下面这个是对LineChartRenderer的重写:

package com.example.myjavaandroid.view; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import com.github.mikephil.charting.animation.ChartAnimator; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider; import com.github.mikephil.charting.interfaces.datasets.IDataSet; import com.github.mikephil.charting.interfaces.datasets.ILineDataSet; import com.github.mikephil.charting.renderer.LineChartRenderer; import com.github.mikephil.charting.utils.ColorTemplate; import com.github.mikephil.charting.utils.Transformer; import com.github.mikephil.charting.utils.ViewPortHandler; import java.util.HashMap; import java.util.List; public class MyLineChartRenderer extends LineChartRenderer { private float yMin = -20f; private float yMax = 20f; private String label = "cyLineChart"; public MyLineChartRenderer(LineDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) { super(chart, animator, viewPortHandler); mChart = chart; mCirclePaintInner = new Paint(Paint.ANTI_ALIAS_FLAG); mCirclePaintInner.setStyle(Paint.Style.FILL); mCirclePaintInner.setColor(Color.WHITE); } @Override protected void drawDataSet(Canvas c, ILineDataSet dataSet) { if (dataSet.getEntryCount() < 1) return; mRenderPaint.setStrokeWidth(dataSet.getLineWidth()); mRenderPaint.setPathEffect(dataSet.getDashPathEffect()); switch (dataSet.getMode()) { default: case LINEAR: case STEPPED: if (dataSet.getLabel() == label) { drawSplitLinear(c, dataSet); } else { drawLinear(c, dataSet); } break; case CUBIC_BEZIER: drawCubicBezier(dataSet); break; case HORIZONTAL_BEZIER: drawHorizontalBezier(dataSet); break; } mRenderPaint.setPathEffect(null); } private float[] mLineBuffer = new float[4]; private void drawSplitLinear(Canvas c, ILineDataSet dataSet) { int entryCount = dataSet.getEntryCount(); final boolean isDrawSteppedEnabled = dataSet.isDrawSteppedEnabled(); final int pointsPerEntryPair = isDrawSteppedEnabled ? 4 : 2; Transformer trans = mChart.getTransformer(dataSet.getAxisDependency()); float phaseY = mAnimator.getPhaseY(); mRenderPaint.setStyle(Paint.Style.STROKE); Canvas canvas = null; // if the data-set is dashed, draw on bitmap-canvas if (dataSet.isDashedLineEnabled()) { canvas = mBitmapCanvas; } else { canvas = c; } mXBounds.set(mChart, dataSet); // if drawing filled is enabled if (dataSet.isDrawFilledEnabled() && entryCount > 0) { drawLinearFill(c, dataSet, trans, mXBounds); } // more than 1 color if (dataSet.getColors().size() > 1) { if (mLineBuffer.length <= pointsPerEntryPair * 2) mLineBuffer = new float[pointsPerEntryPair * 4]; for (int j = mXBounds.min; j <= mXBounds.range mXBounds.min; j ) { Entry e = dataSet.getEntryForIndex(j); if (e == null) continue; mLineBuffer[0] = e.getX(); mLineBuffer[1] = e.getY() * phaseY; if (j < mXBounds.max) { e = dataSet.getEntryForIndex(j 1); if (e == null) break; if (isDrawSteppedEnabled) { mLineBuffer[2] = e.getX(); mLineBuffer[3] = mLineBuffer[1]; mLineBuffer[4] = mLineBuffer[2]; mLineBuffer[5] = mLineBuffer[3]; mLineBuffer[6] = e.getX(); mLineBuffer[7] = e.getY() * phaseY; } else { mLineBuffer[2] = e.getX(); mLineBuffer[3] = e.getY() * phaseY; } } else { mLineBuffer[2] = mLineBuffer[0]; mLineBuffer[3] = mLineBuffer[1]; } trans.pointValuesToPixel(mLineBuffer); if (!mViewPortHandler.isInBoundsRight(mLineBuffer[0])) break; // make sure the lines don't do shitty things outside // bounds if (!mViewPortHandler.isInBoundsLeft(mLineBuffer[2]) || (!mViewPortHandler.isInBoundsTop(mLineBuffer[1]) && !mViewPortHandler .isInBoundsBottom(mLineBuffer[3]))) continue; // get the color that is set for this line-segment mRenderPaint.setColor(dataSet.getColor(j)); canvas.drawLines(mLineBuffer, 0, pointsPerEntryPair * 2, mRenderPaint); } } else { // only one color per dataset if (mLineBuffer.length < Math.max((entryCount) * pointsPerEntryPair, pointsPerEntryPair) * 2) mLineBuffer = new float[Math.max((entryCount) * pointsPerEntryPair, pointsPerEntryPair) * 4]; Entry e1, e2; e1 = dataSet.getEntryForIndex(mXBounds.min); if (e1 != null) { int j = 0; for (int x = mXBounds.min; x <= mXBounds.range mXBounds.min; x ) { e1 = dataSet.getEntryForIndex(x == 0 ? 0 : (x - 1)); e2 = dataSet.getEntryForIndex(x); if (e1 == null || e2 == null) continue; mLineBuffer[j ] = e1.getX(); mLineBuffer[j ] = e1.getY() * phaseY; if (isDrawSteppedEnabled) { mLineBuffer[j ] = e2.getX(); mLineBuffer[j ] = e1.getY() * phaseY; mLineBuffer[j ] = e2.getX(); mLineBuffer[j ] = e1.getY() * phaseY; } mLineBuffer[j ] = e2.getX(); mLineBuffer[j ] = e2.getY() * phaseY; } if (j > 0) { trans.pointValuesToPixel(mLineBuffer); for (YArea yarea : YArea.values()) { int saveId = canvas.save(); float top = (1 - ((yarea.max > yMax ? yMax : yarea.max) - yMin) / (yMax - yMin)) * mViewPortHandler.getChartHeight(); float bottom = (1 - ((yarea.min < yMin ? yMin : yarea.min) - yMin) / (yMax - yMin)) * mViewPortHandler.getChartHeight(); mRenderPaint.setColor(yarea.color); final int size = Math.max((mXBounds.range 1) * pointsPerEntryPair, pointsPerEntryPair) * 2; canvas.clipRect(new Rect(0, (int) top, (int) mViewPortHandler.getChartWidth(), (int) bottom)); mRenderPaint.setColor(yarea.color); canvas.drawLines(mLineBuffer, 0, size, mRenderPaint); canvas.restoreToCount(saveId); } } } } mRenderPaint.setPathEffect(null); } //在这里控制不同区间的颜色,如果这个要经常标动的话,可以作为入参传入,可以提高通用性 private enum YArea { LOW(-30, -4, Color.parseColor("#07A1F1")), MEDIUM_LOW(-4, 2, Color.parseColor("#FF000000")), MEDIUM(2, 8, Color.parseColor("#FFBB86FC")), MEDIUM_HIGH(8, 16, Color.parseColor("#FF3700B3")), HIGH(16, 50, Color.parseColor("#BC133A")); private float min; private float max; private int color; YArea(float min, float max, int color) { this.min = min; this.max = max; this.color = color; } } private HashMap<IDataSet, DataSetImageCache> mImageCaches = new HashMap<>(); private float[] mCirclesBuffer = new float[2]; @Override protected void drawCircles(Canvas c) { mRenderPaint.setStyle(Paint.Style.FILL); float phaseY = mAnimator.getPhaseY(); mCirclesBuffer[0] = 0; mCirclesBuffer[1] = 0; List<ILineDataSet> dataSets = mChart.getLineData().getDataSets(); for (int i = 0; i < dataSets.size(); i ) { ILineDataSet dataSet = dataSets.get(i); if (!dataSet.isVisible() || !dataSet.isDrawCirclesEnabled() || dataSet.getEntryCount() == 0) continue; mCirclePaintInner.setColor(dataSet.getCircleHoleColor()); Transformer trans = mChart.getTransformer(dataSet.getAxisDependency()); mXBounds.set(mChart, dataSet); float circleRadius = dataSet.getCircleRadius(); float circleHoleRadius = dataSet.getCircleHoleRadius(); boolean drawCircleHole = dataSet.isDrawCircleHoleEnabled() && circleHoleRadius < circleRadius && circleHoleRadius > 0.f; boolean drawTransparentCircleHole = drawCircleHole && dataSet.getCircleHoleColor() == ColorTemplate.COLOR_NONE; DataSetImageCache imageCache; if (mImageCaches.containsKey(dataSet)) { imageCache = mImageCaches.get(dataSet); } else { imageCache = new DataSetImageCache(); mImageCaches.put(dataSet, imageCache); } boolean changeRequired = imageCache.init(dataSet); // only fill the cache with new bitmaps if a change is required if (changeRequired) { imageCache.fill(dataSet, drawCircleHole, drawTransparentCircleHole); } int boundsRangeCount = mXBounds.range mXBounds.min; for (int j = mXBounds.min; j <= boundsRangeCount; j ) { Entry e = dataSet.getEntryForIndex(j); if (e == null) break; mCirclesBuffer[0] = e.getX(); mCirclesBuffer[1] = e.getY() * phaseY; trans.pointValuesToPixel(mCirclesBuffer); if (!mViewPortHandler.isInBoundsRight(mCirclesBuffer[0])) break; if (!mViewPortHandler.isInBoundsLeft(mCirclesBuffer[0]) || !mViewPortHandler.isInBoundsY(mCirclesBuffer[1])) continue; Bitmap circleBitmap = imageCache.getBitmap(j); for (YArea yArea : YArea.values()) { if (yArea.min < e.getY() && yArea.max >= e.getY()) { mRenderPaint.setColor(yArea.color); break; } } if (circleBitmap != null) { c.drawCircle(mCirclesBuffer[0], mCirclesBuffer[1], dataSet.getCircleRadius(), mRenderPaint); } } } } private class DataSetImageCache { private Path mCirclePathBuffer = new Path(); private Bitmap[] circleBitmaps; /** * Sets up the cache, returns true if a change of cache was required. * * @param set * @return */ protected boolean init(ILineDataSet set) { int size = set.getCircleColorCount(); boolean changeRequired = false; if (circleBitmaps == null) { circleBitmaps = new Bitmap[size]; changeRequired = true; } else if (circleBitmaps.length != size) { circleBitmaps = new Bitmap[size]; changeRequired = true; } return changeRequired; } /** * Fills the cache with bitmaps for the given dataset. * * @param set * @param drawCircleHole * @param drawTransparentCircleHole */ protected void fill(ILineDataSet set, boolean drawCircleHole, boolean drawTransparentCircleHole) { int colorCount = set.getCircleColorCount(); float circleRadius = set.getCircleRadius(); float circleHoleRadius = set.getCircleHoleRadius(); for (int i = 0; i < colorCount; i ) { Bitmap.Config conf = Bitmap.Config.ARGB_4444; Bitmap circleBitmap = Bitmap.createBitmap((int) (circleRadius * 2.1), (int) (circleRadius * 2.1), conf); Canvas canvas = new Canvas(circleBitmap); circleBitmaps[i] = circleBitmap; mRenderPaint.setColor(set.getCircleColor(i)); if (drawTransparentCircleHole) { // Begin path for circle with hole mCirclePathBuffer.reset(); mCirclePathBuffer.addCircle( circleRadius, circleRadius, circleRadius, Path.Direction.CW); // Cut hole in path mCirclePathBuffer.addCircle( circleRadius, circleRadius, circleHoleRadius, Path.Direction.CCW); // Fill in-between canvas.drawPath(mCirclePathBuffer, mRenderPaint); } else { canvas.drawCircle( circleRadius, circleRadius, circleRadius, mRenderPaint); if (drawCircleHole) { canvas.drawCircle( circleRadius, circleRadius, circleHoleRadius, mCirclePaintInner); } } } } /** * Returns the cached Bitmap at the given index. * * @param index * @return */ protected Bitmap getBitmap(int index) { return circleBitmaps[index % circleBitmaps.length]; } } }

在view部分将MyLineChartRenderer设置给LineChart:

package com.example.myjavaandroid.fragment; import android.content.Context; import android.os.Bundle; import androidx.databinding.DataBindingUtil; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.example.myjavaandroid.R; import com.example.myjavaandroid.databinding.FragmentLineChartBinding; import com.example.myjavaandroid.view.MyLineChartRenderer; import com.github.mikephil.charting.charts.LineChart; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineDataSet; import java.util.ArrayList; import java.util.List; public class LineChartFragment extends Fragment { private Context mContext; private static LineChartFragment instance; private FragmentLineChartBinding binding; private LineChartFragment(Context context) { mContext = context; } public static LineChartFragment getInstance(Context context) { if (instance == null) { instance = new LineChartFragment(context); } return instance; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = DataBindingUtil.inflate(inflater, R.layout.fragment_line_chart, null, false); initData(); initView(); return binding.getRoot(); } privatevoidinitData(){ ...... } private void initView() { LineChart lineChart = binding.lineChart; lineChart.setScaleEnabled(false); lineChart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM); //将lineChart的LineChartRenderer设置为重写的MyLineChartRenderer lineChart.setRenderer(new MyLineChartRenderer(lineChart, lineChart.getAnimator(), lineChart.getViewPortHandler())); lineChart.getAxisLeft().setAxisMinimum(-20f); lineChart.getAxisLeft().setAxisMaximum(20f); } }

​这种实现方式更容易理解和使用,重写的内容也相对少一些​。

​ ​最后的效果是这样的​:

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved