├── .gitignore
├── .idea
├── caches
│ └── build_file_checksums.ser
├── codeStyles
│ └── Project.xml
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── markdown-navigator
│ └── profiles_settings.xml
├── misc.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── wangshijia
│ │ └── www
│ │ └── radachartview
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── wangshijia
│ │ │ └── www
│ │ │ └── radachartview
│ │ │ └── MainActivity.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── wangshijia
│ └── www
│ └── radachartview
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── radarchartview
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── wangshijia
│ │ └── www
│ │ └── radarchartview
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── wangshijia
│ │ │ └── www
│ │ │ └── radarchartview
│ │ │ └── RadarChartView.java
│ └── res
│ │ └── values
│ │ ├── radar_attrs.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── wangshijia
│ └── www
│ └── radarchartview
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | .externalNativeBuild
11 |
--------------------------------------------------------------------------------
/.idea/caches/build_file_checksums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/.idea/caches/build_file_checksums.ser
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RadaChartView
2 | 一个可定制的雷达网状图
3 |
4 | **效果图如下:**
5 |
6 |   
7 |
8 | ```
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | ```
47 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | */build
7 | /captures
8 | .bin
9 | local.properties
10 | build/
11 | gradle/
12 |
13 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | applicationId "com.wangshijia.www.radachartview"
7 | minSdkVersion 21
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | buildToolsVersion '27.0.3'
20 | compileOptions {
21 | sourceCompatibility JavaVersion.VERSION_1_8
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | }
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(include: ['*.jar'], dir: 'libs')
28 | implementation 'com.android.support.constraint:constraint-layout:1.1.2'
29 | testImplementation 'junit:junit:4.12'
30 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
31 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
32 | implementation 'com.android.support:appcompat-v7:27.1.1'
33 | implementation project(':radarchartview')
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/wangshijia/www/radachartview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radachartview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.wangshijia.www.radachartview", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/wangshijia/www/radachartview/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radachartview;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.widget.SeekBar;
6 |
7 | import com.wangshijia.www.radarchartview.RadarChartView;
8 |
9 |
10 | public class MainActivity extends AppCompatActivity {
11 |
12 | private RadarChartView radarChartView;
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.activity_main);
18 | radarChartView = findViewById(R.id.radarCharView);
19 | // radarCharView.setDefaultShader(Color.parseColor("#ff8f4c"), Color.parseColor("#ff4c51"));
20 | radarChartView.addValues("市场", 60);
21 | radarChartView.addValues("题材", 60);
22 | radarChartView.addValues("财务", 60);
23 | radarChartView.addValues("主力", 60);
24 | radarChartView.addValues("技术", 60);
25 | radarChartView.addValues("技术1", 60);
26 | radarChartView.addValues("技术2", 60);
27 | radarChartView.addValues("技术3", 60);
28 | radarChartView.addValues("技术4", 60);
29 | radarChartView.invalidate();
30 |
31 | final SeekBar seekBar = findViewById(R.id.seekBar);
32 | final SeekBar seekBar1 = findViewById(R.id.seekBar1);
33 | seekBar1.setMax(30);
34 | seekBar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
35 | @Override
36 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
37 | updateSum(progress);
38 | }
39 |
40 | @Override
41 | public void onStartTrackingTouch(SeekBar seekBar) {
42 |
43 | }
44 |
45 | @Override
46 | public void onStopTrackingTouch(SeekBar seekBar) {
47 |
48 | }
49 | });
50 | seekBar.setMax(30);
51 | seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
52 | @Override
53 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
54 | updateData((int) (progress));
55 | }
56 |
57 | @Override
58 | public void onStartTrackingTouch(SeekBar seekBar) {
59 |
60 | }
61 |
62 | @Override
63 | public void onStopTrackingTouch(SeekBar seekBar) {
64 |
65 | }
66 | });
67 | }
68 |
69 | private void updateSum(int progress) {
70 | radarChartView.setSideNum(progress);
71 | }
72 |
73 | private void updateData(int size) {
74 | radarChartView.clear();
75 | for (int i = 0; i < size; i++) {
76 | radarChartView.addValues("Text" + i, 60);
77 | }
78 | radarChartView.invalidate();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
35 |
36 |
37 |
47 |
48 |
59 |
60 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RadaChartView
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/wangshijia/www/radachartview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radachartview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.3'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ImportEffort/RadaChartView/d9bd63f7883b2036d9c62f82dc45c1640dae67d3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Jul 19 11:25:04 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/radarchartview/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/radarchartview/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 27
5 |
6 | defaultConfig {
7 | minSdkVersion 21
8 | targetSdkVersion 27
9 | versionCode 1
10 | versionName "1.0"
11 |
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 |
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 |
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | compileOnly 'com.android.support:appcompat-v7:27.1.1'
28 | testImplementation 'junit:junit:4.12'
29 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
30 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
31 | }
32 |
--------------------------------------------------------------------------------
/radarchartview/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/radarchartview/src/androidTest/java/com/wangshijia/www/radarchartview/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radarchartview;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.wangshijia.www.radarchartview.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/radarchartview/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/radarchartview/src/main/java/com/wangshijia/www/radarchartview/RadarChartView.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radarchartview;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.LinearGradient;
8 | import android.graphics.Paint;
9 | import android.graphics.Path;
10 | import android.graphics.PointF;
11 | import android.graphics.Shader;
12 | import android.support.annotation.NonNull;
13 | import android.support.annotation.Nullable;
14 | import android.util.AttributeSet;
15 | import android.view.View;
16 |
17 | import java.util.HashMap;
18 | import java.util.Iterator;
19 | import java.util.LinkedHashMap;
20 | import java.util.Map;
21 |
22 | /***
23 | * 自定义网格雷达View
24 | * @author wangshijia 编辑于 2018/7/19
25 | */
26 | public class RadarChartView extends View {
27 |
28 | /**
29 | * 多边形边个数
30 | */
31 | private int sideNum = 5;
32 | /**
33 | * 刻度绘制网格圈的个数
34 | */
35 | private int gridNum = 4;
36 | /**
37 | * 360 / sideNum 得出的每一份的角度
38 | */
39 | private double angle;
40 |
41 | /**
42 | * 雷达图圆的半径
43 | */
44 | private float radius;
45 | /**
46 | * 数据区域参考最大值用于计算设置数据相对于半径的比例
47 | */
48 | private float axisMax = 100f;
49 | /**
50 | * 字体间距
51 | */
52 | private float textSpacing = 8f;
53 |
54 | private PointF pointF = new PointF();
55 | private Path gridPath = new Path();
56 | private Path connPath = new Path();
57 | private Path dataPath = new Path();
58 | private Path dataOverLinePath = new Path();
59 |
60 | private HashMap valueHash;
61 |
62 | private Paint gridPathPaint;
63 | private Paint valueStrikePaint;
64 | private Paint valueFillPaint;
65 | private Paint valueOverPaint;
66 | private Paint textPaint;
67 | private Paint circleValueTextPaint;
68 | private Paint valueCirclePaint;
69 | private Paint valueCircleFillPaint;
70 |
71 | /**
72 | * 数据覆盖层线条是否绘制的宽度 颜色
73 | */
74 | private boolean drawValueOverStrike = false;
75 | private float dataOverStrikeWidth = 1;
76 | private int colorDataOverStrike = Color.TRANSPARENT;
77 | /**
78 | * 网格线的颜色 和宽度
79 | */
80 | private int colorGrid = Color.GRAY;
81 | private float gridStrikeWidth = 2;
82 | /**
83 | * 数据描边的是否绘制颜色宽度
84 | */
85 | private boolean drawValueStrike = false;
86 | private int colorDataStrike = Color.TRANSPARENT;
87 | private float dataStrikeWidth = 1;
88 | /**
89 | * 数据填充的颜色
90 | */
91 | private boolean drawValueFill = true;
92 | private int colorDataFill = Color.TRANSPARENT;
93 | /**
94 | * 数据文字颜色大小
95 | */
96 | private int colorValueText = Color.BLACK;
97 | private int textSize = 16;
98 |
99 | /**
100 | * 渐变颜色色值
101 | */
102 | private int shaderStartColor = -1;
103 | private int shaderEndColor = -1;
104 | /**
105 | * 是否绘制内容部分尾部的圆圈
106 | */
107 | private boolean drawEndCircle = false;
108 | /**
109 | * 是否绘制内容部分的数值 valueHash.entry.getValue
110 | */
111 | private boolean drawEndValue = true;
112 | private int colorValueCircle = Color.BLACK;
113 | private float valueCircleStrikeWidth = 1;
114 | private int colorValueCircleFill = Color.TRANSPARENT;
115 | /**
116 | * 文字大小
117 | */
118 | private int circleValueTextSize = 8;
119 | private int circleValueTextColor = Color.BLACK;
120 | /**
121 | * 文字与圆圈的间距
122 | */
123 | private float circleTextSpacing = 8;
124 |
125 | private int maxTextNum = 0;
126 |
127 |
128 | public RadarChartView(Context context) {
129 | this(context, null);
130 | }
131 |
132 | public RadarChartView(Context context, @Nullable AttributeSet attrs) {
133 | this(context, attrs, -1);
134 | }
135 |
136 | public RadarChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
137 | super(context, attrs, defStyleAttr);
138 |
139 | TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.RadarChartView, defStyleAttr, 0);
140 | //内容及网格线属性
141 | this.colorGrid = values.getColor(R.styleable.RadarChartView_colorGrid, colorGrid);
142 | this.gridStrikeWidth = values.getDimension(R.styleable.RadarChartView_gridStrikeWidth, gridStrikeWidth);
143 | //填充数据线条颜色
144 | this.colorDataStrike = values.getColor(R.styleable.RadarChartView_colorDataStrike, colorDataStrike);
145 | this.dataStrikeWidth = values.getDimension(R.styleable.RadarChartView_dataStrikeWidth, dataStrikeWidth);
146 |
147 | //填充颜色
148 | this.drawValueFill = values.getBoolean(R.styleable.RadarChartView_drawValueFill, drawValueFill);
149 | this.colorDataFill = values.getColor(R.styleable.RadarChartView_colorDataFill, colorDataFill);
150 | this.shaderStartColor = values.getColor(R.styleable.RadarChartView_shaderStartColor, shaderStartColor);
151 | this.shaderEndColor = values.getColor(R.styleable.RadarChartView_shaderEndColor, shaderEndColor);
152 |
153 | //填充颜色上边覆盖的线条颜色
154 | this.colorDataOverStrike = values.getColor(R.styleable.RadarChartView_colorDataOverStrike, colorDataOverStrike);
155 | this.dataOverStrikeWidth = values.getDimension(R.styleable.RadarChartView_dataOverStrikeWidth, dataOverStrikeWidth);
156 |
157 | //外圈文字属性
158 | this.textSize = values.getDimensionPixelSize(R.styleable.RadarChartView_textSize, textSize);
159 | this.colorValueText = values.getColor(R.styleable.RadarChartView_colorValueText, colorValueText);
160 | this.textSpacing = dp2px(getContext(), (int) textSpacing);
161 | this.textSpacing = values.getDimension(R.styleable.RadarChartView_textSpacing, textSpacing);
162 |
163 | //边数
164 | this.sideNum = values.getInt(R.styleable.RadarChartView_sideNum, sideNum);
165 | this.gridNum = values.getInt(R.styleable.RadarChartView_gridNum, gridNum);
166 |
167 | // 内部圆圈属性
168 | this.drawEndValue = values.getBoolean(R.styleable.RadarChartView_drawEndValue, drawEndValue);
169 | this.drawEndCircle = values.getBoolean(R.styleable.RadarChartView_drawEndCircle, drawEndCircle);
170 | this.colorValueCircle = values.getColor(R.styleable.RadarChartView_colorValueCircle, colorValueCircle);
171 | this.valueCircleStrikeWidth = values.getDimension(R.styleable.RadarChartView_valueCircleStrikeWidth, valueCircleStrikeWidth);
172 | this.circleTextSpacing = dp2px(getContext(), (int) circleTextSpacing);
173 | this.circleTextSpacing = values.getDimension(R.styleable.RadarChartView_circleTextSpacing, circleTextSpacing);
174 | this.colorValueCircleFill = values.getColor(R.styleable.RadarChartView_colorValueCircleFill, colorValueCircleFill);
175 | this.circleValueTextColor = values.getColor(R.styleable.RadarChartView_circleValueTextColor, circleValueTextColor);
176 | this.circleValueTextSize = values.getDimensionPixelSize(R.styleable.RadarChartView_circleValueTextSize, circleValueTextSize);
177 |
178 | this.drawValueStrike = values.getBoolean(R.styleable.RadarChartView_drawValueStrike, drawValueStrike);
179 | this.drawValueOverStrike = values.getBoolean(R.styleable.RadarChartView_drawValueOverStrike, drawValueOverStrike);
180 |
181 | this.axisMax = values.getFloat(R.styleable.RadarChartView_axisMax, axisMax);
182 |
183 | values.recycle();
184 | valueHash = new LinkedHashMap<>(sideNum);
185 | initPaint();
186 | }
187 |
188 |
189 | private void initPaint() {
190 | gridPathPaint = createPaint(colorGrid, 0, gridStrikeWidth, 0);
191 |
192 | valueStrikePaint = createPaint(colorDataStrike, 0, dataStrikeWidth, 0);
193 | valueFillPaint = createPaint(colorDataFill, 1, 1, 0);
194 |
195 | valueOverPaint = createPaint(colorDataOverStrike, 0, dataOverStrikeWidth, 0);
196 | textPaint = createPaint(colorValueText, 2, 1, textSize);
197 |
198 | valueCirclePaint = createPaint(colorValueCircle, 0, valueCircleStrikeWidth, 0);
199 | valueCircleFillPaint = createPaint(colorValueCircleFill, 1, 1, 0);
200 | circleValueTextPaint = createPaint(circleValueTextColor, 1, 1, circleValueTextSize);
201 | }
202 |
203 | /**
204 | * 创建画笔
205 | */
206 | private Paint createPaint(int color, int style, float width, int textSize) {
207 | Paint paint = new Paint();
208 | paint.setColor(color);
209 | paint.setFlags(Paint.ANTI_ALIAS_FLAG);
210 | switch (style) {
211 | case 0:
212 | paint.setStyle(Paint.Style.STROKE);
213 | break;
214 | case 1:
215 | paint.setStyle(Paint.Style.FILL);
216 | break;
217 | case 2:
218 | paint.setStyle(Paint.Style.FILL_AND_STROKE);
219 | break;
220 | default:
221 | break;
222 | }
223 | paint.setStrokeWidth(width);
224 | paint.setTextSize(textSize);
225 | return paint;
226 | }
227 |
228 |
229 | @Override
230 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
231 | super.onSizeChanged(w, h, oldw, oldh);
232 | radius = Math.min(w, h) / 2 - maxTextNum * textSize - textSpacing;
233 | pointF.x = w / 2;
234 | pointF.y = h / 2;
235 | postInvalidate();
236 | }
237 |
238 |
239 | @Override
240 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
241 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
242 |
243 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
244 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
245 | int widthSpec = MeasureSpec.getSize(widthMeasureSpec);
246 | int heightSpec = MeasureSpec.getSize(heightMeasureSpec);
247 |
248 |
249 | int width = getResultMeasureDimension(widthSpec, widthMode);
250 | int height = getResultMeasureDimension(heightSpec, heightMode);
251 | setMeasuredDimension(width, height);
252 | }
253 |
254 | private int getResultMeasureDimension(int size, int mode) {
255 | int result;
256 | //View 设置为 wrap_content 的时候
257 | if (mode == MeasureSpec.AT_MOST) {
258 | result = Math.min(size, dp2px(getContext(), 400));
259 | } else {
260 | result = size;
261 | }
262 | return result;
263 | }
264 |
265 | @Override
266 | protected void onDraw(Canvas canvas) {
267 | super.onDraw(canvas);
268 | // 2 π r = C 假设 r=1 angle 就是 360 度的多少份
269 | angle = (Math.PI * 2 / sideNum);
270 |
271 | canvas.translate(pointF.x, pointF.y);
272 |
273 | drawGrids(canvas);
274 |
275 | if (!valueHash.isEmpty()) {
276 | drawData(canvas);
277 | drawText(canvas);
278 | }
279 | }
280 |
281 | private void drawText(Canvas canvas) {
282 | Iterator> iterator = valueHash.entrySet().iterator();
283 |
284 | for (int i = 0; i < valueHash.size(); i++) {
285 | Map.Entry next = iterator.next();
286 | double degree = angle * i;
287 |
288 | double x = radius * Math.sin(degree);
289 | double y = -radius * Math.cos(degree);
290 |
291 | PointF position = getRelativePositionByText(next.getKey(), textPaint, textSpacing, Math.toDegrees(degree), x, y);
292 |
293 | canvas.drawText(next.getKey(), position.x, position.y, textPaint);
294 | }
295 | }
296 |
297 | /**
298 | * 画网格线
299 | *
300 | * @param canvas
301 | */
302 | private void drawGrids(Canvas canvas) {
303 | float perR = radius / gridNum;
304 | for (int i = 1; i <= gridNum; i++) {
305 | float r = perR * i;
306 | this.gridPath.reset();
307 | this.connPath.reset();
308 | //绘制开始的时 path 起点在原点,需要lineTo第一个点的坐标
309 | for (int j = 0; j < sideNum; j++) {
310 | float x = (float) (r * Math.sin(angle * j));
311 | float y = (float) (-r * Math.cos(angle * j));
312 | if (j == 0) {
313 | gridPath.moveTo(x, y);
314 | } else {
315 | gridPath.lineTo(x, y);
316 | }
317 | connPath.moveTo(0, 0);
318 | connPath.lineTo(x, y);
319 | }
320 | gridPath.close();
321 | canvas.drawPath(gridPath, gridPathPaint);
322 | canvas.drawPath(connPath, gridPathPaint);
323 | }
324 | }
325 |
326 | /**
327 | * 画内部填充区域
328 | *
329 | * @param canvas
330 | */
331 | private void drawData(Canvas canvas) {
332 | Iterator> iterator = valueHash.entrySet().iterator();
333 | dataPath.reset();
334 | dataOverLinePath.reset();
335 |
336 | //坐标缩放系数
337 | float dataRadius = radius / axisMax;
338 | for (int i = 0; i < valueHash.size(); i++) {
339 | Map.Entry data = iterator.next();
340 |
341 | float x = (float) (Math.sin(angle * i) * dataRadius * Math.min(data.getValue(), axisMax));
342 | float y = -(float) (Math.cos(angle * i) * dataRadius * Math.min(data.getValue(), axisMax));
343 |
344 | if (i == 0) {
345 | dataPath.moveTo(x, y);
346 | } else {
347 | dataPath.lineTo(x, y);
348 | }
349 |
350 | dataOverLinePath.moveTo(0, 0);
351 | dataOverLinePath.lineTo(x, y);
352 | }
353 | dataPath.close();
354 | if (drawValueStrike) {
355 | //画线
356 | canvas.drawPath(dataPath, valueStrikePaint);
357 | }
358 |
359 | if (shaderStartColor != -1 && shaderEndColor != -1) {
360 | valueFillPaint.setShader(new LinearGradient(0, -radius, 0, radius, shaderStartColor, shaderEndColor, Shader.TileMode.CLAMP));
361 | canvas.drawPath(dataPath, valueFillPaint);
362 | }
363 |
364 | //是否绘制填充颜色
365 | if (drawValueFill) {
366 | canvas.drawPath(dataPath, valueFillPaint);
367 | }
368 |
369 |
370 | //填充颜色上边是否添加额外的线条覆盖
371 | if (drawValueOverStrike) {
372 | canvas.drawPath(dataOverLinePath, valueOverPaint);
373 | }
374 | //是否绘制数据末尾的源泉
375 | if (drawEndCircle) {
376 | drawCircle(canvas, dataRadius);
377 | }
378 |
379 | }
380 |
381 | private void drawCircle(Canvas canvas, float dataRadius) {
382 |
383 | Iterator> entryIterator = valueHash.entrySet().iterator();
384 | for (int i = 0; i < valueHash.size(); i++) {
385 |
386 | Map.Entry data = entryIterator.next();
387 |
388 | double x = (Math.sin(angle * i) * dataRadius * Math.min(data.getValue(), axisMax));
389 | double y = -(Math.cos(angle * i) * dataRadius * Math.min(data.getValue(), axisMax));
390 |
391 | canvas.drawCircle((float) x, (float) y, 10, valueCircleFillPaint);
392 | canvas.drawCircle((float) x, (float) y, 10, valueCirclePaint);
393 |
394 | if (drawEndValue) {
395 | PointF pointF = getRelativePositionByText(String.valueOf(data.getValue()), circleValueTextPaint, circleTextSpacing, Math.toDegrees(angle * i), x, y);
396 | canvas.drawText(String.valueOf(data.getValue()), pointF.x, pointF.y, circleValueTextPaint);
397 | }
398 | }
399 | }
400 |
401 | /**
402 | * 原来的坐标和文字以及间距计算出应该放置的点的位置
403 | * 一共八个方向
404 | */
405 | private PointF getRelativePositionByText(String text, Paint paint, float textSpacing, double degree, double pointX, double pointY) {
406 |
407 | PointF resultPoint = new PointF();
408 | float tW = paint.measureText(text);
409 |
410 | Paint.FontMetrics fontMetrics = paint.getFontMetrics();
411 | float tH = fontMetrics.descent - fontMetrics.ascent;
412 |
413 | //第一象限
414 | if (pointX > 0 && pointY < 0 && degree != 0) {
415 | resultPoint = new PointF((float) pointX + textSpacing, (float) pointY);
416 | }
417 |
418 | //第=象限
419 | if (pointX < 0 && pointY < 0 && degree != 90.0) {
420 | resultPoint = new PointF((float) pointX - textSpacing - tW, (float) (pointY));
421 | }
422 | //第三象限
423 | if (pointX < 0 && pointY > 0 && degree != 180.0) {
424 | resultPoint = new PointF((float) pointX - textSpacing - tW, (float) (pointY + tH / 2));
425 | }
426 | //第四象限
427 | if (pointX > 0 && pointY > 0 && degree != 270 && degree != 180.0) {
428 | resultPoint = new PointF((float) pointX + textSpacing, (float) (pointY + tH / 2));
429 | }
430 |
431 | //X轴正
432 | if (degree == 0) {
433 | resultPoint = new PointF((float) pointX - tW / 2, (float) (pointY - textSpacing));
434 | }
435 | //X轴负
436 | if (degree == 180) {
437 | resultPoint = new PointF((float) pointX - tW / 2, (float) (pointY + textSpacing + tH / 2));
438 | }
439 | //y轴负
440 | if (degree == 90) {
441 | resultPoint = new PointF((float) pointX + textSpacing, (float) (pointY + tH / 4));//修正为除 4
442 | }
443 | //y轴正
444 | if (degree == 270) {
445 | resultPoint = new PointF((float) pointX - textSpacing - tW, (float) (pointY + tH / 4));
446 | }
447 | return resultPoint;
448 | }
449 |
450 |
451 | public int getSideNum() {
452 | return sideNum;
453 | }
454 |
455 | public void setSideNum(int sideNum) {
456 | this.sideNum = sideNum;
457 | invalidate();
458 | }
459 |
460 | public int getGridNum() {
461 | return gridNum;
462 | }
463 |
464 | public void setGridNum(int gridNum) {
465 | this.gridNum = gridNum;
466 | }
467 |
468 |
469 | public int getColorGrid() {
470 | return colorGrid;
471 | }
472 |
473 | public void setColorGrid(int colorGrid) {
474 | this.colorGrid = colorGrid;
475 | }
476 |
477 | public int getColorDataStrike() {
478 | return colorDataStrike;
479 | }
480 |
481 | public void setColorDataStrike(int colorDataStrike) {
482 | this.colorDataStrike = colorDataStrike;
483 | }
484 |
485 | public int getColorDataFill() {
486 | return colorDataFill;
487 | }
488 |
489 | public void setColorDataFill(int colorDataFill) {
490 | this.colorDataFill = colorDataFill;
491 | }
492 |
493 | public int getColorDataOverStrike() {
494 | return colorDataOverStrike;
495 | }
496 |
497 | public void setColorDataOverStrike(int colorDataOverStrike) {
498 | this.colorDataOverStrike = colorDataOverStrike;
499 | }
500 |
501 | public int getColorValueText() {
502 | return colorValueText;
503 | }
504 |
505 | public void setColorValueText(int colorValueText) {
506 | this.colorValueText = colorValueText;
507 | }
508 |
509 | public boolean isDrawValueStrike() {
510 | return drawValueStrike;
511 | }
512 |
513 | public void setDrawValueStrike(boolean drawValueStrike) {
514 | this.drawValueStrike = drawValueStrike;
515 | }
516 |
517 | public boolean isDrawValueOverStrike() {
518 | return drawValueOverStrike;
519 | }
520 |
521 | public void setDrawValueOverStrike(boolean drawValueOverStrike) {
522 | this.drawValueOverStrike = drawValueOverStrike;
523 | }
524 |
525 | public float getAxisMax() {
526 | return axisMax;
527 | }
528 |
529 | public void setAxisMax(float axisMax) {
530 | this.axisMax = axisMax;
531 | }
532 |
533 | public int getTextSize() {
534 | return textSize;
535 | }
536 |
537 | public void setTextSize(int textSize) {
538 | this.textSize = textSize;
539 | }
540 |
541 | public float getTextSpacing() {
542 | return textSpacing;
543 | }
544 |
545 | public void setTextSpacing(float textSpacing) {
546 | this.textSpacing = textSpacing;
547 | }
548 |
549 | public void addValues(@NonNull String key, @NonNull float presentValue) {
550 | maxTextNum = Math.max(key.length(), maxTextNum);
551 | valueHash.put(key, presentValue);
552 | }
553 |
554 | public void clear() {
555 | valueHash.clear();
556 | invalidate();
557 | }
558 |
559 | public float getGridStrikeWidth() {
560 | return gridStrikeWidth;
561 | }
562 |
563 | public void setGridStrikeWidth(float gridStrikeWidth) {
564 | this.gridStrikeWidth = gridStrikeWidth;
565 | }
566 |
567 | public float getDataOverStrikeWidth() {
568 | return dataOverStrikeWidth;
569 | }
570 |
571 | public void setDataOverStrikeWidth(float dataOverStrikeWidth) {
572 | this.dataOverStrikeWidth = dataOverStrikeWidth;
573 | }
574 |
575 | public float getDataStrikeWidth() {
576 | return dataStrikeWidth;
577 | }
578 |
579 | public void setDataStrikeWidth(float dataStrikeWidth) {
580 | this.dataStrikeWidth = dataStrikeWidth;
581 | }
582 |
583 | public boolean isDrawValueFill() {
584 | return drawValueFill;
585 | }
586 |
587 | public void setDrawValueFill(boolean drawValueFill) {
588 | this.drawValueFill = drawValueFill;
589 | }
590 |
591 | public int getShaderStartColor() {
592 | return shaderStartColor;
593 | }
594 |
595 | public void setShaderStartColor(int shaderStartColor) {
596 | this.shaderStartColor = shaderStartColor;
597 | }
598 |
599 | public int getShaderEndColor() {
600 | return shaderEndColor;
601 | }
602 |
603 | public void setShaderEndColor(int shaderEndColor) {
604 | this.shaderEndColor = shaderEndColor;
605 | }
606 |
607 | public boolean isDrawEndCircle() {
608 | return drawEndCircle;
609 | }
610 |
611 | public void setDrawEndCircle(boolean drawEndCircle) {
612 | this.drawEndCircle = drawEndCircle;
613 | }
614 |
615 | public boolean isDrawEndValue() {
616 | return drawEndValue;
617 | }
618 |
619 | public void setDrawEndValue(boolean drawEndValue) {
620 | this.drawEndValue = drawEndValue;
621 | }
622 |
623 | public int getColorValueCircle() {
624 | return colorValueCircle;
625 | }
626 |
627 | public void setColorValueCircle(int colorValueCircle) {
628 | this.colorValueCircle = colorValueCircle;
629 | }
630 |
631 | public int getColorValueCircleFill() {
632 | return colorValueCircleFill;
633 | }
634 |
635 | public void setColorValueCircleFill(int colorValueCircleFill) {
636 | this.colorValueCircleFill = colorValueCircleFill;
637 | }
638 |
639 | public int getCircleValueTextSize() {
640 | return circleValueTextSize;
641 | }
642 |
643 | public void setCircleValueTextSize(int circleValueTextSize) {
644 | this.circleValueTextSize = circleValueTextSize;
645 | }
646 |
647 | public float getCircleTextSpacing() {
648 | return circleTextSpacing;
649 | }
650 |
651 | public void setCircleTextSpacing(float circleTextSpacing) {
652 | this.circleTextSpacing = circleTextSpacing;
653 | }
654 |
655 | public int getCircleValueTextColor() {
656 | return circleValueTextColor;
657 | }
658 |
659 | public void setCircleValueTextColor(int circleValueTextColor) {
660 | this.circleValueTextColor = circleValueTextColor;
661 | }
662 |
663 | public float getValueCircleStrikeWidth() {
664 | return valueCircleStrikeWidth;
665 | }
666 |
667 | public void setValueCircleStrikeWidth(float valueCircleStrikeWidth) {
668 | this.valueCircleStrikeWidth = valueCircleStrikeWidth;
669 | }
670 |
671 |
672 | private float getCenterY() {
673 | return pointF.y;
674 | }
675 |
676 | private float getCenterX() {
677 | return pointF.x;
678 | }
679 |
680 | public static int dp2px(Context context, int dp) {
681 | return (int) (getDensity(context) * dp + 0.5);
682 | }
683 |
684 | public static int sp2px(Context context, int sp) {
685 | return (int) (getFontDensity(context) * sp + 0.5);
686 | }
687 |
688 | public static int px2dp(Context context, int px) {
689 | return (int) (px / getDensity(context) + 0.5);
690 | }
691 |
692 | public static int px2sp(Context context, int px) {
693 | return (int) (px / getFontDensity(context) + 0.5);
694 | }
695 |
696 | public static float getDensity(Context context) {
697 | return context.getResources().getDisplayMetrics().density;
698 | }
699 |
700 | public static float getFontDensity(Context context) {
701 | return context.getResources().getDisplayMetrics().scaledDensity;
702 | }
703 | }
704 |
--------------------------------------------------------------------------------
/radarchartview/src/main/res/values/radar_attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/radarchartview/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RadarChartView
3 |
4 |
--------------------------------------------------------------------------------
/radarchartview/src/test/java/com/wangshijia/www/radarchartview/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wangshijia.www.radarchartview;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':radarchartview'
2 |
--------------------------------------------------------------------------------