1. 程式人生 > >蛛網雷達圖

蛛網雷達圖


 
package com.example.edz.myapplication.cobweb;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.widget.Scroller; import com.example.edz.myapplication.R; import java.util.ArrayList;
import java.util.List; /** * Created by jiangzehui on 16/9/25. */ public class RxCobwebView extends View { private int center;//中心點 private float one_radius; //外層菱形圓半徑 private float distance;//多邊形之間的間距 private Rect str_rect;//字型矩形 private List<Paint> levelPaintList;//層級顏色 集合 private int
defalutSize = 300;//預設大小 private String[] mSpiderNames; private float[] mSpiderLevels; // 等級列表 private Paint rank_Paint;//各等級進度畫筆 private Paint mSpiderNamePaint;//字型畫筆 private Paint center_paint;//中心線畫筆 private int mSpiderMaxLevel;// 最大等級 private int mSpiderNumber;//蜘蛛數量 private List<ModelSpider> mSpiderList = new ArrayList<>(); private int mSpiderColor;//蛛網內部填充顏色 private int mSpiderRadiusColor;//蛛網半徑顏色 private int mSpiderLevelColor; // 蛛網等級填充的顏色 private int mSpiderLevelStrokeColor; // 蛛網等級描邊的顏色 private boolean mSpiderLevelStroke; // 是否使用蛛網等級的描邊 private float mSpiderLevelStrokeWidth; // 蛛網等級描邊的寬度 private boolean mSpiderRotate;//是否支援手勢旋轉 private int mSpiderNameSize; private GestureDetector mDetector; private Context mContext; private Scroller mScroller; private float mFlingPoint; private double mRotateOrientation; private double mPerimeter = 0; private double mRotateAngle; private PointF mPointCenter; public RxCobwebView(Context context) { this(context, null); } public RxCobwebView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RxCobwebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; initAttrs(attrs); initEvent(); } /** * dp轉px * * @param dpValue dp值 * @return px值 */ public int dp2px(float dpValue) { final float scale = mContext.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } private void initEvent() { defalutSize = dp2px(defalutSize); mSpiderNames = new String[]{"金錢", "能力", "美貌", "智慧", "交際", "口才"}; mSpiderLevels = new float[]{5.0f, 4.1f, 2.3f, 1.1f, 0.1f, 0.5f}; mSpiderList.clear(); for (int position = 0; position < mSpiderNames.length; position++) { mSpiderList.add(new ModelSpider(mSpiderNames[position], mSpiderLevels[position])); } mSpiderNumber = mSpiderList.size(); //初始化字型畫筆 mSpiderNamePaint = new Paint(); mSpiderNamePaint.setAntiAlias(true); mSpiderNamePaint.setColor(Color.BLACK); mSpiderNamePaint.setTextSize(mSpiderNameSize); str_rect = new Rect(); mSpiderNamePaint.getTextBounds(mSpiderList.get(0).getSpiderName(), 0, mSpiderList.get(0).getSpiderName().length(), str_rect); //初始化各等級進度畫筆 rank_Paint = new Paint(); rank_Paint.setAntiAlias(true); rank_Paint.setColor(Color.RED); rank_Paint.setStrokeWidth(8); rank_Paint.setStyle(Paint.Style.STROKE);//設定空心 initLevelPoints(); //初始化 蛛網半徑畫筆 center_paint = new Paint(); center_paint.setAntiAlias(true); center_paint.setColor(mSpiderRadiusColor); mScroller = new Scroller(mContext); mDetector = new GestureDetector(mContext, new GestureListener()); mDetector.setIsLongpressEnabled(false); } @Override public boolean onTouchEvent(MotionEvent event) { if (!mSpiderRotate) return super.onTouchEvent(event); return mDetector.onTouchEvent(event); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); int max = Math.max(Math.abs(x), Math.abs(y)); double rotateDis = CIRCLE_ANGLE * (Math.abs(max - mFlingPoint) / mPerimeter); double rotate = mRotateAngle; if (mRotateOrientation > 0) { rotate += rotateDis; } else if (mRotateOrientation < 0) { rotate -= rotateDis; } handleRotate(rotate); mFlingPoint = max; invalidate(); } } private double CIRCLE_ANGLE = 2 * Math.PI ; public double getNormalizedAngle(double angle) { while (angle < 0) angle += CIRCLE_ANGLE; return angle % CIRCLE_ANGLE; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mPointCenter = new PointF(w / 2, h / 2); } private void handleRotate() { rotate = getNormalizedAngle(rotate); Log.e("tag", "mRotateAngle2: " +mRotateAngle);//大概6.0為一圈 mRotateAngle =
rotate; invalidate(); } private void handleRotate(double rotate) { rotate = getNormalizedAngle(rotate); //rotate = getNormalizedAngle(rotate); Log.e("tag", "rotate: " +rotate); Log.e("tag", "mRotateAngle: " +mRotateAngle); mRotateAngle = 0.5; invalidate(); } /** * 修改顏色透明度 * * @param color * @param alpha * @return */ public static int changeColorAlpha(int color, int alpha) { int red = Color.red(color); int green = Color.green(color); int blue = Color.blue(color); return Color.argb(alpha, red, green, blue); } private void initAttrs(AttributeSet attrs) { TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.RxCobwebView);//獲得這個控制元件對應的屬性。 mSpiderColor = a.getColor(R.styleable.RxCobwebView_spiderColor, getResources().getColor(R.color.colorAccent));//蛛網內部顏色 mSpiderRadiusColor = a.getColor(R.styleable.RxCobwebView_spiderRadiusColor, Color.WHITE);//蛛網半徑顏色 mSpiderLevelStrokeColor = a.getColor(R.styleable.RxCobwebView_spiderLevelColor, getResources().getColor(R.color.custom_progress_orange_progress));//蛛網等級描邊顏色 mSpiderLevelColor = changeColorAlpha(mSpiderLevelStrokeColor, (255 / 2));//蛛網等級顏色 mSpiderLevelStroke = a.getBoolean(R.styleable.RxCobwebView_spiderLevelStroke, true);//是否需要 蛛網等級描邊 mSpiderRotate = a.getBoolean(R.styleable.RxCobwebView_spiderRotate, true);//是否需要 蛛網等級描邊 mSpiderLevelStrokeWidth = a.getFloat(R.styleable.RxCobwebView_spiderLevelStrokeWidth, 3f);//蛛網等級描邊 寬度 mSpiderMaxLevel = a.getInteger(R.styleable.RxCobwebView_spiderMaxLevel, 5);//蛛網最大層級數 mSpiderNameSize = a.getDimensionPixelSize(R.styleable.RxCobwebView_spiderNameSize, dp2px(16));//標題字型大小 a.recycle(); } private void initLevelPoints() { levelPaintList = new ArrayList<>(); //初始化 N 層多邊形畫筆 for (int i = mSpiderMaxLevel; i > 0; i--) { Paint paint = new Paint(); paint.setAntiAlias(true); int scale = mSpiderMaxLevel * 10 / 11; if (scale < 1) { scale = 1; } paint.setColor(changeColorAlpha(mSpiderColor, (255 / (mSpiderMaxLevel + 1) * (mSpiderMaxLevel - i - 1) + 255 / scale) % 255)); paint.setStyle(Paint.Style.FILL);//設定實心 levelPaintList.add(paint); } } @Override protected void onDraw(Canvas canvas) { drawSpiderName(canvas); for (int position = 0; position < mSpiderMaxLevel; position++) { drawCobweb(canvas, position); } //drawSpiderRadiusLine(canvas); drawSpiderLevel(canvas); } /** * 繪製等級進度 */ private void drawSpiderLevel(Canvas canvas) { Path path = new Path(); float nextAngle; float nextRadians; float nextPointX; float nextPointY; float currentRadius; float averageAngle = 360 / mSpiderNumber; float offsetAngle = averageAngle > 0 && mSpiderNumber % 2 == 0 ? averageAngle / 2 : 0; for (int position = 0; position < mSpiderNumber; position++) { float scale = (mSpiderList.get(position).getSpiderLevel() / mSpiderMaxLevel); if (scale >= 1) { scale = 1; } currentRadius = scale * one_radius; nextAngle = offsetAngle + (position * averageAngle); nextRadians = (float) Math.toRadians(nextAngle); nextPointX = (float) (center + Math.sin(nextRadians - mRotateAngle) * currentRadius); nextPointY = (float) (center - Math.cos(nextRadians - mRotateAngle) * currentRadius); if (position == 0) { path.moveTo(nextPointX, nextPointY); } else { path.lineTo(nextPointX, nextPointY); } } Paint scorePaint = new Paint(); scorePaint.setColor(mSpiderLevelColor); scorePaint.setStyle(Paint.Style.FILL_AND_STROKE); scorePaint.setAntiAlias(true); path.close(); canvas.drawPath(path, scorePaint); Paint scoreStrokePaint = null; // 繪製描邊 if (mSpiderLevelStroke) { if (scoreStrokePaint == null) { scoreStrokePaint = new Paint(); scoreStrokePaint.setColor(mSpiderLevelStrokeColor); scoreStrokePaint.setStyle(Paint.Style.STROKE); scoreStrokePaint.setAntiAlias(true); if (mSpiderLevelStrokeWidth > 0) { scoreStrokePaint.setStrokeWidth(mSpiderLevelStrokeWidth); } } canvas.drawPath(path, scoreStrokePaint); } } /** * 繪製字型 * * @param canvas */ private void drawSpiderName(Canvas canvas) { float nextAngle;//下一個轉角 float nextRadians;//下一個弧度 float nextPointX;//下一個X點 float nextPointY;//下一個Y點 float currentRadius;//目前的半徑 float averageAngle = 360 / mSpiderNumber;//蜘蛛數量 float offsetAngle = averageAngle > 0 && mSpiderNumber % 2 == 0 ? averageAngle / 2 : 0;//偏移角 for (int position = 0; position < mSpiderNumber; position++) { currentRadius = (float) (getPaddingTop() + str_rect.height()) + one_radius; nextAngle = offsetAngle + (position * averageAngle); nextRadians = (float) Math.toRadians(nextAngle); String text = mSpiderList.get(position).getSpiderName(); float textWidth = mSpiderNamePaint.measureText(text); Paint.FontMetrics fontMetrics = mSpiderNamePaint.getFontMetrics(); float textHeight = fontMetrics.descent - fontMetrics.ascent; nextPointX = (float) (center + Math.sin(nextRadians - mRotateAngle) * currentRadius - textWidth / 2); nextPointY = (float) (center - Math.cos(nextRadians - mRotateAngle) * currentRadius + textHeight / 4); canvas.drawText(text, nextPointX, nextPointY, mSpiderNamePaint); } mPerimeter = 2 * Math.PI * one_radius; } /** * //繪製層級蛛網 * * @param canvas */ private void drawCobweb(Canvas canvas, int index) { Path path = new Path(); float nextAngle; float nextRadians; float nextPointX; float nextPointY; float currentRadius; float averageAngle = 360 / mSpiderNumber; float offsetAngle = averageAngle > 0 && mSpiderNumber % 2 == 0 ? averageAngle / 2 : 0; for (int position = 0; position < mSpiderNumber; position++) { currentRadius = (index + 1) * one_radius / mSpiderMaxLevel; nextAngle = offsetAngle + (position * averageAngle); nextRadians = (float) Math.toRadians(nextAngle); nextPointX = (float) (center + Math.sin(nextRadians - mRotateAngle) * currentRadius); nextPointY = (float) (center - Math.cos(nextRadians - mRotateAngle) * currentRadius); if (position == 0) { path.moveTo(nextPointX, nextPointY); } else { path.lineTo(nextPointX, nextPointY); } } path.close(); //canvas.drawPath(path, levelPaintList.get(mSpiderMaxLevel - index - 1)); Paint scoreStrokePaint = null; // 繪製描邊 if (mSpiderLevelStroke) { if (scoreStrokePaint == null) { scoreStrokePaint = new Paint(); scoreStrokePaint.setColor(changeColorAlpha(levelPaintList.get(mSpiderMaxLevel - 1).getColor(), 50)); scoreStrokePaint.setStyle(Paint.Style.STROKE); scoreStrokePaint.setAntiAlias(true); if (mSpiderLevelStrokeWidth > 0) { scoreStrokePaint.setStrokeWidth(mSpiderLevelStrokeWidth); } } canvas.drawPath(path, scoreStrokePaint); } } /** * 繪製連線中心的線 * * @param canvas Canvas */ private void drawSpiderRadiusLine(Canvas canvas) { float nextAngle; float nextRadians; float nextPointX; float nextPointY; float averageAngle = 360 / mSpiderNumber; float offsetAngle = averageAngle > 0 && mSpiderNumber % 2 == 0 ? averageAngle / 2 : 0; for (int position = 0; position < mSpiderNumber; position++) { nextAngle = offsetAngle + (position * averageAngle); nextRadians = (float) Math.toRadians(nextAngle); nextPointX = (float) (center + Math.sin(nextRadians - mRotateAngle) * one_radius); nextPointY = (float) (center - Math.cos(nextRadians - mRotateAngle) * one_radius); canvas.drawLine(center, center, nextPointX, nextPointY, center_paint); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int wMode = MeasureSpec.getMode(widthMeasureSpec); int wSize = MeasureSpec.getSize(widthMeasureSpec); int hMode = MeasureSpec.getMode(heightMeasureSpec); int hSize = MeasureSpec.getSize(heightMeasureSpec); int width, height; if (wMode == MeasureSpec.EXACTLY) { width = wSize; } else { width = Math.min(wSize, defalutSize); } if (hMode == MeasureSpec.EXACTLY) { height = hSize; } else { height = Math.min(hSize, defalutSize); } center = width / 2;//中心點 one_radius = center - getPaddingTop() - 2 * str_rect.height(); setMeasuredDimension(width, height); handleRotate(); } public int getSpiderMaxLevel() { return mSpiderMaxLevel; } public void setSpiderMaxLevel(int spiderMaxLevel) { mSpiderMaxLevel = spiderMaxLevel; initLevelPoints(); invalidate(); } public List<ModelSpider> getSpiderList() { return mSpiderList; } public void setSpiderList(@NonNull List<ModelSpider> spiderList) { mSpiderList = spiderList; mSpiderNumber = mSpiderList.size(); invalidate(); } public int getSpiderColor() { return mSpiderColor; } public void setSpiderColor(int spiderColor) { mSpiderColor = spiderColor; initLevelPoints(); invalidate(); } public int getSpiderRadiusColor() { return mSpiderRadiusColor; } public void setSpiderRadiusColor(int spiderRadiusColor) { mSpiderRadiusColor = spiderRadiusColor; invalidate(); } public int getSpiderLevelColor() { return mSpiderLevelStrokeColor; } public void setSpiderLevelColor(int spiderLevelColor) { mSpiderLevelStrokeColor = spiderLevelColor; mSpiderLevelColor = changeColorAlpha(mSpiderLevelStrokeColor, (255 / 2)); invalidate(); } public boolean isSpiderLevelStroke() { return mSpiderLevelStroke; } public void setSpiderLevelStroke(boolean spiderLevelStroke) { mSpiderLevelStroke = spiderLevelStroke; invalidate(); } public float getSpiderLevelStrokeWidth() { return mSpiderLevelStrokeWidth; } public void setSpiderLevelStrokeWidth(float spiderLevelStrokeWidth) { mSpiderLevelStrokeWidth = spiderLevelStrokeWidth; invalidate(); } public int getSpiderNameSize() { return mSpiderNameSize; } public void setSpiderNameSize(int spiderNameSize) { mSpiderNameSize = spiderNameSize; invalidate(); } public class ModelSpider { private String spiderName; private float spiderLevel; public ModelSpider(String spiderName, float spiderLevel) { this.spiderName = spiderName; this.spiderLevel = spiderLevel; } public String getSpiderName() { return spiderName; } public void setSpiderName(String spiderName) { this.spiderName = spiderName; } public float getSpiderLevel() { return spiderLevel; } public void setSpiderLevel(float spiderLevel) { this.spiderLevel = spiderLevel; } } private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { if (!mScroller.isFinished()) { mScroller.forceFinished(true); } return true; } //猛扔 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.e("tag", "onFling: " ); if (Math.abs(velocityX) > Math.abs(velocityY)) { mFlingPoint = e2.getX(); mScroller.fling((int) e2.getX(), 0, (int) velocityX, 0, (int) (-mPerimeter + e2.getX()), (int) (mPerimeter + e2.getX()), 0, 0); } else if (Math.abs(velocityY) > Math.abs(velocityX)) { mFlingPoint = e2.getY(); mScroller.fling(0, (int) e2.getY(), 0, (int) velocityY, 0, 0, (int) (-mPerimeter + e2.getY()), (int) (mPerimeter + e2.getY())); } invalidate(); return super.onFling(e1, e2, velocityX, velocityY); } public double getRotateAngle(PointF p1, PointF p2, PointF mPointCenter) { Log.e("tag", "getRotateAngle: " ); int q1 = getQuadrant(p1, mPointCenter); int q2 = getQuadrant(p2, mPointCenter); double angle1 = getAngle(p1, mPointCenter); double angle2 = getAngle(p2, mPointCenter); if (q1 == q2) { return angle1 - angle2; } else { return 0; } } public double getAngle(PointF p, PointF mPointCenter) { Log.e("tag", "getAngle: " ); float x = p.x - mPointCenter.x; float y = mPointCenter.y - p.y; double angle = Math.atan(y / x); return getNormalizedAngle(angle); } public int getQuadrant(PointF p, PointF mPointCenter) { Log.e("tag", "getQuadrant: " ); float x = p.x; float y = p.y; if (x > mPointCenter.x) { if (y > mPointCenter.y) { return 4; } else if (y < mPointCenter.y) { return 1; } } else if (x < mPointCenter.x) { if (y > mPointCenter.y) { return 3; } else if (y < mPointCenter.y) { return 2; } } return -1; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.e("tag", "onScroll: " ); double rotate = mRotateAngle; double dis = getRotateAngle(new PointF(e2.getX() - distanceX, e2.getY() - distanceY) , new PointF(e2.getX(), e2.getY()), mPointCenter); rotate += dis; handleRotate(rotate); mRotateOrientation = dis; return super.onScroll(e1, e2, distanceX, distanceY); } } }