├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.webp
│ │ │ ├── values
│ │ │ │ ├── themes.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── colors.xml
│ │ │ ├── values-night
│ │ │ │ └── colors.xml
│ │ │ ├── drawable
│ │ │ │ ├── ic_moon.xml
│ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── assets
│ │ │ ├── chart_data_from_issue.json
│ │ │ ├── chart_data_small.json
│ │ │ ├── chart_data.json
│ │ │ └── all_chart_data.json
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── klim
│ │ │ └── tcharts
│ │ │ └── example
│ │ │ ├── CustomScrollView.java
│ │ │ ├── NightMode.java
│ │ │ ├── U.java
│ │ │ └── MainActivity.kt
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── klim
│ │ │ └── tcharts
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── klim
│ │ └── tcharts
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── .idea
├── .name
├── .gitignore
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── compiler.xml
├── misc.xml
└── jarRepositories.xml
├── TCharts
├── .gitignore
├── consumer-rules.pro
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ └── dimens.xml
│ │ │ └── values-night
│ │ │ │ └── colors.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── klim
│ │ │ │ └── tcharts
│ │ │ │ ├── enums
│ │ │ │ └── BorderType.java
│ │ │ │ ├── interfaces
│ │ │ │ ├── OnShowLinesListener.java
│ │ │ │ ├── OnCheckedChangeListener.java
│ │ │ │ └── OnSelectedTimeLineChanged.java
│ │ │ │ ├── utils
│ │ │ │ ├── ColorU.java
│ │ │ │ ├── PaintU.java
│ │ │ │ ├── AnimatorU.java
│ │ │ │ └── SearchU.java
│ │ │ │ ├── Colors.java
│ │ │ │ ├── entities
│ │ │ │ ├── ChartItem.java
│ │ │ │ └── ChartData.java
│ │ │ │ ├── views
│ │ │ │ ├── TitleView.java
│ │ │ │ ├── BorderView.java
│ │ │ │ ├── BaseView.java
│ │ │ │ ├── InfoWindowView.java
│ │ │ │ ├── NavigationView.java
│ │ │ │ └── SelectedWindow.java
│ │ │ │ └── TChart.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── klim
│ │ │ └── tcharts
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── klim
│ │ └── tcharts
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── info
├── preview.mp4
└── preview.webp
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── gradlew
├── README.md
└── LICENSE
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | TChartsExample
--------------------------------------------------------------------------------
/TCharts/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/TCharts/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/TCharts/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/info/preview.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makstron/TCharts/HEAD/info/preview.mp4
--------------------------------------------------------------------------------
/info/preview.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makstron/TCharts/HEAD/info/preview.webp
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':TCharts'
2 | include ':app'
3 | rootProject.name = "TChartsExample"
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makstron/TCharts/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/makstron/TCharts/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/enums/BorderType.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.enums;
2 |
3 | public enum BorderType {
4 | LEFT, RIGHT
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TChartsExample
3 |
4 | Json Example not allowed
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TCharts/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/interfaces/OnShowLinesListener.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.interfaces;
2 |
3 | public interface OnShowLinesListener {
4 | void onShowLines(int lineIndex, boolean show);
5 | }
6 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/interfaces/OnCheckedChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.interfaces;
2 |
3 | public interface OnCheckedChangeListener {
4 | void onCheckedChange(int id, boolean isChecked);
5 | }
6 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/interfaces/OnSelectedTimeLineChanged.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.interfaces;
2 |
3 | public interface OnSelectedTimeLineChanged {
4 | void onTimeLineChanged(long start, long end, boolean changeZoom);
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/chart_data_from_issue.json:
--------------------------------------------------------------------------------
1 | [{"columns":{"x":[1618951646915,1618951647916],"PPFD":[1012,900],"DLI":[70,87]},"types":{"PPFD":"line","DLI":"line","x":"x"},"names":{"PPFD":"PPFD","DLI":"DLI"},"colors":{"PPFD":"#FF00FF00","DLI":"#FFFF0000"}}]
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 24dp
3 | 36dp
4 |
5 |
6 | 16dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/assets/chart_data_small.json:
--------------------------------------------------------------------------------
1 | [{"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000],"y0":[37,20,32,39],"y1":[22,12,30,40]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}}]
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Feb 25 19:13:08 EET 2021
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-6.5-bin.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #517DA2
5 | #426382
6 | #f0f0f0
7 | #373737
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #212D3B
5 | #1A242E
6 | #151e27
7 | #CDCDCD
8 |
9 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/utils/ColorU.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.utils;
2 |
3 | import android.graphics.Color;
4 |
5 | public class ColorU {
6 |
7 | public static int colorSetA(int color, int a) {
8 | return Color.argb(a, Color.red(color), Color.green(color), Color.blue(color));
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TCharts/src/test/java/com/klim/tcharts/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/klim/tcharts/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/utils/PaintU.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.utils;
2 |
3 | import android.graphics.Paint;
4 |
5 | public class PaintU {
6 |
7 | public static Paint createPaint(int color, Paint.Style style) {
8 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
9 | paint.setColor(color);
10 | paint.setStyle(style);
11 | return paint;
12 | }
13 |
14 | public static Paint createPaint(int color, Paint.Style style, float strokeWidth) {
15 | Paint p = createPaint(color, style);
16 | p.setStrokeWidth(strokeWidth);
17 | return p;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/TCharts/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
5 | #3896D4
6 |
7 | #506372
8 | #efeff0
9 | #73C9D8E3
10 |
11 | #FFFFFFFF
12 | #5C000000
13 | #222222
14 |
15 | #BAF5F8F9
16 | #477DA9CA
17 | #92D3E3F0
18 |
19 |
20 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/Colors.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts;
2 |
3 | import android.graphics.Color;
4 |
5 | public class Colors {
6 | public int backgroundColor = Color.RED;
7 |
8 | public int titleFontColor = Color.RED;
9 |
10 | public int detailLabelsFontColor = Color.RED;
11 | public int detailDivisionColor = Color.RED;
12 | public int detailLineSelectedPosition = Color.RED;
13 |
14 | public int infoWindowBackground = Color.RED;
15 | public int infoWindowShadowColor = Color.RED;
16 | public int infoWindowTitleColor = Color.RED;
17 |
18 | public int navFillColor = Color.RED;
19 | public int navBordersColor = Color.RED;
20 | public int navTapCircleColor = Color.RED;
21 | }
22 |
--------------------------------------------------------------------------------
/TCharts/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #1D2733
4 |
5 | #7BC4FB
6 |
7 | #506372
8 | #151e2a
9 | #AD0E1721
10 |
11 | #FF202b38
12 | #5C000000
13 | #FFFFFF
14 |
15 | #BD19232E
16 | #477DA9CA
17 | #8043515c
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_moon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/klim/tcharts/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.klim.tcharts", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/TCharts/src/androidTest/java/com/klim/tcharts/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.klim.tcharts.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/klim/tcharts/example/CustomScrollView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.example;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.MotionEvent;
6 | import android.widget.ScrollView;
7 |
8 | public class CustomScrollView extends ScrollView {
9 | public CustomScrollView(Context context) {
10 | super(context);
11 | }
12 |
13 | public CustomScrollView(Context context, AttributeSet attrs) {
14 | super(context, attrs);
15 | }
16 |
17 | public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
18 | super(context, attrs, defStyleAttr);
19 | }
20 |
21 | @Override
22 | public boolean onInterceptTouchEvent(MotionEvent ev) {
23 | // onTouchEvent(ev);
24 | return false;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/TCharts/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
--------------------------------------------------------------------------------
/TCharts/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/entities/ChartItem.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.entities;
2 |
3 | import java.util.List;
4 |
5 | public class ChartItem {
6 | private long time;
7 | private List values;
8 | private int maxValue;
9 |
10 | public ChartItem(long time, List values) {
11 | this.time = time;
12 | this.values = values;
13 |
14 | if (values != null) {
15 | for (Integer value : values) {
16 | if (value > maxValue) {
17 | maxValue = value;
18 | }
19 | }
20 | }
21 | }
22 |
23 | public long getTime() {
24 | return time;
25 | }
26 |
27 | public List getValues() {
28 | return values;
29 | }
30 |
31 | public Integer getMaxValue() {
32 | return maxValue;
33 | }
34 |
35 | public void updateMaxValue(boolean[] check) {
36 | maxValue = 0;
37 | for (int i = 0; i < values.size(); i++) {
38 | if (check[i] && values.get(i) > maxValue) {
39 | maxValue = values.get(i);
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/utils/AnimatorU.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.utils;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.view.animation.LinearInterpolator;
5 |
6 | public class AnimatorU {
7 |
8 | public static ValueAnimator createIntValueAnimator(int start, int end, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
9 | ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end);
10 | return crValAnim(valueAnimator, duration, updateListener);
11 | }
12 |
13 | public static ValueAnimator createFloatValueAnimator(float start, float end, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
14 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
15 | return crValAnim(valueAnimator, duration, updateListener);
16 | }
17 |
18 | public static ValueAnimator crValAnim(ValueAnimator valueAnimator, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
19 | valueAnimator.addUpdateListener(updateListener);
20 | valueAnimator.setInterpolator(new LinearInterpolator());
21 | valueAnimator.setDuration(duration);
22 | return valueAnimator;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/TCharts/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | minSdkVersion 19
12 | targetSdkVersion 30
13 | versionCode 5
14 | versionName "0.9.4"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 | //kotlin
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | implementation 'androidx.core:core-ktx:1.3.2'
39 |
40 | //test
41 | testImplementation 'junit:junit:4.+'
42 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
44 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 | buildToolsVersion "30.0.3"
9 |
10 | defaultConfig {
11 | applicationId "com.klim.tcharts.example"
12 | minSdkVersion 19
13 | targetSdkVersion 30
14 | versionCode 1
15 | versionName "0.9"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled true
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 | //kotlin
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | //kotlin coroutines
39 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
40 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
41 | //TCharts
42 | implementation project(path: ':TCharts')
43 | //test
44 | testImplementation 'junit:junit:4.+'
45 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
46 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
47 | }
--------------------------------------------------------------------------------
/TCharts/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
5 | 16sp
6 | 8dp
7 | 8dp
8 | 8dp
9 |
10 |
11 | 327dp
12 |
13 | 24dp
14 | 0.5dp
15 | 2.0dp
16 | 11sp
17 | 6dp
18 | 1.5dp
19 | 4dp
20 | 16dp
21 | 6dp
22 | 6dp
23 | 1.5dp
24 | 16dp
25 | 10dp
26 | 16dp
27 |
28 |
29 | 42dp
30 | 5dp
31 | 1.5dp
32 | 3dp
33 |
34 | 1.2dp
35 | 0.9dp
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | # Android Studio 3 in .gitignore file.
48 | .idea/caches
49 | .idea/modules.xml
50 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
51 | .idea/navEditor.xml
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 | .cxx/
61 |
62 | # Google Services (e.g. APIs or Firebase)
63 | # google-services.json
64 |
65 | # Freeline
66 | freeline.py
67 | freeline/
68 | freeline_project_description.json
69 |
70 | # fastlane
71 | fastlane/report.xml
72 | fastlane/Preview.html
73 | fastlane/screenshots
74 | fastlane/test_output
75 | fastlane/readme.md
76 |
77 | # Version control
78 | vcs.xml
79 |
80 | # lint
81 | lint/intermediates/
82 | lint/generated/
83 | lint/outputs/
84 | lint/tmp/
85 | # lint/reports/
86 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/utils/SearchU.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.utils;
2 |
3 | import com.klim.tcharts.entities.ChartItem;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class SearchU {
9 |
10 | /**
11 | * Make first symbol In String Upper case
12 | *
13 | * @param s input String
14 | * @return String with Upper first symbol
15 | */
16 | public static String firstCharUpper(String s) {
17 | return s.substring(0, 1).toUpperCase() + s.substring(1);
18 | }
19 |
20 | public static int binarySearchLeft(List arr, int l, int r, long x) {
21 | if (r >= l) {
22 | int mid = l + (r - l) / 2;
23 | if (arr.get(Math.max(mid - 1, 0)).getTime() <= x && x < arr.get(mid).getTime()) {
24 | return Math.max(mid - 1, 0);
25 | } else if (arr.get(mid).getTime() == x) {
26 | return Math.max(mid - 1, 0);
27 | }
28 |
29 | if (arr.get(mid).getTime() > x) {
30 | return binarySearchLeft(arr, l, mid - 1, x);
31 | }
32 | return binarySearchLeft(arr, mid + 1, r, x);
33 | }
34 | return -1;
35 | }
36 |
37 | public static int binarySearchRight(List arr, int l, int r, long x) {
38 | if (r >= l) {
39 | int mid = l + (r - l) / 2;
40 |
41 | if (arr.get(mid).getTime() < x && x <= arr.get(mid + 1).getTime()) {
42 | return mid + 1;
43 | } else if (arr.get(mid).getTime() == x) {
44 | return mid + 1;
45 | }
46 |
47 | if (arr.get(mid).getTime() > x) {
48 | return binarySearchRight(arr, l, mid - 1, x);
49 | }
50 | return binarySearchRight(arr, mid + 1, r, x);
51 | }
52 | return -1;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/TitleView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.Rect;
6 | import android.graphics.Typeface;
7 | import android.view.View;
8 |
9 | import com.klim.tcharts.Colors;
10 | import com.klim.tcharts.R;
11 | import com.klim.tcharts.utils.PaintU;
12 |
13 | public class TitleView extends BaseView {
14 | private Colors colors;
15 |
16 | private Paint pForTitle;
17 |
18 | // params
19 | public String title = "";
20 | public int titleFontSize = 0;
21 | public boolean showTitle = false;
22 |
23 | public TitleView(View view, Colors colors) {
24 | super(view);
25 | this.colors = colors;
26 | }
27 |
28 | public void init() {
29 | createPaints();
30 | }
31 |
32 | public int calculateHeight() {
33 | int height = 0;
34 | if (showTitle) {
35 | Rect textBounds = new Rect();
36 | pForTitle.getTextBounds("W", 0, "W".length(), textBounds);
37 | height = textBounds.height() + paddingTop + paddingBottom;
38 | } else {
39 | height = Math.round(getDimen(R.dimen.minTitleHeight));
40 | }
41 | return height;
42 | }
43 |
44 | private void createPaints() {
45 | pForTitle = PaintU.createPaint(colors.titleFontColor, Paint.Style.FILL);
46 | pForTitle.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
47 | pForTitle.setTextSize(titleFontSize);
48 | }
49 |
50 | @Override
51 | public void onSizeChanged() {
52 | }
53 |
54 | @Override
55 | public void prepareDataForPrinting(boolean hardPrepare) {
56 |
57 | }
58 |
59 | @Override
60 | public void drawOn(Canvas canvas) {
61 | if (showTitle) {
62 | canvas.drawText(title, posX + paddingLeft, posY + height - paddingTop, pForTitle);
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/klim/tcharts/example/NightMode.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.example;
2 |
3 | import android.app.Activity;
4 | import android.content.SharedPreferences;
5 | import android.content.res.Configuration;
6 | import android.preference.PreferenceManager;
7 |
8 | import java.lang.ref.WeakReference;
9 |
10 | public class NightMode {
11 | private static final String PREF_KEY = "nightModeState";
12 |
13 | private static int sUiNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
14 |
15 | private WeakReference mActivity;
16 | private SharedPreferences mPrefs;
17 |
18 | public NightMode(Activity activity, int theme) {
19 | int currentMode = (activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
20 | mPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
21 |
22 | //init
23 | mActivity = new WeakReference(activity);
24 | if (sUiNightMode == Configuration.UI_MODE_NIGHT_UNDEFINED) {
25 | sUiNightMode = mPrefs.getInt(PREF_KEY, currentMode);
26 | }
27 | updateConfig(sUiNightMode);
28 | activity.setTheme(theme);
29 | }
30 |
31 | public void toggle() {
32 | if (sUiNightMode == Configuration.UI_MODE_NIGHT_YES) {
33 | updateConfig(Configuration.UI_MODE_NIGHT_NO);
34 | } else {
35 | updateConfig(Configuration.UI_MODE_NIGHT_YES);
36 | }
37 | mActivity.get().recreate();
38 | }
39 |
40 | private void updateConfig(int uiNightMode) {
41 | Activity activity = mActivity.get();
42 | if (activity != null) {
43 | Configuration newConfig = new Configuration(activity.getResources().getConfiguration());
44 | newConfig.uiMode &= ~Configuration.UI_MODE_NIGHT_MASK;
45 | newConfig.uiMode |= uiNightMode;
46 | activity.getResources().updateConfiguration(newConfig, null);
47 | sUiNightMode = uiNightMode;
48 | if (mPrefs != null) {
49 | mPrefs.edit().putInt(PREF_KEY, sUiNightMode).apply();
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/entities/ChartData.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.entities;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class ChartData {
7 | private List keys;
8 | private List names;
9 | private List colors;
10 | private List items;
11 | // private ArrayList linesForShow;
12 | private ArrayList maxValueInLine;
13 |
14 | public ChartData(List keys, List names, List colors, List items) {
15 | this.keys = keys;
16 | this.names = names;
17 | this.colors = colors;
18 | this.items = items;
19 |
20 | // linesForShow = new ArrayList<>(names.size());
21 | // for (int i = 0; i < names.size(); i++) {
22 | // linesForShow.add(true);
23 | // }
24 |
25 | //find max value for each lines
26 | maxValueInLine = new ArrayList<>(names.size());
27 | for (int i = 0; i < names.size(); i++) {
28 | maxValueInLine.add(0);
29 | }
30 | for (ChartItem item : items) {
31 | for (int i = 0; i < maxValueInLine.size(); i++) {
32 | if (maxValueInLine.get(i) < item.getValues().get(i)) {
33 | maxValueInLine.set(i, item.getValues().get(i));
34 | }
35 | }
36 | }
37 | }
38 |
39 | public List getKeys() {
40 | return keys;
41 | }
42 |
43 | public List getNames() {
44 | return names;
45 | }
46 |
47 | public List getColors() {
48 | return colors;
49 | }
50 |
51 | public List getItems() {
52 | return items;
53 | }
54 |
55 | // public ArrayList getLinesForShow() {
56 | // return linesForShow;
57 | // }
58 |
59 | public void updateLinesForShow(boolean[] showLines) {
60 | for (ChartItem item : items) {
61 | item.updateMaxValue(showLines);
62 | }
63 | }
64 |
65 | public ArrayList getMaxValueInLine() {
66 | return maxValueInLine;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/BorderView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.Paint;
6 | import android.view.View;
7 |
8 | import com.klim.tcharts.enums.BorderType;
9 |
10 | public class BorderView extends BaseView {
11 | private BorderType type;
12 |
13 | private Paint pen;
14 | private Paint penDebug;
15 |
16 | private boolean selected = false;
17 | private float shiftPositinTap;
18 |
19 | public BorderView(View view, BorderType type, float posX, float posY, int width, int height, Paint pen) {
20 | super(view);
21 | this.posX = posX;
22 | this.posY = posY;
23 | this.width = width;
24 | this.height = height;
25 | this.type = type;
26 | this.pen = pen;
27 |
28 | penDebug = new Paint();
29 | penDebug.setColor(Color.RED);
30 | penDebug.setStrokeWidth(2);
31 | }
32 |
33 | public boolean isItMe(float tapX) {
34 | switch (type) {
35 | case LEFT:
36 | return posX - width * 2 < tapX && tapX < posX + width;
37 | case RIGHT:
38 | return posX < tapX && tapX < posX + width * 3;
39 | }
40 | return false;
41 | }
42 |
43 | @Override
44 | public void prepareDataForPrinting(boolean hardPrepare) {
45 |
46 | }
47 |
48 | @Override
49 | protected void drawOn(Canvas canvas) {
50 | canvas.drawRect(posX, posY, posX + width, posY + height, pen);
51 | // switch (type) {
52 | // case LEFT: {
53 | // canvas.drawLine(posX - width * 2, posY, posX + width, posY + height, penDebug);
54 | // break;
55 | // }
56 | // case RIGHT: {
57 | // canvas.drawLine(posX, posY, posX + width * 3, posY + height, penDebug);
58 | // break;
59 | // }
60 | // }
61 |
62 | super.drawOn(canvas);
63 | }
64 |
65 | public boolean isSelected() {
66 | return selected;
67 | }
68 |
69 | public void setSelected(boolean selected) {
70 | this.selected = selected;
71 | }
72 |
73 | public float getShiftPositinTap() {
74 | return shiftPositinTap;
75 | }
76 |
77 | public void setShiftPositinTap(float shiftPositinTap) {
78 | this.shiftPositinTap = shiftPositinTap;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
20 |
21 |
30 |
31 |
38 |
39 |
40 |
41 |
47 |
48 |
53 |
54 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/klim/tcharts/example/U.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.example;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.content.Context;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.view.animation.LinearInterpolator;
8 |
9 | import java.util.ArrayList;
10 |
11 | /**
12 | * Class with utilities
13 | */
14 |
15 | public class U {
16 |
17 | /**
18 | * Make first symbol In String Upper case
19 | *
20 | * @param s input String
21 | * @return String with Upper first symbol
22 | */
23 | public static String firstCharUpper(String s) {
24 | return s.substring(0, 1).toUpperCase() + s.substring(1);
25 | }
26 |
27 | // public static int binarySearchLeft(ArrayList arr, int l, int r, long x) {
28 | // if (r >= l) {
29 | // int mid = l + (r - l) / 2;
30 | // if (arr.get(Math.max(mid - 1, 0)).getTime() <= x && x < arr.get(mid).getTime()) {
31 | // return Math.max(mid - 1, 0);
32 | // } else if (arr.get(mid).getTime() == x) {
33 | // return Math.max(mid - 1, 0);
34 | // }
35 | //
36 | // if (arr.get(mid).getTime() > x) {
37 | // return binarySearchLeft(arr, l, mid - 1, x);
38 | // }
39 | // return binarySearchLeft(arr, mid + 1, r, x);
40 | // }
41 | // return -1;
42 | // }
43 | //
44 | // public static int binarySearchRight(ArrayList arr, int l, int r, long x) {
45 | // if (r >= l) {
46 | // int mid = l + (r - l) / 2;
47 | //
48 | // if (arr.get(mid).getTime() < x && x <= arr.get(mid + 1).getTime()) {
49 | // return mid + 1;
50 | // } else if (arr.get(mid).getTime() == x) {
51 | // return mid + 1;
52 | // }
53 | //
54 | // if (arr.get(mid).getTime() > x) {
55 | // return binarySearchRight(arr, l, mid - 1, x);
56 | // }
57 | // return binarySearchRight(arr, mid + 1, r, x);
58 | // }
59 | // return -1;
60 | // }
61 |
62 | public static Paint createPaint(int color, Paint.Style style, float strokeWidth) {
63 | Paint p = createPaint(color, style);
64 | p.setStrokeWidth(strokeWidth);
65 | return p;
66 | }
67 |
68 | public static Paint createPaint(int color, Paint.Style style) {
69 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
70 | paint.setColor(color);
71 | paint.setStyle(style);
72 | return paint;
73 | }
74 |
75 | public static int getStatusBarHeight(Context context, int def) {
76 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
77 | if (resourceId > 0) {
78 | return context.getResources().getDimensionPixelSize(resourceId);
79 | }
80 | return def;
81 | }
82 |
83 | public static int colorSetA(int color, int a) {
84 | return Color.argb(a, Color.red(color), Color.green(color), Color.blue(color));
85 | }
86 |
87 | public static ValueAnimator createIntValueAnimator(int start, int end, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
88 | ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end);
89 | return crValAnim(valueAnimator, duration, updateListener);
90 | }
91 |
92 | public static ValueAnimator createFloatValueAnimator(float start, float end, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
93 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
94 | return crValAnim(valueAnimator, duration, updateListener);
95 | }
96 |
97 | public static ValueAnimator crValAnim(ValueAnimator valueAnimator, int duration, ValueAnimator.AnimatorUpdateListener updateListener) {
98 | valueAnimator.addUpdateListener(updateListener);
99 | valueAnimator.setInterpolator(new LinearInterpolator());
100 | valueAnimator.setDuration(duration);
101 | return valueAnimator;
102 | }
103 | }
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | xmlns:android
34 |
35 | ^$
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | xmlns:.*
45 |
46 | ^$
47 |
48 |
49 | BY_NAME
50 |
51 |
52 |
53 |
54 |
55 |
56 | .*:id
57 |
58 | http://schemas.android.com/apk/res/android
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | .*:name
68 |
69 | http://schemas.android.com/apk/res/android
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | name
79 |
80 | ^$
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | style
90 |
91 | ^$
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | .*
101 |
102 | ^$
103 |
104 |
105 | BY_NAME
106 |
107 |
108 |
109 |
110 |
111 |
112 | .*
113 |
114 | http://schemas.android.com/apk/res/android
115 |
116 |
117 | ANDROID_ATTRIBUTE_ORDER
118 |
119 |
120 |
121 |
122 |
123 |
124 | .*
125 |
126 | .*
127 |
128 |
129 | BY_NAME
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/BaseView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 |
10 | import com.klim.tcharts.TChart;
11 |
12 | public abstract class BaseView {
13 | protected Context context;
14 | protected TChart view;
15 | protected float posX;
16 | protected float posY;
17 | protected int width;
18 | protected int height;
19 | protected int paddingTop = 0;
20 | protected int paddingBottom = 0;
21 | protected int paddingLeft = 0;
22 | protected int paddingRight = 0;
23 |
24 | protected float paddingX;
25 |
26 | protected boolean iAmPressed = false;
27 |
28 | public BaseView(View view) {
29 | this.view = (TChart) view;
30 | this.context = view.getContext();
31 | }
32 |
33 | public boolean onTouchEvent(MotionEvent event) {
34 | return false;
35 | }
36 |
37 | public boolean tapOnMe(float x, float y) {
38 | return posX <= x && x <= posX + width && posY <= y && y <= posY + height;
39 | }
40 |
41 | public abstract void prepareDataForPrinting(boolean hardPrepare);
42 |
43 | void drawOn(Canvas canvas) {
44 |
45 | }
46 |
47 | void onSizeChanged() {
48 |
49 | }
50 |
51 | public void drawDebug(Canvas canvas, boolean isDebug) {
52 | if (isDebug) {
53 | drawDebug(canvas, posX, posY, width, height);
54 | }
55 | }
56 |
57 |
58 | public void drawDebug(Canvas canvas, float x, float y, float width, float height) {
59 | //todo do not need paint alvais reinit
60 | Paint tempP = new Paint();
61 | tempP.setStyle(Paint.Style.STROKE);
62 | tempP.setColor(Color.RED);
63 | tempP.setStrokeWidth(1);
64 | canvas.drawRect(x, y, x + width - 1, y + height - 1, tempP);
65 | canvas.drawLine(x, y, x + width - 1, y + height - 1, tempP);
66 | canvas.drawLine(x, y + height - 1, x + width - 1, y, tempP);
67 |
68 | canvas.drawRect(x, y, x + width - 1, y + height - 1, tempP);
69 |
70 | tempP.setStyle(Paint.Style.FILL);
71 | tempP.setColor(Color.parseColor("#50FF0000"));
72 |
73 | canvas.drawRect(x + paddingLeft, y, x + width - paddingRight, y + paddingTop, tempP); //top
74 | canvas.drawRect(x, y + paddingTop, x + paddingLeft, y + height - paddingBottom, tempP); //left
75 | canvas.drawRect(x + width - paddingRight, y + paddingTop, x + width, y + height - paddingBottom, tempP); //right
76 | canvas.drawRect(x + paddingLeft, y + height - paddingBottom, x + width - paddingRight, y + height, tempP); //bottom
77 | }
78 |
79 | public void invalidate() {
80 | view.invalidate();
81 | }
82 |
83 | protected TChart getView() {
84 | return view;
85 | }
86 |
87 | public void onRestoreInstantState() {
88 |
89 | }
90 |
91 | public int getInt(/*@IntegerRes*/ int id) {
92 | return context.getResources().getInteger(id);
93 | }
94 |
95 | public float getDimen(/*@DimenRes*/ int id) {
96 | return context.getResources().getDimension(id);
97 | }
98 |
99 | // public int getColor(/*@ColorRes*/ int id) {
100 | // return context.getResources().getColor(id);
101 | // }
102 |
103 | public boolean isiAmPressed() {
104 | return iAmPressed;
105 | }
106 |
107 | public float getPosX() {
108 | return posX;
109 | }
110 |
111 | public void setPosX(float posX) {
112 | this.posX = posX;
113 | }
114 |
115 | public float getPosY() {
116 | return posY;
117 | }
118 |
119 | public void setPosY(float posY) {
120 | this.posY = posY;
121 | }
122 |
123 | public int getWidth() {
124 | return width;
125 | }
126 |
127 | public void setWidth(int width) {
128 | this.width = width;
129 | }
130 |
131 | public int getHeight() {
132 | return height;
133 | }
134 |
135 | public void setHeight(int height) {
136 | this.height = height;
137 | }
138 |
139 | public int getPaddingTop() {
140 | return paddingTop;
141 | }
142 |
143 | public void setPaddingTop(int paddingTop) {
144 | this.paddingTop = paddingTop;
145 | }
146 |
147 | public int getPaddingBottom() {
148 | return paddingBottom;
149 | }
150 |
151 | public void setPaddingBottom(int paddingBottom) {
152 | this.paddingBottom = paddingBottom;
153 | }
154 |
155 | public int getPaddingLeft() {
156 | return paddingLeft;
157 | }
158 |
159 | public void setPaddingLeft(int paddingLeft) {
160 | this.paddingLeft = paddingLeft;
161 | }
162 |
163 | public int getPaddingRight() {
164 | return paddingRight;
165 | }
166 |
167 | public void setPaddingRight(int paddingRight) {
168 | this.paddingRight = paddingRight;
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TChart
2 | [](https://android-arsenal.com/api?level=19)
3 | [](https://jitpack.io/#makstron/TCharts)
4 |
5 | Simple and fast charts.
6 |
7 | ## Preview
8 | 
9 |
10 | ## Import
11 |
12 | ### jitpack.io
13 | #### gradle
14 | ```gradle
15 | allprojects {
16 | repositories {
17 | ....
18 | maven { url 'https://jitpack.io' }
19 | }
20 | }
21 | ```
22 | ```gradle
23 | dependencies {
24 | implementation 'com.github.makstron:TCharts:0.9'
25 | }
26 | ```
27 | #### maven
28 | ```xml
29 |
30 |
31 | jitpack.io
32 | https://jitpack.io
33 |
34 |
35 | ```
36 | ```xml
37 |
38 | com.github.makstron
39 | TCharts
40 | 0.9.1
41 |
42 | ```
43 |
44 | ## Usage
45 |
46 | ### Sample project
47 | See `app` directory. Sample project is under construction. Not all features are covered yet.
48 |
49 | ### Usage in code
50 |
51 | Example for create data
52 | ```kotlin
53 | ArrayList keys = new ArrayList(); //keys for each chart
54 | ArrayList names = new ArrayList(); //names for chart
55 | ArrayList colors = new ArrayList(); //colors for lines
56 | ArrayList items = new ArrayList(); //charts value for some time
57 | //ChartItem
58 | // time - time point (on x line)
59 | // values - list values for this moment of time in order from keys
60 |
61 | keys.add("y0");
62 | keys.add("y1");
63 | names.add("Red Line");
64 | names.add("Green Line");
65 | colors.add(Color.RED);
66 | colors.add(Color.GREEN);
67 |
68 | long startTime = 1614542230000L;
69 | Random random = new Random();
70 | for (int i = 0; i < 100; i++) {
71 | //time moment
72 | startTime += 86_400_000;
73 |
74 | //all values for this time moment
75 | ArrayList values = new ArrayList();
76 | for (int j = 0; j < keys.size(); j++) {
77 | values.add(random.nextInt(1000));
78 | }
79 |
80 | ChartItem chartItem = new ChartItem(startTime, values);
81 | items.add(chartItem);
82 | }
83 | ChartData chartData = new ChartData(keys, names, colors, items)
84 | ```
85 | ```kotlin
86 | val tChart = TChart(context)
87 | val layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
88 | tChart.layoutParams = layoutParams
89 | tChart.id = View.generateViewId()
90 | tChart.setData(chartData, true)
91 | tChart.setTitle(String.format("Chart #%d", i))
92 | layout.addView(tChart)
93 | ```
94 |
95 | ### Usage in XML
96 | ```xml
97 |
116 | ```
117 |
118 | ### Properties
119 | --------
120 |
121 | | Properties | Default White theme | Default Dark theme |
122 | | ---------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------- |
123 | | backgroundColor | #FFFFFF | #1D2733 |
124 | | showTitle | true | true |
125 | | title | | |
126 | | titleFontSize | 16sp | 16sp |
127 | | titleFontColor | #3896D4 | #7BC4FB |
128 | | detailLabelsFontColor | #506372 | #506372 |
129 | | detailDivisionColor | #efeff0 | #151e2a |
130 | | detailLineSelectedPosition | #73C9D8E3 | #AD0E1721 |
131 | | infoWindowBackground | #FFFFFFFF | #FF202b38 |
132 | | infoWindowShadowColor | #5C000000 | #5C000000 |
133 | | infoWindowTitleColor | #222222 | #FFFFFF |
134 | | navViewFillColor | #BAF5F8F9 | #BD19232E |
135 | | navBordersColor | #477DA9CA | #477DA9CA |
136 | | navTapCircle | #92D3E3F0 | #8043515c |
137 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/InfoWindowView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Point;
8 | import android.graphics.Rect;
9 | import android.graphics.RectF;
10 | import android.graphics.Typeface;
11 | import android.view.View;
12 |
13 | import com.klim.tcharts.Colors;
14 | import com.klim.tcharts.R;
15 | import com.klim.tcharts.interfaces.OnShowLinesListener;
16 | import com.klim.tcharts.utils.ColorU;
17 | import com.klim.tcharts.utils.PaintU;
18 | import com.klim.tcharts.utils.SearchU;
19 |
20 | import java.text.SimpleDateFormat;
21 | import java.util.ArrayList;
22 | import java.util.Calendar;
23 | import java.util.Date;
24 | import java.util.GregorianCalendar;
25 | import java.util.List;
26 |
27 | public class InfoWindowView extends BaseView implements OnShowLinesListener {
28 | private Colors colors;
29 |
30 | private float infoWindowRoutedCorners;
31 | private float padding;
32 | private float infoWindowShadow;
33 | private float infoWindowTitleSize;
34 | private float infoWindowLabelSize;
35 | private float infoWindowLabelValSize;
36 |
37 | private long time;
38 | private List names;
39 | private List chartLinesColor;
40 | private List values;
41 |
42 | private Paint bBitmap;
43 | private Paint pBackground;
44 | private Paint pTitle;
45 | private Paint pLabel;
46 | private Paint pValue;
47 |
48 | //cache background
49 | private Bitmap bitmapBgCache;
50 | private Canvas canvasBgCache;
51 |
52 | //positions elements in info window
53 | private ArrayList posTitle = new ArrayList<>();
54 | private ArrayList posLabel = new ArrayList<>();
55 | private ArrayList posValues = new ArrayList<>();
56 |
57 | private SimpleDateFormat dayFormat = new SimpleDateFormat("E,");
58 | private SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd");
59 |
60 | public InfoWindowView(View view, Colors colors) {
61 | super(view);
62 | this.colors = colors;
63 |
64 | infoWindowRoutedCorners = getDimen(R.dimen.infoWindowRoutedCorners);
65 | padding = getDimen(R.dimen.infoWindowPadding);
66 | infoWindowShadow = getDimen(R.dimen.infoWindowShadow);
67 | infoWindowTitleSize = getDimen(R.dimen.infoWindowTitleSize);
68 | infoWindowLabelSize = getDimen(R.dimen.infoWindowLabelSize);
69 | infoWindowLabelValSize = getDimen(R.dimen.infoWindowLabelValSize);
70 |
71 | createPaints();
72 | }
73 |
74 | private void createPaints() {
75 | bBitmap = new Paint(Paint.FILTER_BITMAP_FLAG);
76 |
77 | pBackground = PaintU.createPaint(colors.infoWindowBackground, Paint.Style.FILL);
78 | pBackground.setShadowLayer(infoWindowShadow, 0.0f, 0.0f, colors.infoWindowShadowColor);
79 |
80 | pTitle = PaintU.createPaint(colors.infoWindowTitleColor, Paint.Style.FILL);
81 | pTitle.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
82 | pTitle.setTextSize(infoWindowTitleSize);
83 |
84 | pLabel = PaintU.createPaint(Color.WHITE, Paint.Style.FILL);
85 | pLabel.setTextSize(infoWindowLabelSize);
86 |
87 | pValue = PaintU.createPaint(Color.WHITE, Paint.Style.FILL);
88 | pValue.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
89 | pValue.setTextSize(infoWindowLabelValSize);
90 | }
91 |
92 | @Override
93 | public void prepareDataForPrinting(boolean hardPrepare) {
94 |
95 | }
96 |
97 | // @Override
98 | public void drawOn(Canvas canvas, int a) {
99 | super.drawOn(canvas);
100 | //draw background
101 | if (bitmapBgCache == null) {
102 | bitmapBgCache = Bitmap.createBitmap((int) (getWidth() + infoWindowShadow * 2), (int) (getHeight() + infoWindowShadow * 2), Bitmap.Config.ARGB_8888);
103 | canvasBgCache = new Canvas(bitmapBgCache);
104 | canvasBgCache.drawRoundRect(new RectF(infoWindowShadow, infoWindowShadow, getWidth() + infoWindowShadow, getHeight() + infoWindowShadow), infoWindowRoutedCorners, infoWindowRoutedCorners, pBackground);
105 | }
106 |
107 | bBitmap.setColor(ColorU.colorSetA(bBitmap.getColor(), a));
108 | canvas.drawBitmap(bitmapBgCache, posX - infoWindowShadow, posY - infoWindowShadow, bBitmap);
109 |
110 | //draw title (date)
111 | Date date = new Date(time);
112 | pTitle.setColor(ColorU.colorSetA(pTitle.getColor(), a));
113 | canvas.drawText(SearchU.firstCharUpper(dayFormat.format(date)), posTitle.get(0).x + posX, posTitle.get(0).y + posY, pTitle);
114 | canvas.drawText(SearchU.firstCharUpper(dateFormat.format(date)), posTitle.get(1).x + posX, posTitle.get(1).y + posY, pTitle);
115 |
116 | //draw values
117 | for (int i = 0; i < values.size(); i++) {
118 | if (getView().linesForShow[i]) {
119 | pLabel.setColor(ColorU.colorSetA(chartLinesColor.get(i), a));
120 | pValue.setColor(ColorU.colorSetA(chartLinesColor.get(i), a));
121 | canvas.drawText(names.get(i), posLabel.get(i).x + posX, posLabel.get(i).y + posY, pLabel);
122 | canvas.drawText(values.get(i) + "", posValues.get(i).x + posX, posValues.get(i).y + posY, pValue);
123 | }
124 | }
125 | super.drawOn(canvas);
126 | }
127 |
128 | /**
129 | * Calculate width and height for info window
130 | * Calculate positions for info window elements
131 | */
132 | public void calcSizePositions() {
133 | height = 0;
134 | width = 0;
135 | bitmapBgCache = null;
136 |
137 | float widthDayOfWeek = 0;
138 | float widthMonth = 0;
139 |
140 | posTitle.clear();
141 | posLabel.clear();
142 | posValues.clear();
143 |
144 | //position for title
145 | height += padding;
146 | height += infoWindowTitleSize;
147 | posTitle.add(new Point((int) (padding), (int) (height))); //week day
148 |
149 | Rect textBounds = new Rect();
150 | Calendar calendar = new GregorianCalendar();
151 | SimpleDateFormat format = new SimpleDateFormat("E,_", context.getResources().getConfiguration().locale);
152 | String temp = "";
153 | for (int day = Calendar.SUNDAY; day <= Calendar.SATURDAY; day++) {
154 | calendar.set(Calendar.DAY_OF_WEEK, day);
155 | temp = format.format(calendar.getTime());
156 | pTitle.getTextBounds(temp, 0, temp.length(), textBounds);
157 | widthDayOfWeek = Math.max(widthDayOfWeek, textBounds.width());
158 | }
159 |
160 | posTitle.add(new Point((int) (padding + widthDayOfWeek), (int) (height))); //month and number
161 |
162 | format.applyPattern("MMM 29");
163 | for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
164 | calendar.set(Calendar.MONTH, month);
165 | temp = format.format(calendar.getTime());
166 | pTitle.getTextBounds(temp, 0, temp.length(), textBounds);
167 | widthMonth = Math.max(widthMonth, textBounds.width());
168 | }
169 |
170 | width = (int) Math.max(width, widthDayOfWeek + widthMonth + padding * 2);
171 |
172 | height += padding;
173 |
174 | //position for labels and values
175 | for (int i = 0; i < names.size(); i++) {
176 | if (getView().linesForShow[i]) {
177 | height += infoWindowLabelSize;
178 | posLabel.add(new Point((int) (padding), (int) (height))); //label
179 | height += infoWindowLabelValSize;
180 | posValues.add(new Point((int) (padding * 3), (int) (height))); //value
181 | } else {
182 | posLabel.add(new Point(0, 0)); //label
183 | posValues.add(new Point(0, 0)); //value
184 | }
185 | }
186 |
187 | height += padding;
188 | }
189 |
190 | public void setNames(List names) {
191 | this.names = names;
192 | }
193 |
194 | public void setColors(List colors) {
195 | this.chartLinesColor = colors;
196 | }
197 |
198 | public void setValues(long time, ArrayList values) {
199 | this.time = time;
200 | this.values = values;
201 | }
202 |
203 | @Override
204 | public void onShowLines(int lineIndex, boolean show) {
205 | bitmapBgCache = null;
206 | calcSizePositions();
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/app/src/main/java/com/klim/tcharts/example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.example
2 |
3 | import android.app.Activity
4 | import android.content.res.ColorStateList
5 | import android.graphics.Color
6 | import android.os.Bundle
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.view.WindowManager
10 | import android.widget.CheckBox
11 | import android.widget.CompoundButton
12 | import android.widget.LinearLayout
13 | import android.widget.Toast
14 | import com.klim.tcharts.TChart
15 | import com.klim.tcharts.entities.ChartData
16 | import com.klim.tcharts.entities.ChartItem
17 | import kotlinx.coroutines.Dispatchers
18 | import kotlinx.coroutines.GlobalScope
19 | import kotlinx.coroutines.launch
20 | import kotlinx.coroutines.withContext
21 | import org.json.JSONArray
22 | import java.io.IOException
23 | import java.util.*
24 | import kotlin.collections.ArrayList
25 |
26 | class MainActivity : Activity(), View.OnClickListener {
27 |
28 | private var mNightMode: NightMode? = null
29 |
30 | private lateinit var statusBarBack: View
31 | private lateinit var menuIconNightMode: View
32 | private lateinit var lloContent: LinearLayout
33 |
34 | override fun onCreate(savedInstanceState: Bundle?) {
35 | super.onCreate(savedInstanceState)
36 | mNightMode = NightMode(this, R.style.AppTheme)
37 | window.setFlags(
38 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
39 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
40 | )
41 |
42 | setContentView(R.layout.activity_main)
43 |
44 | statusBarBack = findViewById(R.id.statusBarBack)
45 | menuIconNightMode = findViewById(R.id.mIconNightMode)
46 | lloContent = findViewById(R.id.lloContent)
47 |
48 | statusBarBack.layoutParams = LinearLayout.LayoutParams(
49 | ViewGroup.LayoutParams.MATCH_PARENT,
50 | U.getStatusBarHeight(this, resources.getDimension(R.dimen.statusBarHeight).toInt())
51 | )
52 |
53 | menuIconNightMode.setOnClickListener(this)
54 |
55 | GlobalScope.launch(Dispatchers.Main) {
56 | val json = withContext(Dispatchers.IO) {
57 | loadJSONFromAsset()
58 | }
59 | json?.let {
60 | val charts = withContext(Dispatchers.Default) {
61 | convertJsonToChartData(it)
62 | }
63 |
64 | val chart = this@MainActivity.findViewById(R.id.tchart)
65 | chart.setData(charts[0])
66 |
67 | addChartsIntoActivity(charts)
68 | } ?: run {
69 | withContext(Dispatchers.Main) {
70 | Toast.makeText(
71 | this@MainActivity,
72 | R.string.error_loading_example,
73 | Toast.LENGTH_SHORT
74 | ).show()
75 | }
76 | }
77 | }
78 | }
79 |
80 | private fun addChartsIntoActivity(charts: ArrayList) {
81 | var i = 0
82 | charts.forEach { chartData ->
83 | val layout = LinearLayout(this)
84 | val linearLayoutParams = LinearLayout.LayoutParams(
85 | ViewGroup.LayoutParams.MATCH_PARENT,
86 | ViewGroup.LayoutParams.WRAP_CONTENT
87 | )
88 | linearLayoutParams.topMargin = resources.getDimension(R.dimen.chartBottomMargin).toInt()
89 | linearLayoutParams.bottomMargin =
90 | resources.getDimension(R.dimen.chartBottomMargin).toInt()
91 | layout.layoutParams = linearLayoutParams
92 | layout.orientation = LinearLayout.VERTICAL
93 | lloContent.addView(layout)
94 |
95 | val tChart = TChart(this)
96 | val layoutParams = LinearLayout.LayoutParams(
97 | ViewGroup.LayoutParams.MATCH_PARENT,
98 | ViewGroup.LayoutParams.WRAP_CONTENT
99 | )
100 |
101 | tChart.layoutParams = layoutParams
102 | tChart.id = View.generateViewId()
103 | tChart.setData(chartData)
104 | tChart.setPadding(
105 | resources.getDimension(R.dimen.cbHorizontalMargin).toInt(),
106 | resources.getDimension(R.dimen.cbHorizontalMargin).toInt(),
107 | resources.getDimension(R.dimen.cbHorizontalMargin).toInt(),
108 | resources.getDimension(R.dimen.cbHorizontalMargin).toInt()
109 | )
110 | tChart.setTitle(String.format("Chart #%d", i))
111 | layout.addView(tChart)
112 |
113 | for (i in 0 until chartData.keys.size) {
114 | val checkBox = CheckBox(this)
115 | checkBox.tag = chartData.keys[i]
116 | checkBox.text = chartData.names[i]
117 | checkBox.isChecked = true
118 | checkBox.setTextColor(this@MainActivity.resources.getColor(R.color.textColor))
119 | checkBox.setOnCheckedChangeListener { buttonView, isChecked ->
120 | tChart.showLine(buttonView.tag.toString(), isChecked)
121 | }
122 |
123 | val states = arrayOf(
124 | intArrayOf(android.R.attr.state_checked),
125 | intArrayOf(-android.R.attr.state_checked)
126 | )
127 | val colors = intArrayOf(chartData.colors[i], chartData.colors[i])
128 |
129 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
130 | checkBox.buttonTintList = ColorStateList(states, colors)
131 | }
132 | val layoutParams = LinearLayout.LayoutParams(
133 | ViewGroup.LayoutParams.WRAP_CONTENT,
134 | ViewGroup.LayoutParams.WRAP_CONTENT
135 | )
136 | layoutParams.leftMargin = resources.getDimension(R.dimen.cbHorizontalMargin).toInt()
137 | layoutParams.rightMargin =
138 | resources.getDimension(R.dimen.cbHorizontalMargin).toInt()
139 | checkBox.layoutParams = layoutParams
140 | layout.addView(checkBox)
141 | }
142 |
143 | i++
144 | }
145 | }
146 |
147 | override fun onClick(v: View) {
148 | when (v.id) {
149 | R.id.mIconNightMode -> mNightMode!!.toggle()
150 | }
151 | }
152 |
153 | private fun loadJSONFromAsset(): String? {
154 | try {
155 | // val inputStream = assets.open("all_chart_data.json")
156 | val inputStream = assets.open("chart_data.json")
157 | val size = inputStream.available()
158 | val buffer = ByteArray(size)
159 | inputStream.read(buffer)
160 | inputStream.close()
161 | return String(buffer)//, "UTF-8"
162 | } catch (ex: IOException) {
163 | ex.printStackTrace()
164 | return null
165 | }
166 | }
167 |
168 | private fun convertJsonToChartData(json: String): ArrayList {
169 | val charts = ArrayList()
170 | try {
171 | val jsArray = JSONArray(json)
172 | for (i in 0 until jsArray.length()) {
173 | val jsChart = jsArray.getJSONObject(i)
174 | val jsTypes = jsChart.getJSONObject("types");
175 | val jsNames = jsChart.getJSONObject("names")
176 | val jsColors = jsChart.getJSONObject("colors")
177 | val jsColumns = jsChart.getJSONObject("columns")
178 |
179 | val keys = ArrayList(jsNames.length())
180 | val names = ArrayList(jsNames.length())
181 | val colors = ArrayList(jsColors.length())
182 | val rows = ArrayList(jsColumns.length())
183 | var xRow = JSONArray()
184 |
185 | //find x line and other lines
186 | // var xName: String = ""
187 | val iteratorTypes = jsTypes.keys()
188 | while (iteratorTypes.hasNext()) {
189 | val key = iteratorTypes.next()
190 | if (jsTypes.getString(key) == "x") {
191 | xRow = jsColumns.getJSONArray(key)
192 | } else {
193 | keys.add(key)
194 | //names
195 | names.add(jsNames.getString(key))
196 | //colors
197 | colors.add(Color.parseColor(jsColors.getString(key)))
198 | //columns
199 | rows.add(jsColumns.getJSONArray(key))
200 | }
201 | }
202 |
203 | val chartItems: ArrayList = ArrayList()
204 |
205 | for (x in 0 until xRow.length()) {
206 | val valuesForOneX = ArrayList(keys.size)
207 | for (row in rows) {
208 | valuesForOneX.add(row.getInt(x))
209 | }
210 | chartItems.add(ChartItem(xRow.getLong(x), valuesForOneX))
211 | }
212 |
213 | charts.add(ChartData(keys, names, colors, chartItems))
214 | }
215 | } catch (e: Exception) {
216 | e.printStackTrace()
217 | }
218 | return charts
219 | }
220 | }
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/NavigationView.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.ValueAnimator;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 |
12 | import com.klim.tcharts.Colors;
13 | import com.klim.tcharts.R;
14 | import com.klim.tcharts.entities.ChartData;
15 | import com.klim.tcharts.entities.ChartItem;
16 | import com.klim.tcharts.interfaces.OnSelectedTimeLineChanged;
17 | import com.klim.tcharts.interfaces.OnShowLinesListener;
18 | import com.klim.tcharts.utils.AnimatorU;
19 | import com.klim.tcharts.utils.PaintU;
20 |
21 | import java.util.ArrayList;
22 |
23 | public class NavigationView extends BaseView implements OnShowLinesListener {
24 | private SelectedWindow selectedWindow;
25 |
26 | private ChartData data = null;
27 | private int maxValue;
28 | private long minTime;
29 | private long maxTime;
30 | private long startShowMinTime;
31 | private long startShowMaxTime;
32 | private float pixelInTime;
33 | private float pixelInValue;
34 |
35 | private ArrayList prepareLines;
36 | private boolean needRePrepare = true;
37 |
38 | private float maxValueLocal;
39 | private boolean enableShowLine = false;
40 |
41 | private ValueAnimator animatorsMaxValue;
42 |
43 | private int lineIndex = -1; // for pain last hide line
44 |
45 | //params
46 | private float paddingDataGraph;
47 | public Colors colors;
48 |
49 | //paints
50 | private Paint pForLine;
51 | private Paint pForHideLine;
52 |
53 | public NavigationView(View view, Colors colors) {
54 | super(view);
55 | this.colors = colors;
56 | selectedWindow = new SelectedWindow(this.view, colors);
57 |
58 | //params
59 | paddingDataGraph = getDimen(R.dimen.chartNavLineTopBottomPadding);
60 |
61 | createAnimators();
62 | }
63 |
64 | public void init() {
65 | createPaints();
66 | }
67 |
68 | private void createPaints() {
69 | //paints
70 | pForLine = PaintU.createPaint(Color.WHITE, Paint.Style.STROKE, getDimen(R.dimen.chartNavLineWeight));
71 | pForLine.setStrokeCap(Paint.Cap.ROUND);
72 |
73 | pForHideLine = PaintU.createPaint(colors.backgroundColor, Paint.Style.STROKE, getDimen(R.dimen.chartNavLineWeight));
74 | pForHideLine.setStrokeCap(Paint.Cap.ROUND);
75 | }
76 |
77 | private void createAnimators() {
78 | animatorsMaxValue = AnimatorU.createFloatValueAnimator(maxValueLocal, maxValue, 200, animation -> {
79 | maxValueLocal = (Float) animation.getAnimatedValue();
80 | // valueInPixel = availableHeight / maxValueLocal;
81 | pixelInValue = (height - paddingDataGraph * 2) / maxValueLocal;
82 | prepareDataForPrinting(true);
83 | invalidate();
84 | });
85 | animatorsMaxValue.addListener(new AnimatorListenerAdapter() {
86 | @Override
87 | public void onAnimationEnd(Animator animation) {
88 | super.onAnimationEnd(animation);
89 | enableShowLine = true;
90 | prepareDataForPrinting(true);
91 | invalidate();
92 | }
93 | });
94 | }
95 |
96 | private void calculateTimeValueInPixel() {
97 | if (data != null) {
98 | minTime = data.getItems().get(0).getTime();
99 | maxTime = data.getItems().get(data.getItems().size() - 1).getTime();
100 | pixelInTime = width / (float) (maxTime - minTime);
101 | if (maxValue > 0) {
102 | pixelInValue = (height - paddingDataGraph * 2) / maxValue;
103 | }
104 | selectedWindow.setTimeInPixel(pixelInTime, minTime, maxTime);
105 | }
106 | }
107 |
108 | public int calculateHeight() {
109 | return Math.round(getDimen(R.dimen.navViewDesiredHeight));
110 | }
111 |
112 | @Override
113 | public void onSizeChanged() {
114 | if (width != 0 && height != 0 && data != null) {
115 | calculateTimeValueInPixel();
116 | prepareDataForPrinting(false);
117 | }
118 | selectedWindow.onSizeChanged();
119 | }
120 |
121 | @Override
122 | public void prepareDataForPrinting(boolean hardPrepare) {
123 | if (needRePrepare || hardPrepare) {
124 | prepareLines = new ArrayList<>(data.getItems().get(0).getValues().size());
125 | float[] arrLines;
126 | for (int l = 0; l < data.getItems().get(0).getValues().size(); l++) {
127 | if (getView().linesForShow[l] && (lineIndex != l || (enableShowLine && lineIndex == l))) {
128 | float lastx = 0;
129 | float lasty = 0;
130 | float curx = 0;
131 | float cury = 0;
132 |
133 | boolean firstPoint = true;
134 | arrLines = new float[(data.getItems().size()) * 4];
135 | ChartItem chartItem;
136 | for (int i = 0; i < data.getItems().size(); i++) {
137 | chartItem = data.getItems().get(i);
138 |
139 | curx = posX + (chartItem.getTime() - minTime) * pixelInTime;
140 | cury = posY + (height) - (pixelInValue * chartItem.getValues().get(l) + paddingDataGraph);
141 | System.out.println(posY);
142 |
143 | if (firstPoint) {
144 | firstPoint = false;
145 | } else {
146 | arrLines[i * 4] = lastx;
147 | arrLines[i * 4 + 1] = lasty;
148 | arrLines[i * 4 + 2] = curx;
149 | arrLines[i * 4 + 3] = cury;
150 | }
151 | lastx = curx;
152 | lasty = cury;
153 | }
154 | } else {
155 | arrLines = null;
156 | }
157 | prepareLines.add(arrLines);
158 | }
159 | needRePrepare = false;
160 | }
161 | }
162 |
163 | @Override
164 | public void drawOn(Canvas canvas) {
165 | for (int l = 0; l < getView().linesForShow.length; l++) {
166 | if (getView().linesForShow[l] && (lineIndex != l || (enableShowLine && lineIndex == l))) {
167 | //todo seted color every time?
168 | pForLine.setColor(data.getColors().get(l));
169 | canvas.drawLines(prepareLines.get(l), pForLine);
170 | }
171 | }
172 |
173 | //clear left right overpaint
174 | canvas.drawLine(posX + paddingX - getDimen(R.dimen.chartNavLineWeight) / 2, posY, posX + paddingX - getDimen(R.dimen.chartNavLineWeight) / 2, posY + height, pForHideLine);
175 | canvas.drawLine(posX + paddingX + width + getDimen(R.dimen.chartNavLineWeight) / 2, posY, posX + paddingX + getDimen(R.dimen.chartNavLineWeight) / 2 + width, posY + height, pForHideLine);
176 |
177 | //draw window
178 | selectedWindow.drawOn(canvas);
179 |
180 | super.drawOn(canvas);
181 | }
182 |
183 | public boolean onTouchEvent(MotionEvent event) {
184 | switch (event.getAction()) {
185 | case MotionEvent.ACTION_DOWN: {
186 | iAmPressed = true;
187 | break;
188 | }
189 | case MotionEvent.ACTION_MOVE: {
190 | break;
191 | }
192 | case MotionEvent.ACTION_UP:
193 | case MotionEvent.ACTION_CANCEL: {
194 | iAmPressed = false;
195 | break;
196 | }
197 | }
198 | return selectedWindow.onTouchEvent(event);
199 | }
200 |
201 | public void setData(ChartData data, long start, long end) {
202 | setStartPeriodTimes(start, end);
203 | this.data = data;
204 | updateMaxValue();
205 | maxValueLocal = maxValue;
206 | if (width != 0 && height != 0 && data != null) {
207 | calculateTimeValueInPixel();
208 | prepareDataForPrinting(false);
209 | }
210 | selectedWindow.onSizeChanged();
211 | }
212 |
213 | public void setPosX(float posX) {
214 | this.posX = posX;
215 | selectedWindow.setPosX(posX);
216 | }
217 |
218 | public void setPosY(float posY) {
219 | this.posY = posY;
220 | selectedWindow.setPosY(posY);
221 | }
222 |
223 | public void setStartPeriodTimes(long start, long end) {
224 | this.startShowMinTime = start;
225 | this.startShowMaxTime = end;
226 | selectedWindow.setStartPeriodTimes(start, end);
227 | }
228 |
229 | @Override
230 | public void setWidth(int width) {
231 | super.setWidth(width);
232 | selectedWindow.setWidth(width);
233 | }
234 |
235 | @Override
236 | public void setHeight(int height) {
237 | super.setHeight(height);
238 | selectedWindow.setHeight(height);
239 | }
240 |
241 | public void addOnSelectedTimeLineChanged(OnSelectedTimeLineChanged onSelectedTimeLineChanged) {
242 | selectedWindow.addOnSelectedTimeLineChanged(onSelectedTimeLineChanged);
243 | }
244 |
245 | private void updateMaxValue() {
246 | maxValue = 0;
247 | for (int i = 0; i < data.getMaxValueInLine().size(); i++) {
248 | if (getView().linesForShow[i] && maxValue < data.getMaxValueInLine().get(i)) {
249 | maxValue = data.getMaxValueInLine().get(i);
250 | }
251 | }
252 | }
253 |
254 | @Override
255 | public void onShowLines(int lineIndex, boolean show) {
256 | this.lineIndex = lineIndex;
257 | needRePrepare = true;
258 | updateMaxValue();
259 | calculateTimeValueInPixel();
260 |
261 | if (show) {
262 | enableShowLine = false;
263 | }
264 | animatorsMaxValue.setFloatValues(maxValueLocal, maxValue);
265 | animatorsMaxValue.start();
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/views/SelectedWindow.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts.views;
2 |
3 | import android.animation.ValueAnimator;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Point;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 |
10 | import com.klim.tcharts.Colors;
11 | import com.klim.tcharts.R;
12 | import com.klim.tcharts.enums.BorderType;
13 |
14 | import com.klim.tcharts.interfaces.OnSelectedTimeLineChanged;
15 | import com.klim.tcharts.utils.AnimatorU;
16 | import com.klim.tcharts.utils.PaintU;
17 |
18 | import java.util.ArrayList;
19 |
20 | public class SelectedWindow extends BaseView {
21 |
22 | private Paint pForGray;
23 | private Paint pen;
24 | private Paint pTapCircle;
25 |
26 | private Point tapPosition;
27 |
28 | private BorderView borderViewLeft;
29 | private BorderView borderViewRight;
30 |
31 | private ArrayList onSelectedTimeLineChanged = new ArrayList<>();
32 |
33 | private boolean selected = false;
34 |
35 | private ValueAnimator animCirclRadius;
36 | private float maxCircRadius;
37 | private float curCircRadius;
38 |
39 | private long startShowMinTime;
40 | private long startShowMaxTime;
41 |
42 | private float timeInPixel;
43 | private long minTime;
44 | private long maxTime;
45 |
46 | public SelectedWindow(View view, Colors colors) {
47 | super(view);
48 |
49 | pForGray = PaintU.createPaint(colors.navFillColor, Paint.Style.FILL);
50 | pen = PaintU.createPaint(colors.navBordersColor, Paint.Style.FILL);
51 | pTapCircle = PaintU.createPaint(colors.navTapCircleColor, Paint.Style.FILL);
52 |
53 | borderViewLeft = new BorderView(view, BorderType.LEFT, 400, posY, Math.round(getDimen(R.dimen.chartNavBorderWidth)), getHeight(), pen);
54 | borderViewRight = new BorderView(view, BorderType.RIGHT, posX + width, posY, Math.round(getDimen(R.dimen.chartNavBorderWidth)), getHeight(), pen);
55 |
56 | maxCircRadius = getHeight() * 0.8f;
57 |
58 | createAnimators();
59 | }
60 |
61 | private void createAnimators() {
62 | animCirclRadius = AnimatorU.createFloatValueAnimator(0, maxCircRadius, 200, new ValueAnimator.AnimatorUpdateListener() {
63 | @Override
64 | public void onAnimationUpdate(ValueAnimator animation) {
65 | curCircRadius = (Float) animation.getAnimatedValue();
66 | invalidate();
67 | }
68 | });
69 | }
70 |
71 | @Override
72 | public void prepareDataForPrinting(boolean hardPrepare) {
73 |
74 | }
75 |
76 | @Override
77 | public void drawOn(Canvas canvas) {
78 | //left gray part
79 | canvas.drawRect(posX, posY, borderViewLeft.getPosX(), posY + height, pForGray);
80 |
81 | //borders
82 | borderViewLeft.drawOn(canvas);
83 | borderViewRight.drawOn(canvas);
84 | //line between
85 | canvas.drawRect(borderViewLeft.getPosX() + borderViewLeft.getWidth(), posY, borderViewRight.getPosX(), posY + getDimen(R.dimen.chartNavBorderTopHeight), pen);
86 | canvas.drawRect(borderViewLeft.getPosX() + borderViewLeft.getWidth(), posY + height - getDimen(R.dimen.chartNavBorderTopHeight), borderViewRight.getPosX(), posY + height, pen);
87 |
88 | //right gray part
89 | canvas.drawRect(borderViewRight.getPosX() + borderViewRight.getWidth(), posY, posX + width, posY + height, pForGray);
90 |
91 | //tap circle
92 | if (tapPosition != null) {
93 | canvas.drawCircle(tapPosition.x, tapPosition.y, curCircRadius, pTapCircle);
94 | }
95 |
96 | super.drawOn(canvas);
97 | }
98 |
99 | @Override
100 | public boolean onTouchEvent(MotionEvent event) {
101 | float tapX = event.getX();
102 |
103 | switch (event.getAction()) {
104 | case MotionEvent.ACTION_DOWN: {
105 | actionDown(tapX);
106 | return true;
107 | }
108 | case MotionEvent.ACTION_MOVE: {
109 | if (Math.abs(tapX) >= 1) {
110 | actionMove(tapX);
111 | }
112 | return true;
113 | }
114 | case MotionEvent.ACTION_UP:
115 | case MotionEvent.ACTION_CANCEL: {
116 | actionUp();
117 | return true;
118 | }
119 | default:
120 | return false;
121 | }
122 | }
123 |
124 | private void actionDown(float tapX) {
125 | if (borderViewLeft.isItMe(tapX)) { //left border
126 | borderViewLeft.setSelected(true);
127 | borderViewLeft.setShiftPositinTap(tapX - borderViewLeft.getPosX());
128 | } else if (borderViewLeft.getPosX() + borderViewLeft.getWidth() < tapX && tapX < borderViewRight.getPosX()) { //center
129 | selected = true;
130 | borderViewLeft.setShiftPositinTap(tapX - borderViewLeft.getPosX());
131 | borderViewRight.setShiftPositinTap(tapX - borderViewRight.getPosX());
132 | } else if (borderViewRight.isItMe(tapX)) { //right border
133 | borderViewRight.setSelected(true);
134 | borderViewRight.setShiftPositinTap(tapX - borderViewRight.getPosX());
135 | }
136 |
137 | if (borderViewLeft.isSelected() || selected || borderViewRight.isSelected()) {
138 | tapPosition = new Point((int) tapX, (int) (posY + height / 2));
139 | if (animCirclRadius.isRunning()) {
140 | animCirclRadius.cancel();
141 | }
142 | animCirclRadius.setFloatValues(curCircRadius, maxCircRadius);
143 | animCirclRadius.start();
144 | }
145 | }
146 |
147 | private void actionMove(float tapX) {
148 | if (borderViewLeft.isSelected()) {
149 | float newPosL = tapX - borderViewLeft.getShiftPositinTap();
150 | if (newPosL < posX) {
151 | newPosL = posX;
152 | } else if (newPosL + borderViewLeft.getWidth() > borderViewRight.getPosX()) {
153 | newPosL = borderViewRight.getPosX() - borderViewLeft.getWidth();
154 | }
155 | borderViewLeft.setPosX(newPosL);
156 | } else if (selected) {
157 | float newPosL = tapX - borderViewLeft.getShiftPositinTap();
158 | float newPosR = tapX - borderViewRight.getShiftPositinTap();
159 | float distance = borderViewRight.getPosX() - borderViewLeft.getPosX();
160 | if (newPosL < posX) {
161 | newPosL = posX;
162 | newPosR = newPosL + distance;
163 | } else if (newPosR + borderViewRight.getWidth() > posX + width) {
164 | newPosR = posX + width - borderViewLeft.getWidth();
165 | newPosL = newPosR - distance;
166 | }
167 | borderViewLeft.setPosX(newPosL);
168 | borderViewRight.setPosX(newPosR);
169 | } else if (borderViewRight.isSelected()) {
170 | float newPosR = tapX - borderViewRight.getShiftPositinTap();
171 | if (newPosR < borderViewLeft.getPosX() + borderViewLeft.getWidth()) {
172 | newPosR = borderViewLeft.getPosX() + borderViewLeft.getWidth();
173 | } else if (newPosR + borderViewRight.getWidth() > posX + width) {
174 | newPosR = posX + width - borderViewLeft.getWidth();
175 | }
176 | borderViewRight.setPosX(newPosR);
177 | }
178 |
179 | if (borderViewLeft.isSelected() || selected || borderViewRight.isSelected()) {
180 | tapPosition.x = (int) tapX;
181 | }
182 |
183 | sendTimeLineChanged();
184 | }
185 |
186 | private void sendTimeLineChanged() {
187 | onSelectedTimeLineChanged = onSelectedTimeLineChanged;
188 | if (onSelectedTimeLineChanged != null) {
189 | for (OnSelectedTimeLineChanged onSelectedTimeLineChanged : onSelectedTimeLineChanged)
190 | onSelectedTimeLineChanged.onTimeLineChanged(
191 | Math.max((long) ((borderViewLeft.getPosX() - posX) / timeInPixel) + minTime, minTime),
192 | Math.min((long) ((borderViewRight.getPosX() + borderViewRight.getWidth() - posX) / timeInPixel) + minTime, maxTime),
193 | !selected);
194 | }
195 | }
196 |
197 | private void actionUp() {
198 | borderViewLeft.setSelected(false);
199 | selected = false;
200 | borderViewRight.setSelected(false);
201 |
202 | if (animCirclRadius.isRunning()) {
203 | animCirclRadius.cancel();
204 | }
205 | animCirclRadius.setFloatValues(curCircRadius, 0);
206 | animCirclRadius.start();
207 | }
208 |
209 | public void setStartPeriodTimes(long start, long end) {
210 | startShowMinTime = start;
211 | startShowMaxTime = end;
212 | }
213 |
214 | @Override
215 | public void setPosY(float posY) {
216 | super.setPosY(posY);
217 | borderViewLeft.setPosY(posY);
218 | borderViewRight.setPosY(posY);
219 | }
220 |
221 | @Override
222 | public void setHeight(int height) {
223 | super.setHeight(height);
224 | borderViewLeft.setHeight(height);
225 | borderViewRight.setHeight(height);
226 | }
227 |
228 | @Override
229 | public void setWidth(int width) {
230 | super.setWidth(width);
231 | }
232 |
233 | @Override
234 | public void onSizeChanged() {
235 | if (width != 0 && height != 0 && startShowMinTime != 0 && startShowMaxTime != 0 && minTime != 0 && maxTime != 0) {
236 | moveBordersToStart();
237 | }
238 | }
239 |
240 | private void moveBordersToStart() {
241 | borderViewLeft.setPosX((startShowMinTime - minTime) * timeInPixel + posX);
242 | if (startShowMaxTime == maxTime) {
243 | borderViewRight.setPosX(posX + width - borderViewRight.getWidth());
244 | } else {
245 | borderViewRight.setPosX((startShowMaxTime - minTime) * timeInPixel - borderViewRight.getWidth() + posX);
246 | }
247 | sendTimeLineChanged();
248 | }
249 |
250 | public void addOnSelectedTimeLineChanged(OnSelectedTimeLineChanged onSelectedTimeLineChanged) {
251 | this.onSelectedTimeLineChanged.add(onSelectedTimeLineChanged);
252 | }
253 |
254 | public void setTimeInPixel(float timeInPixel, long minTime, long maxTime) {
255 | this.timeInPixel = timeInPixel;
256 | this.minTime = minTime;
257 | this.maxTime = maxTime;
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/TCharts/src/main/java/com/klim/tcharts/TChart.java:
--------------------------------------------------------------------------------
1 | package com.klim.tcharts;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Color;
7 | import android.graphics.LinearGradient;
8 | import android.graphics.Paint;
9 | import android.graphics.RectF;
10 | import android.graphics.Shader;
11 | import android.os.Bundle;
12 | import android.os.Parcelable;
13 | import android.util.AttributeSet;
14 | import android.view.MotionEvent;
15 | import android.view.View;
16 |
17 | import androidx.core.content.ContextCompat;
18 |
19 | import com.klim.tcharts.entities.ChartData;
20 | import com.klim.tcharts.entities.ChartItem;
21 | import com.klim.tcharts.interfaces.OnSelectedTimeLineChanged;
22 | import com.klim.tcharts.utils.PaintU;
23 | import com.klim.tcharts.views.DetailView;
24 | import com.klim.tcharts.views.NavigationView;
25 | import com.klim.tcharts.views.TitleView;
26 |
27 | import java.util.ArrayList;
28 | import java.util.Random;
29 |
30 | public class TChart extends View implements OnSelectedTimeLineChanged {
31 | private int width = 0;
32 | private int height = 0;
33 |
34 | private int titlePaddingTop = 0;
35 | private int titlePaddingBottom = 0;
36 |
37 | private int divisionCount = 0;
38 |
39 | private int detailHeight = 0;
40 | private int navHeight = 0;
41 |
42 | private TitleView titleView;
43 | private DetailView detailView;
44 | private NavigationView navigationView;
45 |
46 | public boolean[] linesForShow;
47 |
48 | //parametrs
49 | private boolean debug = false; //todo get from settings
50 | private String title = "";
51 | private int titleFontSize = 0;
52 | private boolean showTitle = false;
53 | private Colors colors = new Colors();
54 |
55 | private ChartData data = null;
56 | private long selectedStartTime = 0;
57 | private long selectedEndTime = 0;
58 |
59 | //paints
60 | private Paint pFill;
61 | private Paint paintForTopShadow;
62 |
63 | private RectF topShadowSize;
64 | private Shader shader;
65 |
66 | public TChart(Context context) {
67 | super(context);
68 | init(null);
69 | }
70 |
71 | public TChart(Context context, AttributeSet attrs) {
72 | super(context, attrs);
73 | init(attrs);
74 | }
75 |
76 | public TChart(Context context, AttributeSet attrs, int defStyleAttr) {
77 | super(context, attrs, defStyleAttr);
78 | init(attrs);
79 | }
80 |
81 | private void init(AttributeSet attrs) {
82 | setLayerType(View.LAYER_TYPE_HARDWARE, null);
83 |
84 | int[] attributes = new int[]{android.R.attr.paddingLeft, android.R.attr.paddingTop, android.R.attr.paddingRight, android.R.attr.paddingBottom};
85 | TypedArray arr = getContext().obtainStyledAttributes(attrs, attributes);
86 | int leftPadding = 0;
87 | int topPadding = 0;
88 | int rightPadding = 0;
89 | int bottomPadding = 0;
90 | try {
91 | leftPadding = arr.getDimensionPixelOffset(0, Math.round(getResources().getDimension(R.dimen.paddingDefault)));
92 | topPadding = arr.getDimensionPixelOffset(1, Math.round(getResources().getDimension(R.dimen.paddingDefault)));
93 | rightPadding = arr.getDimensionPixelOffset(2, Math.round(getResources().getDimension(R.dimen.paddingDefault)));
94 | bottomPadding = arr.getDimensionPixelOffset(3, Math.round(getResources().getDimension(R.dimen.paddingDefault)));
95 | } finally {
96 | arr.recycle();
97 | }
98 | setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
99 |
100 | TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.TChart, 0, 0);
101 | try {
102 | colors.backgroundColor = a.getColor(R.styleable.TChart_backgroundColor, ContextCompat.getColor(getContext(), R.color.chartBackground));
103 |
104 | title = a.getString(R.styleable.TChart_title);
105 | titleFontSize = a.getDimensionPixelSize(R.styleable.TChart_titleFontSize, Math.round(getResources().getDimension(R.dimen.titleFontSize)));
106 | showTitle = a.getBoolean(R.styleable.TChart_showTitle, showTitle);
107 | colors.titleFontColor = a.getColor(R.styleable.TChart_titleFontColor, ContextCompat.getColor(getContext(), R.color.titleFont));
108 |
109 | colors.detailLabelsFontColor = a.getColor(R.styleable.TChart_detailLabelsFontColor, ContextCompat.getColor(getContext(), R.color.detailLabelsFont));
110 | colors.detailDivisionColor = a.getColor(R.styleable.TChart_detailDivisionColor, ContextCompat.getColor(getContext(), R.color.detailDivision));
111 | colors.detailLineSelectedPosition = a.getColor(R.styleable.TChart_detailLineSelectedPosition, ContextCompat.getColor(getContext(), R.color.lineSelectedPosition));
112 |
113 | colors.infoWindowBackground = a.getColor(R.styleable.TChart_infoWindowBackground, ContextCompat.getColor(getContext(), R.color.infoWindowBackground));
114 | colors.infoWindowShadowColor = a.getColor(R.styleable.TChart_infoWindowShadowColor, ContextCompat.getColor(getContext(), R.color.infoWindowShadow));
115 | colors.infoWindowTitleColor = a.getColor(R.styleable.TChart_infoWindowTitleColor, ContextCompat.getColor(getContext(), R.color.infoWindowTitle));
116 |
117 | colors.navFillColor = a.getColor(R.styleable.TChart_navViewFillColor, ContextCompat.getColor(getContext(), R.color.navFill));
118 | colors.navBordersColor = a.getColor(R.styleable.TChart_navBordersColor, ContextCompat.getColor(getContext(), R.color.navBorders));
119 | colors.navTapCircleColor = a.getColor(R.styleable.TChart_navTapCircleColor, ContextCompat.getColor(getContext(), R.color.navTapCircle));
120 | } finally {
121 | a.recycle();
122 | }
123 |
124 | titlePaddingTop = Math.round(getResources().getDimension(R.dimen.titlePaddingTop));
125 | titlePaddingBottom = Math.round(getResources().getDimension(R.dimen.titlePaddingBottom));
126 |
127 | detailHeight = Math.round(getResources().getDimension(R.dimen.detailViewDesiredHeight));
128 | navHeight = Math.round(getResources().getDimension(R.dimen.navViewDesiredHeight));
129 |
130 | //init sub views
131 | titleView = new TitleView(this, colors);
132 | titleView.title = title;
133 | titleView.setPaddingTop(titlePaddingTop);
134 | titleView.setPaddingBottom(titlePaddingBottom);
135 | titleView.titleFontSize = titleFontSize;
136 | titleView.showTitle = showTitle;
137 | titleView.init();
138 |
139 | navigationView = new NavigationView(this, colors);
140 | navigationView.init();
141 |
142 | detailView = new DetailView(this, colors, divisionCount);
143 | detailView.setPaddingLeft(getPaddingLeft());
144 | detailView.setPaddingRight(getPaddingRight());
145 | detailView.init();
146 |
147 | initPaints();
148 |
149 | divisionCount = 6; //todo get from params
150 |
151 | navigationView.addOnSelectedTimeLineChanged(detailView);
152 | navigationView.addOnSelectedTimeLineChanged(this);
153 |
154 | setPlaceholder();
155 | }
156 |
157 | private void setPlaceholder() {
158 | if (isInEditMode()) {
159 | ArrayList keys = new ArrayList(); //keys for each chart
160 | ArrayList names = new ArrayList(); //names for chart
161 | ArrayList colors = new ArrayList(); //colors for lines
162 | ArrayList items = new ArrayList(); //charts value for some time
163 | //ChartItem
164 | // time - time point (on x line)
165 | // values - list values for this moment of time in order from keys
166 |
167 | keys.add("y0");
168 | keys.add("y1");
169 | names.add("Red Line");
170 | names.add("Green Line");
171 | colors.add(Color.parseColor("#EA4335"));
172 | colors.add(Color.parseColor("#34A853"));
173 |
174 | long startTime = 1614542230000L;
175 | Random random = new Random();
176 | for (int i = 0; i < 100; i++) {
177 | //time moment
178 | startTime += 86_400_000;
179 |
180 | //all values for this time moment
181 | ArrayList values = new ArrayList();
182 | for (int j = 0; j < keys.size(); j++) {
183 | values.add(random.nextInt(100) + (i > 90 ? 100 : 0));
184 | }
185 |
186 | ChartItem chartItem = new ChartItem(startTime, values);
187 | items.add(chartItem);
188 | }
189 | setData(new ChartData(keys, names, colors, items));
190 | }
191 | }
192 |
193 | public void showLine(String lineKey, boolean show) {
194 | int position = 0;
195 | for (int i = 0; i < data.getKeys().size(); i++) {
196 | if (data.getKeys().get(i).equals(lineKey)) {
197 | position = i;
198 | break;
199 | }
200 | }
201 | linesForShow[position] = show;
202 | data.updateLinesForShow(linesForShow);
203 | navigationView.onShowLines(position, show);
204 | detailView.onShowLines(position, show);
205 | }
206 |
207 | private void initPaints() {
208 | pFill = PaintU.createPaint(colors.backgroundColor, Paint.Style.FILL);
209 | paintForTopShadow = new Paint();
210 | }
211 |
212 | @Override
213 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
214 | int desiredWidth = getLayoutParams().width;
215 | int widthMode = MeasureSpec.getMode(widthMeasureSpec);
216 | int widthSize = MeasureSpec.getSize(widthMeasureSpec);
217 |
218 | //Measure Width
219 | if (widthMode == MeasureSpec.EXACTLY) {
220 | //Must be this size
221 | width = widthSize;
222 | } else if (widthMode == MeasureSpec.AT_MOST) {
223 | //Can't be bigger than...
224 | width = Math.min(desiredWidth, widthSize);
225 | } else {
226 | //Be whatever you want
227 | width = desiredWidth;
228 | }
229 |
230 | titleView.setWidth(width - getPaddingLeft() - getPaddingRight());
231 | titleView.setPosX(getPaddingLeft());
232 | navigationView.setWidth(width - getPaddingLeft() - getPaddingRight());
233 | navigationView.setPosX(getPaddingLeft());
234 | detailView.setWidth(width);
235 | detailView.setPosX(0);
236 |
237 | int heightMode = MeasureSpec.getMode(heightMeasureSpec);
238 | int heightSize = MeasureSpec.getSize(heightMeasureSpec);
239 |
240 | if (heightMode == MeasureSpec.EXACTLY) { //Must be this size
241 | height = heightSize;
242 | } else if (heightMode == MeasureSpec.AT_MOST) { //Can't be bigger than...
243 | height = Math.min(desiredWidth, heightSize);
244 | } else { //Be whatever you want
245 | // height = desiredHeight;
246 | }
247 |
248 | int titleHeight;
249 | int navHeight;
250 | int detailHeight;
251 | if (heightMode == MeasureSpec.EXACTLY || heightMode == MeasureSpec.AT_MOST) {
252 | titleHeight = titleView.calculateHeight();
253 | navHeight = navigationView.calculateHeight();
254 | detailHeight = height - getPaddingTop() - getPaddingBottom() - titleHeight - navHeight;
255 | } else {
256 | titleHeight = titleView.calculateHeight();
257 | navHeight = navigationView.calculateHeight();
258 | detailHeight = detailView.calculateHeight();
259 | height = getPaddingTop() + titleHeight + navHeight + detailHeight + getPaddingBottom();
260 | }
261 |
262 | titleView.setHeight(titleHeight);
263 | titleView.setPosY(getPaddingTop());
264 | detailView.setHeight(detailHeight);
265 | detailView.setPosY(getPaddingTop() + titleHeight);
266 | navigationView.setPosY(getPaddingTop() + titleHeight + detailHeight);
267 | navigationView.setHeight(navHeight);
268 |
269 | setMeasuredDimension(widthMeasureSpec, height);
270 | }
271 |
272 | @Override
273 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
274 | super.onSizeChanged(w, h, oldw, oldh);
275 |
276 | topShadowSize = new RectF(0, 0, width, titleView.getHeight());
277 | shader = new LinearGradient(0, 0, 0, titleView.getHeight(), colors.backgroundColor, Color.TRANSPARENT, Shader.TileMode.CLAMP);
278 | paintForTopShadow.setShader(shader);
279 |
280 | titleView.onSizeChanged();
281 | navigationView.onSizeChanged();
282 | detailView.onSizeChanged();
283 | }
284 |
285 | @Override
286 | protected void onDraw(Canvas canvas) {
287 | super.onDraw(canvas);
288 |
289 | canvas.drawPaint(pFill);
290 |
291 | if (data != null) {
292 | detailView.drawOn(canvas);
293 | detailView.drawDebug(canvas, debug);
294 | navigationView.drawOn(canvas);
295 | navigationView.drawDebug(canvas, debug);
296 | }
297 |
298 | //draw top shadow
299 | canvas.drawRect(topShadowSize, paintForTopShadow);
300 |
301 | //drawTitle
302 | titleView.drawOn(canvas);
303 | titleView.drawDebug(canvas, debug);
304 |
305 | }
306 |
307 | @Override
308 | public boolean onTouchEvent(MotionEvent event) {
309 | float tapY = event.getY();
310 | boolean res = false;
311 |
312 | switch (event.getAction()) {
313 | case MotionEvent.ACTION_DOWN: {
314 | if (navigationView.getPosY() < tapY && tapY < navigationView.getPosY() + navigationView.getHeight()) {
315 | res = navigationView.onTouchEvent(event);
316 | }
317 | if (detailView.getPosY() < tapY && tapY < detailView.getPosY() + detailView.getHeight()) {
318 | res = detailView.onTouchEvent(event);
319 | }
320 | break;
321 | }
322 | case MotionEvent.ACTION_MOVE: {
323 | if (navigationView.isiAmPressed()) {
324 | res = navigationView.onTouchEvent(event);
325 | } else if (detailView.isiAmPressed()) {
326 | res = detailView.onTouchEvent(event);
327 | }
328 | break;
329 | }
330 | case MotionEvent.ACTION_UP:
331 | case MotionEvent.ACTION_CANCEL: {
332 | if (navigationView.isiAmPressed()) {
333 | res = navigationView.onTouchEvent(event);
334 | } else if (detailView.isiAmPressed()) {
335 | res = detailView.onTouchEvent(event);
336 | }
337 | break;
338 | }
339 | default:
340 | res = false;
341 | }
342 |
343 | if (res) {
344 | navigationView.prepareDataForPrinting(false);
345 | detailView.prepareDataForPrinting(false);
346 |
347 | invalidate();
348 | }
349 | return res;
350 | }
351 |
352 | @Override
353 | protected Parcelable onSaveInstanceState() {
354 | Bundle bundle = new Bundle();
355 | bundle.putParcelable("superState", super.onSaveInstanceState());
356 | bundle.putLong("curStartTime", selectedStartTime);
357 | bundle.putLong("curEndTime", selectedEndTime);
358 | bundle.putBooleanArray("linesForShow", linesForShow);
359 | return bundle;
360 | }
361 |
362 | @Override
363 | protected void onRestoreInstanceState(Parcelable state) {
364 | if (state != null && state instanceof Bundle) {
365 | Bundle bundle = (Bundle) state;
366 | this.selectedStartTime = bundle.getLong("curStartTime");
367 | this.selectedEndTime = bundle.getLong("curEndTime");
368 | // if (saveShowedLines) {
369 | this.linesForShow = bundle.getBooleanArray("linesForShow");
370 | // data.updateLinesForShow(linesForShow);
371 | // }
372 | state = bundle.getParcelable("superState");
373 | }
374 | super.onRestoreInstanceState(state);
375 |
376 | navigationView.setStartPeriodTimes(selectedStartTime, selectedEndTime);
377 | }
378 |
379 | @Override
380 | public void onTimeLineChanged(long start, long end, boolean changeZoom) {
381 | selectedStartTime = start;
382 | selectedEndTime = end;
383 | }
384 |
385 | public void setData(ChartData data) {
386 | this.data = data;
387 | linesForShow = new boolean[data.getNames().size()];
388 | for (int i = 0; i < data.getNames().size(); i++) {
389 | linesForShow[i] = true;
390 | }
391 |
392 | int startTime = 0;
393 | if (data.getItems().size() >= 9) {
394 | startTime = data.getItems().size() - (int) (data.getItems().size() / 3);
395 | }
396 | selectedStartTime = data.getItems().get(startTime).getTime();
397 | selectedEndTime = data.getItems().get(data.getItems().size() - 1).getTime();
398 |
399 | detailView.setData(data, selectedStartTime, selectedEndTime);
400 | navigationView.setData(data, selectedStartTime, selectedEndTime);
401 |
402 | invalidate();
403 | }
404 |
405 | //params
406 | public void setTitle(String title) {
407 | this.title = title;
408 | }
409 | }
410 |
--------------------------------------------------------------------------------
/app/src/main/assets/chart_data.json:
--------------------------------------------------------------------------------
1 | [{"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[37,20,32,39,32,35,19,65,36,62,113,69,120,60,51,49,71,122,149,69,57,21,33,55,92,62,47,50,56,116,63,60,55,65,76,33,45,64,54,81,180,123,106,37,60,70,46,68,46,51,33,57,75,70,95,70,50,68,63,66,53,38,52,109,121,53,36,71,96,55,58,29,31,55,52,44,126,191,73,87,255,278,219,170,129,125,126,84,65,53,154,57,71,64,75,72,39,47,52,73,89,156,86,105,88,45,33,56,142,124,114,64],"y1":[22,12,30,40,33,23,18,41,45,69,57,61,70,47,31,34,40,55,27,57,48,32,40,49,54,49,34,51,51,51,66,51,94,60,64,28,44,96,49,73,30,88,63,42,56,67,52,67,35,61,40,55,63,61,105,59,51,76,63,57,47,56,51,98,103,62,54,104,48,41,41,37,30,28,26,37,65,86,70,81,54,74,70,50,74,79,85,62,36,46,68,43,66,50,28,66,39,23,63,74,83,66,40,60,29,36,27,54,89,50,73,52]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},{"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[6706,7579,7798,8307,7866,7736,7816,7630,7536,7105,7178,7619,7917,7483,5772,5700,5435,4837,4716,4890,4753,4820,4538,12162,39444,25765,18012,14421,13249,11310,10377,9399,8917,8259,7902,9442,47596,36160,23866,18500,15488,13722,12270,13413,10574,7092,7159,7880,8821,8306,7780,7963,7837,7611,7334,7413,7015,6742,6557,6593,6680,6725,6345,5988,6365,9911,28833,19694,14873,11911,10498,9708,8893,8365,7960,7694,45529,42858,31508,23289,19147,15874,14551,13124,11778,10809,10522,9918,9436,8617,8765,8194,8035,7865,7573,7422,7047,7147,6861,6669,6363,12073,32381,21390,15311,12819,11655,10696,9678,9143,8296,7852],"y1":[3522,4088,4146,4477,4202,4157,4177,4203,4223,3948,3946,3898,3979,4052,3279,3229,3302,3040,3054,2982,3077,2965,2973,5148,22485,13077,9055,7446,6824,5995,5787,5367,4997,4689,4630,4785,22365,15244,10626,8666,7681,6929,6219,6367,5402,4932,4844,5146,5265,4887,4714,4722,4718,4693,4746,4819,4455,4419,4323,4407,4277,11589,6100,5076,4769,8929,14002,9756,7520,6343,5633,5415,5052,4850,4624,4480,14102,24005,14263,10845,9028,7755,7197,7001,6737,6254,6150,5922,5603,5048,5423,5003,5035,4747,4814,4661,4462,4516,4221,4111,4053,12515,15781,10499,8175,6831,6287,5990,5590,5148,4760,4809]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},{"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[4747,4849,5045,5184,5746,5400,5424,5576,6436,5337,4840,5379,4678,4736,5074,4897,4349,5089,4543,5033,5047,4871,4812,4723,4545,4723,4721,4384,4277,4682,4805,4001,4610,5241,5113,4059,4529,4673,5291,5154,5123,5535,5540,5161,5666,5584,6999,6854,5083,5361,5863,5792,5586,6106,5481,5532,5853,5809,6244,6156,5596,5426,5422,5413,4795,5113,5279,5530,4939,4983,4984,5527,5765,5001,5818,6061,5956,5288,5837,5703,5440,5238,5957,6432,6389,6064,7065,5981,5779,6567,6320,5634,6023,5702,6066,5797,6163,6182,4906,5637,7073,6679,5831,6015,6266,6128,6156,6218,6050,6140,5877,7147],"y1":[4605,5036,4956,5168,5008,5069,5223,5360,5695,5209,4796,5028,4931,5123,4987,4964,4982,5037,5050,5144,5049,4971,4911,4792,4562,4597,4759,4761,4646,4543,4597,4428,4213,4270,3961,4784,4699,4711,4855,4717,4563,4923,5041,4895,4877,5001,5410,5033,5045,5184,4976,5207,5354,5205,4887,4831,5083,5148,5369,5176,5022,4880,4969,5135,4836,4764,4782,4783,4646,4755,4744,4932,5059,4851,4614,4718,5018,5034,5223,5007,4839,4763,4761,5048,5330,5106,5956,5135,5006,4919,5511,5114,5122,5314,5089,5022,4918,4986,4626,4675,4951,4921,5173,5145,5209,4967,5030,5120,5030,4946,4795,5224]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},{"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[41,31,62,65,66,79,52,26,42,68,71,86,65,54,33,70,52,68,75,92,69,28,33,84,65,56,42,44,26,34,45,49,83,83,66,31,43,55,57,55,54,45,51,64,27,19,38,38,44,49,42,50,60,73,86,65,51,54,48,61,82,83,53,52,48,64,96,103,68,73,58,42,81,80,76,106,93,65,69,104,75,79,92,73,49,63,76,79,83,70,55,47,42,111,93,74,99,107,52,65,80,82,74,154,106,39,40,77,85,66,52,25],"y1":[19,10,36,41,28,39,24,16,14,40,39,37,47,28,16,32,25,29,36,45,38,11,25,37,35,22,25,30,16,20,32,34,37,26,31,10,19,32,34,23,25,22,21,18,11,18,18,23,11,18,22,19,27,27,30,25,27,23,28,30,23,31,27,16,30,21,36,33,25,34,16,24,37,33,26,24,31,21,37,32,35,31,30,27,15,17,38,40,32,34,30,17,21,28,36,30,24,25,20,24,22,42,34,47,40,29,29,31,39,30,29,18]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},{"columns":{"x":[1520035200000,1520121600000,1520208000000,1520294400000,1520380800000,1520467200000,1520553600000,1520640000000,1520726400000,1520812800000,1520899200000,1520985600000,1521072000000,1521158400000,1521244800000,1521331200000,1521417600000,1521504000000,1521590400000,1521676800000,1521763200000,1521849600000,1521936000000,1522022400000,1522108800000,1522195200000,1522281600000,1522368000000,1522454400000,1522540800000,1522627200000,1522713600000,1522800000000,1522886400000,1522972800000,1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000],"y0":[2298660,2253410,2515820,2506600,2460240,2408400,2317430,2240100,2295900,2609800,2594200,2626400,2615000,2617800,2394500,2391100,2608300,2676000,2637700,2766600,3186500,3067700,2570700,2935000,2949200,2913500,2763600,3216300,2343500,2361000,2580000,2591800,2595200,2569500,2587700,2372500,2351200,2465600,2625100,2651300,2686700,2783300,2417400,2383800,2736300,2751100,2678900,2622300,2586000,2365700,2407700,2541300,2600400,2581500,2576200,2550100,2334500,2139400,2015400,2019900,2210100,2191800,2240700,2107400,2026900,2258000,2255200,2123200,2267800,2236100,2065700,2093300,2315300,2333200,2349800,2318300,2275000,2110300,2077100,2335200,2357400,2350000,2293800,2303600,2118700,2100300,2219700,2361100,2349500,2347800,2318400,2141600,2178600,2432500,2448700,2440300,2450100,2424100,2229900,2152400,2402600,2401000,2418100,2408600,2408400,2212600,2189000,2450800,2444500,2451900,2451000,2442600,2287900,2221100,2451900,2460200,2460900,2319900,2270300,2183800,2195300,2485000,2460900,2500600,2495300,2479100,2290600,2235800,2459900,2484500,2491000,2525600,2477300,2223700,2146700,2528200,2567800,2556300,2540700,2503000,2301200,2251600,2538600,2596500,2553900,2534200,2527300,2337400,2332900,2688500,2585700,2559600,2651600,2586800,2445700,2472300,2633000,2664600,2649400,2648900,2644600,2406400,2426200,2694000,2740600,2711800,2700900,2645800,2422800,2438500,2697500,2712500,2690300,2684400,2517300,2435300,2444300,2781800,2807800,2804500,2771300,2798800,2633300,2597100,2946300,2889800,2949600,2951400,2928800,2701400,2709900,3012900,3019100,2977200,3012400,2989800,2752100,2749100,3033300,3050400,3023800,3066400,3047800,2792200,2799300,3096100,3132500,3082400,3071200,3021400,2818300,2737500,3037800,3123700,3138900,3181800,3118500,2834500,2826900,3171000,3175900,3184300,3195800,3129100,2834100,2876800,3019000,3214000,3227900,3189600,3187800,2886800,2880500,3218200,3253700,3260400,3243300,3204000,2962700,2968600,3282100,3618900,3017000,3037300,3044500,2758900,2784600,3032900,3132400,3075800,3108200,3076200,2851800,2837800,3107500,3146800,3145100,3145300,3158400,2872100,2823800,3190400,3209300,3170800,3195300,3183000,2910300,2937400,3297100,3293600,3278400,3234200,3224000,3013900,2955300,3303900,3323300,3352600,3348400,3340600,3110600,3066400,3409200,3462100,3394200,3383100,3433700,3184000,3092700,3417400,4505200,3094500,3106100,3083200,3005600,2866700,2984100,2954200,3086800,3070500,3040900,2903500,3592500,3316200,2930500,2961900,3009600,3027200,2871600,2831600,2881700,3054200,3116600,3120800,3157300,2950700,2982700,3192800,3223300,3219500,3235900,3214100,3004400,2963500,3280400,3262400,3256000,3258400,3264900,3107500,3057400,3326600,3332400,3357000,3365100,3359500,3127400,3130200,3367100,3422700,3436400,3431100,3600000,3146100,3170900,3467300,3483400,3473600,3454700,3390200,3213600,3188800,3498200,3498600,3493500,3478900,3446400,3239200,3229100,3559600,3563600,3549800,3577300,3524400,3282500,3271300,3599200,3575200,3554400,3540300,3450600,2812000],"y1":[1130400,1065370,1211030,1215590,1206540,1206720,1085450,1047320,1071720,1253170,1261050,1264660,1260240,1264840,1130440,1121660,1294120,1290780,1284540,1302860,1296810,1165450,1128830,1302070,1304470,1307090,1268000,1302160,1159330,1163530,1327140,1320680,1319200,1306810,1287990,1121240,1145070,1132400,1310310,1329340,1340060,1333530,1167040,1153260,1356930,1366500,1375970,1378570,1357460,1192240,1188650,1386450,1400570,1395730,1404160,1378120,1195410,1082000,1189660,1197540,1367850,1389070,1386300,1282240,1209450,1409070,1409450,1271120,1424860,1399990,1240640,1248530,1451770,1460240,1466100,1460990,1446730,1268830,1263270,1473530,1476230,1480760,1460520,1454730,1263910,1227240,1303900,1474760,1473400,1477380,1466790,1285620,1280100,1491820,1499660,1496260,1485990,1473140,1301290,1273440,1487420,1494560,1500790,1508660,1489400,1301960,1297680,1501170,1503000,1488980,1501170,1479060,1367980,1296050,1493920,1487830,1479120,1338410,1318550,1266620,1285640,1487970,1489080,1489580,1475400,1471140,1316010,1271940,1476160,1480670,1491030,1480940,1477640,1305750,1296770,1483400,1494440,1495740,1485900,1484400,1319160,1284010,1488140,1502910,1503450,1485410,1498200,1323200,1303150,1506840,1523440,1521490,1516770,1504300,1327520,1307630,1518100,1521370,1521280,1521660,1517700,1349880,1333010,1543800,1553730,1546490,1541710,1532690,1367020,1354040,1560080,1564990,1565050,1561110,1406570,1340850,1368550,1600180,1630760,1621360,1636580,1652580,1489550,1465750,1731080,1730190,1732260,1730210,1724800,1519480,1520490,1758280,1774530,1770690,1781100,1762270,1551690,1541620,1787290,1795490,1802940,1799130,1778850,1560040,1564580,1822410,1819680,1812390,1814100,1798060,1587880,1589320,1833920,1843420,1851460,1845550,1822980,1596860,1595900,1866000,1860480,1862600,1863950,1827540,1585280,1588970,1683930,1879500,1883300,1879040,1846160,1639090,1632580,1895780,1897620,1906000,1906730,1895290,1670120,1670190,1914360,1932890,1933160,1921800,1898720,1673530,1685190,1937730,1951850,1949900,1949020,1923160,1718450,1704040,1964800,1975140,2002510,1985340,1959000,1736810,1727670,2006070,2013910,2012460,1999630,1977020,1754720,1778560,2060360,2057730,2055990,2036720,2027870,1824680,1794140,2067460,2078290,2094100,2080950,2062080,1836850,1828130,2102920,2112450,2098790,2116900,2080290,1863760,1841050,2105790,2106420,2151300,2098890,2085380,1955580,1819790,1916140,1913670,2080350,2058160,2034960,1911480,1823940,2087990,1774260,1833950,1906680,1902490,1760460,1748060,1775740,1974730,2013790,2026250,2022210,1835820,1835930,2096230,2098020,2095770,2114060,2099370,1902800,1854380,2132520,2143600,2146120,2143820,2157910,1929390,1905550,2183760,2185970,2198030,2198160,2182120,1950150,1931800,2215380,2216240,2226480,2220480,2208790,1972190,1957520,2253470,2247170,2245720,2285890,2220730,1986340,1967720,2264340,2270140,2267210,2268950,2246450,2048760,1994100,2288680,2296010,2313730,2311290,2293790,2034250,2025380,2326190,2323990,2320790,2271600,2244270,1663290],"y2":[820900,766050,894390,894540,887590,814490,786610,744660,770920,930330,930190,942060,933690,922280,810770,809760,952010,959070,957020,955890,948250,825710,804970,958480,959090,970200,907010,950150,825240,820890,971020,973560,967940,960360,931820,795020,753860,808740,970000,981020,979810,975840,829690,819300,992290,998040,1006540,1013790,995130,848190,851890,1024210,1032210,1032290,1027510,1010090,850110,741740,844400,850410,1006690,1018470,1011630,916990,861050,1039650,1032640,904200,1045560,1022330,888970,896300,1073460,1074860,1074820,1074880,1057340,909410,906710,1078860,1092760,1083360,1078680,1067310,903090,858360,947540,1089590,1095060,1093130,1070660,915380,916530,1108410,1109460,1097230,1094520,1074630,915520,915750,1101730,1104580,1107930,1116850,1106360,928500,928210,1110530,1103230,1099970,1106180,1096060,982050,932620,1100880,1099970,1080040,959480,951360,902160,916070,1094120,1092530,1089290,1081760,1073320,937320,900010,1084910,1082620,1080960,1074050,1077810,925090,913970,1082900,1089240,1088890,1088720,1084170,938750,904060,1091540,1093660,1104520,1085860,1091880,939720,919790,1098590,1110310,1105580,1105220,1096580,940670,923480,1102360,1102760,1102280,1108680,1109210,955490,944730,1125380,1127440,1123070,1123910,1121160,966340,946940,1141980,1146790,1147420,1132920,990870,946370,964610,1171550,1187000,1186370,1199100,1213000,1062280,1035740,1274070,1276740,1280670,1282770,1257200,1085370,1080510,1293120,1308880,1302170,1317570,1298110,1111780,1106410,1317620,1318010,1332680,1328530,1305330,1113540,1119830,1340410,1348770,1346910,1352950,1324040,1139450,1136680,1355970,1364950,1377510,1375770,1338490,1140310,1151830,1374520,1374330,1378990,1372390,1347390,1135560,1121640,1217410,1390340,1392710,1383070,1372400,1170430,1169550,1404540,1412720,1414110,1417200,1388240,1194260,1188850,1416140,1425890,1426380,1410520,1388600,1197940,1197680,1432620,1448350,1436320,1438890,1412650,1222040,1215220,1454190,1456740,1490670,1470910,1438940,1243620,1241210,1483460,1489950,1488440,1482490,1465050,1261450,1281800,1552680,1527050,1526500,1511360,1497560,1302860,1292930,1547830,1550610,1546490,1547790,1525750,1324580,1321580,1576620,1575060,1570240,1574670,1543830,1341780,1341710,1577840,1565630,1580460,1569570,1543390,1431880,1301600,1401500,1401040,1530910,1526670,1498750,1383070,1284000,1401510,1189880,1309810,1380230,1383630,1254140,1216830,1243860,1442240,1481680,1480680,1490700,1315410,1300930,1530520,1532340,1539150,1541510,1532770,1344910,1325530,1563330,1568490,1580110,1575130,1564880,1369810,1359060,1608230,1605640,1605970,1601640,1590810,1381740,1375190,1625850,1621800,1629910,1628510,1609760,1397880,1392180,1647700,1646770,1644200,1667150,1610910,1408450,1395010,1652870,1658870,1660310,1659060,1629490,1435450,1407720,1675610,1682450,1682070,1693010,1669030,1448500,1439490,1710110,1702690,1707000,1662770,1512800,1101660],"y3":[409540,377260,456380,460230,452020,389350,397230,369000,382180,473570,477470,477550,478030,466150,397480,406380,494570,494680,482810,487700,475090,400520,397940,484160,487740,493260,434500,475410,398650,404690,491980,493410,485250,484740,465490,377460,353960,396390,493300,497560,495110,485260,394770,402910,500540,506260,509680,514010,494350,405360,412560,513030,521320,515730,518170,499850,394960,328510,406450,408080,501980,507800,496990,442530,414260,525770,513440,442660,526810,500190,426220,436110,546820,543480,545420,540530,527770,431050,443100,549550,551600,548120,542290,528810,435370,407250,463200,553640,554110,555820,536470,440460,447740,563330,561850,556430,550910,539440,441200,442310,563100,563760,559230,570870,555280,447750,455570,564630,562510,556050,555560,556470,484080,451320,561060,553630,540660,473500,472500,438550,447590,548670,549580,539920,541510,540380,450260,432260,535950,545160,543810,536990,539680,446570,444470,543450,549070,547840,541430,540200,450080,431800,549290,545890,556300,536500,543890,450890,440180,550850,554740,553460,553440,546420,446710,436640,553270,547750,551920,547610,545500,449220,447510,560050,561560,561560,556630,559340,461630,456300,569070,574800,575220,566180,472200,450530,462960,590290,597250,592970,604870,613050,512200,495980,649860,645070,636950,647120,630390,518820,525990,661700,659770,660650,669560,644510,529610,539520,673850,668530,673770,669480,654540,536090,548400,690100,684900,687040,685940,666360,560140,553050,696740,694490,703000,697980,674460,548230,557370,697150,700110,701170,695810,669780,543500,540170,597430,711500,699770,698520,682170,568380,572950,715580,716050,720770,720660,695220,572970,578170,722280,724280,727910,719820,699840,580870,586270,729850,733680,726590,731270,709330,593070,600500,743590,743690,767660,747140,730510,607540,610480,762440,772960,763480,758490,741090,614450,645760,831130,792100,780410,778620,761000,643620,650320,802640,805900,803960,800580,783660,648310,668150,825940,818650,816630,821000,782790,657850,671660,817660,816020,821380,816280,800240,712510,648060,711170,709110,802240,792710,772260,691490,636050,649450,566120,651310,701910,702270,627880,605290,621710,744830,762830,765640,764140,648720,642430,786580,778790,780060,789170,772600,652160,648950,795360,802250,808010,801890,793490,669240,665310,814370,810880,814580,813950,802070,670450,674250,823010,820620,821400,820760,804300,681870,681460,831580,835600,835390,840770,810700,675170,680870,832000,836790,845630,844560,821810,690310,683810,851150,848090,846480,858340,831290,696470,695540,866980,868190,861720,834530,706650,439140]},"types":{"y0":"line","y1":"line","y2":"line","y3":"line","x":"x"},"names":{"y0":"#0","y1":"#1","y2":"#2","y3":"#3"},"colors":{"y0":"#cb513a","y1":"#73c03a","y2":"#65b9ac","y3":"#4682b4"}}]
--------------------------------------------------------------------------------
/app/src/main/assets/all_chart_data.json:
--------------------------------------------------------------------------------
1 | [
2 | {"columns":{"x":[1618951646915],"PPFD":[1012],"DLI":[70]},"types":{"PPFD":"line","DLI":"line","x":"x"},"names":{"PPFD":"PPFD","DLI":"DLI"},"colors":{"PPFD":"#FF00FF00","DLI":"#FFFF0000"}},
3 | {"columns":{"x":[1618951646915,1618951647916],"PPFD":[1012,900],"DLI":[70,87]},"types":{"PPFD":"line","DLI":"line","x":"x"},"names":{"PPFD":"PPFD","DLI":"DLI"},"colors":{"PPFD":"#FF00FF00","DLI":"#FFFF0000"}},
4 | {"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000],"y0":[37,20,32,39],"y1":[22,12,30,40]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},
5 | {"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[37,20,32,39,32,35,19,65,36,62,113,69,120,60,51,49,71,122,149,69,57,21,33,55,92,62,47,50,56,116,63,60,55,65,76,33,45,64,54,81,180,123,106,37,60,70,46,68,46,51,33,57,75,70,95,70,50,68,63,66,53,38,52,109,121,53,36,71,96,55,58,29,31,55,52,44,126,191,73,87,255,278,219,170,129,125,126,84,65,53,154,57,71,64,75,72,39,47,52,73,89,156,86,105,88,45,33,56,142,124,114,64],"y1":[22,12,30,40,33,23,18,41,45,69,57,61,70,47,31,34,40,55,27,57,48,32,40,49,54,49,34,51,51,51,66,51,94,60,64,28,44,96,49,73,30,88,63,42,56,67,52,67,35,61,40,55,63,61,105,59,51,76,63,57,47,56,51,98,103,62,54,104,48,41,41,37,30,28,26,37,65,86,70,81,54,74,70,50,74,79,85,62,36,46,68,43,66,50,28,66,39,23,63,74,83,66,40,60,29,36,27,54,89,50,73,52]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},
6 | {"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[6706,7579,7798,8307,7866,7736,7816,7630,7536,7105,7178,7619,7917,7483,5772,5700,5435,4837,4716,4890,4753,4820,4538,12162,39444,25765,18012,14421,13249,11310,10377,9399,8917,8259,7902,9442,47596,36160,23866,18500,15488,13722,12270,13413,10574,7092,7159,7880,8821,8306,7780,7963,7837,7611,7334,7413,7015,6742,6557,6593,6680,6725,6345,5988,6365,9911,28833,19694,14873,11911,10498,9708,8893,8365,7960,7694,45529,42858,31508,23289,19147,15874,14551,13124,11778,10809,10522,9918,9436,8617,8765,8194,8035,7865,7573,7422,7047,7147,6861,6669,6363,12073,32381,21390,15311,12819,11655,10696,9678,9143,8296,7852],"y1":[3522,4088,4146,4477,4202,4157,4177,4203,4223,3948,3946,3898,3979,4052,3279,3229,3302,3040,3054,2982,3077,2965,2973,5148,22485,13077,9055,7446,6824,5995,5787,5367,4997,4689,4630,4785,22365,15244,10626,8666,7681,6929,6219,6367,5402,4932,4844,5146,5265,4887,4714,4722,4718,4693,4746,4819,4455,4419,4323,4407,4277,11589,6100,5076,4769,8929,14002,9756,7520,6343,5633,5415,5052,4850,4624,4480,14102,24005,14263,10845,9028,7755,7197,7001,6737,6254,6150,5922,5603,5048,5423,5003,5035,4747,4814,4661,4462,4516,4221,4111,4053,12515,15781,10499,8175,6831,6287,5990,5590,5148,4760,4809]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},
7 | {"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[4747,4849,5045,5184,5746,5400,5424,5576,6436,5337,4840,5379,4678,4736,5074,4897,4349,5089,4543,5033,5047,4871,4812,4723,4545,4723,4721,4384,4277,4682,4805,4001,4610,5241,5113,4059,4529,4673,5291,5154,5123,5535,5540,5161,5666,5584,6999,6854,5083,5361,5863,5792,5586,6106,5481,5532,5853,5809,6244,6156,5596,5426,5422,5413,4795,5113,5279,5530,4939,4983,4984,5527,5765,5001,5818,6061,5956,5288,5837,5703,5440,5238,5957,6432,6389,6064,7065,5981,5779,6567,6320,5634,6023,5702,6066,5797,6163,6182,4906,5637,7073,6679,5831,6015,6266,6128,6156,6218,6050,6140,5877,7147],"y1":[4605,5036,4956,5168,5008,5069,5223,5360,5695,5209,4796,5028,4931,5123,4987,4964,4982,5037,5050,5144,5049,4971,4911,4792,4562,4597,4759,4761,4646,4543,4597,4428,4213,4270,3961,4784,4699,4711,4855,4717,4563,4923,5041,4895,4877,5001,5410,5033,5045,5184,4976,5207,5354,5205,4887,4831,5083,5148,5369,5176,5022,4880,4969,5135,4836,4764,4782,4783,4646,4755,4744,4932,5059,4851,4614,4718,5018,5034,5223,5007,4839,4763,4761,5048,5330,5106,5956,5135,5006,4919,5511,5114,5122,5314,5089,5022,4918,4986,4626,4675,4951,4921,5173,5145,5209,4967,5030,5120,5030,4946,4795,5224]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},
8 | {"columns":{"x":[1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000],"y0":[41,31,62,65,66,79,52,26,42,68,71,86,65,54,33,70,52,68,75,92,69,28,33,84,65,56,42,44,26,34,45,49,83,83,66,31,43,55,57,55,54,45,51,64,27,19,38,38,44,49,42,50,60,73,86,65,51,54,48,61,82,83,53,52,48,64,96,103,68,73,58,42,81,80,76,106,93,65,69,104,75,79,92,73,49,63,76,79,83,70,55,47,42,111,93,74,99,107,52,65,80,82,74,154,106,39,40,77,85,66,52,25],"y1":[19,10,36,41,28,39,24,16,14,40,39,37,47,28,16,32,25,29,36,45,38,11,25,37,35,22,25,30,16,20,32,34,37,26,31,10,19,32,34,23,25,22,21,18,11,18,18,23,11,18,22,19,27,27,30,25,27,23,28,30,23,31,27,16,30,21,36,33,25,34,16,24,37,33,26,24,31,21,37,32,35,31,30,27,15,17,38,40,32,34,30,17,21,28,36,30,24,25,20,24,22,42,34,47,40,29,29,31,39,30,29,18]},"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"#0","y1":"#1"},"colors":{"y0":"#3DC23F","y1":"#F34C44"}},
9 | {"columns":{"x":[1520035200000,1520121600000,1520208000000,1520294400000,1520380800000,1520467200000,1520553600000,1520640000000,1520726400000,1520812800000,1520899200000,1520985600000,1521072000000,1521158400000,1521244800000,1521331200000,1521417600000,1521504000000,1521590400000,1521676800000,1521763200000,1521849600000,1521936000000,1522022400000,1522108800000,1522195200000,1522281600000,1522368000000,1522454400000,1522540800000,1522627200000,1522713600000,1522800000000,1522886400000,1522972800000,1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000],"y0":[2298660,2253410,2515820,2506600,2460240,2408400,2317430,2240100,2295900,2609800,2594200,2626400,2615000,2617800,2394500,2391100,2608300,2676000,2637700,2766600,3186500,3067700,2570700,2935000,2949200,2913500,2763600,3216300,2343500,2361000,2580000,2591800,2595200,2569500,2587700,2372500,2351200,2465600,2625100,2651300,2686700,2783300,2417400,2383800,2736300,2751100,2678900,2622300,2586000,2365700,2407700,2541300,2600400,2581500,2576200,2550100,2334500,2139400,2015400,2019900,2210100,2191800,2240700,2107400,2026900,2258000,2255200,2123200,2267800,2236100,2065700,2093300,2315300,2333200,2349800,2318300,2275000,2110300,2077100,2335200,2357400,2350000,2293800,2303600,2118700,2100300,2219700,2361100,2349500,2347800,2318400,2141600,2178600,2432500,2448700,2440300,2450100,2424100,2229900,2152400,2402600,2401000,2418100,2408600,2408400,2212600,2189000,2450800,2444500,2451900,2451000,2442600,2287900,2221100,2451900,2460200,2460900,2319900,2270300,2183800,2195300,2485000,2460900,2500600,2495300,2479100,2290600,2235800,2459900,2484500,2491000,2525600,2477300,2223700,2146700,2528200,2567800,2556300,2540700,2503000,2301200,2251600,2538600,2596500,2553900,2534200,2527300,2337400,2332900,2688500,2585700,2559600,2651600,2586800,2445700,2472300,2633000,2664600,2649400,2648900,2644600,2406400,2426200,2694000,2740600,2711800,2700900,2645800,2422800,2438500,2697500,2712500,2690300,2684400,2517300,2435300,2444300,2781800,2807800,2804500,2771300,2798800,2633300,2597100,2946300,2889800,2949600,2951400,2928800,2701400,2709900,3012900,3019100,2977200,3012400,2989800,2752100,2749100,3033300,3050400,3023800,3066400,3047800,2792200,2799300,3096100,3132500,3082400,3071200,3021400,2818300,2737500,3037800,3123700,3138900,3181800,3118500,2834500,2826900,3171000,3175900,3184300,3195800,3129100,2834100,2876800,3019000,3214000,3227900,3189600,3187800,2886800,2880500,3218200,3253700,3260400,3243300,3204000,2962700,2968600,3282100,3618900,3017000,3037300,3044500,2758900,2784600,3032900,3132400,3075800,3108200,3076200,2851800,2837800,3107500,3146800,3145100,3145300,3158400,2872100,2823800,3190400,3209300,3170800,3195300,3183000,2910300,2937400,3297100,3293600,3278400,3234200,3224000,3013900,2955300,3303900,3323300,3352600,3348400,3340600,3110600,3066400,3409200,3462100,3394200,3383100,3433700,3184000,3092700,3417400,4505200,3094500,3106100,3083200,3005600,2866700,2984100,2954200,3086800,3070500,3040900,2903500,3592500,3316200,2930500,2961900,3009600,3027200,2871600,2831600,2881700,3054200,3116600,3120800,3157300,2950700,2982700,3192800,3223300,3219500,3235900,3214100,3004400,2963500,3280400,3262400,3256000,3258400,3264900,3107500,3057400,3326600,3332400,3357000,3365100,3359500,3127400,3130200,3367100,3422700,3436400,3431100,3600000,3146100,3170900,3467300,3483400,3473600,3454700,3390200,3213600,3188800,3498200,3498600,3493500,3478900,3446400,3239200,3229100,3559600,3563600,3549800,3577300,3524400,3282500,3271300,3599200,3575200,3554400,3540300,3450600,2812000],"y1":[1130400,1065370,1211030,1215590,1206540,1206720,1085450,1047320,1071720,1253170,1261050,1264660,1260240,1264840,1130440,1121660,1294120,1290780,1284540,1302860,1296810,1165450,1128830,1302070,1304470,1307090,1268000,1302160,1159330,1163530,1327140,1320680,1319200,1306810,1287990,1121240,1145070,1132400,1310310,1329340,1340060,1333530,1167040,1153260,1356930,1366500,1375970,1378570,1357460,1192240,1188650,1386450,1400570,1395730,1404160,1378120,1195410,1082000,1189660,1197540,1367850,1389070,1386300,1282240,1209450,1409070,1409450,1271120,1424860,1399990,1240640,1248530,1451770,1460240,1466100,1460990,1446730,1268830,1263270,1473530,1476230,1480760,1460520,1454730,1263910,1227240,1303900,1474760,1473400,1477380,1466790,1285620,1280100,1491820,1499660,1496260,1485990,1473140,1301290,1273440,1487420,1494560,1500790,1508660,1489400,1301960,1297680,1501170,1503000,1488980,1501170,1479060,1367980,1296050,1493920,1487830,1479120,1338410,1318550,1266620,1285640,1487970,1489080,1489580,1475400,1471140,1316010,1271940,1476160,1480670,1491030,1480940,1477640,1305750,1296770,1483400,1494440,1495740,1485900,1484400,1319160,1284010,1488140,1502910,1503450,1485410,1498200,1323200,1303150,1506840,1523440,1521490,1516770,1504300,1327520,1307630,1518100,1521370,1521280,1521660,1517700,1349880,1333010,1543800,1553730,1546490,1541710,1532690,1367020,1354040,1560080,1564990,1565050,1561110,1406570,1340850,1368550,1600180,1630760,1621360,1636580,1652580,1489550,1465750,1731080,1730190,1732260,1730210,1724800,1519480,1520490,1758280,1774530,1770690,1781100,1762270,1551690,1541620,1787290,1795490,1802940,1799130,1778850,1560040,1564580,1822410,1819680,1812390,1814100,1798060,1587880,1589320,1833920,1843420,1851460,1845550,1822980,1596860,1595900,1866000,1860480,1862600,1863950,1827540,1585280,1588970,1683930,1879500,1883300,1879040,1846160,1639090,1632580,1895780,1897620,1906000,1906730,1895290,1670120,1670190,1914360,1932890,1933160,1921800,1898720,1673530,1685190,1937730,1951850,1949900,1949020,1923160,1718450,1704040,1964800,1975140,2002510,1985340,1959000,1736810,1727670,2006070,2013910,2012460,1999630,1977020,1754720,1778560,2060360,2057730,2055990,2036720,2027870,1824680,1794140,2067460,2078290,2094100,2080950,2062080,1836850,1828130,2102920,2112450,2098790,2116900,2080290,1863760,1841050,2105790,2106420,2151300,2098890,2085380,1955580,1819790,1916140,1913670,2080350,2058160,2034960,1911480,1823940,2087990,1774260,1833950,1906680,1902490,1760460,1748060,1775740,1974730,2013790,2026250,2022210,1835820,1835930,2096230,2098020,2095770,2114060,2099370,1902800,1854380,2132520,2143600,2146120,2143820,2157910,1929390,1905550,2183760,2185970,2198030,2198160,2182120,1950150,1931800,2215380,2216240,2226480,2220480,2208790,1972190,1957520,2253470,2247170,2245720,2285890,2220730,1986340,1967720,2264340,2270140,2267210,2268950,2246450,2048760,1994100,2288680,2296010,2313730,2311290,2293790,2034250,2025380,2326190,2323990,2320790,2271600,2244270,1663290],"y2":[820900,766050,894390,894540,887590,814490,786610,744660,770920,930330,930190,942060,933690,922280,810770,809760,952010,959070,957020,955890,948250,825710,804970,958480,959090,970200,907010,950150,825240,820890,971020,973560,967940,960360,931820,795020,753860,808740,970000,981020,979810,975840,829690,819300,992290,998040,1006540,1013790,995130,848190,851890,1024210,1032210,1032290,1027510,1010090,850110,741740,844400,850410,1006690,1018470,1011630,916990,861050,1039650,1032640,904200,1045560,1022330,888970,896300,1073460,1074860,1074820,1074880,1057340,909410,906710,1078860,1092760,1083360,1078680,1067310,903090,858360,947540,1089590,1095060,1093130,1070660,915380,916530,1108410,1109460,1097230,1094520,1074630,915520,915750,1101730,1104580,1107930,1116850,1106360,928500,928210,1110530,1103230,1099970,1106180,1096060,982050,932620,1100880,1099970,1080040,959480,951360,902160,916070,1094120,1092530,1089290,1081760,1073320,937320,900010,1084910,1082620,1080960,1074050,1077810,925090,913970,1082900,1089240,1088890,1088720,1084170,938750,904060,1091540,1093660,1104520,1085860,1091880,939720,919790,1098590,1110310,1105580,1105220,1096580,940670,923480,1102360,1102760,1102280,1108680,1109210,955490,944730,1125380,1127440,1123070,1123910,1121160,966340,946940,1141980,1146790,1147420,1132920,990870,946370,964610,1171550,1187000,1186370,1199100,1213000,1062280,1035740,1274070,1276740,1280670,1282770,1257200,1085370,1080510,1293120,1308880,1302170,1317570,1298110,1111780,1106410,1317620,1318010,1332680,1328530,1305330,1113540,1119830,1340410,1348770,1346910,1352950,1324040,1139450,1136680,1355970,1364950,1377510,1375770,1338490,1140310,1151830,1374520,1374330,1378990,1372390,1347390,1135560,1121640,1217410,1390340,1392710,1383070,1372400,1170430,1169550,1404540,1412720,1414110,1417200,1388240,1194260,1188850,1416140,1425890,1426380,1410520,1388600,1197940,1197680,1432620,1448350,1436320,1438890,1412650,1222040,1215220,1454190,1456740,1490670,1470910,1438940,1243620,1241210,1483460,1489950,1488440,1482490,1465050,1261450,1281800,1552680,1527050,1526500,1511360,1497560,1302860,1292930,1547830,1550610,1546490,1547790,1525750,1324580,1321580,1576620,1575060,1570240,1574670,1543830,1341780,1341710,1577840,1565630,1580460,1569570,1543390,1431880,1301600,1401500,1401040,1530910,1526670,1498750,1383070,1284000,1401510,1189880,1309810,1380230,1383630,1254140,1216830,1243860,1442240,1481680,1480680,1490700,1315410,1300930,1530520,1532340,1539150,1541510,1532770,1344910,1325530,1563330,1568490,1580110,1575130,1564880,1369810,1359060,1608230,1605640,1605970,1601640,1590810,1381740,1375190,1625850,1621800,1629910,1628510,1609760,1397880,1392180,1647700,1646770,1644200,1667150,1610910,1408450,1395010,1652870,1658870,1660310,1659060,1629490,1435450,1407720,1675610,1682450,1682070,1693010,1669030,1448500,1439490,1710110,1702690,1707000,1662770,1512800,1101660],"y3":[409540,377260,456380,460230,452020,389350,397230,369000,382180,473570,477470,477550,478030,466150,397480,406380,494570,494680,482810,487700,475090,400520,397940,484160,487740,493260,434500,475410,398650,404690,491980,493410,485250,484740,465490,377460,353960,396390,493300,497560,495110,485260,394770,402910,500540,506260,509680,514010,494350,405360,412560,513030,521320,515730,518170,499850,394960,328510,406450,408080,501980,507800,496990,442530,414260,525770,513440,442660,526810,500190,426220,436110,546820,543480,545420,540530,527770,431050,443100,549550,551600,548120,542290,528810,435370,407250,463200,553640,554110,555820,536470,440460,447740,563330,561850,556430,550910,539440,441200,442310,563100,563760,559230,570870,555280,447750,455570,564630,562510,556050,555560,556470,484080,451320,561060,553630,540660,473500,472500,438550,447590,548670,549580,539920,541510,540380,450260,432260,535950,545160,543810,536990,539680,446570,444470,543450,549070,547840,541430,540200,450080,431800,549290,545890,556300,536500,543890,450890,440180,550850,554740,553460,553440,546420,446710,436640,553270,547750,551920,547610,545500,449220,447510,560050,561560,561560,556630,559340,461630,456300,569070,574800,575220,566180,472200,450530,462960,590290,597250,592970,604870,613050,512200,495980,649860,645070,636950,647120,630390,518820,525990,661700,659770,660650,669560,644510,529610,539520,673850,668530,673770,669480,654540,536090,548400,690100,684900,687040,685940,666360,560140,553050,696740,694490,703000,697980,674460,548230,557370,697150,700110,701170,695810,669780,543500,540170,597430,711500,699770,698520,682170,568380,572950,715580,716050,720770,720660,695220,572970,578170,722280,724280,727910,719820,699840,580870,586270,729850,733680,726590,731270,709330,593070,600500,743590,743690,767660,747140,730510,607540,610480,762440,772960,763480,758490,741090,614450,645760,831130,792100,780410,778620,761000,643620,650320,802640,805900,803960,800580,783660,648310,668150,825940,818650,816630,821000,782790,657850,671660,817660,816020,821380,816280,800240,712510,648060,711170,709110,802240,792710,772260,691490,636050,649450,566120,651310,701910,702270,627880,605290,621710,744830,762830,765640,764140,648720,642430,786580,778790,780060,789170,772600,652160,648950,795360,802250,808010,801890,793490,669240,665310,814370,810880,814580,813950,802070,670450,674250,823010,820620,821400,820760,804300,681870,681460,831580,835600,835390,840770,810700,675170,680870,832000,836790,845630,844560,821810,690310,683810,851150,848090,846480,858340,831290,696470,695540,866980,868190,861720,834530,706650,439140]},"types":{"y0":"line","y1":"line","y2":"line","y3":"line","x":"x"},"names":{"y0":"#0","y1":"#1","y2":"#2","y3":"#3"},"colors":{"y0":"#cb513a","y1":"#73c03a","y2":"#65b9ac","y3":"#4682b4"}}
10 | ]
--------------------------------------------------------------------------------