diff --git a/README.markdown b/README.markdown index a92cf3288..7732c6a8b 100644 --- a/README.markdown +++ b/README.markdown @@ -1,5 +1,7 @@ # Chart and Graph Library for Android +## Project maintainer wanted! For time reasons I can not continue to maintain GraphView. Contact me if you are interested and serious about this project. g.jjoe64@gmail.com + ## What is GraphView GraphView is a library for Android to programmatically create @@ -45,11 +47,11 @@ Supported graph types: 1) Add gradle dependency: ``` -compile 'com.jjoe64:graphview:4.2.1' +implementation 'com.jjoe64:graphview:4.2.2' ``` 2) Add view to layout: -``` +```xml series = new LineGraphSeries(new DataPoint[] { new DataPoint(0, 1), @@ -76,9 +78,9 @@ graph.addSeries(series); ## More examples and documentation -Get started at project homepage +Get started at project wiki homepage To show you how to integrate the library into an existing project see the GraphView-Demos project! See GraphView-Demos for examples. https://github.com/jjoe64/GraphView-Demos
-
View GraphView page http://android-graphview.org +View GraphView wiki page https://github.com/jjoe64/GraphView/wiki diff --git a/README.new-version.md b/README.new-version.md index 524542b75..8bd815f25 100644 --- a/README.new-version.md +++ b/README.new-version.md @@ -23,6 +23,8 @@ and/or here as ascii => needs some time +hardcode gpg key password in maven_push.gradle + hardcode user/pwd of nexus account in maven_push.gradle success gradle task uploadArchives @@ -45,8 +47,13 @@ Release entry Wait some days -How to create a new .jar file --------------------------------- -success this gradle task -- ./gradlew --rerun-tasks clearJar makeJar -- cp build/outputs/myCompiledLibrary.jar public/GraphView-4.2.0.jar +## update java doc + +$ javadoc -d javadoc -sourcepath src/main/java/ -subpackages com.jjoe64 +$ mv javadoc/ .. +$ git checkout gh-pages +$ rm -rf javadoc +$ mv ../javadoc/ . +$ git add javadoc +$ git commit -a + diff --git a/build.gradle b/build.gradle index 0c1ecbece..ddd7534ac 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,28 @@ buildscript { repositories { mavenCentral() + google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:3.5.3' } } -task wrapper(type: Wrapper) { - gradleVersion = '3.3' +wrapper { + gradleVersion = '5.6' } apply plugin: 'com.android.library' + android { - compileSdkVersion 22 - buildToolsVersion '25.0.0' + compileSdkVersion 27 + buildToolsVersion '28.0.3' defaultConfig { minSdkVersion 9 - targetSdkVersion 22 + targetSdkVersion 27 versionCode 1 versionName "1.0" } @@ -35,7 +38,7 @@ android { } dependencies { - compile 'com.android.support:support-v4:22.1.1' + implementation 'androidx.core:core:1.0.0-beta01' } @@ -57,3 +60,8 @@ makeJar.dependsOn(clearJar, build) apply from: './maven_push.gradle' +repositories { + google() + mavenCentral() + jcenter() +} \ No newline at end of file diff --git a/doc-assets/1059439_1.png b/doc-assets/1059439_1.png new file mode 100644 index 000000000..8be6dde8b Binary files /dev/null and b/doc-assets/1059439_1.png differ diff --git a/doc-assets/4000611_1.png b/doc-assets/4000611_1.png new file mode 100644 index 000000000..a373f0487 Binary files /dev/null and b/doc-assets/4000611_1.png differ diff --git a/doc-assets/469160_orig_1.png b/doc-assets/469160_orig_1.png new file mode 100644 index 000000000..7b96d263a Binary files /dev/null and b/doc-assets/469160_orig_1.png differ diff --git a/doc-assets/5901645_1.png b/doc-assets/5901645_1.png new file mode 100644 index 000000000..962804de9 Binary files /dev/null and b/doc-assets/5901645_1.png differ diff --git a/doc-assets/6316193_orig_1.png b/doc-assets/6316193_orig_1.png new file mode 100644 index 000000000..f4f6e462a Binary files /dev/null and b/doc-assets/6316193_orig_1.png differ diff --git a/doc-assets/9303658_1.png b/doc-assets/9303658_1.png new file mode 100644 index 000000000..bbba36477 Binary files /dev/null and b/doc-assets/9303658_1.png differ diff --git a/doc-assets/Screen_Shot_2016_10_08_at_12_19_56_1.png b/doc-assets/Screen_Shot_2016_10_08_at_12_19_56_1.png new file mode 100644 index 000000000..b5d610643 Binary files /dev/null and b/doc-assets/Screen_Shot_2016_10_08_at_12_19_56_1.png differ diff --git a/doc-assets/Screen_Shot_2016_10_08_at_12_20_56_1.png b/doc-assets/Screen_Shot_2016_10_08_at_12_20_56_1.png new file mode 100644 index 000000000..77780bb31 Binary files /dev/null and b/doc-assets/Screen_Shot_2016_10_08_at_12_20_56_1.png differ diff --git a/doc-assets/Screen_Shot_2016_10_08_at_12_23_38_1.png b/doc-assets/Screen_Shot_2016_10_08_at_12_23_38_1.png new file mode 100644 index 000000000..745fc291c Binary files /dev/null and b/doc-assets/Screen_Shot_2016_10_08_at_12_23_38_1.png differ diff --git a/doc-assets/Screen_Shot_2016_10_08_at_12_24_19_1.png b/doc-assets/Screen_Shot_2016_10_08_at_12_24_19_1.png new file mode 100644 index 000000000..6f4433146 Binary files /dev/null and b/doc-assets/Screen_Shot_2016_10_08_at_12_24_19_1.png differ diff --git a/doc-assets/Screenshot_20161008_122642_1_1.png b/doc-assets/Screenshot_20161008_122642_1_1.png new file mode 100644 index 000000000..8aba95d2f Binary files /dev/null and b/doc-assets/Screenshot_20161008_122642_1_1.png differ diff --git a/doc-assets/Screenshot_20161011_210215_1.png b/doc-assets/Screenshot_20161011_210215_1.png new file mode 100644 index 000000000..0ed502672 Binary files /dev/null and b/doc-assets/Screenshot_20161011_210215_1.png differ diff --git a/doc-assets/Screenshot_20161012_180242_1.png b/doc-assets/Screenshot_20161012_180242_1.png new file mode 100644 index 000000000..acb238f26 Binary files /dev/null and b/doc-assets/Screenshot_20161012_180242_1.png differ diff --git a/doc-assets/Screenshot_20161012_180257_1.png b/doc-assets/Screenshot_20161012_180257_1.png new file mode 100644 index 000000000..dca262fe7 Binary files /dev/null and b/doc-assets/Screenshot_20161012_180257_1.png differ diff --git a/doc-assets/Screenshot_20161012_180325_1.png b/doc-assets/Screenshot_20161012_180325_1.png new file mode 100644 index 000000000..f20b1436c Binary files /dev/null and b/doc-assets/Screenshot_20161012_180325_1.png differ diff --git a/doc-assets/Screenshot_20161012_180336_1.png b/doc-assets/Screenshot_20161012_180336_1.png new file mode 100644 index 000000000..ae45497de Binary files /dev/null and b/doc-assets/Screenshot_20161012_180336_1.png differ diff --git a/doc-assets/Screenshot_20161012_180355_1.png b/doc-assets/Screenshot_20161012_180355_1.png new file mode 100644 index 000000000..f9797826c Binary files /dev/null and b/doc-assets/Screenshot_20161012_180355_1.png differ diff --git a/doc-assets/Screenshot_20161012_180404_1.png b/doc-assets/Screenshot_20161012_180404_1.png new file mode 100644 index 000000000..069978e9d Binary files /dev/null and b/doc-assets/Screenshot_20161012_180404_1.png differ diff --git a/doc-assets/snapshotshare_1.png b/doc-assets/snapshotshare_1.png new file mode 100644 index 000000000..82901109b Binary files /dev/null and b/doc-assets/snapshotshare_1.png differ diff --git a/gradle.properties b/gradle.properties index c4365909f..86a27f74c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=4.2.1 -VERSION_CODE=16 +VERSION_NAME=4.2.2 +VERSION_CODE=17 GROUP=com.jjoe64 POM_DESCRIPTION=Android Graph Library for creating zoomable and scrollable charts. @@ -7,8 +7,8 @@ POM_URL=http://android-graphview.org/ POM_SCM_URL=https://github.com/jjoe64/GraphView POM_SCM_CONNECTION=scm:git@github.com:jjoe64/GraphView.git POM_SCM_DEV_CONNECTION=scm:git@github.com:jjoe64/GraphView.git -POM_LICENCE_NAME=GNU GENERAL PUBLIC LICENSE including GPL linking exception -POM_LICENCE_URL=https://github.com/jjoe64/GraphView/blob/master/license.txtl +POM_LICENCE_NAME=Apache License, Version 2.0 +POM_LICENCE_URL=https://github.com/jjoe64/GraphView/blob/master/license.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=jjoe64 POM_DEVELOPER_NAME=Jonas Gehring diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372aef5..01b8bf6b1 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7c943b4ce..25f587d12 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Jun 02 09:21:22 CEST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip diff --git a/gradlew b/gradlew index 9d82f7891..cccdd3d51 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730b..e95643d6a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/maven_push.gradle b/maven_push.gradle index be187d216..3d15ef167 100644 --- a/maven_push.gradle +++ b/maven_push.gradle @@ -13,7 +13,7 @@ gradle.taskGraph.whenReady { taskGraph -> def id = "D8C3B041" def file = "/Users/jonas/.gnupg/secring.gpg" - def password = "joAJsd8278(§i2nf" + def password = "" allprojects { ext."signing.keyId" = id } allprojects { ext."signing.secretKeyRingFile" = file } @@ -35,11 +35,11 @@ if (isReleaseBuild()) { } def getRepositoryUsername() { - return hasProperty('nexusUsername') ? nexusUsername : "jjoe64" + return "" } def getRepositoryPassword() { - return hasProperty('nexusPassword') ? nexusPassword : "eeghoYo7" + return "" } def isReleaseBuild() { @@ -52,7 +52,9 @@ afterEvaluate { project -> mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + pom.groupId = GROUP pom.artifactId = POM_ARTIFACT_ID + pom.version = VERSION_NAME repository(url: sonatypeRepositoryUrl) { authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) @@ -64,6 +66,7 @@ afterEvaluate { project -> description POM_DESCRIPTION url POM_URL + scm { url POM_SCM_URL connection POM_SCM_CONNECTION diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 0ab342f13..120f744d6 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -3,8 +3,6 @@ package="com.jjoe64.graphview" android:versionCode="1" android:versionName="1.0"> - - diff --git a/src/main/java/com/jjoe64/graphview/GraphView.java b/src/main/java/com/jjoe64/graphview/GraphView.java index 5283b761b..a01da0fbf 100644 --- a/src/main/java/com/jjoe64/graphview/GraphView.java +++ b/src/main/java/com/jjoe64/graphview/GraphView.java @@ -616,6 +616,10 @@ public void takeSnapshotAndShare(Context context, String imageName, String title inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes); String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, imageName, null); + if (path == null) { + // most likely a security problem + throw new SecurityException("Could not get path from MediaStore. Please check permissions."); + } Intent i = new Intent(Intent.ACTION_SEND); i.setType("image/*"); diff --git a/src/main/java/com/jjoe64/graphview/GridLabelRenderer.java b/src/main/java/com/jjoe64/graphview/GridLabelRenderer.java index 1a756ed9c..37210b4e7 100644 --- a/src/main/java/com/jjoe64/graphview/GridLabelRenderer.java +++ b/src/main/java/com/jjoe64/graphview/GridLabelRenderer.java @@ -324,6 +324,13 @@ public void setSecondScaleLabelVerticalWidth(Integer newWidth) { mLabelVerticalSecondScaleWidth = newWidth; } + /** + * activate or deactivate human rounding of the + * horizontal axis. GraphView tries to fit the labels + * to display numbers that can be divided by 1, 2, or 5. + */ + private boolean mHumanRoundingY; + /** * activate or deactivate human rounding of the * horizontal axis. GraphView tries to fit the labels @@ -332,7 +339,7 @@ public void setSecondScaleLabelVerticalWidth(Integer newWidth) { * By default this is enabled. It makes sense to deactivate it * when using Dates on the x axis. */ - private boolean mHumanRounding; + private boolean mHumanRoundingX; /** * create the default grid label renderer. @@ -346,7 +353,8 @@ public GridLabelRenderer(GraphView graphView) { resetStyles(); mNumVerticalLabels = 5; mNumHorizontalLabels = 5; - mHumanRounding = true; + mHumanRoundingX = true; + mHumanRoundingY = true; } /** @@ -436,8 +444,18 @@ public void reloadStyles() { * @return if human rounding is enabled */ - public boolean isHumanRounding() { - return mHumanRounding; + public boolean isHumanRoundingX() { + return mHumanRoundingX; + } + + /** + * GraphView tries to fit the labels + * to display numbers that can be divided by 1, 2, or 5. + * + * @return if human rounding is enabled + */ + public boolean isHumanRoundingY() { + return mHumanRoundingY; } /** @@ -448,10 +466,26 @@ public boolean isHumanRounding() { * By default this is enabled. It makes sense to deactivate it * when using Dates on the x axis. * - * @param humanRounding false to deactivate + * @param humanRoundingX false to deactivate + * @param humanRoundingY false to deactivate + */ + public void setHumanRounding(boolean humanRoundingX, boolean humanRoundingY) { + this.mHumanRoundingX = humanRoundingX; + this.mHumanRoundingY = humanRoundingY; + } + + /** + * activate or deactivate human rounding of the + * horizontal axis. GraphView tries to fit the labels + * to display numbers that can be divided by 1, 2, or 5. + * + * By default this is enabled. + * + * @param humanRoundingBoth false to deactivate on both axises */ - public void setHumanRounding(boolean humanRounding) { - this.mHumanRounding = humanRounding; + public void setHumanRounding(boolean humanRoundingBoth) { + this.mHumanRoundingX = humanRoundingBoth; + this.mHumanRoundingY = humanRoundingBoth; } /** @@ -622,10 +656,14 @@ protected boolean adjustVerticalSecondScale() { // it can happen that we need to add some more labels to fill the complete screen numVerticalLabels = (int) ((mGraphView.getSecondScale().mCurrentViewport.height()*-1 / exactSteps)) + 2; + // ensure that the value is valid (minimum 2) + // see https://github.com/appsthatmatter/GraphView/issues/520 + numVerticalLabels = Math.max(numVerticalLabels, 2); + if (mStepsVerticalSecondScale != null) { mStepsVerticalSecondScale.clear(); } else { - mStepsVerticalSecondScale = new LinkedHashMap<>((int) numVerticalLabels); + mStepsVerticalSecondScale = new LinkedHashMap<>(numVerticalLabels); } int height = mGraphView.getGraphContentHeight(); @@ -692,7 +730,7 @@ protected boolean adjustVertical(boolean changeBounds) { } // human rounding to have nice numbers (1, 2, 5, ...) - if (isHumanRounding()) { + if (isHumanRoundingY()) { exactSteps = humanRound(exactSteps, changeBounds); } else if (mStepsVertical != null && mStepsVertical.size() > 1) { // else choose other nice steps that previous @@ -831,7 +869,7 @@ protected boolean adjustHorizontal(boolean changeBounds) { } // human rounding to have nice numbers (1, 2, 5, ...) - if (isHumanRounding()) { + if (isHumanRoundingX()) { exactSteps = humanRound(exactSteps, false); } else if (mStepsHorizontal != null && mStepsHorizontal.size() > 1) { // else choose other nice steps that previous diff --git a/src/main/java/com/jjoe64/graphview/LegendRenderer.java b/src/main/java/com/jjoe64/graphview/LegendRenderer.java index 9286cb776..61ea019b2 100644 --- a/src/main/java/com/jjoe64/graphview/LegendRenderer.java +++ b/src/main/java/com/jjoe64/graphview/LegendRenderer.java @@ -148,6 +148,15 @@ public void resetStyles() { cachedLegendWidth = 0; } + protected List getAllSeries() { + List allSeries = new ArrayList(); + allSeries.addAll(mGraphView.getSeries()); + if (mGraphView.mSecondScale != null) { + allSeries.addAll(mGraphView.getSecondScale().getSeries()); + } + return allSeries; + } + /** * draws the legend if it is visible * @@ -161,11 +170,7 @@ public void draw(Canvas canvas) { int shapeSize = (int) (mStyles.textSize*0.8d); - List allSeries = new ArrayList(); - allSeries.addAll(mGraphView.getSeries()); - if (mGraphView.mSecondScale != null) { - allSeries.addAll(mGraphView.getSecondScale().getSeries()); - } + List allSeries = getAllSeries(); // width int legendWidth = mStyles.width; diff --git a/src/main/java/com/jjoe64/graphview/UniqueLegendRenderer.java b/src/main/java/com/jjoe64/graphview/UniqueLegendRenderer.java new file mode 100644 index 000000000..d0289bd78 --- /dev/null +++ b/src/main/java/com/jjoe64/graphview/UniqueLegendRenderer.java @@ -0,0 +1,36 @@ +package com.jjoe64.graphview; + +import android.util.Pair; + +import com.jjoe64.graphview.series.Series; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A LegendRenderer that renders items with the same name and color only once in the legend + * Created by poseidon on 27.02.18. + */ +public class UniqueLegendRenderer extends LegendRenderer { + /** + * creates legend renderer + * + * @param graphView regarding graphview + */ + public UniqueLegendRenderer(GraphView graphView) { + super(graphView); + } + + @Override + protected List getAllSeries() { + List originalSeries = super.getAllSeries(); + List distinctSeries = new ArrayList(); + Set> uniqueSeriesKeys = new HashSet>(); + for(Series series : originalSeries) + if(uniqueSeriesKeys.add(new Pair(series.getColor(), series.getTitle()))) + distinctSeries.add(series); + return distinctSeries; + } +} diff --git a/src/main/java/com/jjoe64/graphview/Viewport.java b/src/main/java/com/jjoe64/graphview/Viewport.java index b8954214b..ce674cce8 100644 --- a/src/main/java/com/jjoe64/graphview/Viewport.java +++ b/src/main/java/com/jjoe64/graphview/Viewport.java @@ -19,8 +19,8 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.support.v4.view.ViewCompat; -import android.support.v4.widget.EdgeEffectCompat; +import androidx.core.view.ViewCompat; +import androidx.core.widget.EdgeEffectCompat; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; @@ -50,14 +50,14 @@ public class Viewport { /** * this reference value is used to generate the * vertical labels. It is used when the y axis bounds - * is set manual and humanRounding=false. it will be the minValueY value. + * is set manual and humanRoundingY=false. it will be the minValueY value. */ protected double referenceY = Double.NaN; /** * this reference value is used to generate the * horizontal labels. It is used when the x axis bounds - * is set manual and humanRounding=false. it will be the minValueX value. + * is set manual and humanRoundingX=false. it will be the minValueX value. */ protected double referenceX = Double.NaN; @@ -83,7 +83,7 @@ public class Viewport { protected double getReferenceX() { // if the bounds is manual then we take the // original manual min y value as reference - if (isXAxisBoundsManual() && !mGraphView.getGridLabelRenderer().isHumanRounding()) { + if (isXAxisBoundsManual() && !mGraphView.getGridLabelRenderer().isHumanRoundingX()) { if (Double.isNaN(referenceX)) { referenceX = getMinX(false); } @@ -1263,7 +1263,7 @@ public void setScrollableY(boolean scrollableY) { protected double getReferenceY() { // if the bounds is manual then we take the // original manual min y value as reference - if (isYAxisBoundsManual() && !mGraphView.getGridLabelRenderer().isHumanRounding()) { + if (isYAxisBoundsManual() && !mGraphView.getGridLabelRenderer().isHumanRoundingY()) { if (Double.isNaN(referenceY)) { referenceY = getMinY(false); } diff --git a/src/main/java/com/jjoe64/graphview/series/BarGraphSeries.java b/src/main/java/com/jjoe64/graphview/series/BarGraphSeries.java index 5db99e1da..d8ab9ca13 100644 --- a/src/main/java/com/jjoe64/graphview/series/BarGraphSeries.java +++ b/src/main/java/com/jjoe64/graphview/series/BarGraphSeries.java @@ -19,7 +19,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; -import android.support.v4.view.ViewCompat; +import androidx.core.view.ViewCompat; import android.util.Log; import android.view.animation.AccelerateInterpolator; @@ -279,8 +279,11 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { } double left = x + contentLeft - offset + spacing/2 + currentSeriesOrder*barWidth; - double top = (contentTop - y) + contentHeight; double right = left + barWidth; + if (left > contentLeft + contentWidth || right < contentLeft) { + continue; + } + double top = (contentTop - y) + contentHeight; double bottom = (contentTop - y0) + contentHeight - (graphView.getGridLabelRenderer().isHighlightZeroLines()?4:1); boolean reverse = top > bottom; diff --git a/src/main/java/com/jjoe64/graphview/series/LineGraphSeries.java b/src/main/java/com/jjoe64/graphview/series/LineGraphSeries.java index a7ba85941..3d56125dd 100644 --- a/src/main/java/com/jjoe64/graphview/series/LineGraphSeries.java +++ b/src/main/java/com/jjoe64/graphview/series/LineGraphSeries.java @@ -1,13 +1,13 @@ /** * GraphView * Copyright 2016 Jonas Gehring - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + *

* http://www.apache.org/licenses/LICENSE-2.0 - * + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; -import android.support.v4.view.ViewCompat; +import androidx.core.view.ViewCompat; import android.view.animation.AccelerateInterpolator; import com.jjoe64.graphview.GraphView; @@ -252,7 +252,7 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { float firstX = -1; float firstY = -1; float lastRenderedX = Float.NaN; - int i=0; + int i = 0; float lastAnimationReferenceX = graphLeft; boolean sameXSkip = false; @@ -281,18 +281,18 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { boolean skipDraw = false; if (x > graphWidth) { // end right - double b = ((graphWidth - lastEndX) * (y - lastEndY)/(x - lastEndX)); - y = lastEndY+b; + double b = ((graphWidth - lastEndX) * (y - lastEndY) / (x - lastEndX)); + y = lastEndY + b; x = graphWidth; isOverdrawEndPoint = true; } if (y < 0) { // end bottom // skip when previous and this point is out of bound if (lastEndY < 0) { - skipDraw=true; + skipDraw = true; } else { - double b = ((0 - lastEndY) * (x - lastEndX)/(y - lastEndY)); - x = lastEndX+b; + double b = ((0 - lastEndY) * (x - lastEndX) / (y - lastEndY)); + x = lastEndX + b; } y = 0; isOverdrawY = isOverdrawEndPoint = true; @@ -300,17 +300,17 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { if (y > graphHeight) { // end top // skip when previous and this point is out of bound if (lastEndY > graphHeight) { - skipDraw=true; + skipDraw = true; } else { - double b = ((graphHeight - lastEndY) * (x - lastEndX)/(y - lastEndY)); - x = lastEndX+b; + double b = ((graphHeight - lastEndY) * (x - lastEndX) / (y - lastEndY)); + x = lastEndX + b; } y = graphHeight; isOverdrawY = isOverdrawEndPoint = true; } if (lastEndX < 0) { // start left - double b = ((0 - x) * (y - lastEndY)/(lastEndX - x)); - lastEndY = y-b; + double b = ((0 - x) * (y - lastEndY) / (lastEndX - x)); + lastEndY = y - b; lastEndX = 0; } @@ -320,7 +320,7 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { if (lastEndY < 0) { // start bottom if (!skipDraw) { double b = ((0 - y) * (x - lastEndX) / (lastEndY - y)); - lastEndX = x-b; + lastEndX = x - b; } lastEndY = 0; isOverdrawY = true; @@ -328,8 +328,8 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { if (lastEndY > graphHeight) { // start top // skip when previous and this point is out of bound if (!skipDraw) { - double b = ((graphHeight - y) * (x - lastEndX)/(lastEndY - y)); - lastEndX = x-b; + double b = ((graphHeight - y) * (x - lastEndX) / (lastEndY - y)); + lastEndX = x - b; } lastEndY = graphHeight; isOverdrawY = true; @@ -365,12 +365,12 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { mAnimationStartFrameNo++; } } - float timeFactor = (float) (currentTime-mAnimationStart) / ANIMATION_DURATION; + float timeFactor = (float) (currentTime - mAnimationStart) / ANIMATION_DURATION; float factor = mAnimationInterpolator.getInterpolation(timeFactor); if (timeFactor <= 1.0) { - startXAnimated = (startX-lastAnimationReferenceX) * factor + lastAnimationReferenceX; + startXAnimated = (startX - lastAnimationReferenceX) * factor + lastAnimationReferenceX; startXAnimated = Math.max(startXAnimated, lastAnimationReferenceX); - endXAnimated = (endX-lastAnimationReferenceX) * factor + lastAnimationReferenceX; + endXAnimated = (endX - lastAnimationReferenceX) * factor + lastAnimationReferenceX; ViewCompat.postInvalidateOnAnimation(graphView); } else { // animation finished @@ -397,16 +397,16 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { mPath.moveTo(startXAnimated, startY); } // performance opt. - if (Float.isNaN(lastRenderedX) || Math.abs(endX-lastRenderedX) > .3f) { + if (Float.isNaN(lastRenderedX) || Math.abs(endX - lastRenderedX) > .3f) { if (mDrawAsPath) { mPath.lineTo(endXAnimated, endY); } else { // draw vertical lines that were skipped if (sameXSkip) { sameXSkip = false; - renderLine(canvas, new float[] {lastRenderedX, minYOnSameX, lastRenderedX, maxYOnSameX}, paint); + renderLine(canvas, new float[]{lastRenderedX, minYOnSameX, lastRenderedX, maxYOnSameX}, paint); } - renderLine(canvas, new float[] {startXAnimated, startY, endXAnimated, endY}, paint); + renderLine(canvas, new float[]{startXAnimated, startY, endXAnimated, endY}, paint); } lastRenderedX = endX; } else { @@ -452,17 +452,17 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { float first_X = (float) x + (graphLeft + 1); float first_Y = (float) (graphTop - y) + graphHeight; - if (first_X >= graphLeft && first_Y <= (graphTop+graphHeight)) { + if (first_X >= graphLeft && first_Y <= (graphTop + graphHeight)) { if (mAnimated && (Double.isNaN(mLastAnimatedValue) || mLastAnimatedValue < valueX)) { long currentTime = System.currentTimeMillis(); if (mAnimationStart == 0) { // start animation mAnimationStart = currentTime; } - float timeFactor = (float) (currentTime-mAnimationStart) / ANIMATION_DURATION; + float timeFactor = (float) (currentTime - mAnimationStart) / ANIMATION_DURATION; float factor = mAnimationInterpolator.getInterpolation(timeFactor); if (timeFactor <= 1.0) { - first_X = (first_X-lastAnimationReferenceX) * factor + lastAnimationReferenceX; + first_X = (first_X - lastAnimationReferenceX) * factor + lastAnimationReferenceX; ViewCompat.postInvalidateOnAnimation(graphView); } else { // animation finished @@ -475,6 +475,7 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { paint.setStyle(Paint.Style.FILL); canvas.drawCircle(first_X, first_Y, mStyles.dataPointsRadius, paint); paint.setStyle(prevStyle); + registerDataPoint(first_X, first_Y, value); } } lastEndY = orgY; @@ -511,6 +512,11 @@ public void draw(GraphView graphView, Canvas canvas, boolean isSecondScale) { * @param paint */ private void renderLine(Canvas canvas, float[] pts, Paint paint) { + if (pts.length == 4 && pts[0] == pts[2] && pts[1] == pts[3]) { + // avoid zero length lines, to makes troubles on some devices + // see https://github.com/appsthatmatter/GraphView/issues/499 + return; + } canvas.drawLines(pts, paint); } @@ -599,7 +605,7 @@ public void setDataPointsRadius(float dataPointsRadius) { } /** - * @return the background color for the filling under + * @return the background color for the filling under * the line. * @see #setDrawBackground(boolean) */ @@ -677,7 +683,7 @@ public void appendData(E dataPoint, boolean scrollToEnd, int maxDataPoints, bool private boolean isAnimationActive() { if (mAnimated) { long curr = System.currentTimeMillis(); - return curr-mAnimationStart <= ANIMATION_DURATION; + return curr - mAnimationStart <= ANIMATION_DURATION; } return false; }