├── .gitignore
├── .gradle
├── 4.1
│ ├── fileChanges
│ │ └── last-build.bin
│ └── fileContent
│ │ └── fileContent.lock
└── buildOutputCleanup
│ └── cache.properties
├── KelloCharts.iml
├── LICENSE
├── PrivacyPolicy.html
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── kellocharts-sample
├── .gitignore
├── build.gradle
├── kellocharts-library.iml
├── kellocharts-sample.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── co
│ │ └── csadev
│ │ └── kellocharts
│ │ └── sample
│ │ ├── AboutActivity.kt
│ │ ├── BubbleChartActivity.kt
│ │ ├── ColumnChartActivity.kt
│ │ ├── ComboLineColumnChartActivity.kt
│ │ ├── GoodBadChartActivity.kt
│ │ ├── LineChartActivity.kt
│ │ ├── LineColumnDependencyActivity.kt
│ │ ├── MainActivity.kt
│ │ ├── PieChartActivity.kt
│ │ ├── PreviewColumnChartActivity.kt
│ │ ├── PreviewLineChartActivity.kt
│ │ ├── SpeedChartActivity.kt
│ │ ├── TempoChartActivity.kt
│ │ └── ViewPagerChartsActivity.kt
│ └── res
│ ├── color
│ └── selector_text_link.xml
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── drawable-xxxhdpi
│ └── ic_launcher.png
│ ├── layout
│ ├── activity_about.xml
│ ├── activity_bubble_chart.xml
│ ├── activity_column_chart.xml
│ ├── activity_combo_line_column_chart.xml
│ ├── activity_good_bad.xml
│ ├── activity_line_chart.xml
│ ├── activity_line_column_dependency.xml
│ ├── activity_main.xml
│ ├── activity_pie_chart.xml
│ ├── activity_preview_column_chart.xml
│ ├── activity_preview_line_chart.xml
│ ├── activity_tempo_chart.xml
│ ├── activity_view_pager_charts.xml
│ ├── fragment_about.xml
│ ├── fragment_bubble_chart.xml
│ ├── fragment_column_chart.xml
│ ├── fragment_combo_line_column_chart.xml
│ ├── fragment_good_bad.xml
│ ├── fragment_line_chart.xml
│ ├── fragment_line_column_dependency.xml
│ ├── fragment_main.xml
│ ├── fragment_pie_chart.xml
│ ├── fragment_preview_column_chart.xml
│ ├── fragment_preview_line_chart.xml
│ ├── fragment_tempo_chart.xml
│ ├── fragment_view_pager_charts.xml
│ └── list_item_sample.xml
│ ├── menu
│ ├── bubble_chart.xml
│ ├── column_chart.xml
│ ├── combo_line_column_chart.xml
│ ├── line_chart.xml
│ ├── main.xml
│ ├── pie_chart.xml
│ ├── preview_column_chart.xml
│ ├── preview_line_chart.xml
│ └── tempo_chart.xml
│ ├── values-land
│ └── dimens.xml
│ ├── values-sw600dp
│ └── dimens.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── kellocharts
├── .gitignore
├── build.gradle
├── kellocharts.iml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── co
│ │ └── csadev
│ │ └── kellocharts
│ │ ├── animation
│ │ ├── AnimatorInterfaces.kt
│ │ ├── ChartDataAnimatorV14.kt
│ │ ├── ChartViewportAnimatorV14.kt
│ │ ├── DummyChartAnimationListener.kt
│ │ └── PieChartRotationAnimatorV14.kt
│ │ ├── computator
│ │ ├── ChartComputator.kt
│ │ └── PreviewChartComputator.kt
│ │ ├── formatter
│ │ ├── DateFormatters.kt
│ │ ├── ValueFormatterHelper.kt
│ │ ├── ValueFormatterInterfaces.kt
│ │ └── ValueFormatters.kt
│ │ ├── gesture
│ │ ├── ChartScroller.kt
│ │ ├── ChartTouchHandler.kt
│ │ ├── ChartZoomer.kt
│ │ ├── ContainerScrollType.kt
│ │ ├── PieChartTouchHandler.kt
│ │ ├── PreviewChartTouchHandler.kt
│ │ ├── ZoomType.kt
│ │ └── ZoomerCompat.kt
│ │ ├── listener
│ │ ├── ChartListeners.kt
│ │ └── DummyChartListeners.kt
│ │ ├── model
│ │ ├── AbstractChartData.kt
│ │ ├── Axis.kt
│ │ ├── AxisValue.kt
│ │ ├── BubbleChartData.kt
│ │ ├── BubbleValue.kt
│ │ ├── ChartData.kt
│ │ ├── Column.kt
│ │ ├── ColumnChartData.kt
│ │ ├── ComboLineColumnChartData.kt
│ │ ├── Line.kt
│ │ ├── LineChartData.kt
│ │ ├── PieChartData.kt
│ │ ├── PointValue.kt
│ │ ├── SelectedValue.kt
│ │ ├── SliceValue.kt
│ │ ├── SubcolumnValue.kt
│ │ ├── ValueShape.kt
│ │ ├── Viewport.kt
│ │ └── dsl
│ │ │ ├── DataDslProviders.kt
│ │ │ ├── LayoutDslProviders.kt
│ │ │ └── ValueDslProviders.kt
│ │ ├── provider
│ │ └── ChartDataProviders.kt
│ │ ├── renderer
│ │ ├── AbstractChartRenderer.kt
│ │ ├── AxesRenderer.kt
│ │ ├── BubbleChartRenderer.kt
│ │ ├── ChartRenderer.kt
│ │ ├── ColumnChartRenderer.kt
│ │ ├── ComboChartRenderer.kt
│ │ ├── ComboLineColumnChartRenderer.kt
│ │ ├── LineChartRenderer.kt
│ │ ├── PieChartRenderer.kt
│ │ ├── PreviewColumnChartRenderer.kt
│ │ └── PreviewLineChartRenderer.kt
│ │ ├── util
│ │ ├── AxisAutoValues.kt
│ │ ├── ChartUtils.kt
│ │ └── FloatUtils.kt
│ │ └── view
│ │ ├── AbstractChartView.kt
│ │ ├── BubbleChartView.kt
│ │ ├── Chart.kt
│ │ ├── ColumnChartView.kt
│ │ ├── ComboLineColumnChartView.kt
│ │ ├── LineChartView.kt
│ │ ├── PieChartView.kt
│ │ ├── PreviewColumnChartView.kt
│ │ ├── PreviewLineChartView.kt
│ │ └── hack
│ │ ├── HackyDrawerLayout.kt
│ │ └── HackyViewPager.kt
│ └── res
│ └── values
│ └── strings.xml
├── libs
└── gradle-play-publisher-1.2.3.jar
├── logo_design.xcf
├── play_feature.png
├── play_icon.png
├── screenshots
├── bar_chart_horizontal.png
├── bar_chart_vertical.png
├── bubble_chart_horizontal.png
├── bubble_chart_vertical.png
├── icon_screenshot.png
├── line_chart_horizontal.png
├── line_chart_vertical.png
├── pie_chart_horizontal.png
├── pie_chart_vertical_menu.png
├── preview_line_chart_vertical.png
└── preview_list.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .idea
3 | kellocharts-sample/release
4 | local.properties
5 | .gradle
6 |
--------------------------------------------------------------------------------
/.gradle/4.1/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gradle/4.1/fileContent/fileContent.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/.gradle/4.1/fileContent/fileContent.lock
--------------------------------------------------------------------------------
/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Fri Oct 12 23:47:04 CEST 2018
2 | gradle.version=4.6
3 |
--------------------------------------------------------------------------------
/KelloCharts.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KelloCharts for Android
2 | Kotlin Charts/graphs library for Android compatible with API 21+ (Android 5.0), several chart types with support for scaling, scrolling and animations
3 | Works best when hardware acceleration is available, so API 14+(Android 4.0) is recommended.
4 | Apache License 2.0.
5 |
6 | # Build badges and gradle availability coming soon
7 |
8 | ## Features
9 |
10 | - Line chart(cubic lines, filled lines, scattered points)
11 | - Column chart(grouped, stacked, negative values)
12 | - Pie chart
13 | - Bubble chart
14 | - Combo chart(columns/lines)
15 | - Preview charts(for column chart and line chart)
16 | - Zoom(pinch to zoom, double tap zoom), scroll and fling
17 | - Custom and auto-generated axes(top, bottom, left, right, inside)
18 | - Animations
19 |
20 | ## Screens and Demos
21 |
22 | - Code of a demo application is in `kellocharts-sample` directory
23 | - Demo App coming soon
24 |
25 | ## Usage
26 |
27 | Every chart view can be defined in layout xml file:
28 |
29 | ```xml
30 |
34 | ```
35 |
36 | or created in code and added to layout later:
37 |
38 | ```Kotlin
39 | LineChartView chart = new LineChartView(context)
40 | layout.addView(chart)
41 | ```
42 |
43 | Use methods from *Chart classes to define chart behaviour, example methods:
44 |
45 | ```Kotlin
46 | Chart.isInteractive = isInteractive
47 | Chart.zoomType = zoomType
48 | Chart.setContainerScrollEnabled(boolean isEnabled, ContainerScrollType type)
49 | ```
50 |
51 | Use methods from data models to define how chart looks like, example methods:
52 |
53 | ```Kotlin
54 | ChartData.axisXBottom = axisX
55 | ColumnChartData.isStacked = isStacked
56 | Line.strokeWidth = strokeWidthDp
57 | ```
58 |
59 | Every chart has its own method to set chart data and its own data model, example for line chart:
60 |
61 | ```Kotlin
62 | arrayListOf(PointValue(0, 2), PointValue(1, 4), PointValue(2, 3), PointValue(3, 4))
63 |
64 | val line = Line(values, color = Color.BLUE, isCubic = true)
65 | val lines = arrayListOf(line)
66 |
67 | val data = LineChartData(lines)
68 |
69 | val chart = LineChartView(context)
70 | chart.lineChartData = data
71 | ```
72 |
73 | Also, available as a DSL, same example as above:
74 |
75 | ```Kotlin
76 | lineData {
77 | lines {
78 | line {
79 | color = Color.BLUE
80 | isCubic = true
81 | pointValues {
82 | point {
83 | x = 0f
84 | y = 2f
85 | }
86 | point {
87 | x = 1f
88 | y = 4f
89 | }
90 | point {
91 | x = 2f
92 | y = 3f
93 | }
94 | point {
95 | x = 3f
96 | y = 4f
97 | }
98 | }
99 | }
100 | }
101 | }
102 | ```
103 |
104 | After the chart data has been set you can still modify its attributes but right after that you should call
105 | `*.*ChartData` setter again to let chart recalculate and redraw data. There is also an option to use copy constructor for deep copy of
106 | chart data. You can safely modify copy in other threads and pass it to `*.*ChartData` setter later.
107 |
108 |
109 | ## Contributing
110 |
111 | Yes :) If you found a bug, have an idea how to improve library or have a question, please create new issue or comment existing one. If you would like to contribute code fork the repository and send a pull request.
112 |
113 | ## License
114 |
115 | KelloCharts
116 | Copyright 2018 Charles Anderson
117 |
118 | Licensed under the Apache License, Version 2.0 (the "License");
119 | you may not use this file except in compliance with the License.
120 | You may obtain a copy of the License at
121 |
122 | http://www.apache.org/licenses/LICENSE-2.0
123 |
124 | Unless required by applicable law or agreed to in writing, software
125 | distributed under the License is distributed on an "AS IS" BASIS,
126 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127 | See the License for the specific language governing permissions and
128 | limitations under the License.
129 |
130 | ---
131 | KelloCharts library is developed from the original HelloCharts library available:
132 | https://github.com/lecho/hellocharts-android
133 |
134 | ---
135 | KelloCharts library uses code from InteractiveChart sample available
136 | on Android Developers page:
137 |
138 | http://developer.android.com/training/gestures/scale.html
139 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.2.71'
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.2.1'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
13 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
14 | classpath 'com.github.triplet.gradle:play-publisher:1.2.2'
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | android.enableJetifier=true
13 | android.useAndroidX=true
14 | org.gradle.jvmargs=-Xmx1536m
15 |
16 | # When configured, Gradle will run in incubating parallel mode.
17 | # This option should only be used with decoupled projects. More details, visit
18 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
19 | # org.gradle.parallel=true
20 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 23 18:35:54 EDT 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.6-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/kellocharts-sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/kellocharts-sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-android-extensions'
5 | apply plugin: 'com.github.triplet.play'
6 |
7 | android {
8 | compileSdkVersion 28
9 | defaultConfig {
10 | applicationId "co.csadev.kellocharts"
11 | minSdkVersion 21
12 | targetSdkVersion 28
13 | versionCode 3
14 | versionName "2.0.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | implementation fileTree(dir: 'libs', include: ['*.jar'])
26 | implementation(project(':kellocharts'))
27 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
28 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
29 | implementation 'androidx.appcompat:appcompat:1.0.0'
30 | }
31 |
--------------------------------------------------------------------------------
/kellocharts-sample/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 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
26 |
27 |
30 |
31 |
34 |
35 |
38 |
39 |
42 |
43 |
46 |
47 |
50 |
51 |
54 |
55 |
58 |
59 |
62 |
63 |
66 |
67 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/java/co/csadev/kellocharts/sample/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.sample
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.pm.PackageManager
7 | import android.net.Uri
8 | import android.os.Bundle
9 | import android.util.Log
10 | import android.util.Pair
11 | import android.view.LayoutInflater
12 | import android.view.View
13 | import android.view.ViewGroup
14 | import android.widget.TextView
15 | import androidx.appcompat.app.AppCompatActivity
16 | import androidx.fragment.app.Fragment
17 |
18 | class AboutActivity : AppCompatActivity() {
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | setContentView(R.layout.activity_about)
23 | if (savedInstanceState == null) {
24 | supportFragmentManager.beginTransaction().add(R.id.container, PlaceholderFragment()).commit()
25 | }
26 | }
27 |
28 | /**
29 | * A placeholder fragment containing a simple view.
30 | */
31 | class PlaceholderFragment : Fragment() {
32 |
33 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
34 | val rootView = inflater.inflate(R.layout.fragment_about, container, false)
35 |
36 | val version = rootView.findViewById(R.id.version)
37 | version.text = getAppVersionAndBuild(activity).first
38 |
39 | val gotToGithub = rootView.findViewById(R.id.go_to_github)
40 | gotToGithub.setOnClickListener { launchWebBrowser(activity, GITHUB_URL) }
41 |
42 | return rootView
43 | }
44 | }
45 |
46 | companion object {
47 | val TAG = AboutActivity::class.java.simpleName
48 | val GITHUB_URL = "github.com/gtcompscientist/kellocharts"
49 |
50 | fun getAppVersionAndBuild(context: Context?): Pair {
51 | try {
52 | val pInfo = context!!.packageManager.getPackageInfo(context.packageName, 0)
53 | return Pair(pInfo.versionName, pInfo.versionCode)
54 | } catch (e: Exception) {
55 | Log.e(TAG, "Could not get version number")
56 | return Pair("", 0)
57 | }
58 |
59 | }
60 |
61 | @SuppressLint("DefaultLocale")
62 | fun launchWebBrowser(context: Context?, url: String): Boolean {
63 | var url = url
64 | try {
65 | url = url.toLowerCase()
66 | if (!url.startsWith("http://") || !url.startsWith("https://")) {
67 | url = "http://" + url
68 | }
69 |
70 | val intent = Intent(Intent.ACTION_VIEW)
71 | intent.data = Uri.parse(url)
72 | val resolveInfo = context!!.packageManager.resolveActivity(intent,
73 | PackageManager.MATCH_DEFAULT_ONLY)
74 | if (null == resolveInfo) {
75 | Log.e(TAG, "No activity to handle web intent")
76 | return false
77 | }
78 | context.startActivity(intent)
79 | Log.i(TAG, "Launching browser with url: " + url)
80 | return true
81 | } catch (e: Exception) {
82 | Log.e(TAG, "Could not start web browser", e)
83 | return false
84 | }
85 |
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/java/co/csadev/kellocharts/sample/GoodBadChartActivity.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.sample
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.fragment.app.Fragment
9 | import co.csadev.kellocharts.model.Line
10 | import co.csadev.kellocharts.model.LineChartData
11 | import co.csadev.kellocharts.model.PointValue
12 | import co.csadev.kellocharts.util.ChartUtils
13 | import co.csadev.kellocharts.view.LineChartView
14 |
15 | class GoodBadChartActivity : AppCompatActivity() {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_good_bad)
20 | if (savedInstanceState == null) {
21 | supportFragmentManager.beginTransaction().add(R.id.container, PlaceholderFragment()).commit()
22 | }
23 | }
24 |
25 | /**
26 | * A placeholder fragment containing a simple view.
27 | */
28 | class PlaceholderFragment : Fragment() {
29 |
30 | private var chart: LineChartView? = null
31 | private var data: LineChartData? = null
32 |
33 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
34 | val rootView = inflater.inflate(R.layout.fragment_good_bad, container, false)
35 |
36 | chart = rootView.findViewById(R.id.chart) as LineChartView
37 |
38 | generateDefaultData()
39 | chart?.lineChartData = data!!
40 |
41 | // Increase viewport height for better look
42 | val v = chart!!.maximumViewport
43 | val dy = v.height() * 0.2f
44 | v.inset(0f, -dy)
45 | chart!!.maximumViewport = v
46 | chart!!.currentViewport = v
47 |
48 | return rootView
49 | }
50 |
51 | private fun generateDefaultData() {
52 |
53 | // Generate data, every line has 3 points to form filled triangle. Point radius is set to 1 to be almost
54 | // invisible but it has to be there because without points there is not labels. Area transparency is set to
55 | // 255(full opacity).
56 |
57 | // Important note. This example uses negative values, to properly fill area below 0 chart base value have to
58 | // be set to 0. That is default base value but if you want to be sure you can call data.setBaseValue(0)
59 | // method.
60 |
61 | var line: Line
62 | var values: MutableList
63 | val lines = ArrayList()
64 |
65 | // First good triangle
66 | values = ArrayList()
67 | values.add(PointValue(0, 0, "".toCharArray()))
68 | values.add(PointValue(1, 1, "Very Good:)".toCharArray()))
69 | values.add(PointValue(2, 0, "".toCharArray()))
70 |
71 | line = Line(values)
72 | line.color = ChartUtils.COLOR_GREEN
73 | line.areaTransparency = 255
74 | line.isFilled = true
75 | line.pointRadius = 1
76 | line.hasLabels = true
77 | lines.add(line)
78 |
79 | // Second good triangle
80 | values = ArrayList()
81 | values.add(PointValue(3, 0, "".toCharArray()))
82 | values.add(PointValue(4f, 0.5f, "Good Enough".toCharArray()))
83 | values.add(PointValue(5, 0, "".toCharArray()))
84 |
85 | line = Line(values)
86 | line.color = ChartUtils.COLOR_GREEN
87 | line.areaTransparency = 255
88 | line.isFilled = true
89 | line.pointRadius = 1
90 | line.hasLabels = true
91 | lines.add(line)
92 |
93 | // Bad triangle
94 | values = ArrayList()
95 | values.add(PointValue(1, 0, "".toCharArray()))
96 | values.add(PointValue(2, -1, "Very Bad".toCharArray()))
97 | values.add(PointValue(3, 0, "".toCharArray()))
98 |
99 | line = Line(values)
100 | line.color = ChartUtils.COLOR_RED
101 | line.areaTransparency = 255
102 | line.isFilled = true
103 | line.pointRadius = 1
104 | line.hasLabels = true
105 | lines.add(line)
106 |
107 | data = LineChartData(lines)
108 |
109 | // *** Important, set base value to 0 to fill negative part of chart.
110 | // data.setBaseValue(0);
111 |
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/color/selector_text_link.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/kellocharts-sample/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/kellocharts-sample/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/kellocharts-sample/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/kellocharts-sample/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/kellocharts-sample/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_bubble_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_column_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_combo_line_column_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_good_bad.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_line_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_line_column_dependency.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_pie_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_preview_column_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_preview_line_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_tempo_chart.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/activity_view_pager_charts.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_about.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
15 |
16 |
24 |
25 |
33 |
34 |
41 |
42 |
47 |
48 |
52 |
53 |
54 |
61 |
62 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_bubble_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_column_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_combo_line_column_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_good_bad.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_line_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_line_column_dependency.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
19 |
25 |
26 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_pie_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_preview_column_chart.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
19 |
25 |
26 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_preview_line_chart.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
19 |
25 |
26 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_tempo_chart.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/fragment_view_pager_charts.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/layout/list_item_sample.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/bubble_chart.xml:
--------------------------------------------------------------------------------
1 |
56 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/column_chart.xml:
--------------------------------------------------------------------------------
1 |
68 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/combo_line_column_chart.xml:
--------------------------------------------------------------------------------
1 |
43 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/line_chart.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/pie_chart.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/preview_column_chart.xml:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/preview_line_chart.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/menu/tempo_chart.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 38sp
4 | 12dp
5 |
6 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 | 54sp
9 | 24dp
10 |
11 |
12 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | 64dp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #33B5E5
5 | #8033B5E5
6 | #0099CC
7 | #FF8800
8 | #FFBB33
9 |
10 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 | 42sp
7 | 16dp
8 |
9 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | KelloCharts
5 | About
6 | LineChartActivity
7 | ColumnChartActivity
8 | PieChartActivity
9 | BubbleChartActivity
10 | PreviewLineChartActivity
11 | PreviewColumnChartActivity
12 | ComboLineColumnChartActivity
13 | LineColumnDependency
14 | GoodBadActivity
15 | TempoChartActivity
16 | SpeedChartActivity
17 | ViewPagerChartsActivity
18 | Section 1
19 | Section 2
20 | Section 3
21 | AboutActivity
22 | "Library version "
23 | Charles Anderson 2018
24 | App icon
25 | Go to GitHub
26 |
27 |
--------------------------------------------------------------------------------
/kellocharts-sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/kellocharts/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/kellocharts/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 |
4 | android {
5 | compileSdkVersion 28
6 |
7 | defaultConfig {
8 | minSdkVersion 21
9 | targetSdkVersion 28
10 | versionCode 4
11 | versionName "2.0.0"
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 |
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(dir: 'libs', include: ['*.jar'])
25 | implementation 'androidx.appcompat:appcompat:1.0.0'
26 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
27 | }
28 | repositories {
29 | mavenCentral()
30 | }
31 |
32 | ext {
33 | bintrayRepo = 'KelloCharts'
34 | bintrayName = 'KelloCharts'
35 |
36 | publishedGroupId = 'co.csadev'
37 | libraryName = 'KelloCharts'
38 | artifact = 'kellocharts'
39 |
40 | libraryDescription = 'Kotlin Charts/graphs library for Android compatible with API 21+, several chart types with support for scaling, scrolling and animations'
41 |
42 | siteUrl = 'https://github.com/gtcompscientist/KelloCharts'
43 | gitUrl = 'https://github.com/gtcompscientist/KelloCharts.git'
44 |
45 | libraryVersion = android.defaultConfig.versionName
46 |
47 | developerId = 'gtcompscientist'
48 | developerName = 'Charles Anderson'
49 | developerEmail = 'csadevapps@gmail.com'
50 |
51 | licenseName = 'The Apache Software License, Version 2.0'
52 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
53 | allLicenses = ["Apache-2.0"]
54 | }
55 |
56 | tasks.withType(Javadoc) {
57 | // Ignores errors from mavenAndroidJavadocs task
58 | // (reference: github.com/novoda/bintray-release/issues/71#issuecomment-164324255)
59 | options.addStringOption('Xdoclint:none', '-quiet')
60 | options.addStringOption('encoding', 'UTF-8')
61 | excludes = ['**/*.kt'] // < ---- Exclude all kotlin files from javadoc file.
62 | }
63 |
64 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle'
65 | apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/bintrayv1.gradle'
--------------------------------------------------------------------------------
/kellocharts/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 |
--------------------------------------------------------------------------------
/kellocharts/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/animation/AnimatorInterfaces.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.animation
2 |
3 | import co.csadev.kellocharts.model.Viewport
4 | import java.util.*
5 |
6 | val FAST_ANIMATION_DURATION = 200L
7 |
8 | interface ChartAnimationListener : EventListener {
9 | fun onAnimationStarted()
10 | fun onAnimationFinished()
11 | }
12 |
13 | interface ChartDataAnimator {
14 | val isAnimationStarted: Boolean
15 | fun startAnimation(duration: Long)
16 | fun cancelAnimation()
17 | fun setChartAnimationListener(animationListener: ChartAnimationListener?)
18 | companion object {
19 | val DEFAULT_ANIMATION_DURATION: Long = 500
20 | }
21 | }
22 |
23 | interface ChartViewportAnimator {
24 | val isAnimationStarted: Boolean
25 | fun startAnimation(startViewport: Viewport, targetViewport: Viewport)
26 | fun startAnimation(startViewport: Viewport, targetViewport: Viewport, duration: Long)
27 | fun cancelAnimation()
28 | fun setChartAnimationListener(animationListener: ChartAnimationListener?)
29 | }
30 |
31 | interface PieChartRotationAnimator {
32 | val isAnimationStarted: Boolean
33 | fun startAnimation(startAngle: Float, angleToRotate: Float)
34 | fun cancelAnimation()
35 | fun setChartAnimationListener(animationListener: ChartAnimationListener?)
36 | }
37 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/animation/ChartDataAnimatorV14.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.animation
2 |
3 | import android.animation.Animator
4 | import android.animation.Animator.AnimatorListener
5 | import android.animation.ValueAnimator
6 | import android.animation.ValueAnimator.AnimatorUpdateListener
7 | import android.annotation.SuppressLint
8 |
9 | import co.csadev.kellocharts.view.Chart
10 |
11 | @SuppressLint("NewApi")
12 | class ChartDataAnimatorV14(private val chart: Chart) : ChartDataAnimator, AnimatorListener, AnimatorUpdateListener {
13 | private val animator: ValueAnimator
14 | private var animationListener: ChartAnimationListener? = DummyChartAnimationListener()
15 |
16 | override val isAnimationStarted: Boolean
17 | get() = animator.isStarted
18 |
19 | init {
20 | animator = ValueAnimator.ofFloat(0.0f, 1.0f)
21 | animator.addListener(this)
22 | animator.addUpdateListener(this)
23 | }
24 |
25 | override fun startAnimation(duration: Long) {
26 | if (duration >= 0) {
27 | animator.duration = duration
28 | } else {
29 | animator.duration = ChartDataAnimator.Companion.DEFAULT_ANIMATION_DURATION
30 | }
31 | animator.start()
32 | }
33 |
34 | override fun cancelAnimation() {
35 | animator.cancel()
36 | }
37 |
38 | override fun onAnimationUpdate(animation: ValueAnimator) {
39 | chart.animationDataUpdate(animation.animatedFraction)
40 | }
41 |
42 | override fun onAnimationCancel(animation: Animator) {}
43 |
44 | override fun onAnimationEnd(animation: Animator) {
45 | chart.animationDataFinished()
46 | animationListener?.onAnimationFinished()
47 | }
48 |
49 | override fun onAnimationRepeat(animation: Animator) {}
50 |
51 | override fun onAnimationStart(animation: Animator) {
52 | animationListener?.onAnimationStarted()
53 | }
54 |
55 | override fun setChartAnimationListener(animationListener: ChartAnimationListener?) {
56 | this.animationListener = animationListener
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/animation/ChartViewportAnimatorV14.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.animation
2 |
3 | import android.animation.Animator
4 | import android.animation.Animator.AnimatorListener
5 | import android.animation.ValueAnimator
6 | import android.animation.ValueAnimator.AnimatorUpdateListener
7 | import android.annotation.SuppressLint
8 |
9 | import co.csadev.kellocharts.model.Viewport
10 | import co.csadev.kellocharts.model.set
11 | import co.csadev.kellocharts.view.Chart
12 |
13 | @SuppressLint("NewApi")
14 | class ChartViewportAnimatorV14(private val chart: Chart) : ChartViewportAnimator, AnimatorListener, AnimatorUpdateListener {
15 | private val animator: ValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
16 | private val startViewport = Viewport()
17 | private val targetViewport = Viewport()
18 | private val newViewport = Viewport()
19 | private var animationListener: ChartAnimationListener? = DummyChartAnimationListener()
20 |
21 | override val isAnimationStarted: Boolean
22 | get() = animator.isStarted
23 |
24 | init {
25 | animator.addListener(this)
26 | animator.addUpdateListener(this)
27 | animator.duration = FAST_ANIMATION_DURATION
28 | }
29 |
30 | override fun startAnimation(startViewport: Viewport, targetViewport: Viewport) {
31 | this.startViewport.set(startViewport)
32 | this.targetViewport.set(targetViewport)
33 | animator.duration = FAST_ANIMATION_DURATION
34 | animator.start()
35 | }
36 |
37 | override fun startAnimation(startViewport: Viewport, targetViewport: Viewport, duration: Long) {
38 | this.startViewport.set(startViewport)
39 | this.targetViewport.set(targetViewport)
40 | animator.duration = duration
41 | animator.start()
42 | }
43 |
44 | override fun cancelAnimation() {
45 | animator.cancel()
46 | }
47 |
48 | override fun onAnimationUpdate(animation: ValueAnimator) {
49 | val scale = animation.animatedFraction
50 | val diffLeft = (targetViewport.left - startViewport.left) * scale
51 | val diffTop = (targetViewport.top - startViewport.top) * scale
52 | val diffRight = (targetViewport.right - startViewport.right) * scale
53 | val diffBottom = (targetViewport.bottom - startViewport.bottom) * scale
54 | newViewport.set(startViewport.left + diffLeft, startViewport.top + diffTop, startViewport.right + diffRight, startViewport.bottom + diffBottom)
55 | chart.currentViewport = newViewport
56 | }
57 |
58 | override fun onAnimationCancel(animation: Animator) {}
59 |
60 | override fun onAnimationEnd(animation: Animator) {
61 | chart.currentViewport = targetViewport
62 | animationListener?.onAnimationFinished()
63 | }
64 |
65 | override fun onAnimationRepeat(animation: Animator) {}
66 |
67 | override fun onAnimationStart(animation: Animator) {
68 | animationListener?.onAnimationStarted()
69 | }
70 |
71 | override fun setChartAnimationListener(animationListener: ChartAnimationListener?) {
72 | this.animationListener = animationListener
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/animation/DummyChartAnimationListener.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.animation
2 |
3 | class DummyChartAnimationListener : ChartAnimationListener {
4 | override fun onAnimationStarted() { }
5 | override fun onAnimationFinished() { }
6 | }
7 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/animation/PieChartRotationAnimatorV14.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.animation
2 |
3 | import android.animation.Animator
4 | import android.animation.Animator.AnimatorListener
5 | import android.animation.ValueAnimator
6 | import android.animation.ValueAnimator.AnimatorUpdateListener
7 | import android.annotation.SuppressLint
8 |
9 | import co.csadev.kellocharts.view.PieChartView
10 |
11 | @SuppressLint("NewApi")
12 | class PieChartRotationAnimatorV14 @JvmOverloads constructor(private val chart: PieChartView, duration: Long = 200L) : PieChartRotationAnimator, AnimatorListener, AnimatorUpdateListener {
13 | private val animator: ValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
14 | private var startRotation = 0f
15 | private var targetRotation = 0f
16 | private var animationListener: ChartAnimationListener = DummyChartAnimationListener()
17 |
18 | override val isAnimationStarted: Boolean
19 | get() = animator.isStarted
20 |
21 | init {
22 | animator.duration = duration
23 | animator.addListener(this)
24 | animator.addUpdateListener(this)
25 | }
26 |
27 | override fun startAnimation(startAngle: Float, angleToRotate: Float) {
28 | this.startRotation = (startAngle % 360 + 360) % 360
29 | this.targetRotation = (angleToRotate % 360 + 360) % 360
30 | animator.start()
31 | }
32 |
33 | override fun cancelAnimation() {
34 | animator.cancel()
35 | }
36 |
37 | override fun onAnimationUpdate(animation: ValueAnimator) {
38 | val scale = animation.animatedFraction
39 | var rotation = startRotation + (targetRotation - startRotation) * scale
40 | rotation = (rotation % 360 + 360) % 360
41 | chart.setChartRotation(rotation.toInt(), false)
42 | }
43 |
44 | override fun onAnimationCancel(animation: Animator) {}
45 |
46 | override fun onAnimationEnd(animation: Animator) {
47 | chart.setChartRotation(targetRotation.toInt(), false)
48 | animationListener.onAnimationFinished()
49 | }
50 |
51 | override fun onAnimationRepeat(animation: Animator) {}
52 |
53 | override fun onAnimationStart(animation: Animator) {
54 | animationListener.onAnimationStarted()
55 | }
56 |
57 | override fun setChartAnimationListener(animationListener: ChartAnimationListener?) {
58 | if (null == animationListener) {
59 | this.animationListener = DummyChartAnimationListener()
60 | } else {
61 | this.animationListener = animationListener
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/computator/PreviewChartComputator.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.computator
2 |
3 | import co.csadev.kellocharts.model.Viewport
4 |
5 | /**
6 | * Version of ChartComputator for preview charts. It always uses maxViewport as visible viewport and currentViewport as
7 | * preview area.
8 | */
9 | class PreviewChartComputator : ChartComputator() {
10 |
11 | override fun computeRawX(valueX: Float): Float {
12 | val pixelOffset = (valueX - maximumViewport.left) * (contentRectMinusAllMargins.width() / maximumViewport
13 | .width())
14 | return contentRectMinusAllMargins.left + pixelOffset
15 | }
16 |
17 | override fun computeRawY(valueY: Float): Float {
18 | val pixelOffset = (valueY - maximumViewport.bottom) * (contentRectMinusAllMargins.height() / maximumViewport
19 | .height())
20 | return contentRectMinusAllMargins.bottom - pixelOffset
21 | }
22 |
23 | override var visibleViewport: Viewport
24 | get() = maximumViewport
25 | set(value) { maximumViewport = value }
26 |
27 | override fun constrainViewport(left: Float, top: Float, right: Float, bottom: Float) {
28 | super.constrainViewport(left, top, right, bottom)
29 | viewportChangeListener?.onViewportChanged(currentViewport)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/formatter/DateFormatters.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("unused")
2 |
3 | package co.csadev.kellocharts.formatter
4 |
5 | import co.csadev.kellocharts.model.*
6 | import java.text.DateFormat
7 | import java.util.*
8 | import kotlin.math.roundToLong
9 |
10 | private const val nullTerminator = '\u0000'
11 |
12 | private fun DateFormat.formatValue(formattedValue: CharArray, value: Float): Int {
13 | val dateResult = format(Date(value.roundToLong()))
14 | val dateLength = dateResult.length
15 | dateResult.mapIndexed { index, c ->
16 | formattedValue[index] = c
17 | }
18 | for (i in dateLength until formattedValue.size) {
19 | formattedValue[i] = nullTerminator
20 | }
21 | return dateLength
22 | }
23 |
24 |
25 |
26 | class DateAxisValueFormatter(private val dateFormat: DateFormat) : AxisValueFormatter {
27 | override fun formatValueForManualAxis(formattedValue: CharArray, axisValue: AxisValue)
28 | = dateFormat.formatValue(formattedValue, axisValue.value)
29 |
30 | override fun formatValueForAutoGeneratedAxis(formattedValue: CharArray, value: Float, autoDecimalDigits: Int)
31 | = dateFormat.formatValue(formattedValue, value)
32 |
33 | }
34 |
35 | class DateBubbleChartValueFormatterX(private val dateFormat: DateFormat) : BubbleChartValueFormatter {
36 | override fun formatChartValue(formattedValue: CharArray, value: BubbleValue)
37 | = dateFormat.formatValue(formattedValue, value.x)
38 | }
39 |
40 | class DateBubbleChartValueFormatterY(private val dateFormat: DateFormat) : BubbleChartValueFormatter {
41 | override fun formatChartValue(formattedValue: CharArray, value: BubbleValue)
42 | = dateFormat.formatValue(formattedValue, value.y)
43 | }
44 |
45 | class DateBubbleChartValueFormatterZ(private val dateFormat: DateFormat) : BubbleChartValueFormatter {
46 | override fun formatChartValue(formattedValue: CharArray, value: BubbleValue)
47 | = dateFormat.formatValue(formattedValue, value.z)
48 | }
49 |
50 | class DateColumnChartValueFormatter(private val dateFormat: DateFormat) : ColumnChartValueFormatter {
51 | override fun formatChartValue(formattedValue: CharArray, value: SubcolumnValue)
52 | = dateFormat.formatValue(formattedValue, value.value)
53 | }
54 |
55 | class DateLineChartValueFormatterX(private val dateFormat: DateFormat) : LineChartValueFormatter {
56 | override fun formatChartValue(formattedValue: CharArray, value: PointValue)
57 | = dateFormat.formatValue(formattedValue, value.x)
58 | }
59 |
60 | class DateLineChartValueFormatterY(private val dateFormat: DateFormat) : LineChartValueFormatter {
61 | override fun formatChartValue(formattedValue: CharArray, value: PointValue)
62 | = dateFormat.formatValue(formattedValue, value.y)
63 | }
64 |
65 | class DatePieChartValueFormatter(private val dateFormat: DateFormat) : PieChartValueFormatter {
66 | override fun formatChartValue(formattedValue: CharArray, value: SliceValue)
67 | = dateFormat.formatValue(formattedValue, value.value)
68 | }
69 |
70 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/formatter/ValueFormatterHelper.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.formatter
2 |
3 | import android.util.Log
4 | import co.csadev.kellocharts.util.FloatUtils
5 | import java.text.DecimalFormat
6 | import java.text.NumberFormat
7 |
8 | class ValueFormatterHelper(var decimalDigitsNumber: Int = Int.MIN_VALUE, var appendedText: CharArray = CharArray(0), var prependedText: CharArray = CharArray(0), var decimalSeparator: Char = '.') {
9 |
10 | fun determineDecimalSeparator() {
11 | val numberFormat = NumberFormat.getInstance()
12 | if (numberFormat is DecimalFormat) {
13 | decimalSeparator = numberFormat.decimalFormatSymbols.decimalSeparator
14 | }
15 | }
16 |
17 | fun setDecimalSeparator(decimalSeparator: Char): ValueFormatterHelper {
18 | val nullChar = '\u0000'
19 | if (nullChar != decimalSeparator) {
20 | this.decimalSeparator = decimalSeparator
21 | }
22 | return this
23 | }
24 |
25 | /**
26 | * Formats float value. Result is stored in (output) formattedValue array. Method
27 | * returns number of chars of formatted value. The formatted value starts at index [formattedValue.length -
28 | * charsNumber] and ends at index [formattedValue.length-1].
29 | * Note: If label is not null it will be used as formattedValue instead of float value.
30 | * Note: Parameter defaultDigitsNumber is used only if you didn't change decimalDigintsNumber value using
31 | * method [.setDecimalDigitsNumber].
32 | */
33 | @JvmOverloads
34 | fun formatFloatValueWithPrependedAndAppendedText(formattedValue: CharArray, value: Float, defaultDigitsNumber: Int, label: CharArray? = null): Int {
35 | if (null != label) {
36 | // If custom label is not null use only name characters as formatted value.
37 | // Copy label into formatted value array.
38 | var labelLength = label.size
39 | if (labelLength > formattedValue.size) {
40 | Log.w(TAG, "Label length is larger than buffer size(64chars), some chars will be skipped!")
41 | labelLength = formattedValue.size
42 | }
43 | System.arraycopy(label, 0, formattedValue, formattedValue.size - labelLength, labelLength)
44 | return labelLength
45 | }
46 |
47 | val appliedDigitsNumber = getAppliedDecimalDigitsNumber(defaultDigitsNumber)
48 | val charsNumber = formatFloatValue(formattedValue, value, appliedDigitsNumber)
49 | appendText(formattedValue)
50 | prependText(formattedValue, charsNumber)
51 | return charsNumber + prependedText.size + appendedText.size
52 | }
53 |
54 | /**
55 | * @see .formatFloatValueWithPrependedAndAppendedText
56 | */
57 | fun formatFloatValueWithPrependedAndAppendedText(formattedValue: CharArray, value: Float, label: CharArray?): Int {
58 | return formatFloatValueWithPrependedAndAppendedText(formattedValue, value, DEFAULT_DIGITS_NUMBER, label)
59 | }
60 |
61 | fun formatFloatValue(formattedValue: CharArray, value: Float, decimalDigitsNumber: Int): Int {
62 | return FloatUtils.formatFloat(formattedValue, value, formattedValue.size - appendedText.size,
63 | decimalDigitsNumber,
64 | decimalSeparator)
65 | }
66 |
67 | fun appendText(formattedValue: CharArray) {
68 | if (appendedText.isNotEmpty()) {
69 | System.arraycopy(appendedText, 0, formattedValue, formattedValue.size - appendedText.size,
70 | appendedText.size)
71 | }
72 | }
73 |
74 | fun prependText(formattedValue: CharArray, charsNumber: Int) {
75 | if (prependedText.isNotEmpty()) {
76 | System.arraycopy(prependedText, 0, formattedValue, formattedValue.size - charsNumber - appendedText.size
77 | - prependedText.size, prependedText.size)
78 | }
79 | }
80 |
81 | fun getAppliedDecimalDigitsNumber(defaultDigitsNumber: Int): Int {
82 | val appliedDecimalDigitsNumber: Int
83 | if (decimalDigitsNumber < 0) {
84 | //When decimalDigitsNumber < 0 that means that user didn't set that value and defaultDigitsNumber should
85 | // be used.
86 | appliedDecimalDigitsNumber = defaultDigitsNumber
87 | } else {
88 | appliedDecimalDigitsNumber = decimalDigitsNumber
89 | }
90 | return appliedDecimalDigitsNumber
91 | }
92 |
93 | companion object {
94 | val DEFAULT_DIGITS_NUMBER = 0
95 | private val TAG = "ValueFormatterHelper"
96 | }
97 |
98 | }
99 | /**
100 | * @see .formatFloatValueWithPrependedAndAppendedText
101 | */
102 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/formatter/ValueFormatterInterfaces.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.formatter
2 |
3 | import co.csadev.kellocharts.model.*
4 |
5 | interface AxisValueFormatter {
6 | fun formatValueForManualAxis(formattedValue: CharArray, axisValue: AxisValue): Int
7 | fun formatValueForAutoGeneratedAxis(formattedValue: CharArray, value: Float, autoDecimalDigits: Int): Int
8 | }
9 |
10 | interface BubbleChartValueFormatter {
11 | fun formatChartValue(formattedValue: CharArray, value: BubbleValue): Int
12 | }
13 |
14 | interface ColumnChartValueFormatter {
15 | fun formatChartValue(formattedValue: CharArray, value: SubcolumnValue): Int
16 | }
17 |
18 | interface LineChartValueFormatter {
19 | fun formatChartValue(formattedValue: CharArray, value: PointValue): Int
20 | }
21 |
22 | interface PieChartValueFormatter {
23 | fun formatChartValue(formattedValue: CharArray, value: SliceValue): Int
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/formatter/ValueFormatters.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.formatter
2 |
3 | import co.csadev.kellocharts.model.*
4 |
5 | open class ValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') {
6 | internal val valueFormatterHelper = ValueFormatterHelper(decimalDigitsNumber, appendedText, prependedText, decimalSeparator)
7 |
8 | open var decimalDigitsNumber: Int
9 | get() = valueFormatterHelper.decimalDigitsNumber
10 | set(value) { valueFormatterHelper.decimalDigitsNumber = value }
11 |
12 | open var appendedText: CharArray
13 | get() = valueFormatterHelper.appendedText
14 | set(value) { valueFormatterHelper.appendedText = value }
15 |
16 | open var prependedText: CharArray
17 | get() = valueFormatterHelper.prependedText
18 | set(value) { valueFormatterHelper.prependedText = value }
19 |
20 | open var decimalSeparator: Char
21 | get() = valueFormatterHelper.decimalSeparator
22 | set(value) { valueFormatterHelper.decimalSeparator = value }
23 |
24 | init {
25 | valueFormatterHelper.determineDecimalSeparator()
26 | }
27 | }
28 |
29 | open class SimplePieChartValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') : ValueFormatter(decimalDigitsNumber, appendedText, prependedText, decimalSeparator), PieChartValueFormatter {
30 | override fun formatChartValue(formattedValue: CharArray, value: SliceValue)
31 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, value.value, value.label)
32 | }
33 |
34 | open class SimpleLineChartValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') : ValueFormatter(decimalDigitsNumber, appendedText, prependedText, decimalSeparator), LineChartValueFormatter {
35 | override fun formatChartValue(formattedValue: CharArray, value: PointValue)
36 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, value.y, value.label)
37 | }
38 |
39 | open class SimpleColumnChartValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') : ValueFormatter(decimalDigitsNumber, appendedText, prependedText, decimalSeparator), ColumnChartValueFormatter {
40 | override fun formatChartValue(formattedValue: CharArray, value: SubcolumnValue)
41 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, value.value, value.label)
42 | }
43 |
44 | open class SimpleBubbleChartValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') : ValueFormatter(decimalDigitsNumber, appendedText, prependedText, decimalSeparator), BubbleChartValueFormatter {
45 | override fun formatChartValue(formattedValue: CharArray, value: BubbleValue)
46 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, value.z, value.label)
47 | }
48 |
49 | open class SimpleAxisValueFormatter(decimalDigitsNumber: Int = Int.MIN_VALUE, appendedText: CharArray = CharArray(0), prependedText: CharArray = CharArray(0), decimalSeparator: Char = '.') : ValueFormatter(decimalDigitsNumber, appendedText, prependedText, decimalSeparator), AxisValueFormatter {
50 | override fun formatValueForManualAxis(formattedValue: CharArray, axisValue: AxisValue)
51 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, axisValue.value, axisValue.label)
52 | override fun formatValueForAutoGeneratedAxis(formattedValue: CharArray, value: Float, autoDecimalDigits: Int)
53 | = valueFormatterHelper.formatFloatValueWithPrependedAndAppendedText(formattedValue, value, autoDecimalDigits)
54 | }
55 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/ChartScroller.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.gesture
2 |
3 | import android.content.Context
4 | import android.graphics.Point
5 | import androidx.core.widget.ScrollerCompat
6 |
7 | import co.csadev.kellocharts.computator.ChartComputator
8 | import co.csadev.kellocharts.model.Viewport
9 | import co.csadev.kellocharts.model.set
10 |
11 | /**
12 | * Encapsulates scrolling functionality.
13 | */
14 | class ChartScroller(context: Context) {
15 |
16 | private val scrollerStartViewport = Viewport() // Used only for zooms and flings
17 | private val surfaceSizeBuffer = Point()// Used for scroll and flings
18 | private val scroller: ScrollerCompat
19 |
20 | init {
21 | scroller = ScrollerCompat.create(context)
22 | }
23 |
24 | fun startScroll(computator: ChartComputator): Boolean {
25 | scroller.abortAnimation()
26 | scrollerStartViewport.set(computator.currentViewport)
27 | return true
28 | }
29 |
30 | fun scroll(computator: ChartComputator, distanceX: Float, distanceY: Float, scrollResult: ScrollResult): Boolean {
31 |
32 | // Scrolling uses math based on the viewport (as opposed to math using pixels). Pixel offset is the offset in
33 | // screen pixels, while viewport offset is the offset within the current viewport. For additional
34 | // information on
35 | // surface sizes and pixel offsets, see the docs for {@link computeScrollSurfaceSize()}. For additional
36 | // information about the viewport, see the comments for {@link mCurrentViewport}.
37 |
38 | val maxViewport = computator.maximumViewport
39 | val visibleViewport = computator.visibleViewport
40 | val currentViewport = computator.currentViewport
41 | val contentRect = computator.contentRectMinusAllMargins
42 |
43 | val canScrollLeft = currentViewport.left > maxViewport.left
44 | val canScrollRight = currentViewport.right < maxViewport.right
45 | val canScrollTop = currentViewport.top < maxViewport.top
46 | val canScrollBottom = currentViewport.bottom > maxViewport.bottom
47 |
48 | var canScrollX = false
49 | var canScrollY = false
50 |
51 | if (canScrollLeft && distanceX <= 0) {
52 | canScrollX = true
53 | } else if (canScrollRight && distanceX >= 0) {
54 | canScrollX = true
55 | }
56 |
57 | if (canScrollTop && distanceY <= 0) {
58 | canScrollY = true
59 | } else if (canScrollBottom && distanceY >= 0) {
60 | canScrollY = true
61 | }
62 |
63 | if (canScrollX || canScrollY) {
64 |
65 | computator.computeScrollSurfaceSize(surfaceSizeBuffer)
66 |
67 | val viewportOffsetX = distanceX * visibleViewport.width() / contentRect.width()
68 | val viewportOffsetY = -distanceY * visibleViewport.height() / contentRect.height()
69 |
70 | computator
71 | .setViewportTopLeft(currentViewport.left + viewportOffsetX, currentViewport.top + viewportOffsetY)
72 | }
73 |
74 | scrollResult.canScrollX = canScrollX
75 | scrollResult.canScrollY = canScrollY
76 |
77 | return canScrollX || canScrollY
78 | }
79 |
80 | fun computeScrollOffset(computator: ChartComputator): Boolean {
81 | if (scroller.computeScrollOffset()) {
82 | // The scroller isn't finished, meaning a fling or programmatic pan operation is
83 | // currently active.
84 |
85 | val maxViewport = computator.maximumViewport
86 |
87 | computator.computeScrollSurfaceSize(surfaceSizeBuffer)
88 |
89 | val currXRange = maxViewport.left + maxViewport.width() * scroller.currX / surfaceSizeBuffer.x
90 | val currYRange = maxViewport.top - maxViewport.height() * scroller.currY / surfaceSizeBuffer.y
91 |
92 | computator.setViewportTopLeft(currXRange, currYRange)
93 |
94 | return true
95 | }
96 |
97 | return false
98 | }
99 |
100 | fun fling(velocityX: Int, velocityY: Int, computator: ChartComputator): Boolean {
101 | // Flings use math in pixels (as opposed to math based on the viewport).
102 | computator.computeScrollSurfaceSize(surfaceSizeBuffer)
103 | scrollerStartViewport.set(computator.currentViewport)
104 |
105 | val startX = (surfaceSizeBuffer.x * (scrollerStartViewport.left - computator.maximumViewport.left) / computator.maximumViewport.width()).toInt()
106 | val startY = (surfaceSizeBuffer.y * (computator.maximumViewport.top - scrollerStartViewport.top) / computator.maximumViewport.height()).toInt()
107 |
108 | // TODO probably should be mScroller.forceFinish but ScrollerCompat doesn't have that method.
109 | scroller.abortAnimation()
110 |
111 | val width = computator.contentRectMinusAllMargins.width()
112 | val height = computator.contentRectMinusAllMargins.height()
113 | scroller.fling(startX, startY, velocityX, velocityY, 0, surfaceSizeBuffer.x - width + 1, 0,
114 | surfaceSizeBuffer.y - height + 1)
115 | return true
116 | }
117 |
118 | class ScrollResult {
119 | var canScrollX: Boolean = false
120 | var canScrollY: Boolean = false
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/ChartZoomer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.gesture
2 |
3 | import android.content.Context
4 | import android.graphics.PointF
5 | import android.view.MotionEvent
6 |
7 | import co.csadev.kellocharts.computator.ChartComputator
8 | import co.csadev.kellocharts.model.Viewport
9 | import co.csadev.kellocharts.model.set
10 |
11 | /**
12 | * Encapsulates zooming functionality.
13 | */
14 | class ChartZoomer(context: Context, var zoomType: ZoomType?) {
15 | private val zoomer = ZoomerCompat(context)
16 | private val zoomFocalPoint = PointF()// Used for double tap zoom
17 | private val viewportFocus = PointF()
18 | private val scrollerStartViewport = Viewport() // Used only for zooms and flings
19 |
20 | fun startZoom(e: MotionEvent, computator: ChartComputator): Boolean {
21 | zoomer.forceFinished(true)
22 | scrollerStartViewport.set(computator.currentViewport)
23 | if (!computator.rawPixelsToDataPoint(e.x, e.y, zoomFocalPoint)) {
24 | // Focus point is not within content area.
25 | return false
26 | }
27 | zoomer.startZoom(ZOOM_AMOUNT)
28 | return true
29 | }
30 |
31 | fun computeZoom(computator: ChartComputator): Boolean {
32 | if (zoomer.computeZoom()) {
33 | // Performs the zoom since a zoom is in progress.
34 | val newWidth = (1.0f - zoomer.currZoom) * scrollerStartViewport.width()
35 | val newHeight = (1.0f - zoomer.currZoom) * scrollerStartViewport.height()
36 | val pointWithinViewportX = (zoomFocalPoint.x - scrollerStartViewport.left) / scrollerStartViewport.width()
37 | val pointWithinViewportY = (zoomFocalPoint.y - scrollerStartViewport.bottom) / scrollerStartViewport.height()
38 |
39 | val left = zoomFocalPoint.x - newWidth * pointWithinViewportX
40 | val top = zoomFocalPoint.y + newHeight * (1 - pointWithinViewportY)
41 | val right = zoomFocalPoint.x + newWidth * (1 - pointWithinViewportX)
42 | val bottom = zoomFocalPoint.y - newHeight * pointWithinViewportY
43 | setCurrentViewport(computator, left, top, right, bottom)
44 | return true
45 | }
46 | return false
47 | }
48 |
49 | fun scale(computator: ChartComputator, focusX: Float, focusY: Float, scale: Float): Boolean {
50 | /**
51 | * Smaller viewport means bigger zoom so for zoomIn scale should have value <1, for zoomOout >1
52 | */
53 | val newWidth = scale * computator.currentViewport.width()
54 | val newHeight = scale * computator.currentViewport.height()
55 | if (!computator.rawPixelsToDataPoint(focusX, focusY, viewportFocus)) {
56 | // Focus point is not within content area.
57 | return false
58 | }
59 |
60 | val left = viewportFocus.x - (focusX - computator.contentRectMinusAllMargins.left) * (newWidth / computator.contentRectMinusAllMargins.width())
61 | val top = viewportFocus.y + (focusY - computator.contentRectMinusAllMargins.top) * (newHeight / computator.contentRectMinusAllMargins.height())
62 | val right = left + newWidth
63 | val bottom = top - newHeight
64 | setCurrentViewport(computator, left, top, right, bottom)
65 | return true
66 | }
67 |
68 | private fun setCurrentViewport(computator: ChartComputator, left: Float, top: Float, right: Float, bottom: Float) {
69 | val currentViewport = computator.currentViewport
70 | when (zoomType ?: return) {
71 | ZoomType.HORIZONTAL -> computator.setCurrentViewport(left, currentViewport.top, right, currentViewport.bottom)
72 | ZoomType.VERTICAL -> computator.setCurrentViewport(currentViewport.left, top, currentViewport.right, bottom)
73 | ZoomType.HORIZONTAL_AND_VERTICAL -> computator.setCurrentViewport(left, top, right, bottom)
74 | }
75 | }
76 |
77 | companion object {
78 | val ZOOM_AMOUNT = 0.25f
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/ContainerScrollType.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.gesture
2 |
3 | /**
4 | * Enum used to inform chart in which type of container it exists.
5 | */
6 | enum class ContainerScrollType {
7 | HORIZONTAL, VERTICAL
8 | }
9 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/PreviewChartTouchHandler.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.gesture
2 |
3 | import android.content.Context
4 | import android.view.GestureDetector
5 | import android.view.MotionEvent
6 | import android.view.ScaleGestureDetector
7 |
8 | import co.csadev.kellocharts.view.Chart
9 |
10 | /**
11 | * Touch Handler for preview charts. It scroll and zoom only preview area, not all preview chart data.
12 | */
13 | class PreviewChartTouchHandler(context: Context, chart: Chart) : ChartTouchHandler(context, chart) {
14 |
15 | init {
16 | gestureDetector = GestureDetector(context, PreviewChartGestureListener())
17 | scaleGestureDetector = ScaleGestureDetector(context, ChartScaleGestureListener())
18 |
19 | // Disable value touch and selection mode, by default not needed for preview chart.
20 | isValueTouchEnabled = false
21 | isValueSelectionEnabled = false
22 | }
23 |
24 | protected inner class ChartScaleGestureListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
25 |
26 | override fun onScale(detector: ScaleGestureDetector): Boolean {
27 | if (isZoomEnabled) {
28 | var scale = detector.currentSpan / detector.previousSpan
29 | if (java.lang.Float.isInfinite(scale)) {
30 | scale = 1f
31 | }
32 | return chartZoomer.scale(computator, detector.focusX, detector.focusY, scale)
33 | }
34 |
35 | return false
36 | }
37 | }
38 |
39 | protected inner class PreviewChartGestureListener : ChartTouchHandler.ChartGestureListener() {
40 |
41 | override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
42 | return super.onScroll(e1, e2, -distanceX, -distanceY)
43 | }
44 |
45 | override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
46 | return super.onFling(e1, e2, -velocityX, -velocityY)
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/ZoomType.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.gesture
2 |
3 | enum class ZoomType {
4 | HORIZONTAL, VERTICAL, HORIZONTAL_AND_VERTICAL
5 | }
6 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/gesture/ZoomerCompat.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package co.csadev.kellocharts.gesture
18 |
19 | import android.content.Context
20 | import android.os.SystemClock
21 | import android.view.animation.DecelerateInterpolator
22 | import android.view.animation.Interpolator
23 |
24 | /**
25 | * A simple class that animates double-touch zoom gestures. Functionally similar to a [android.widget.Scroller].
26 | */
27 | class ZoomerCompat(context: Context) {
28 | /**
29 | * The interpolator, used for making zooms animate 'naturally.'
30 | */
31 | private val mInterpolator: Interpolator
32 |
33 | /**
34 | * The total animation duration for a zoom.
35 | */
36 | private val mAnimationDurationMillis: Long
37 |
38 | /**
39 | * Whether or not the current zoom has finished.
40 | */
41 | private var mFinished = true
42 |
43 | /**
44 | * The current zoom value; computed by [.computeZoom].
45 | */
46 | /**
47 | * Returns the current zoom level.
48 | *
49 | * @see android.widget.Scroller.getCurrX
50 | */
51 | var currZoom: Float = 0.toFloat()
52 | private set
53 |
54 | /**
55 | * The time the zoom started, computed using [SystemClock.elapsedRealtime].
56 | */
57 | private var mStartRTC: Long = 0
58 |
59 | /**
60 | * The destination zoom factor.
61 | */
62 | private var mEndZoom: Float = 0.toFloat()
63 |
64 | init {
65 | mInterpolator = DecelerateInterpolator()
66 | // TODO: use constant
67 | mAnimationDurationMillis = DEFAULT_SHORT_ANIMATION_DURATION.toLong()
68 | }
69 |
70 | /**
71 | * Forces the zoom finished state to the given value. Unlike [.abortAnimation], the current zoom value isn't
72 | * set to the ending value.
73 | *
74 | * @see android.widget.Scroller.forceFinished
75 | */
76 | fun forceFinished(finished: Boolean) {
77 | mFinished = finished
78 | }
79 |
80 | /**
81 | * Aborts the animation, setting the current zoom value to the ending value.
82 | *
83 | * @see android.widget.Scroller.abortAnimation
84 | */
85 | fun abortAnimation() {
86 | mFinished = true
87 | currZoom = mEndZoom
88 | }
89 |
90 | /**
91 | * Starts a zoom from 1.0 to (1.0 + endZoom). That is, to zoom from 100% to 125%, endZoom should by 0.25f.
92 | *
93 | * @see android.widget.Scroller.startScroll
94 | */
95 | fun startZoom(endZoom: Float) {
96 | mStartRTC = SystemClock.elapsedRealtime()
97 | mEndZoom = endZoom
98 |
99 | mFinished = false
100 | currZoom = 1f
101 | }
102 |
103 | /**
104 | * Computes the current zoom level, returning true if the zoom is still active and false if the zoom has finished.
105 | *
106 | * @see android.widget.Scroller.computeScrollOffset
107 | */
108 | fun computeZoom(): Boolean {
109 | if (mFinished) {
110 | return false
111 | }
112 |
113 | val tRTC = SystemClock.elapsedRealtime() - mStartRTC
114 | if (tRTC >= mAnimationDurationMillis) {
115 | mFinished = true
116 | currZoom = mEndZoom
117 | return false
118 | }
119 |
120 | val t = tRTC * 1f / mAnimationDurationMillis
121 | currZoom = mEndZoom * mInterpolator.getInterpolation(t)
122 | return true
123 | }
124 |
125 | companion object {
126 | private val DEFAULT_SHORT_ANIMATION_DURATION = 200
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/listener/ChartListeners.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.listener
2 |
3 | import co.csadev.kellocharts.model.*
4 |
5 | interface BubbleChartOnValueSelectListener : OnValueDeselectListener {
6 | fun onValueSelected(bubbleIndex: Int, value: BubbleValue)
7 | }
8 |
9 | interface ColumnChartOnValueSelectListener : OnValueDeselectListener {
10 | fun onValueSelected(columnIndex: Int, subcolumnIndex: Int, value: SubcolumnValue)
11 | }
12 |
13 | interface ComboLineColumnChartOnValueSelectListener : OnValueDeselectListener {
14 | fun onColumnValueSelected(columnIndex: Int, subcolumnIndex: Int, value: SubcolumnValue)
15 | fun onPointValueSelected(lineIndex: Int, pointIndex: Int, value: PointValue)
16 | }
17 |
18 | interface LineChartOnValueSelectListener : OnValueDeselectListener {
19 | fun onValueSelected(lineIndex: Int, pointIndex: Int, value: PointValue)
20 | }
21 |
22 | interface OnValueDeselectListener {
23 | fun onValueDeselected()
24 | }
25 |
26 | interface PieChartOnValueSelectListener : OnValueDeselectListener {
27 | fun onValueSelected(arcIndex: Int, value: SliceValue)
28 | }
29 |
30 | interface ViewportChangeListener {
31 | fun onViewportChanged(viewport: Viewport)
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/listener/DummyChartListeners.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.listener
2 |
3 | import co.csadev.kellocharts.model.*
4 |
5 | class DummyBubbleChartOnValueSelectListener : BubbleChartOnValueSelectListener {
6 | override fun onValueSelected(bubbleIndex: Int, value: BubbleValue) { }
7 | override fun onValueDeselected() { }
8 | }
9 |
10 | class DummyColumnChartOnValueSelectListener : ColumnChartOnValueSelectListener {
11 | override fun onValueSelected(columnIndex: Int, subcolumnIndex: Int, value: SubcolumnValue) {}
12 | override fun onValueDeselected() {}
13 | }
14 |
15 |
16 | class DummyCompoLineColumnChartOnValueSelectListener : ComboLineColumnChartOnValueSelectListener {
17 | override fun onColumnValueSelected(columnIndex: Int, subcolumnIndex: Int, value: SubcolumnValue) { }
18 | override fun onPointValueSelected(lineIndex: Int, pointIndex: Int, value: PointValue) { }
19 | override fun onValueDeselected() { }
20 | }
21 |
22 | class DummyLineChartOnValueSelectListener : LineChartOnValueSelectListener {
23 | override fun onValueSelected(lineIndex: Int, pointIndex: Int, value: PointValue) { }
24 | override fun onValueDeselected() { }
25 | }
26 |
27 | class DummyPieChartOnValueSelectListener : PieChartOnValueSelectListener {
28 | override fun onValueSelected(arcIndex: Int, value: SliceValue) { }
29 | override fun onValueDeselected() { }
30 | }
31 |
32 | class DummyViewportChangeListener : ViewportChangeListener {
33 | override fun onViewportChanged(viewport: Viewport) { }
34 | }
35 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/AbstractChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import android.graphics.Color
4 | import android.graphics.Typeface
5 |
6 | import co.csadev.kellocharts.util.ChartUtils
7 |
8 | /**
9 | * Base class for most chart data models.
10 | */
11 | abstract class AbstractChartData : ChartData {
12 | override var axisXBottom: Axis? = null
13 | override var axisYLeft: Axis? = null
14 | override var axisXTop: Axis? = null
15 | override var axisYRight: Axis? = null
16 | override var valueLabelTextColor = Color.WHITE
17 | override var valueLabelTextSize = DEFAULT_TEXT_SIZE_SP
18 | override var valueLabelTypeface: Typeface? = null
19 |
20 | /**
21 | * If true each value label will have background rectangle
22 | */
23 | override var isValueLabelBackgroundEnabled = true
24 |
25 | /**
26 | * If true and [.isValueLabelBackgroundEnabled] is true each label will have background rectangle and that
27 | * rectangle will be filled with color specified for given value.
28 | */
29 | override var isValueLabelBackgroundAuto = true
30 |
31 | /**
32 | * If [.isValueLabelBackgroundEnabled] is true and [.isValueLabelBackgrountAuto] is false each label
33 | * will have background rectangle and that rectangle will be filled with this color. Helpful if you want all labels
34 | * to have the same background color.
35 | */
36 | override var valueLabelBackgroundColor = ChartUtils.darkenColor(ChartUtils.DEFAULT_DARKEN_COLOR)
37 |
38 | fun deepCopy(newItem: AbstractChartData) {
39 | newItem.axisXBottom = axisXBottom
40 | newItem.axisXTop = axisXTop
41 | newItem.axisYLeft = axisYLeft
42 | newItem.axisYRight = axisYRight
43 | newItem.valueLabelTextColor = valueLabelTextColor
44 | newItem.valueLabelTextSize = valueLabelTextSize
45 | newItem.valueLabelTypeface = valueLabelTypeface
46 | }
47 |
48 | fun withData(original: AbstractChartData) : AbstractChartData {
49 | axisXBottom = original.axisXBottom
50 | axisXTop = original.axisXTop
51 | axisYLeft = original.axisYLeft
52 | axisYRight = original.axisYRight
53 | valueLabelTextColor = original.valueLabelTextColor
54 | valueLabelTextSize = original.valueLabelTextSize
55 | valueLabelTypeface = original.valueLabelTypeface
56 | return this
57 | }
58 |
59 | companion object {
60 | val DEFAULT_TEXT_SIZE_SP = 12
61 | }
62 |
63 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/Axis.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import android.graphics.Color
4 | import android.graphics.Typeface
5 | import co.csadev.kellocharts.formatter.AxisValueFormatter
6 | import co.csadev.kellocharts.formatter.SimpleAxisValueFormatter
7 | import co.csadev.kellocharts.util.ChartUtils
8 | import java.util.*
9 |
10 | /**
11 | * Single axis model. By default axis is auto-generated. Use [.setAutoGenerated] to disable axis values
12 | * generation and set values manually using [.setValues]. If Axis is auto-generated [.setValues]
13 | * will be ignored but if you set some values Axis will switch to manual mode. Change how axis labels are displayed by
14 | * changing formatter [.setFormatter]. Axis can have a name
15 | * that should be displayed next to
16 | * labels(that depends on renderer implementation), you can change name using [.setName], by default axis
17 | * name is empty and therefore not displayed.
18 | */
19 | class Axis(values: MutableList = ArrayList(),
20 | var name: String? = null,
21 | var isAutoGenerated: Boolean = true,
22 | var hasLines: Boolean = false,
23 | var isInside: Boolean = false,
24 | var textColor: Int = Color.LTGRAY,
25 | var lineColor: Int = ChartUtils.DEFAULT_DARKEN_COLOR,
26 | var textSize: Int = DEFAULT_TEXT_SIZE_SP,
27 | maxLabelChars: Int = DEFAULT_MAX_AXIS_LABEL_CHARS,
28 | var typeface: Typeface? = null,
29 | var formatter: AxisValueFormatter = SimpleAxisValueFormatter(),
30 | var hasSeparationLine: Boolean = true,
31 | var hasTiltedLabels: Boolean = false,
32 | var isReversed: Boolean = false,
33 | var maxLabels: Int = -1) {
34 |
35 | var maxLabelChars: Int = maxLabelChars
36 | set(value) {
37 | field = Math.min(32, Math.max(0, value))
38 | }
39 |
40 | var values: MutableList = values
41 | get() {
42 | //Copy and transfer to ensure that other value logic stays intact
43 | if (isReversed) {
44 | return field.indices.reversed().mapTo(ArrayList()) { field[it] }
45 | }
46 | return field
47 | }
48 | set(value) {
49 | field = value
50 | this.isAutoGenerated = false
51 | }
52 |
53 | fun copy() = Axis(values.map { it.copy() }.toMutableList(), name, isAutoGenerated, hasLines, isInside, textColor, lineColor, textSize, maxLabelChars, typeface, formatter, hasSeparationLine)
54 |
55 | companion object {
56 | const val DEFAULT_TEXT_SIZE_SP = 12
57 | const val DEFAULT_MAX_AXIS_LABEL_CHARS = 3
58 |
59 | /**
60 | * Generates Axis with values from start to stop inclusive.
61 | */
62 | fun generateAxisFromRange(start: Float, stop: Float, step: Float): Axis {
63 |
64 | val values = ArrayList()
65 | var value = start
66 | while (value <= stop) {
67 | val axisValue = AxisValue(value)
68 | values.add(axisValue)
69 | value += step
70 | }
71 |
72 | return Axis(values = values)
73 | }
74 |
75 | /**
76 | * Generates Axis with values from given list.
77 | */
78 | fun generateAxisFromCollection(axisValues: List): Axis {
79 | val values = ArrayList()
80 | var index = 0
81 | for (value in axisValues) {
82 | val axisValue = AxisValue(value)
83 | values.add(axisValue)
84 | ++index
85 | }
86 |
87 | return Axis(values = values)
88 | }
89 |
90 | /**
91 | * Generates Axis with values and labels from given lists, both lists must have the same size.
92 | */
93 | fun generateAxisFromCollection(axisValues: List, axisValuesLabels: List): Axis {
94 | if (axisValues.size != axisValuesLabels.size) {
95 | throw IllegalArgumentException("Values and labels lists must have the same size!")
96 | }
97 | return Axis(values = axisValues.mapIndexedTo(ArrayList()) { index, value -> AxisValue(value, axisValuesLabels[index].toCharArray()) })
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/AxisValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import java.util.*
4 |
5 | /**
6 | * Single axis value, use it to manually set axis labels position. You can use label attribute to display text instead
7 | * of number but value formatter implementation have to handle it.
8 | */
9 | class AxisValue(var value: Float = 0f, var label: CharArray? = null) {
10 | constructor(value: Int, label: CharArray? = null) : this(value.toFloat(), label)
11 | constructor(value: Int, label: String) : this(value.toFloat(), label.toCharArray())
12 |
13 | fun copy() = AxisValue(this.value, this.label)
14 |
15 | override fun equals(other: Any?): Boolean {
16 | if (this === other) return true
17 | if (other == null || javaClass != other.javaClass) return false
18 |
19 | val axisValue = other as AxisValue?
20 |
21 | if (java.lang.Float.compare(axisValue!!.value, value) != 0) return false
22 | return Arrays.equals(label, axisValue.label)
23 |
24 | }
25 |
26 | override fun hashCode(): Int {
27 | var result = if (value != +0.0f) java.lang.Float.floatToIntBits(value) else 0
28 | result = 31 * result + if (label != null) Arrays.hashCode(label) else 0
29 | return result
30 | }
31 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/BubbleChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.formatter.BubbleChartValueFormatter
4 | import co.csadev.kellocharts.formatter.SimpleBubbleChartValueFormatter
5 | import co.csadev.kellocharts.model.dsl.bubbleData
6 | import co.csadev.kellocharts.view.Chart
7 | import java.util.*
8 |
9 | /**
10 | * Data for BubbleChart.
11 | */
12 | class BubbleChartData(var values: MutableList = ArrayList(), var formatter: BubbleChartValueFormatter = SimpleBubbleChartValueFormatter(), hasLabels: Boolean = false, var hasLabelsOnlyForSelected: Boolean = false, var minBubbleRadius: Int = DEFAULT_MIN_BUBBLE_RADIUS_DP, var bubbleScale: Float = DEFAULT_BUBBLE_SCALE) : AbstractChartData() {
13 | var hasLabels = hasLabels
14 | set(value) {
15 | field = value
16 | if (field) hasLabelsOnlyForSelected = false
17 | }
18 |
19 | fun copy() = BubbleChartData(values.map { it.copy() }.toMutableList(), formatter, hasLabels, hasLabelsOnlyForSelected, minBubbleRadius, bubbleScale)
20 |
21 | override fun update(scale: Float) {
22 | for (value in values) {
23 | value.update(scale)
24 | }
25 | }
26 |
27 | override fun finish() {
28 | for (value in values) {
29 | value.finish()
30 | }
31 | }
32 |
33 | /**
34 | * Set true if you want to show value labels only for selected value, works best when chart has
35 | * isValueSelectionEnabled set to true [Chart.setValueSelectionEnabled].
36 | */
37 | fun setHasLabelsOnlyForSelected(hasLabelsOnlyForSelected: Boolean): BubbleChartData {
38 | this.hasLabelsOnlyForSelected = hasLabelsOnlyForSelected
39 | if (hasLabelsOnlyForSelected) {
40 | this.hasLabels = false
41 | }
42 | return this
43 | }
44 |
45 | companion object {
46 | val DEFAULT_MIN_BUBBLE_RADIUS_DP = 6
47 | val DEFAULT_BUBBLE_SCALE = 1f
48 |
49 | fun generateDummyData() =
50 | bubbleData {
51 | bubbles {
52 | bubble {
53 | x = 0f
54 | y = 20f
55 | z = 15000f
56 | }
57 | bubble {
58 | x = 3f
59 | y = 22f
60 | z = 20000f
61 | }
62 | bubble {
63 | x = 5f
64 | y = 25f
65 | z = 5000f
66 | }
67 | bubble {
68 | x = 7f
69 | y = 30f
70 | z = 30000f
71 | }
72 | bubble {
73 | x = 11f
74 | y = 22f
75 | z = 10f
76 | }
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/BubbleValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.util.ChartUtils
4 | import co.csadev.kellocharts.view.Chart
5 | import java.util.*
6 |
7 | /**
8 | * Single value drawn as bubble on BubbleChart.
9 | */
10 | class BubbleValue(x: Float = 0f, y: Float = 0f, z: Float = 0f, color: Int = ChartUtils.DEFAULT_COLOR, var label: CharArray? = null, var shape: ValueShape? = ValueShape.CIRCLE) {
11 | /**
12 | * Current X value.
13 | */
14 | var x: Float = x
15 | private set
16 | /**
17 | * Current Y value.
18 | */
19 | var y: Float = y
20 | private set
21 | /**
22 | * Current Z value , third bubble value interpreted as bubble area.
23 | */
24 | var z: Float = z
25 | private set
26 |
27 | var color = color
28 | set(value) {
29 | field = value
30 | darkenColor = ChartUtils.darkenColor(field)
31 | }
32 | var darkenColor = ChartUtils.DEFAULT_DARKEN_COLOR
33 | private set
34 |
35 | /**
36 | * Origin X value, used during value animation.
37 | */
38 | private var originX: Float = x
39 | /**
40 | * Origin Y value, used during value animation.
41 | */
42 | private var originY: Float = y
43 | /**
44 | * Origin Z value, used during value animation.
45 | */
46 | private var originZ: Float = z
47 |
48 | /**
49 | * Difference between originX value and target X value.
50 | */
51 | private var diffX: Float = x - originX
52 |
53 | /**
54 | * Difference between originX value and target X value.
55 | */
56 | private var diffY: Float = y - originY
57 |
58 | /**
59 | * Difference between originX value and target X value.
60 | */
61 | private var diffZ: Float = z - originZ
62 |
63 | fun copy() = BubbleValue(x, y, z, color, label)
64 |
65 | fun update(scale: Float) {
66 | x = originX + diffX * scale
67 | y = originY + diffY * scale
68 | z = originZ + diffZ * scale
69 | }
70 |
71 | fun finish() {
72 | set(originX + diffX, originY + diffY, originZ + diffZ)
73 | }
74 |
75 | operator fun set(x: Float, y: Float, z: Float): BubbleValue {
76 | this.x = x
77 | this.y = y
78 | this.z = z
79 | this.originX = x
80 | this.originY = y
81 | this.originZ = z
82 | this.diffX = 0f
83 | this.diffY = 0f
84 | this.diffZ = 0f
85 | return this
86 | }
87 |
88 | /**
89 | * Set target values that should be reached when data animation finish then call [Chart.startDataAnimation]
90 | */
91 | fun setTarget(targetX: Float, targetY: Float, targetZ: Float): BubbleValue {
92 | set(x, y, z)
93 | this.diffX = targetX - originX
94 | this.diffY = targetY - originY
95 | this.diffZ = targetZ - originZ
96 | return this
97 | }
98 |
99 | override fun toString(): String {
100 | return "BubbleValue [x=$x, y=$y, z=$z]"
101 | }
102 |
103 | override fun equals(o: Any?): Boolean {
104 | if (this === o) return true
105 | if (o == null || javaClass != o.javaClass) return false
106 |
107 | val that = o as BubbleValue?
108 |
109 | if (color != that!!.color) return false
110 | if (darkenColor != that.darkenColor) return false
111 | if (java.lang.Float.compare(that.diffX, diffX) != 0) return false
112 | if (java.lang.Float.compare(that.diffY, diffY) != 0) return false
113 | if (java.lang.Float.compare(that.diffZ, diffZ) != 0) return false
114 | if (java.lang.Float.compare(that.originX, originX) != 0) return false
115 | if (java.lang.Float.compare(that.originY, originY) != 0) return false
116 | if (java.lang.Float.compare(that.originZ, originZ) != 0) return false
117 | if (java.lang.Float.compare(that.x, x) != 0) return false
118 | if (java.lang.Float.compare(that.y, y) != 0) return false
119 | if (java.lang.Float.compare(that.z, z) != 0) return false
120 | if (!Arrays.equals(label, that.label)) return false
121 | return shape === that.shape
122 |
123 | }
124 |
125 | override fun hashCode(): Int {
126 | var result = if (x != +0.0f) java.lang.Float.floatToIntBits(x) else 0
127 | result = 31 * result + if (y != +0.0f) java.lang.Float.floatToIntBits(y) else 0
128 | result = 31 * result + if (z != +0.0f) java.lang.Float.floatToIntBits(z) else 0
129 | result = 31 * result + if (originX != +0.0f) java.lang.Float.floatToIntBits(originX) else 0
130 | result = 31 * result + if (originY != +0.0f) java.lang.Float.floatToIntBits(originY) else 0
131 | result = 31 * result + if (originZ != +0.0f) java.lang.Float.floatToIntBits(originZ) else 0
132 | result = 31 * result + if (diffX != +0.0f) java.lang.Float.floatToIntBits(diffX) else 0
133 | result = 31 * result + if (diffY != +0.0f) java.lang.Float.floatToIntBits(diffY) else 0
134 | result = 31 * result + if (diffZ != +0.0f) java.lang.Float.floatToIntBits(diffZ) else 0
135 | result = 31 * result + color
136 | result = 31 * result + darkenColor
137 | result = 31 * result + if (shape != null) shape!!.hashCode() else 0
138 | result = 31 * result + if (label != null) Arrays.hashCode(label) else 0
139 | return result
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/ChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import android.graphics.Typeface
4 |
5 | /**
6 | * Base interface for all chart data models.
7 | */
8 | interface ChartData {
9 |
10 | /**
11 | * @see .setAxisXBottom
12 | */
13 | /**
14 | * Set horizontal axis at the bottom of the chart. Pass null to remove that axis.
15 | *
16 | * @param axisX
17 | */
18 | var axisXBottom: Axis?
19 |
20 | /**
21 | * @see .setAxisYLeft
22 | */
23 | /**
24 | * Set vertical axis on the left of the chart. Pass null to remove that axis.
25 | *
26 | * @param axisY
27 | */
28 | var axisYLeft: Axis?
29 |
30 | /**
31 | * @see .setAxisXTop
32 | */
33 | /**
34 | * Set horizontal axis at the top of the chart. Pass null to remove that axis.
35 | *
36 | * @param axisX
37 | */
38 | var axisXTop: Axis?
39 |
40 | /**
41 | * @see .setAxisYRight
42 | */
43 | /**
44 | * Set vertical axis on the right of the chart. Pass null to remove that axis.
45 | *
46 | * @param axisY
47 | */
48 | var axisYRight: Axis?
49 |
50 | /**
51 | * Returns color used to draw value label text.
52 | */
53 | var valueLabelTextColor: Int
54 |
55 | /**
56 | * Returns text size for value label in SP units.
57 | */
58 | /**
59 | * Set text size for value label in SP units.
60 | */
61 | var valueLabelTextSize: Int
62 |
63 | /**
64 | * Returns Typeface for value labels.
65 | *
66 | * @return Typeface or null if Typeface is not set.
67 | */
68 | /**
69 | * Set Typeface for all values labels.
70 | *
71 | * @param typeface
72 | */
73 | var valueLabelTypeface: Typeface?
74 |
75 | /**
76 | * @see .setValueLabelBackgroundEnabled
77 | */
78 | /**
79 | * Set whether labels should have rectangle background. Default is true.
80 | */
81 | var isValueLabelBackgroundEnabled: Boolean
82 |
83 | /**
84 | * @see .setValueLabelBackgroundAuto
85 | */
86 | /**
87 | * Set false if you want to set custom color for all value labels. Default is true.
88 | */
89 | var isValueLabelBackgroundAuto: Boolean
90 |
91 | /**
92 | * @see .setValueLabelBackgroundColor
93 | */
94 | /**
95 | * Set value labels background. This value is used only if isValueLabelBackgroundAuto returns false. Default is
96 | * green.
97 | */
98 | var valueLabelBackgroundColor: Int
99 |
100 | /**
101 | * Updates data by scale during animation.
102 | *
103 | * @param scale value from 0 to 1.0
104 | */
105 | fun update(scale: Float)
106 |
107 | /**
108 | * Inform data that animation finished(data should be update with scale 1.0f).
109 | */
110 | fun finish()
111 | }
112 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/Column.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.formatter.ColumnChartValueFormatter
4 | import co.csadev.kellocharts.formatter.SimpleColumnChartValueFormatter
5 | import java.util.*
6 |
7 | /**
8 | * Single column for ColumnChart. One column can be divided into multiple sub-columns(ColumnValues) especially for
9 | * stacked ColumnChart.
10 | * Note: you can set X value for columns or sub-columns, columns are by default indexed from 0 to numOfColumns-1 and
11 | * column index is used as column X value, so first column has X value 0, second clumn has X value 1 etc.
12 | * If you want to display AxisValue for given column you should initialize AxisValue with X value of that column.
13 | */
14 | class Column(var values: MutableList = ArrayList(), hasLabels: Boolean = false, hasLabelsOnlyForSelected: Boolean = false, var formatter: ColumnChartValueFormatter = SimpleColumnChartValueFormatter()) {
15 | var hasLabels: Boolean = hasLabels
16 | set(value) {
17 | field = value
18 | if (field) hasLabelsOnlyForSelected = false
19 | }
20 |
21 | var hasLabelsOnlyForSelected: Boolean = hasLabelsOnlyForSelected
22 | set(value) {
23 | field = value
24 | if (field) hasLabels = false
25 | }
26 |
27 | fun update(scale: Float) = values.forEach { it.update(scale) }
28 |
29 | fun finish() = values.forEach { it.finish() }
30 |
31 | fun copy() = Column(values.map { it.copy() }.toMutableList(), hasLabels, hasLabelsOnlyForSelected, formatter)
32 | }
33 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/ColumnChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.model.dsl.columnData
4 | import java.util.*
5 |
6 | /**
7 | * Data model for column chart. Note: you can set X value for columns or sub-columns, columns are by default indexed
8 | * from 0 to numOfColumns-1 and
9 | * column index is used as column X value, so first column has X value 0, second clumn has X value 1 etc.
10 | * If you want to display AxisValue for given column you should initialize AxisValue with X value of that column.
11 | */
12 | class ColumnChartData(var columns: MutableList = ArrayList(), var isStacked: Boolean = false, var isHorizontal: Boolean = true) : AbstractChartData() {
13 | var fillRatio = DEFAULT_FILL_RATIO
14 | set(value) {
15 | field = Math.min(1f, Math.max(0f, value))
16 | }
17 | var baseValue = DEFAULT_BASE_VALUE
18 |
19 |
20 | var _axisXTop: Axis? = null
21 | override var axisXTop: Axis?
22 | get() {
23 | return if (isHorizontal) {
24 | _axisYRight
25 | } else _axisXTop
26 | }
27 | set(value) { _axisXTop = value }
28 | var _axisXBottom: Axis? = null
29 | override var axisXBottom: Axis?
30 | get() {
31 | return if (isHorizontal) {
32 | _axisYLeft
33 | } else _axisXBottom
34 | }
35 | set(value) { _axisXBottom = value }
36 | var _axisYLeft: Axis? = null
37 | override var axisYLeft: Axis?
38 | get() {
39 | return if (isHorizontal) {
40 | _axisXBottom
41 | } else _axisYLeft
42 | }
43 | set(value) { _axisYLeft = value }
44 | var _axisYRight: Axis? = null
45 | override var axisYRight: Axis?
46 | get() {
47 | return if (isHorizontal) {
48 | _axisXTop
49 | } else _axisYRight
50 | }
51 | set(value) { _axisYRight = value }
52 |
53 | fun copy() = ColumnChartData(columns.map { it.copy() }.toMutableList(), isStacked, isHorizontal).withData(this) as ColumnChartData
54 |
55 | override fun update(scale: Float) {
56 | for (column in columns) {
57 | column.update(scale)
58 | }
59 |
60 | }
61 |
62 | override fun finish() = columns.forEach { it.finish() }
63 |
64 | companion object {
65 | const val DEFAULT_FILL_RATIO = 0.75f
66 | const val DEFAULT_BASE_VALUE = 0.0f
67 |
68 | fun generateDummyData() =
69 | columnData {
70 | columns {
71 | column {
72 | columnValues {
73 | subcolumn {
74 | value = 4f
75 | }
76 | subcolumn {
77 | value = 3f
78 | }
79 | subcolumn {
80 | value = 2f
81 | }
82 | subcolumn {
83 | value = 1f
84 | }
85 | }
86 | }
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/ComboLineColumnChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | /**
4 | * Data model for combo line-column chart. It uses ColumnChartData and LineChartData internally.
5 | */
6 | class ComboLineColumnChartData(var columnChartData: ColumnChartData = ColumnChartData(), var lineChartData: LineChartData = LineChartData()) : AbstractChartData() {
7 | override fun update(scale: Float) {
8 | columnChartData.update(scale)
9 | lineChartData.update(scale)
10 | }
11 |
12 | override fun finish() {
13 | columnChartData.finish()
14 | lineChartData.finish()
15 | }
16 |
17 | companion object {
18 | fun generateDummyData() = ComboLineColumnChartData(ColumnChartData.generateDummyData(), LineChartData.generateDummyData())
19 | fun fromComboData(data: ComboLineColumnChartData) = ComboLineColumnChartData(data.columnChartData, data.lineChartData).withData(data) as ComboLineColumnChartData
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/Line.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import android.graphics.PathEffect
4 | import co.csadev.kellocharts.formatter.LineChartValueFormatter
5 | import co.csadev.kellocharts.formatter.SimpleLineChartValueFormatter
6 | import co.csadev.kellocharts.util.ChartUtils
7 | import java.util.*
8 |
9 | /**
10 | * Single line for line chart.
11 | */
12 | class Line(var values: MutableList = ArrayList(),
13 | color: Int = ChartUtils.DEFAULT_COLOR,
14 | pointColor: Int = color,
15 | darkenColor: Int = ChartUtils.darkenColor(color),
16 | var formatter: LineChartValueFormatter = SimpleLineChartValueFormatter(),
17 | var shape: ValueShape = ValueShape.CIRCLE,
18 | var isFilled: Boolean = false,
19 | isSquare: Boolean = false,
20 | isCubic: Boolean = false,
21 | var pointRadius: Int = DEFAULT_POINT_RADIUS_DP,
22 | var areaTransparency: Int = DEFAULT_AREA_TRANSPARENCY,
23 | var strokeWidth: Int = DEFAULT_LINE_STROKE_WIDTH_DP,
24 | var hasPoints: Boolean = true,
25 | var hasLines: Boolean = true,
26 | hasLabels: Boolean = true,
27 | hasLabelsOnlyForSelected: Boolean = true,
28 | var pathEffect: PathEffect? = null) {
29 | var color = color
30 | set(value) {
31 | field = value
32 | if (pointColor == UNINITIALIZED) darkenColor = ChartUtils.darkenColor(field)
33 | }
34 |
35 | var pointColor = pointColor
36 | get() = if (field == UNINITIALIZED) color else field
37 | set(value) {
38 | field = value
39 | darkenColor = ChartUtils.darkenColor(if (field == UNINITIALIZED) color else field)
40 | }
41 |
42 | var darkenColor = darkenColor
43 | private set
44 |
45 | var isSquare = isSquare
46 | set(value) {
47 | field = value
48 | if (field) isCubic = false
49 | }
50 | var isCubic = isCubic
51 | set(value) {
52 | field = value
53 | if (field) isSquare = false
54 | }
55 |
56 | var hasLabels = hasLabels
57 | set(value) {
58 | field = value
59 | if (field) hasLabelsOnlyForSelected = false
60 | }
61 | var hasLabelsOnlyForSelected = hasLabelsOnlyForSelected
62 | set(value) {
63 | field = value
64 | if (field) hasLabels = false
65 | }
66 |
67 | fun copy() = Line(values.map { it.copy() }.toMutableList(), color, pointColor, darkenColor, formatter, shape, isFilled, isSquare, isCubic, pointRadius, areaTransparency, strokeWidth, hasPoints, hasLines, hasLabels, hasLabelsOnlyForSelected, pathEffect)
68 |
69 | fun update(scale: Float) = values.forEach { it.update(scale) }
70 |
71 | fun finish() = values.forEach { it.finish() }
72 |
73 | companion object {
74 | internal val DEFAULT_LINE_STROKE_WIDTH_DP = 3
75 | internal val DEFAULT_POINT_RADIUS_DP = 6
76 | internal val DEFAULT_AREA_TRANSPARENCY = 64
77 | val UNINITIALIZED = 0
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/LineChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.model.dsl.lineData
4 | import java.util.*
5 |
6 | /**
7 | * Data model for LineChartView.
8 | */
9 | class LineChartData(var lines: MutableList = ArrayList(), var baseValue: Float = DEFAULT_BASE_VALUE) : AbstractChartData() {
10 |
11 | override fun update(scale: Float) {
12 | for (line in lines) {
13 | line.update(scale)
14 | }
15 | }
16 |
17 | override fun finish() {
18 | for (line in lines) {
19 | line.finish()
20 | }
21 | }
22 |
23 | fun copy() = LineChartData(lines.map { it.copy() }.toMutableList(), baseValue).withData(this) as LineChartData
24 |
25 | companion object {
26 | const val DEFAULT_BASE_VALUE = 0.0f
27 |
28 | fun generateDummyData() =
29 | lineData {
30 | lines {
31 | line {
32 | pointValues {
33 | point {
34 | x = 0f
35 | y = 2f
36 | }
37 | point {
38 | x = 1f
39 | y = 4f
40 | }
41 | point {
42 | x = 2f
43 | y = 3f
44 | }
45 | point {
46 | x = 3f
47 | y = 4f
48 | }
49 | }
50 | }
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/PieChartData.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import android.graphics.Color
4 | import android.graphics.Typeface
5 | import co.csadev.kellocharts.formatter.PieChartValueFormatter
6 | import co.csadev.kellocharts.formatter.SimplePieChartValueFormatter
7 | import co.csadev.kellocharts.model.dsl.pieData
8 | import co.csadev.kellocharts.model.dsl.sliceValue
9 | import java.util.*
10 |
11 | /**
12 | * Data for PieChart, by default it doesn't have axes.
13 | */
14 | class PieChartData(var values: MutableList = ArrayList(),
15 | override var axisXBottom: Axis? = null,
16 | override var axisYLeft: Axis? = null,
17 | hasLabels: Boolean = false,
18 | hasLabelsOnlyForSelected: Boolean = false,
19 | var hasLabelsOutside: Boolean = false,
20 | var hasCenterCircle: Boolean = false,
21 | var centerCircleColor: Int = Color.TRANSPARENT,
22 | var centerCircleScale: Float = DEFAULT_CENTER_CIRCLE_SCALE,
23 | var centerText1Color: Int = Color.BLACK,
24 | var centerText1FontSize: Int = DEFAULT_CENTER_TEXT1_SIZE_SP,
25 | var centerText1Typeface: Typeface? = null,
26 | var centerText1: String? = null,
27 | var centerText2Color: Int = Color.BLACK,
28 | var centerText2FontSize: Int = DEFAULT_CENTER_TEXT2_SIZE_SP,
29 | var centerText2Typeface: Typeface? = null,
30 | var centerText2: String? = null,
31 | var sliceSpacing: Int = DEFAULT_SLICE_SPACING_DP,
32 | var formatter: PieChartValueFormatter = SimplePieChartValueFormatter()) : AbstractChartData() {
33 | var hasLabels = hasLabels
34 | set(value) {
35 | field = value
36 | if (field) hasLabelsOnlyForSelected = false
37 | }
38 | var hasLabelsOnlyForSelected = hasLabelsOnlyForSelected
39 | set(value) {
40 | field = value
41 | if (field) hasLabels = false
42 | }
43 |
44 | override fun update(scale: Float) {
45 | for (value in values) {
46 | value.update(scale)
47 | }
48 | }
49 |
50 | override fun finish() {
51 | for (value in values) {
52 | value.finish()
53 | }
54 | }
55 |
56 | fun copy() = PieChartData(values.map { it.copy() }.toMutableList(), axisXBottom, axisYLeft, hasLabels, hasLabelsOnlyForSelected, hasLabelsOutside, hasCenterCircle, centerCircleColor, centerCircleScale, centerText1Color, centerText1FontSize, centerText1Typeface, centerText1, centerText2Color, centerText2FontSize, centerText2Typeface, centerText2, sliceSpacing, formatter).withData(this)
57 |
58 | companion object {
59 | const val DEFAULT_CENTER_TEXT1_SIZE_SP = 42
60 | const val DEFAULT_CENTER_TEXT2_SIZE_SP = 16
61 | const val DEFAULT_CENTER_CIRCLE_SCALE = 0.6f
62 | internal const val DEFAULT_SLICE_SPACING_DP = 2
63 |
64 | fun generateDummyData() =
65 | pieData {
66 | sliceValues {
67 | sliceValue {
68 | slice { value = 40f }
69 | }
70 | sliceValue {
71 | slice { value = 20f }
72 | }
73 | sliceValue {
74 | slice { value = 30f }
75 | }
76 | sliceValue {
77 | slice { value = 50f }
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/PointValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.view.Chart
4 | import java.util.*
5 |
6 | /**
7 | * Single point coordinates, used for LineChartData.
8 | */
9 | class PointValue(x: Float = 0f, y: Float = 0f, var label: CharArray? = null) {
10 | constructor(x: Int, y: Int, label: CharArray? = null) : this(x.toFloat(), y.toFloat(), label)
11 | constructor(x: Int, y: Int, label: String) : this(x.toFloat(), y.toFloat(), label.toCharArray())
12 | constructor(x: Float, y: Float, label: String) : this(x, y, label.toCharArray())
13 |
14 | var x: Float = x
15 | private set
16 | var y: Float = y
17 | private set
18 | private var originX: Float = x
19 | private var originY: Float = y
20 | private var diffX: Float = x - originX
21 | private var diffY: Float = y - originY
22 |
23 | fun copy() = PointValue(x, y, label)
24 |
25 | fun update(scale: Float) {
26 | x = originX + diffX * scale
27 | y = originY + diffY * scale
28 | }
29 |
30 | fun finish() {
31 | set(originX + diffX, originY + diffY)
32 | }
33 |
34 | operator fun set(x: Float, y: Float): PointValue {
35 | this.x = x
36 | this.y = y
37 | this.originX = x
38 | this.originY = y
39 | this.diffX = 0f
40 | this.diffY = 0f
41 | return this
42 | }
43 |
44 | /**
45 | * Set target values that should be reached when data animation finish then call [Chart.startDataAnimation]
46 | */
47 | fun setTarget(targetX: Float, targetY: Float): PointValue {
48 | set(x, y)
49 | this.diffX = targetX - originX
50 | this.diffY = targetY - originY
51 | return this
52 | }
53 |
54 | override fun toString(): String {
55 | return "PointValue [x=$x, y=$y]"
56 | }
57 |
58 | override fun equals(other: Any?): Boolean {
59 | if (this === other) return true
60 | if (other == null || javaClass != other.javaClass) return false
61 |
62 | val that = other as PointValue?
63 |
64 | if (that!!.diffX.compareTo(diffX) != 0) return false
65 | if (that.diffY.compareTo(diffY) != 0) return false
66 | if (that.originX.compareTo(originX) != 0) return false
67 | if (that.originY.compareTo(originY) != 0) return false
68 | if (that.x.compareTo(x) != 0) return false
69 | if (that.y.compareTo(y) != 0) return false
70 | return Arrays.equals(label, that.label)
71 |
72 | }
73 |
74 | override fun hashCode(): Int {
75 | var result = if (x != +0.0f) java.lang.Float.floatToIntBits(x) else 0
76 | result = 31 * result + if (y != +0.0f) java.lang.Float.floatToIntBits(y) else 0
77 | result = 31 * result + if (originX != +0.0f) java.lang.Float.floatToIntBits(originX) else 0
78 | result = 31 * result + if (originY != +0.0f) java.lang.Float.floatToIntBits(originY) else 0
79 | result = 31 * result + if (diffX != +0.0f) java.lang.Float.floatToIntBits(diffX) else 0
80 | result = 31 * result + if (diffY != +0.0f) java.lang.Float.floatToIntBits(diffY) else 0
81 | result = 31 * result + if (label != null) Arrays.hashCode(label) else 0
82 | return result
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/SelectedValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | /**
4 | * Holds selected values indexes, i.e. for LineChartModel it will be firstIndex=lineIndex; secondIndex=valueIndex.
5 | */
6 | class SelectedValue(var firstIndex: Int = 0, var secondIndex: Int = 0, var type: SelectedValueType? = SelectedValueType.NONE) {
7 |
8 | /**
9 | * Return true if selected value have meaningful value.
10 | */
11 | val isSet: Boolean
12 | get() = firstIndex >= 0 && secondIndex >= 0
13 |
14 | operator fun set(firstIndex: Int, secondIndex: Int, type: SelectedValueType?) {
15 | this.firstIndex = firstIndex
16 | this.secondIndex = secondIndex
17 | if (null != type) {
18 | this.type = type
19 | } else {
20 | this.type = SelectedValueType.NONE
21 | }
22 | }
23 |
24 | fun set(selectedValue: SelectedValue) {
25 | this.firstIndex = selectedValue.firstIndex
26 | this.secondIndex = selectedValue.secondIndex
27 | this.type = selectedValue.type
28 | }
29 |
30 | fun clear() {
31 | set(Integer.MIN_VALUE, Integer.MIN_VALUE, SelectedValueType.NONE)
32 | }
33 |
34 | override fun hashCode(): Int {
35 | val prime = 31
36 | var result = 1
37 | result = prime * result + firstIndex
38 | result = prime * result + secondIndex
39 | result = prime * result + if (type == null) 0 else type!!.hashCode()
40 | return result
41 | }
42 |
43 | override fun equals(other: Any?): Boolean {
44 | if (this === other)
45 | return true
46 | if (other == null)
47 | return false
48 | if (javaClass != other.javaClass)
49 | return false
50 | val other = other as SelectedValue?
51 | if (firstIndex != other!!.firstIndex)
52 | return false
53 | if (secondIndex != other.secondIndex)
54 | return false
55 | return type == other.type
56 | }
57 |
58 | override fun toString(): String {
59 | return "SelectedValue [firstIndex=$firstIndex, secondIndex=$secondIndex, type=$type]"
60 | }
61 |
62 | /**
63 | * Used in combo chart to determine if selected value is used for line or column selection.
64 | */
65 | enum class SelectedValueType {
66 | NONE, LINE, COLUMN
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/SliceValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.util.ChartUtils
4 | import co.csadev.kellocharts.view.Chart
5 | import java.util.*
6 |
7 | /**
8 | * Model representing single slice on PieChart.
9 | */
10 | class SliceValue(value: Float = 0f, private var originValue: Float = value, private var diff: Float = 0f, color: Int = ChartUtils.DEFAULT_COLOR, var label: CharArray? = null) {
11 | var darkenColor = ChartUtils.darkenColor(color)
12 | private set
13 |
14 | fun update(scale: Float) {
15 | value = originValue + diff * scale
16 | }
17 |
18 | fun finish() {
19 | value = originValue + diff
20 | }
21 |
22 | var value: Float = value
23 | set(value) {
24 | field = value
25 | this.originValue = value
26 | this.diff = 0f
27 | }
28 |
29 | var color: Int = color
30 | set(value) {
31 | field = value
32 | this.darkenColor = ChartUtils.darkenColor(field)
33 | }
34 |
35 | /**
36 | * Set target value that should be reached when data animation finish then call [Chart.startDataAnimation]
37 | *
38 | * @param target
39 | * @return
40 | */
41 | fun setTarget(target: Float): SliceValue {
42 | value = value
43 | this.diff = target - originValue
44 | return this
45 | }
46 |
47 | override fun toString(): String {
48 | return "SliceValue [value=$value]"
49 | }
50 |
51 | override fun equals(o: Any?): Boolean {
52 | if (this === o) return true
53 | if (o == null || javaClass != o.javaClass) return false
54 |
55 | val that = o as SliceValue?
56 |
57 | if (color != that!!.color) return false
58 | if (darkenColor != that.darkenColor) return false
59 | if (that.diff.compareTo(diff) != 0) return false
60 | if (that.originValue.compareTo(originValue) != 0) return false
61 | if (that.value.compareTo(value) != 0) return false
62 | return Arrays.equals(label, that.label)
63 |
64 | }
65 |
66 | override fun hashCode(): Int {
67 | var result = if (value != +0.0f) java.lang.Float.floatToIntBits(value) else 0
68 | result = 31 * result + if (originValue != +0.0f) java.lang.Float.floatToIntBits(originValue) else 0
69 | result = 31 * result + if (diff != +0.0f) java.lang.Float.floatToIntBits(diff) else 0
70 | result = 31 * result + color
71 | result = 31 * result + darkenColor
72 | result = 31 * result + if (label != null) Arrays.hashCode(label) else 0
73 | return result
74 | }
75 |
76 | fun copy() = SliceValue(this.value, color = this.color, label = this.label)
77 | }
78 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/SubcolumnValue.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | import co.csadev.kellocharts.util.ChartUtils
4 | import co.csadev.kellocharts.view.Chart
5 | import java.util.*
6 |
7 | /**
8 | * Single sub-column value for ColumnChart.
9 | */
10 | class SubcolumnValue(value: Float = 0f, color: Int = ChartUtils.DEFAULT_COLOR, var label: CharArray? = null) {
11 |
12 | var value: Float = value
13 | set (value) {
14 | field = value
15 | this.originValue = value
16 | this.diff = 0f
17 | }
18 | private var originValue: Float = 0.toFloat()
19 | private var diff: Float = 0.toFloat()
20 | var color: Int = color
21 | set (value) {
22 | field = value
23 | this.darkenColor = ChartUtils.darkenColor(field)
24 | }
25 | var darkenColor = ChartUtils.darkenColor(color)
26 | private set
27 |
28 | fun update(scale: Float) {
29 | value = originValue + diff * scale
30 | }
31 |
32 | fun finish() {
33 | value = originValue + diff
34 | }
35 |
36 | /**
37 | * Set target value that should be reached when data animation finish then call [Chart.startDataAnimation]
38 | *
39 | * @param target
40 | * @return
41 | */
42 | fun setTarget(target: Float): SubcolumnValue {
43 | value = value
44 | this.diff = target - originValue
45 | return this
46 | }
47 |
48 | override fun toString(): String {
49 | return "ColumnValue [value=$value]"
50 | }
51 |
52 | override fun equals(other: Any?): Boolean {
53 | if (this === other) return true
54 | if (other == null || javaClass != other.javaClass) return false
55 |
56 | val that = other as SubcolumnValue?
57 |
58 | if (color != that!!.color) return false
59 | if (darkenColor != that.darkenColor) return false
60 | if (java.lang.Float.compare(that.diff, diff) != 0) return false
61 | if (java.lang.Float.compare(that.originValue, originValue) != 0) return false
62 | if (java.lang.Float.compare(that.value, value) != 0) return false
63 | return Arrays.equals(label, that.label)
64 |
65 | }
66 |
67 | override fun hashCode(): Int {
68 | var result = if (value != +0.0f) java.lang.Float.floatToIntBits(value) else 0
69 | result = 31 * result + if (originValue != +0.0f) java.lang.Float.floatToIntBits(originValue) else 0
70 | result = 31 * result + if (diff != +0.0f) java.lang.Float.floatToIntBits(diff) else 0
71 | result = 31 * result + color
72 | result = 31 * result + darkenColor
73 | result = 31 * result + if (label != null) Arrays.hashCode(label) else 0
74 | return result
75 | }
76 |
77 | fun copy() = SubcolumnValue(value, color, label)
78 | }
79 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/ValueShape.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model
2 |
3 | enum class ValueShape {
4 | CIRCLE, SQUARE, DIAMOND
5 | }
6 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/dsl/DataDslProviders.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model.dsl
2 |
3 | import android.graphics.Color
4 | import android.graphics.Typeface
5 | import co.csadev.kellocharts.formatter.BubbleChartValueFormatter
6 | import co.csadev.kellocharts.formatter.PieChartValueFormatter
7 | import co.csadev.kellocharts.formatter.SimpleBubbleChartValueFormatter
8 | import co.csadev.kellocharts.formatter.SimplePieChartValueFormatter
9 | import co.csadev.kellocharts.model.*
10 | import co.csadev.kellocharts.model.BubbleChartData.Companion.DEFAULT_BUBBLE_SCALE
11 | import co.csadev.kellocharts.model.BubbleChartData.Companion.DEFAULT_MIN_BUBBLE_RADIUS_DP
12 | import co.csadev.kellocharts.model.LineChartData.Companion.DEFAULT_BASE_VALUE
13 | import java.util.*
14 |
15 | @DslMarker
16 | annotation class BubbleDataDsl
17 |
18 | fun bubbleData(block: BubbleChartDataBuilder.() -> Unit): BubbleChartData = BubbleChartDataBuilder().apply(block).build()
19 | @BubbleDataDsl
20 | class BubbleChartDataBuilder {
21 | private var values: MutableList = ArrayList()
22 | var formatter: BubbleChartValueFormatter = SimpleBubbleChartValueFormatter()
23 | var hasLabels: Boolean = false
24 | var hasLabelsOnlyForSelected: Boolean = false
25 | var minBubbleRadius: Int = DEFAULT_MIN_BUBBLE_RADIUS_DP
26 | var bubbleScale: Float = DEFAULT_BUBBLE_SCALE
27 |
28 | fun bubbles(block: BUBBLEVALUES.() -> Unit) {
29 | values.addAll(BUBBLEVALUES().apply(block))
30 | }
31 |
32 | fun build(): BubbleChartData = BubbleChartData(
33 | values,
34 | formatter,
35 | hasLabels,
36 | hasLabelsOnlyForSelected,
37 | minBubbleRadius,
38 | bubbleScale
39 | )
40 | }
41 |
42 | @DslMarker
43 | annotation class ColumnDataDsl
44 |
45 | fun columnData(block: ColumnChartDataBuilder.() -> Unit): ColumnChartData = ColumnChartDataBuilder().apply(block).build()
46 | @ColumnDataDsl
47 | class ColumnChartDataBuilder {
48 | private var columns: MutableList = ArrayList()
49 | var isStacked: Boolean = false
50 | var isHorizontal: Boolean = true
51 |
52 | fun columns(block: COLUMNS.() -> Unit) {
53 | columns.addAll(COLUMNS().apply(block))
54 | }
55 |
56 | fun build(): ColumnChartData = ColumnChartData(columns, isStacked, isHorizontal)
57 | }
58 |
59 | @DslMarker
60 | annotation class LineDataDsl
61 |
62 | fun lineData(block: LineChartDataBuilder.() -> Unit): LineChartData = LineChartDataBuilder().apply(block).build()
63 | @LineDataDsl
64 | class LineChartDataBuilder {
65 | private var lines: MutableList = ArrayList()
66 | var baseValue: Float = DEFAULT_BASE_VALUE
67 |
68 | fun lines(block: LINES.() -> Unit) {
69 | lines.addAll(LINES().apply(block))
70 | }
71 |
72 | fun build(): LineChartData = LineChartData(lines, baseValue)
73 | }
74 |
75 | @DslMarker
76 | annotation class PieDataDsl
77 |
78 | fun pieData(block: PieChartDataBuilder.() -> Unit): PieChartData = PieChartDataBuilder().apply(block).build()
79 | @PieDataDsl
80 | class PieChartDataBuilder {
81 | private var values: MutableList = ArrayList()
82 | var axisXBottom: Axis? = null
83 | var axisYLeft: Axis? = null
84 | var hasLabels: Boolean = false
85 | var hasLabelsOnlyForSelected: Boolean = false
86 | var hasLabelsOutside: Boolean = false
87 | var hasCenterCircle: Boolean = false
88 | var centerCircleColor: Int = Color.TRANSPARENT
89 | var centerCircleScale: Float = PieChartData.DEFAULT_CENTER_CIRCLE_SCALE
90 | var centerText1Color: Int = Color.BLACK
91 | var centerText1FontSize: Int = PieChartData.DEFAULT_CENTER_TEXT1_SIZE_SP
92 | var centerText1Typeface: Typeface? = null
93 | var centerText1: String? = null
94 | var centerText2Color: Int = Color.BLACK
95 | var centerText2FontSize: Int = PieChartData.DEFAULT_CENTER_TEXT2_SIZE_SP
96 | var centerText2Typeface: Typeface? = null
97 | var centerText2: String? = null
98 | var sliceSpacing: Int = PieChartData.DEFAULT_SLICE_SPACING_DP
99 | var formatter: PieChartValueFormatter = SimplePieChartValueFormatter()
100 |
101 | fun sliceValues(block: SLICEVALUES.() -> Unit) {
102 | values.addAll(SLICEVALUES().apply(block))
103 | }
104 |
105 | fun build(): PieChartData = PieChartData(
106 | values,
107 | axisXBottom,
108 | axisYLeft,
109 | hasLabels,
110 | hasLabelsOnlyForSelected,
111 | hasLabelsOutside,
112 | hasCenterCircle,
113 | centerCircleColor,
114 | centerCircleScale,
115 | centerText1Color,
116 | centerText1FontSize,
117 | centerText1Typeface,
118 | centerText1,
119 | centerText2Color,
120 | centerText2FontSize,
121 | centerText2Typeface,
122 | centerText2,
123 | sliceSpacing,
124 | formatter
125 | )
126 | }
127 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/dsl/LayoutDslProviders.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model.dsl
2 |
3 | import android.graphics.Color
4 | import android.graphics.PathEffect
5 | import android.graphics.Typeface
6 | import co.csadev.kellocharts.formatter.*
7 | import co.csadev.kellocharts.model.*
8 | import co.csadev.kellocharts.model.Axis.Companion.DEFAULT_MAX_AXIS_LABEL_CHARS
9 | import co.csadev.kellocharts.util.ChartUtils
10 | import java.util.*
11 |
12 | @DslMarker
13 | annotation class AxisDsl
14 |
15 | fun axis(block: AxisBuilder.() -> Unit): Axis = AxisBuilder().apply(block).build()
16 | @AxisDsl
17 | class AxisBuilder {
18 | private var values: MutableList = ArrayList()
19 | var name: String? = null
20 | var isAutoGenerated: Boolean = true
21 | var hasLines: Boolean = false
22 | var isInside: Boolean = false
23 | var textColor: Int = Color.LTGRAY
24 | var lineColor: Int = ChartUtils.DEFAULT_DARKEN_COLOR
25 | var textSize: Int = Axis.DEFAULT_TEXT_SIZE_SP
26 | var maxLabelChars: Int = DEFAULT_MAX_AXIS_LABEL_CHARS
27 | var typeface: Typeface? = null
28 | var formatter: AxisValueFormatter = SimpleAxisValueFormatter()
29 | var hasSeparationLine: Boolean = true
30 | var hasTiltedLabels: Boolean = false
31 | var isReversed: Boolean = false
32 | var maxLabels: Int = -1
33 |
34 | fun values(block: AXISVALUES.() -> Unit) {
35 | values.addAll(AXISVALUES().apply(block))
36 | }
37 |
38 | fun build(): Axis = Axis(
39 | values,
40 | name,
41 | isAutoGenerated,
42 | hasLines,
43 | isInside,
44 | textColor,
45 | lineColor,
46 | textSize,
47 | maxLabelChars,
48 | typeface,
49 | formatter,
50 | hasSeparationLine,
51 | hasTiltedLabels,
52 | isReversed,
53 | maxLabels
54 | )
55 | }
56 |
57 | @DslMarker
58 | annotation class ColumnDsl
59 |
60 | fun column(block: ColumnBuilder.() -> Unit): Column = ColumnBuilder().apply(block).build()
61 | class ColumnBuilder {
62 | private var values: MutableList = ArrayList()
63 | var hasLabels: Boolean = false
64 | var hasLabelsOnlyForSelected: Boolean = false
65 | var formatter: ColumnChartValueFormatter = SimpleColumnChartValueFormatter()
66 |
67 | fun columnValues(block: SUBCOLUMNVALUES.() -> Unit) {
68 | values.addAll(SUBCOLUMNVALUES().apply(block))
69 | }
70 |
71 | fun build(): Column = Column(values, hasLabels, hasLabelsOnlyForSelected, formatter)
72 | }
73 | @ColumnDsl
74 | class COLUMNS: ArrayList() {
75 | fun column(block: ColumnBuilder.() -> Unit) {
76 | add(ColumnBuilder().apply(block).build())
77 | }
78 | }
79 |
80 | @DslMarker
81 | annotation class LineDsl
82 |
83 | fun line(block: LineBuilder.() -> Unit): Line = LineBuilder().apply(block).build()
84 | @LineDsl
85 | class LineBuilder {
86 |
87 | private var values: MutableList = ArrayList()
88 |
89 | var color: Int = ChartUtils.DEFAULT_COLOR
90 | var pointColor: Int = color
91 | var darkenColor: Int = ChartUtils.darkenColor(color)
92 | var formatter: LineChartValueFormatter = SimpleLineChartValueFormatter()
93 | var shape: ValueShape = ValueShape.CIRCLE
94 | var isFilled: Boolean = false
95 | var isSquare: Boolean = false
96 | var isCubic: Boolean = false
97 | var pointRadius: Int = Line.DEFAULT_POINT_RADIUS_DP
98 | var areaTransparency: Int = Line.DEFAULT_AREA_TRANSPARENCY
99 | var strokeWidth: Int = Line.DEFAULT_LINE_STROKE_WIDTH_DP
100 | var hasPoints: Boolean = true
101 | var hasLines: Boolean = true
102 | var hasLabels: Boolean = true
103 | var hasLabelsOnlyForSelected: Boolean = true
104 | var pathEffect: PathEffect? = null
105 |
106 | fun pointValues(block: POINTVALUES.() -> Unit) {
107 | values.addAll(POINTVALUES().apply(block))
108 | }
109 |
110 | fun build(): Line = Line(
111 | values,
112 | color,
113 | pointColor,
114 | darkenColor,
115 | formatter,
116 | shape,
117 | isFilled,
118 | isSquare,
119 | isCubic,
120 | pointRadius,
121 | areaTransparency,
122 | strokeWidth,
123 | hasPoints,
124 | hasLines,
125 | hasLabels,
126 | hasLabelsOnlyForSelected,
127 | pathEffect
128 | )
129 | }
130 | @LineDsl
131 | class LINES: ArrayList() {
132 | fun line(block: LineBuilder.() -> Unit) {
133 | add(LineBuilder().apply(block).build())
134 | }
135 | }
136 |
137 | fun viewport(block: Viewport.() -> Unit): Viewport = Viewport().apply(block)
138 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/model/dsl/ValueDslProviders.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.model.dsl
2 |
3 | import co.csadev.kellocharts.model.*
4 | import co.csadev.kellocharts.util.ChartUtils
5 |
6 | @DslMarker
7 | annotation class AxisValueDsl
8 |
9 | @AxisValueDsl
10 | class AXISVALUES: ArrayList() {
11 | fun axis(block: AxisValue.() -> Unit) {
12 | add(AxisValue().apply(block))
13 | }
14 | }
15 |
16 | @DslMarker
17 | annotation class BubbleValueDsl
18 |
19 | @BubbleValueDsl
20 | class BubbleValueBuilder {
21 | var x: Float = 0f
22 | var y: Float = 0f
23 | var z: Float = 0f
24 | var color: Int = ChartUtils.DEFAULT_COLOR
25 | var label: CharArray? = null
26 | var shape: ValueShape? = ValueShape.CIRCLE
27 |
28 | fun build() = BubbleValue(x, y, z, color, label, shape)
29 | }
30 | @BubbleValueDsl
31 | class BUBBLEVALUES: ArrayList() {
32 | fun bubble(block: BubbleValueBuilder.() -> Unit) {
33 | add(BubbleValueBuilder().apply(block).build())
34 | }
35 | }
36 |
37 | @DslMarker
38 | annotation class PointValueDsl
39 |
40 | @PointValueDsl
41 | class PointValueBuilder {
42 | var x: Float = 0f
43 | var y: Float = 0f
44 | var label: CharArray? = null
45 |
46 | fun build() = PointValue(x, y, label)
47 | }
48 | @PointValueDsl
49 | class POINTVALUES: ArrayList() {
50 | fun point(block: PointValueBuilder.() -> Unit) {
51 | add(PointValueBuilder().apply(block).build())
52 | }
53 | }
54 |
55 | @DslMarker
56 | annotation class SelectedValueDsl
57 |
58 | @SelectedValueDsl
59 | class SELECTEDVALUES: ArrayList() {
60 | fun point(block: SelectedValue.() -> Unit) {
61 | add(SelectedValue().apply(block))
62 | }
63 | }
64 |
65 | @DslMarker
66 | annotation class SliceValueDsl
67 |
68 | fun sliceValue(block: SliceValue.() -> Unit): SliceValue = SliceValue().apply(block)
69 | @SliceValueDsl
70 | class SLICEVALUES: ArrayList() {
71 | fun slice(block: SliceValue.() -> Unit) {
72 | add(SliceValue().apply(block))
73 | }
74 | }
75 |
76 | @DslMarker
77 | annotation class SubcolumnValueDsl
78 |
79 | @SubcolumnValueDsl
80 | class SUBCOLUMNVALUES: ArrayList() {
81 | fun subcolumn(block: SubcolumnValue.() -> Unit) {
82 | add(SubcolumnValue().apply(block))
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/provider/ChartDataProviders.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.provider
2 |
3 | import co.csadev.kellocharts.model.*
4 |
5 | interface BubbleChartDataProvider {
6 | var bubbleChartData: BubbleChartData
7 | }
8 |
9 | interface ColumnChartDataProvider {
10 | var columnChartData: ColumnChartData
11 | }
12 |
13 | interface ComboLineColumnChartDataProvider {
14 | var comboLineColumnChartData: ComboLineColumnChartData
15 | }
16 |
17 | interface LineChartDataProvider {
18 | var lineChartData: LineChartData
19 | }
20 |
21 | interface PieChartDataProvider {
22 | var pieChartData: PieChartData
23 | }
24 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/AbstractChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.content.Context
4 | import android.graphics.*
5 | import android.graphics.Paint.Align
6 | import android.graphics.Paint.FontMetricsInt
7 | import co.csadev.kellocharts.computator.ChartComputator
8 | import co.csadev.kellocharts.model.SelectedValue
9 | import co.csadev.kellocharts.model.Viewport
10 | import co.csadev.kellocharts.util.ChartUtils
11 | import co.csadev.kellocharts.view.Chart
12 |
13 | /**
14 | * Abstract renderer implementation, every chart renderer extends this class(although it is not required it helps).
15 | */
16 | abstract class AbstractChartRenderer(context: Context, protected var chart: Chart) : ChartRenderer {
17 | var DEFAULT_LABEL_MARGIN_DP = 4
18 | protected var computator: ChartComputator
19 | /**
20 | * Paint for value labels.
21 | */
22 | protected var labelPaint = Paint()
23 | /**
24 | * Paint for labels background.
25 | */
26 | protected var labelBackgroundPaint = Paint()
27 | /**
28 | * Holds coordinates for label background rect.
29 | */
30 | protected var labelBackgroundRect = RectF()
31 | /**
32 | * Font metrics for label paint, used to determine text height.
33 | */
34 | protected var fontMetrics = FontMetricsInt()
35 | /**
36 | * If true maximum and current viewport will be calculated when chart data change or during data animations.
37 | */
38 | override var isViewportCalculationEnabled = true
39 | protected var density: Float = 0.toFloat()
40 | protected var scaledDensity: Float = 0.toFloat()
41 | override var selectedValue = SelectedValue()
42 | protected var labelBuffer = CharArray(64)
43 | protected var labelOffset: Int = 0
44 | protected var labelMargin: Int = 0
45 | protected var isValueLabelBackgroundEnabled: Boolean = false
46 | protected var isValueLabelBackgroundAuto: Boolean = false
47 | override val isTouched: Boolean
48 | get() = selectedValue.isSet
49 | override var currentViewport: Viewport
50 | get() = computator.currentViewport
51 | set(value) { computator.currentViewport = value }
52 | override var maximumViewport: Viewport
53 | get() = computator.maximumViewport
54 | set(value) { computator.maximumViewport = value }
55 |
56 | init {
57 | this.density = context.resources.displayMetrics.density
58 | this.scaledDensity = context.resources.displayMetrics.scaledDensity
59 | this.computator = chart.chartComputator
60 |
61 | labelMargin = ChartUtils.dp2px(density, DEFAULT_LABEL_MARGIN_DP)
62 | labelOffset = labelMargin
63 |
64 | labelPaint.isAntiAlias = true
65 | labelPaint.style = Paint.Style.FILL
66 | labelPaint.textAlign = Align.LEFT
67 | labelPaint.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
68 | labelPaint.color = Color.WHITE
69 |
70 | labelBackgroundPaint.isAntiAlias = true
71 | labelBackgroundPaint.style = Paint.Style.FILL
72 | }
73 |
74 | override fun resetRenderer() {
75 | this.computator = chart.chartComputator
76 | }
77 |
78 | override fun onChartDataChanged() {
79 | val data = chart.chartData
80 |
81 | val typeface = chart.chartData.valueLabelTypeface
82 | if (null != typeface) {
83 | labelPaint.typeface = typeface
84 | }
85 |
86 | labelPaint.color = data.valueLabelTextColor
87 | labelPaint.textSize = ChartUtils.sp2px(scaledDensity, data.valueLabelTextSize).toFloat()
88 | labelPaint.getFontMetricsInt(fontMetrics)
89 |
90 | this.isValueLabelBackgroundEnabled = data.isValueLabelBackgroundEnabled
91 | this.isValueLabelBackgroundAuto = data.isValueLabelBackgroundAuto
92 | this.labelBackgroundPaint.color = data.valueLabelBackgroundColor
93 |
94 | // Important - clear selection when data changed.
95 | selectedValue.clear()
96 |
97 | }
98 |
99 | /**
100 | * Draws label text and label background if isValueLabelBackgroundEnabled is true.
101 | */
102 | protected fun drawLabelTextAndBackground(canvas: Canvas, labelBuffer: CharArray, startIndex: Int, numChars: Int,
103 | autoBackgroundColor: Int) {
104 | val textX: Float
105 | val textY: Float
106 |
107 | if (isValueLabelBackgroundEnabled) {
108 |
109 | if (isValueLabelBackgroundAuto) {
110 | labelBackgroundPaint.color = autoBackgroundColor
111 | }
112 |
113 | canvas.drawRect(labelBackgroundRect, labelBackgroundPaint)
114 |
115 | textX = labelBackgroundRect.left + labelMargin
116 | textY = labelBackgroundRect.bottom - labelMargin
117 | } else {
118 | textX = labelBackgroundRect.left
119 | textY = labelBackgroundRect.bottom
120 | }
121 |
122 | canvas.drawText(labelBuffer, startIndex, numChars, textX, textY, labelPaint)
123 | }
124 |
125 | override fun clearTouch() {
126 | selectedValue.clear()
127 | }
128 |
129 | }
130 |
131 | class InternalChartRendererBase(context: Context, chart: Chart) : AbstractChartRenderer(context, chart) {
132 | override fun onChartSizeChanged() { }
133 | override fun onChartViewportChanged() { }
134 | override fun draw(canvas: Canvas) { }
135 | override fun drawUnclipped(canvas: Canvas) { }
136 | override fun checkTouch(touchX: Float, touchY: Float): Boolean { return false }
137 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/ChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.graphics.Canvas
4 |
5 | import co.csadev.kellocharts.model.SelectedValue
6 | import co.csadev.kellocharts.model.Viewport
7 |
8 | /**
9 | * Interface for all chart renderer.
10 | */
11 | interface ChartRenderer {
12 |
13 | /**
14 | * Returns true if there is value selected.
15 | */
16 | val isTouched: Boolean
17 |
18 | var maximumViewport: Viewport
19 |
20 | var currentViewport: Viewport
21 |
22 | var isViewportCalculationEnabled: Boolean
23 |
24 | var selectedValue: SelectedValue
25 |
26 | fun onChartSizeChanged()
27 |
28 | fun onChartDataChanged()
29 |
30 | fun onChartViewportChanged()
31 |
32 | fun resetRenderer()
33 |
34 | /**
35 | * Draw chart data.
36 | */
37 | fun draw(canvas: Canvas)
38 |
39 | /**
40 | * Draw chart data that should not be clipped to contentRect area.
41 | */
42 | fun drawUnclipped(canvas: Canvas)
43 |
44 | /**
45 | * Checks if given pixel coordinates corresponds to any chart value. If yes return true and set selectedValue, if
46 | * not selectedValue should be *cleared* and method should return false.
47 | */
48 | fun checkTouch(touchX: Float, touchY: Float): Boolean
49 |
50 | /**
51 | * Clear value selection.
52 | */
53 | fun clearTouch()
54 | }
55 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/ComboChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import co.csadev.kellocharts.model.Viewport
6 | import co.csadev.kellocharts.model.set
7 | import co.csadev.kellocharts.view.Chart
8 | import java.util.*
9 |
10 | open class ComboChartRenderer(context: Context, chart: Chart) : AbstractChartRenderer(context, chart) {
11 |
12 | internal var renderers: MutableList = ArrayList()
13 | protected var unionViewport = Viewport()
14 |
15 | override fun onChartSizeChanged() {
16 | for (renderer in renderers) {
17 | renderer.onChartSizeChanged()
18 | }
19 | }
20 |
21 | override fun onChartDataChanged() {
22 | super.onChartDataChanged()
23 | for (renderer in renderers) {
24 | renderer.onChartDataChanged()
25 | }
26 | onChartViewportChanged()
27 | }
28 |
29 | override fun onChartViewportChanged() {
30 | if (isViewportCalculationEnabled) {
31 | var rendererIndex = 0
32 | for (renderer in renderers) {
33 | renderer.onChartViewportChanged()
34 | if (rendererIndex == 0) {
35 | unionViewport.set(renderer.maximumViewport)
36 | } else {
37 | unionViewport.union(renderer.maximumViewport)
38 | }
39 | ++rendererIndex
40 | }
41 | computator.maximumViewport = unionViewport
42 | computator.currentViewport = unionViewport
43 | }
44 |
45 |
46 | }
47 |
48 | override fun draw(canvas: Canvas) {
49 | for (renderer in renderers) {
50 | renderer.draw(canvas)
51 | }
52 | }
53 |
54 | override fun drawUnclipped(canvas: Canvas) {
55 | for (renderer in renderers) {
56 | renderer.drawUnclipped(canvas)
57 | }
58 | }
59 |
60 | override fun checkTouch(touchX: Float, touchY: Float): Boolean {
61 | selectedValue.clear()
62 | var rendererIndex = renderers.size - 1
63 | while (rendererIndex >= 0) {
64 | val renderer = renderers[rendererIndex]
65 | if (renderer.checkTouch(touchX, touchY)) {
66 | selectedValue.set(renderer.selectedValue)
67 | break
68 | }
69 | rendererIndex--
70 | }
71 |
72 | //clear the rest of renderers if value was selected, if value was not selected this loop
73 | // will not be executed.
74 | rendererIndex--
75 | while (rendererIndex >= 0) {
76 | val renderer = renderers[rendererIndex]
77 | renderer.clearTouch()
78 | rendererIndex--
79 | }
80 |
81 | return isTouched
82 | }
83 |
84 | override fun clearTouch() {
85 | for (renderer in renderers) {
86 | renderer.clearTouch()
87 | }
88 | selectedValue.clear()
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/ComboLineColumnChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.content.Context
4 |
5 | import co.csadev.kellocharts.provider.ColumnChartDataProvider
6 | import co.csadev.kellocharts.provider.LineChartDataProvider
7 | import co.csadev.kellocharts.view.Chart
8 |
9 | class ComboLineColumnChartRenderer(context: Context, chart: Chart, private val columnChartRenderer: ColumnChartRenderer,
10 | private val lineChartRenderer: LineChartRenderer) : ComboChartRenderer(context, chart) {
11 |
12 | constructor(context: Context, chart: Chart, columnChartDataProvider: ColumnChartDataProvider, lineChartDataProvider: LineChartDataProvider)
13 | : this(context, chart, ColumnChartRenderer(context, chart, columnChartDataProvider), LineChartRenderer(context, chart, lineChartDataProvider))
14 |
15 | constructor(context: Context, chart: Chart, columnChartRenderer: ColumnChartRenderer, lineChartDataProvider: LineChartDataProvider)
16 | : this(context, chart, columnChartRenderer, LineChartRenderer(context, chart, lineChartDataProvider))
17 |
18 | constructor(context: Context, chart: Chart, columnChartDataProvider: ColumnChartDataProvider, lineChartRenderer: LineChartRenderer)
19 | : this(context, chart, ColumnChartRenderer(context, chart, columnChartDataProvider), lineChartRenderer)
20 |
21 | init {
22 | renderers.add(this.columnChartRenderer)
23 | renderers.add(this.lineChartRenderer)
24 | }
25 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/PreviewColumnChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import co.csadev.kellocharts.provider.ColumnChartDataProvider
8 | import co.csadev.kellocharts.util.ChartUtils
9 | import co.csadev.kellocharts.view.Chart
10 |
11 | /**
12 | * Renderer for preview chart based on ColumnChart. In addition to drawing chart data it also draw current viewport as
13 | * preview area.
14 | */
15 | class PreviewColumnChartRenderer(context: Context, chart: Chart, dataProvider: ColumnChartDataProvider) : ColumnChartRenderer(context, chart, dataProvider) {
16 |
17 | private val previewPaint = Paint()
18 |
19 | var previewColor: Int
20 | get() = previewPaint.color
21 | set(color) {
22 | previewPaint.color = color
23 | }
24 |
25 | init {
26 | previewPaint.isAntiAlias = true
27 | previewPaint.color = Color.LTGRAY
28 | previewPaint.strokeWidth = ChartUtils.dp2px(density, DEFAULT_PREVIEW_STROKE_WIDTH_DP).toFloat()
29 | }
30 |
31 | override fun drawUnclipped(canvas: Canvas) {
32 | super.drawUnclipped(canvas)
33 | val currentViewport = computator.currentViewport
34 | val left = computator.computeRawX(currentViewport.left)
35 | val top = computator.computeRawY(currentViewport.top)
36 | val right = computator.computeRawX(currentViewport.right)
37 | val bottom = computator.computeRawY(currentViewport.bottom)
38 | previewPaint.alpha = DEFAULT_PREVIEW_TRANSPARENCY
39 | previewPaint.style = Paint.Style.FILL
40 | canvas.drawRect(left, top, right, bottom, previewPaint)
41 | previewPaint.style = Paint.Style.STROKE
42 | previewPaint.alpha = FULL_ALPHA
43 | canvas.drawRect(left, top, right, bottom, previewPaint)
44 | }
45 |
46 | companion object {
47 | private val DEFAULT_PREVIEW_TRANSPARENCY = 64
48 | private val FULL_ALPHA = 255
49 | private val DEFAULT_PREVIEW_STROKE_WIDTH_DP = 2
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/renderer/PreviewLineChartRenderer.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.renderer
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import co.csadev.kellocharts.provider.LineChartDataProvider
8 | import co.csadev.kellocharts.util.ChartUtils
9 | import co.csadev.kellocharts.view.Chart
10 |
11 | /**
12 | * Renderer for preview chart based on LineChart. In addition to drawing chart data it also draw current viewport as
13 | * preview area.
14 | */
15 | class PreviewLineChartRenderer(context: Context, chart: Chart, dataProvider: LineChartDataProvider) : LineChartRenderer(context, chart, dataProvider) {
16 |
17 | private val previewPaint = Paint()
18 |
19 | var previewColor: Int
20 | get() = previewPaint.color
21 | set(color) {
22 | previewPaint.color = color
23 | }
24 |
25 | init {
26 | previewPaint.isAntiAlias = true
27 | previewPaint.color = Color.LTGRAY
28 | previewPaint.strokeWidth = ChartUtils.dp2px(density, DEFAULT_PREVIEW_STROKE_WIDTH_DP).toFloat()
29 | }
30 |
31 | override fun drawUnclipped(canvas: Canvas) {
32 | super.drawUnclipped(canvas)
33 | val currentViewport = computator.currentViewport
34 | val left = computator.computeRawX(currentViewport.left)
35 | val top = computator.computeRawY(currentViewport.top)
36 | val right = computator.computeRawX(currentViewport.right)
37 | val bottom = computator.computeRawY(currentViewport.bottom)
38 | previewPaint.alpha = DEFAULT_PREVIEW_TRANSPARENCY
39 | previewPaint.style = Paint.Style.FILL
40 | canvas.drawRect(left, top, right, bottom, previewPaint)
41 | previewPaint.style = Paint.Style.STROKE
42 | previewPaint.alpha = FULL_ALPHA
43 | canvas.drawRect(left, top, right, bottom, previewPaint)
44 | }
45 |
46 | companion object {
47 | private val DEFAULT_PREVIEW_TRANSPARENCY = 64
48 | private val FULL_ALPHA = 255
49 | private val DEFAULT_PREVIEW_STROKE_WIDTH_DP = 2
50 | }
51 | }
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/util/AxisAutoValues.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.util
2 |
3 | /**
4 | * A simple class representing axis label values used only for auto generated axes.
5 | */
6 | class AxisAutoValues {
7 | var values = floatArrayOf()
8 | var valuesNumber: Int = 0
9 | var decimals: Int = 0
10 | }
11 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/util/ChartUtils.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.util
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.TypedValue
6 |
7 | object ChartUtils {
8 |
9 | val DEFAULT_COLOR = Color.parseColor("#DFDFDF")
10 | val DEFAULT_DARKEN_COLOR = Color.parseColor("#DDDDDD")
11 | val COLOR_BLUE = Color.parseColor("#33B5E5")
12 | val COLOR_VIOLET = Color.parseColor("#AA66CC")
13 | val COLOR_GREEN = Color.parseColor("#99CC00")
14 | val COLOR_ORANGE = Color.parseColor("#FFBB33")
15 | val COLOR_RED = Color.parseColor("#FF4444")
16 | val COLORS = intArrayOf(COLOR_BLUE, COLOR_VIOLET, COLOR_GREEN, COLOR_ORANGE, COLOR_RED)
17 | private val DARKEN_SATURATION = 1.1f
18 | private val DARKEN_INTENSITY = 0.9f
19 | private var COLOR_INDEX = 0
20 |
21 | fun pickColor(): Int {
22 | return COLORS[Math.round(Math.random() * (COLORS.size - 1)).toInt()]
23 | }
24 |
25 | fun nextColor(): Int {
26 | if (COLOR_INDEX >= COLORS.size) {
27 | COLOR_INDEX = 0
28 | }
29 | return COLORS[COLOR_INDEX++]
30 | }
31 |
32 | fun dp2px(density: Float, dp: Int): Int {
33 | return if (dp == 0) {
34 | 0
35 | } else (dp * density + 0.5f).toInt()
36 |
37 | }
38 |
39 | fun px2dp(density: Float, px: Int): Int {
40 | return Math.ceil((px / density).toDouble()).toInt()
41 | }
42 |
43 | fun sp2px(scaledDensity: Float, sp: Int): Int {
44 | return if (sp == 0) {
45 | 0
46 | } else (sp * scaledDensity + 0.5f).toInt()
47 | }
48 |
49 | fun px2sp(scaledDensity: Float, px: Int): Int {
50 | return Math.ceil((px / scaledDensity).toDouble()).toInt()
51 | }
52 |
53 | fun mm2px(context: Context, mm: Int): Int {
54 | return (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, mm.toFloat(), context.resources
55 | .displayMetrics) + 0.5f).toInt()
56 | }
57 |
58 | fun darkenColor(color: Int): Int {
59 | val hsv = FloatArray(3)
60 | val alpha = Color.alpha(color)
61 | Color.colorToHSV(color, hsv)
62 | hsv[1] = Math.min(hsv[1] * DARKEN_SATURATION, 1.0f)
63 | hsv[2] = hsv[2] * DARKEN_INTENSITY
64 | val tempColor = Color.HSVToColor(hsv)
65 | return Color.argb(alpha, Color.red(tempColor), Color.green(tempColor), Color.blue(tempColor))
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/BubbleChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import androidx.core.view.ViewCompat
7 | import co.csadev.kellocharts.BuildConfig
8 | import co.csadev.kellocharts.listener.BubbleChartOnValueSelectListener
9 | import co.csadev.kellocharts.listener.DummyBubbleChartOnValueSelectListener
10 | import co.csadev.kellocharts.model.BubbleChartData
11 | import co.csadev.kellocharts.model.ChartData
12 | import co.csadev.kellocharts.provider.BubbleChartDataProvider
13 | import co.csadev.kellocharts.renderer.BubbleChartRenderer
14 |
15 | /**
16 | * BubbleChart, supports circle bubbles and square bubbles.
17 | *
18 | * @author lecho
19 | */
20 | class BubbleChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : AbstractChartView(context, attrs, defStyle), BubbleChartDataProvider {
21 | var onValueTouchListener: BubbleChartOnValueSelectListener = DummyBubbleChartOnValueSelectListener()
22 |
23 | var bubbleChartRenderer: BubbleChartRenderer = BubbleChartRenderer(context, this, this)
24 |
25 | override var bubbleChartData: BubbleChartData = BubbleChartData.generateDummyData()
26 | set(value) {
27 | if (BuildConfig.DEBUG) {
28 | Log.d(TAG, "Setting data for BubbleChartView")
29 | }
30 | field = value
31 | super.onChartDataChange()
32 | }
33 |
34 | override val chartData: ChartData
35 | get() = bubbleChartData
36 |
37 | init {
38 | chartRenderer = bubbleChartRenderer
39 | bubbleChartData = BubbleChartData.generateDummyData()
40 | }
41 |
42 | override fun callTouchListener() {
43 | val selectedValue = chartRenderer.selectedValue
44 |
45 | if (selectedValue.isSet) {
46 | val value = bubbleChartData.values[selectedValue.firstIndex]
47 | onValueTouchListener.onValueSelected(selectedValue.firstIndex, value)
48 | } else {
49 | onValueTouchListener.onValueDeselected()
50 | }
51 | }
52 |
53 | /**
54 | * Removes empty spaces, top-bottom for portrait orientation and left-right for landscape. This method has to be
55 | * called after view View#onSizeChanged() method is called and chart data is set. This method may be inaccurate.
56 | *
57 | * @see BubbleChartRenderer.removeMargins
58 | */
59 | fun removeMargins() {
60 | bubbleChartRenderer.removeMargins()
61 | ViewCompat.postInvalidateOnAnimation(this)
62 | }
63 |
64 | companion object {
65 | private val TAG = "BubbleChartView"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/ColumnChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import co.csadev.kellocharts.BuildConfig
7 | import co.csadev.kellocharts.listener.ColumnChartOnValueSelectListener
8 | import co.csadev.kellocharts.listener.DummyColumnChartOnValueSelectListener
9 | import co.csadev.kellocharts.model.ChartData
10 | import co.csadev.kellocharts.model.ColumnChartData
11 | import co.csadev.kellocharts.provider.ColumnChartDataProvider
12 | import co.csadev.kellocharts.renderer.ColumnChartRenderer
13 |
14 | /**
15 | * ColumnChart/BarChart, supports subcolumns, stacked columns, horizontal mode, and negative values.
16 | *
17 | * @author Leszek Wach
18 | */
19 | open class ColumnChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : AbstractChartView(context, attrs, defStyle), ColumnChartDataProvider {
20 | override var columnChartData: ColumnChartData = ColumnChartData.generateDummyData()
21 | set(value) {
22 | if (BuildConfig.DEBUG) {
23 | Log.d(TAG, "Setting data for ColumnChartView")
24 | }
25 | field = value
26 | super.onChartDataChange()
27 |
28 | }
29 |
30 | override val chartData: ChartData
31 | get() = columnChartData
32 |
33 | var onValueTouchListener: ColumnChartOnValueSelectListener? = DummyColumnChartOnValueSelectListener()
34 | set(touchListener) {
35 | if (null != touchListener) {
36 | field = touchListener
37 | }
38 | }
39 |
40 | init {
41 | chartRenderer = ColumnChartRenderer(context, this, this)
42 | }
43 |
44 | override fun callTouchListener() {
45 | val selectedValue = chartRenderer.selectedValue
46 |
47 | if (selectedValue.isSet) {
48 | val value = columnChartData.columns[selectedValue.firstIndex].values[selectedValue.secondIndex]
49 | this.onValueTouchListener?.onValueSelected(selectedValue.firstIndex, selectedValue.secondIndex, value)
50 | } else {
51 | this.onValueTouchListener?.onValueDeselected()
52 | }
53 | }
54 |
55 | companion object {
56 | private val TAG = "ColumnChartView"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/ComboLineColumnChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import co.csadev.kellocharts.BuildConfig
7 | import co.csadev.kellocharts.listener.ComboLineColumnChartOnValueSelectListener
8 | import co.csadev.kellocharts.listener.DummyCompoLineColumnChartOnValueSelectListener
9 | import co.csadev.kellocharts.model.ChartData
10 | import co.csadev.kellocharts.model.ColumnChartData
11 | import co.csadev.kellocharts.model.ComboLineColumnChartData
12 | import co.csadev.kellocharts.model.LineChartData
13 | import co.csadev.kellocharts.model.SelectedValue.SelectedValueType
14 | import co.csadev.kellocharts.provider.ColumnChartDataProvider
15 | import co.csadev.kellocharts.provider.ComboLineColumnChartDataProvider
16 | import co.csadev.kellocharts.provider.LineChartDataProvider
17 | import co.csadev.kellocharts.renderer.ColumnChartRenderer
18 | import co.csadev.kellocharts.renderer.ComboLineColumnChartRenderer
19 | import co.csadev.kellocharts.renderer.LineChartRenderer
20 |
21 | /**
22 | * ComboChart, supports ColumnChart combined with LineChart. Lines are always drawn on top.
23 | *
24 | * @author Leszek Wach
25 | */
26 | class ComboLineColumnChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : AbstractChartView(context, attrs, defStyle), ComboLineColumnChartDataProvider {
27 | var columnChartDataProvider: ColumnChartDataProvider = ComboColumnChartDataProvider()
28 | var lineChartDataProvider: LineChartDataProvider = ComboLineChartDataProvider()
29 | var onValueTouchListener: ComboLineColumnChartOnValueSelectListener = DummyCompoLineColumnChartOnValueSelectListener()
30 |
31 | override// generateDummyData();
32 | var comboLineColumnChartData: ComboLineColumnChartData = ComboLineColumnChartData.generateDummyData()
33 | set(value) {
34 | if (BuildConfig.DEBUG) {
35 | Log.d(TAG, "Setting data for ComboLineColumnChartView")
36 | }
37 | field = value
38 | super.onChartDataChange()
39 | }
40 |
41 | override val chartData: ChartData
42 | get() = comboLineColumnChartData
43 |
44 | init {
45 | chartRenderer = ComboLineColumnChartRenderer(context, this, columnChartDataProvider, lineChartDataProvider)
46 | }
47 |
48 | override fun callTouchListener() {
49 | val selectedValue = chartRenderer.selectedValue
50 |
51 | if (selectedValue.isSet) {
52 |
53 | if (SelectedValueType.COLUMN == selectedValue.type) {
54 |
55 | val value = comboLineColumnChartData.columnChartData.columns[selectedValue.firstIndex].values[selectedValue.secondIndex]
56 | onValueTouchListener.onColumnValueSelected(selectedValue.firstIndex,
57 | selectedValue.secondIndex, value)
58 |
59 | } else if (SelectedValueType.LINE == selectedValue.type) {
60 |
61 | val value = comboLineColumnChartData.lineChartData.lines[selectedValue.firstIndex].values[selectedValue.secondIndex]
62 | onValueTouchListener.onPointValueSelected(selectedValue.firstIndex, selectedValue.secondIndex,
63 | value)
64 |
65 | } else {
66 | throw IllegalArgumentException("Invalid selected value type " + selectedValue.type!!.name)
67 | }
68 | } else {
69 | onValueTouchListener.onValueDeselected()
70 | }
71 | }
72 |
73 | fun setColumnChartRenderer(context: Context, columnChartRenderer: ColumnChartRenderer) {
74 | chartRenderer = ComboLineColumnChartRenderer(context, this, columnChartRenderer, lineChartDataProvider)
75 | }
76 |
77 | fun setLineChartRenderer(context: Context, lineChartRenderer: LineChartRenderer) {
78 | chartRenderer = ComboLineColumnChartRenderer(context, this, columnChartDataProvider, lineChartRenderer)
79 | }
80 |
81 | private inner class ComboLineChartDataProvider : LineChartDataProvider {
82 |
83 | override var lineChartData: LineChartData
84 | get() = comboLineColumnChartData.lineChartData
85 | set(data) { comboLineColumnChartData.lineChartData = data }
86 |
87 | }
88 |
89 | private inner class ComboColumnChartDataProvider : ColumnChartDataProvider {
90 |
91 | override var columnChartData: ColumnChartData
92 | get() = comboLineColumnChartData.columnChartData
93 | set(data) { comboLineColumnChartData.columnChartData = data }
94 |
95 | }
96 |
97 | companion object {
98 | private val TAG = "ComboLCChartView"
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/LineChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import co.csadev.kellocharts.BuildConfig
7 | import co.csadev.kellocharts.listener.DummyLineChartOnValueSelectListener
8 | import co.csadev.kellocharts.listener.LineChartOnValueSelectListener
9 | import co.csadev.kellocharts.model.ChartData
10 | import co.csadev.kellocharts.model.LineChartData
11 | import co.csadev.kellocharts.provider.LineChartDataProvider
12 | import co.csadev.kellocharts.renderer.LineChartRenderer
13 |
14 | /**
15 | * LineChart, supports cubic lines, filled lines, circle and square points. Point radius and stroke width can be
16 | * adjusted using LineChartData attributes.
17 | *
18 | * @author Leszek Wach
19 | */
20 | open class LineChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : AbstractChartView(context, attrs, defStyle), LineChartDataProvider {
21 | var onValueTouchListener: LineChartOnValueSelectListener = DummyLineChartOnValueSelectListener()
22 |
23 | override var lineChartData: LineChartData = LineChartData.generateDummyData()
24 | set(value) {
25 | if (BuildConfig.DEBUG) {
26 | Log.d(TAG, "Setting data for LineChartView")
27 | }
28 | field = value
29 | super.onChartDataChange()
30 | }
31 |
32 | override val chartData: ChartData
33 | get() = lineChartData
34 |
35 | init {
36 | chartRenderer = LineChartRenderer(context, this, this)
37 | }
38 |
39 | override fun callTouchListener() {
40 | val selectedValue = chartRenderer.selectedValue
41 |
42 | if (selectedValue.isSet) {
43 | val point = lineChartData.lines[selectedValue.firstIndex].values[selectedValue.secondIndex]
44 | onValueTouchListener.onValueSelected(selectedValue.firstIndex, selectedValue.secondIndex, point)
45 | } else {
46 | onValueTouchListener.onValueDeselected()
47 | }
48 | }
49 |
50 | companion object {
51 | private val TAG = "LineChartView"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/PreviewColumnChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import androidx.core.view.ViewCompat
7 | import co.csadev.kellocharts.BuildConfig
8 | import co.csadev.kellocharts.computator.ChartComputator
9 | import co.csadev.kellocharts.computator.PreviewChartComputator
10 | import co.csadev.kellocharts.gesture.PreviewChartTouchHandler
11 | import co.csadev.kellocharts.model.ColumnChartData
12 | import co.csadev.kellocharts.renderer.PreviewColumnChartRenderer
13 |
14 | /**
15 | * Preview chart that can be used as overview for other ColumnChart. When you change Viewport of this chart, visible
16 | * area of other chart will change. For that you need also to use
17 | * [Chart.setViewportChangeListener]
18 | *
19 | * @author Leszek Wach
20 | */
21 | class PreviewColumnChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : ColumnChartView(context, attrs, defStyle) {
22 | override val chartComputator: ChartComputator = PreviewChartComputator()
23 | protected var previewChartRenderer: PreviewColumnChartRenderer = PreviewColumnChartRenderer(context, this, this)
24 |
25 | var previewColor: Int
26 | get() = previewChartRenderer.previewColor
27 | set(color) {
28 | if (BuildConfig.DEBUG) {
29 | Log.d(TAG, "Changing preview area color")
30 | }
31 |
32 | previewChartRenderer.previewColor = color
33 | ViewCompat.postInvalidateOnAnimation(this)
34 | }
35 |
36 | init {
37 | touchHandler = PreviewChartTouchHandler(context, this)
38 | chartRenderer = previewChartRenderer
39 | columnChartData = ColumnChartData.generateDummyData()
40 | }
41 |
42 | override fun canScrollHorizontally(direction: Int): Boolean {
43 | val offset = computeHorizontalScrollOffset()
44 | val range = computeHorizontalScrollRange() - computeHorizontalScrollExtent()
45 | if (range == 0) return false
46 | return if (direction < 0) {
47 | offset > 0
48 | } else {
49 | offset < range - 1
50 | }
51 | }
52 |
53 | companion object {
54 | private val TAG = "ColumnChartView"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/PreviewLineChartView.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.util.Log
6 | import androidx.core.view.ViewCompat
7 | import co.csadev.kellocharts.BuildConfig
8 | import co.csadev.kellocharts.computator.ChartComputator
9 | import co.csadev.kellocharts.computator.PreviewChartComputator
10 | import co.csadev.kellocharts.gesture.PreviewChartTouchHandler
11 | import co.csadev.kellocharts.model.LineChartData
12 | import co.csadev.kellocharts.renderer.PreviewLineChartRenderer
13 |
14 | /**
15 | * Preview chart that can be used as overview for other LineChart. When you change Viewport of this chart, visible area
16 | * of other chart will change. For that you need also to use
17 | * [Chart.setViewportChangeListener]
18 | *
19 | * @author Leszek Wach
20 | */
21 | class PreviewLineChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : LineChartView(context, attrs, defStyle) {
22 | override val chartComputator: ChartComputator = PreviewChartComputator()
23 | protected var previewChartRenderer: PreviewLineChartRenderer = PreviewLineChartRenderer(context, this, this)
24 |
25 | var previewColor: Int
26 | get() = previewChartRenderer.previewColor
27 | set(color) {
28 | if (BuildConfig.DEBUG) {
29 | Log.d(TAG, "Changing preview area color")
30 | }
31 |
32 | previewChartRenderer.previewColor = color
33 | ViewCompat.postInvalidateOnAnimation(this)
34 | }
35 |
36 | init {
37 | touchHandler = PreviewChartTouchHandler(context, this)
38 | chartRenderer = previewChartRenderer
39 | lineChartData = LineChartData.generateDummyData()
40 | }
41 |
42 | override fun canScrollHorizontally(direction: Int): Boolean {
43 | val offset = computeHorizontalScrollOffset()
44 | val range = computeHorizontalScrollRange() - computeHorizontalScrollExtent()
45 | if (range == 0) return false
46 | return if (direction < 0) {
47 | offset > 0
48 | } else {
49 | offset < range - 1
50 | }
51 | }
52 |
53 | companion object {
54 | private val TAG = "PreviewLineChartView"
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/hack/HackyDrawerLayout.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view.hack
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import androidx.drawerlayout.widget.DrawerLayout
7 |
8 | /**
9 | * Hacky fix for issue with DrawerLayout https://github.com/chrisbanes/PhotoView/issues/72
10 | */
11 | class HackyDrawerLayout : DrawerLayout {
12 |
13 | constructor(context: Context) : super(context) {}
14 |
15 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
16 |
17 | constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
18 |
19 | override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
20 | try {
21 | return super.onInterceptTouchEvent(ev)
22 | } catch (e: Exception) {
23 | e.printStackTrace()
24 | return false
25 | }
26 |
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/kellocharts/src/main/java/co/csadev/kellocharts/view/hack/HackyViewPager.kt:
--------------------------------------------------------------------------------
1 | package co.csadev.kellocharts.view.hack
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import androidx.viewpager.widget.ViewPager
7 |
8 | /**
9 | * ScaleGestureDetector seems to mess up the touch events, which means that ViewGroups which make use of
10 | * onInterceptTouchEvent throw a lot of IllegalArgumentException: pointerIndex out of range.There's not much I can do
11 | * in my code for now, but we can mask the result by just catching the problem and ignoring
12 | * it.
13 | *
14 | * @author Chris Banes
15 | */
16 | class HackyViewPager : ViewPager {
17 |
18 | constructor(context: Context) : super(context) {}
19 |
20 | constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
21 |
22 | override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
23 | try {
24 | return super.onInterceptTouchEvent(ev)
25 | } catch (e: Exception) {
26 | e.printStackTrace()
27 | return false
28 | }
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/kellocharts/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | KelloCharts
3 |
4 |
--------------------------------------------------------------------------------
/libs/gradle-play-publisher-1.2.3.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/libs/gradle-play-publisher-1.2.3.jar
--------------------------------------------------------------------------------
/logo_design.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/logo_design.xcf
--------------------------------------------------------------------------------
/play_feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/play_feature.png
--------------------------------------------------------------------------------
/play_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/play_icon.png
--------------------------------------------------------------------------------
/screenshots/bar_chart_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/bar_chart_horizontal.png
--------------------------------------------------------------------------------
/screenshots/bar_chart_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/bar_chart_vertical.png
--------------------------------------------------------------------------------
/screenshots/bubble_chart_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/bubble_chart_horizontal.png
--------------------------------------------------------------------------------
/screenshots/bubble_chart_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/bubble_chart_vertical.png
--------------------------------------------------------------------------------
/screenshots/icon_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/icon_screenshot.png
--------------------------------------------------------------------------------
/screenshots/line_chart_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/line_chart_horizontal.png
--------------------------------------------------------------------------------
/screenshots/line_chart_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/line_chart_vertical.png
--------------------------------------------------------------------------------
/screenshots/pie_chart_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/pie_chart_horizontal.png
--------------------------------------------------------------------------------
/screenshots/pie_chart_vertical_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/pie_chart_vertical_menu.png
--------------------------------------------------------------------------------
/screenshots/preview_line_chart_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/preview_line_chart_vertical.png
--------------------------------------------------------------------------------
/screenshots/preview_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gtcompscientist/KelloCharts/c78ce8c4ba1991f30f379ec47cf4c38749341c57/screenshots/preview_list.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':kellocharts', ':kellocharts-sample'
2 |
--------------------------------------------------------------------------------