├── .gitignore ├── README.md ├── build.gradle ├── demo ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── fabernovel │ │ └── d3library │ │ └── demo │ │ ├── MenuActivity.java │ │ ├── activities │ │ ├── BarChartActivity.java │ │ ├── BoxPlotActivity.java │ │ ├── CustomArcsActivity.java │ │ ├── DrawPolygonActivity.java │ │ ├── GrowingLineChartActivity.java │ │ ├── MultipleAreasActivity.java │ │ ├── MultipleBarChartsActivity.java │ │ ├── ObjectArcsActivity.java │ │ ├── RectangleActionsActivity.java │ │ └── TurningArcsActivity.java │ │ └── adapter │ │ ├── ActivityView.java │ │ ├── ActivityViewHolder.java │ │ ├── ActivityViewModel.java │ │ └── RecyclerAdapter.java │ └── res │ ├── drawable │ └── ic_right_chevron.xml │ ├── layout │ ├── activity_menu.xml │ ├── activity_view.xml │ ├── demo_activity.xml │ ├── demo_message_activity.xml │ └── view_activity.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── devApp ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── fabernovel │ │ └── d3library │ │ └── dev_app │ │ └── MainActivity.java │ └── res │ ├── layout │ └── main_activity.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── fabernovel │ │ └── d3library │ │ ├── D3Drawable.java │ │ ├── D3View.java │ │ ├── action │ │ ├── OnClickAction.java │ │ ├── OnPinchAction.java │ │ ├── OnScrollAction.java │ │ ├── PinchType.java │ │ └── ScrollDirection.java │ │ ├── arc │ │ ├── AngleBitmapValueRunnable.java │ │ ├── Angles.java │ │ ├── AnglesValueRunnable.java │ │ ├── ColorsRunnable.java │ │ ├── D3Arc.java │ │ ├── D3ArcDrawer.java │ │ ├── InnerRadiusValueRunnable.java │ │ ├── LabelsCoordinates.java │ │ ├── LabelsRunnable.java │ │ ├── LabelsValueRunnable.java │ │ ├── OffsetXValueRunnable.java │ │ ├── OffsetYValueRunnable.java │ │ └── OuterRadiusValueRunnable.java │ │ ├── area │ │ ├── AreaBitmapValueRunnable.java │ │ └── D3Area.java │ │ ├── axes │ │ ├── AxisBitmapValueRunnable.java │ │ ├── AxisDefaultInitializer.java │ │ ├── AxisOrientation.java │ │ ├── D3Axis.java │ │ ├── D3AxisActionsInitializer.java │ │ ├── D3AxisDrawer.java │ │ ├── D3DomainFunction.java │ │ ├── D3FloatFunction.java │ │ ├── D3RangeFunction.java │ │ ├── HorizontalAlignment.java │ │ ├── LegendProperties.java │ │ ├── TicksValueRunnable.java │ │ └── VerticalAlignment.java │ │ ├── barchart │ │ ├── D3BarChart.java │ │ ├── D3StackBarChart.java │ │ └── FloatsValueRunnable.java │ │ ├── boxplot │ │ ├── D3BoxPlot.java │ │ ├── Statistics.java │ │ └── StatisticsComputer.java │ │ ├── curve │ │ ├── D3Curve.java │ │ ├── GetTicksXRunnable.java │ │ └── GetTicksYRunnable.java │ │ ├── helper │ │ ├── ArrayConverterHelper.java │ │ ├── ColorHelper.java │ │ └── TextHelper.java │ │ ├── line │ │ ├── CoordinatesValueStorage.java │ │ └── D3Line.java │ │ ├── mappers │ │ ├── D3FloatDataMapperFunction.java │ │ ├── D3IntDataMapperFunction.java │ │ └── D3StringDataMapperFunction.java │ │ ├── polygon │ │ ├── D3Polygon.java │ │ ├── OffsetRunnable.java │ │ └── PolygonBitmapValueRunnable.java │ │ ├── scale │ │ ├── D3Converter.java │ │ ├── D3LabelFunction.java │ │ ├── D3Scale.java │ │ ├── Interpolator.java │ │ ├── LinearInterpolator.java │ │ └── WrapperDomainFunction.java │ │ └── threading │ │ ├── BitmapValueRunnable.java │ │ ├── ThreadPool.java │ │ ├── ValueRunnable.java │ │ └── ValueStorage.java │ └── res │ └── values │ ├── public.xml │ └── strings.xml ├── screenshots ├── arc.png ├── area.png ├── barchart.png ├── boxplot.png ├── line.gif ├── line.png ├── polygon.gif ├── stackbarchart.png └── turningarcs.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | .idea/ -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /demo/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | android { 20 | compileSdkVersion 25 21 | buildToolsVersion "26.0.0" 22 | 23 | defaultConfig { 24 | applicationId "com.fabernovel.d3library.demo" 25 | minSdkVersion 18 26 | targetSdkVersion 25 27 | versionCode 1 28 | versionName "1.0" 29 | 30 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 31 | 32 | } 33 | buildTypes { 34 | release { 35 | minifyEnabled false 36 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 37 | } 38 | } 39 | } 40 | 41 | dependencies { 42 | compile fileTree(dir: 'libs', include: ['*.jar']) 43 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 44 | exclude group: 'com.android.support', module: 'support-annotations' 45 | }) 46 | compile 'com.android.support:appcompat-v7:25.0.0' 47 | compile 'com.android.support:recyclerview-v7:25.0.0' 48 | compile 'com.android.support:cardview-v7:25.0.0' 49 | 50 | compile 'net.danlew:android.joda:2.9.9' 51 | 52 | compile "com.jakewharton:butterknife-compiler:8.4.0" 53 | compile "com.jakewharton:butterknife:8.4.0" 54 | 55 | compile "io.norberg:auto-matter:0.13.3" 56 | testCompile 'junit:junit:4.12' 57 | compile 'javax.annotation:javax.annotation-api:1.2' 58 | compile project(path: ':library') 59 | } 60 | -------------------------------------------------------------------------------- /demo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 49 | 50 | 54 | 55 | 59 | 60 | 64 | 65 | 69 | 70 | 74 | 75 | 79 | 80 | 84 | 85 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/MenuActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.Nullable; 22 | import android.support.v7.widget.LinearLayoutManager; 23 | import android.support.v7.widget.RecyclerView; 24 | 25 | import com.fabernovel.d3library.demo.activities.BarChartActivity; 26 | import com.fabernovel.d3library.demo.activities.BoxPlotActivity; 27 | import com.fabernovel.d3library.demo.activities.CustomArcsActivity; 28 | import com.fabernovel.d3library.demo.activities.DrawPolygonActivity; 29 | import com.fabernovel.d3library.demo.activities.GrowingLineChartActivity; 30 | import com.fabernovel.d3library.demo.activities.MultipleAreasActivity; 31 | import com.fabernovel.d3library.demo.activities.MultipleBarChartsActivity; 32 | import com.fabernovel.d3library.demo.activities.ObjectArcsActivity; 33 | import com.fabernovel.d3library.demo.activities.RectangleActionsActivity; 34 | import com.fabernovel.d3library.demo.activities.TurningArcsActivity; 35 | import com.fabernovel.d3library.demo.adapter.ActivityViewModelBuilder; 36 | import com.fabernovel.d3library.demo.adapter.RecyclerAdapter; 37 | 38 | import butterknife.BindView; 39 | import butterknife.ButterKnife; 40 | 41 | public class MenuActivity extends Activity { 42 | @BindView(R.id.recycler) RecyclerView recyclerView; 43 | 44 | private RecyclerAdapter adapter; 45 | 46 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_menu); 49 | ButterKnife.bind(this); 50 | setupRecyclerView(); 51 | } 52 | 53 | private void setupRecyclerView() { 54 | adapter = new RecyclerAdapter(getLayoutInflater()); 55 | recyclerView.setAdapter(adapter); 56 | 57 | RecyclerView.LayoutManager manager = new LinearLayoutManager( 58 | this, LinearLayoutManager.VERTICAL, false 59 | ); 60 | recyclerView.setLayoutManager(manager); 61 | 62 | adapter.addActivity( 63 | new ActivityViewModelBuilder() 64 | .title("Custom arcs") 65 | .activityClass(CustomArcsActivity.class) 66 | .build() 67 | ); 68 | 69 | adapter.addActivity( 70 | new ActivityViewModelBuilder() 71 | .title("Turning arcs") 72 | .activityClass(TurningArcsActivity.class) 73 | .build() 74 | ); 75 | 76 | adapter.addActivity( 77 | new ActivityViewModelBuilder() 78 | .title("Object arcs") 79 | .activityClass(ObjectArcsActivity.class) 80 | .build() 81 | ); 82 | 83 | adapter.addActivity( 84 | new ActivityViewModelBuilder() 85 | .title("Rectangle actions") 86 | .activityClass(RectangleActionsActivity.class) 87 | .build() 88 | ); 89 | 90 | adapter.addActivity( 91 | new ActivityViewModelBuilder() 92 | .title("Sales bar chart") 93 | .activityClass(BarChartActivity.class) 94 | .build() 95 | ); 96 | 97 | adapter.addActivity( 98 | new ActivityViewModelBuilder() 99 | .title("Sales stacking bar charts") 100 | .activityClass(MultipleBarChartsActivity.class) 101 | .build() 102 | ); 103 | 104 | adapter.addActivity( 105 | new ActivityViewModelBuilder() 106 | .title("Growing line chart") 107 | .activityClass(GrowingLineChartActivity.class) 108 | .build() 109 | ); 110 | 111 | adapter.addActivity( 112 | new ActivityViewModelBuilder() 113 | .title("Multiple areas") 114 | .activityClass(MultipleAreasActivity.class) 115 | .build() 116 | ); 117 | 118 | adapter.addActivity( 119 | new ActivityViewModelBuilder() 120 | .title("Draw polygon") 121 | .activityClass(DrawPolygonActivity.class) 122 | .build() 123 | ); 124 | 125 | adapter.addActivity( 126 | new ActivityViewModelBuilder() 127 | .title("Box plot") 128 | .activityClass(BoxPlotActivity.class) 129 | .build() 130 | ); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/BarChartActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | 24 | import com.fabernovel.d3library.demo.R; 25 | import com.fabernovel.d3library.D3View; 26 | import com.fabernovel.d3library.axes.AxisOrientation; 27 | import com.fabernovel.d3library.axes.D3Axis; 28 | import com.fabernovel.d3library.axes.D3FloatFunction; 29 | import com.fabernovel.d3library.axes.HorizontalAlignment; 30 | import com.fabernovel.d3library.barchart.D3BarChart; 31 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 32 | import com.fabernovel.d3library.scale.D3Converter; 33 | import com.fabernovel.d3library.scale.D3LabelFunction; 34 | 35 | import org.joda.time.DateTime; 36 | 37 | import butterknife.BindView; 38 | import butterknife.ButterKnife; 39 | 40 | public class BarChartActivity extends Activity { 41 | private static final int MAXIMUM_SALES = 500; 42 | private static final int FRUIT_NUMBER = 3; 43 | private static final int DEFAULT_DATA_NUMBER = 4; 44 | 45 | @BindView(R.id.d3view) D3View view; 46 | 47 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.demo_activity); 50 | ButterKnife.bind(this); 51 | 52 | final D3Axis salesAxis = 53 | new D3Axis<>(AxisOrientation.RIGHT, Integer.class) 54 | .domain(new Integer[]{0, FRUIT_NUMBER * MAXIMUM_SALES}); 55 | 56 | final D3Axis timeAxis = 57 | new D3Axis(AxisOrientation.BOTTOM) 58 | .domain(new DateTime[]{new DateTime(), new DateTime().plusDays(5)}) 59 | .ticks(DEFAULT_DATA_NUMBER + 2) 60 | .converter(getDateTimeConverter()) 61 | .onScrollAction(null) 62 | .onPinchAction(null) 63 | .labelFunction(new D3LabelFunction() { 64 | String format = "dd/MM/yyyy"; 65 | 66 | @Override public String getLabel(DateTime object) { 67 | return object.toString(format); 68 | } 69 | }) 70 | .legendHorizontalAlignment(HorizontalAlignment.CENTER); 71 | 72 | Sales[] sales = buildSales(DEFAULT_DATA_NUMBER); 73 | D3BarChart stackBarChart = 74 | new D3BarChart<>(sales) 75 | .x(new D3FloatDataMapperFunction() { 76 | @Override public float compute(Sales object, int position, Sales[] data) { 77 | return timeAxis.scale().value(object.date); 78 | } 79 | }) 80 | .y(new D3FloatDataMapperFunction() { 81 | @Override public float compute(Sales object, int position, Sales[] data) { 82 | return salesAxis.scale().value(0); 83 | } 84 | }) 85 | .dataWidth(new D3FloatFunction() { 86 | @Override public float getFloat() { 87 | float[] range = timeAxis.range(); 88 | return (range[1] - range[0]) / (1.25F * timeAxis.ticks()); 89 | } 90 | }) 91 | .dataHeight(new D3FloatDataMapperFunction() { 92 | @Override public float compute( 93 | Sales object, int position, Sales[] data 94 | ) { 95 | return salesAxis.scale().value(0) - salesAxis.scale().value( 96 | object.apples + object.bananas + object.strawberries 97 | ); 98 | } 99 | }) 100 | .setClipRect( 101 | new D3FloatFunction() { 102 | @Override public float getFloat() { 103 | return 0.05f * view.getWidth(); 104 | } 105 | }, 106 | new D3FloatFunction() { 107 | @Override public float getFloat() { 108 | return 0F; 109 | } 110 | }, 111 | new D3FloatFunction() { 112 | @Override public float getFloat() { 113 | return 0.95f * view.getWidth(); 114 | } 115 | }, 116 | new D3FloatFunction() { 117 | @Override public float getFloat() { 118 | return view.getHeight() * 0.95f; 119 | } 120 | } 121 | ); 122 | view.add(stackBarChart); 123 | view.add(salesAxis); 124 | view.add(timeAxis); 125 | } 126 | 127 | @NonNull private D3Converter getDateTimeConverter() { 128 | return new D3Converter() { 129 | @Override public float convert(DateTime toConvert) { 130 | return toConvert.getMillis(); 131 | } 132 | 133 | @Override public DateTime invert(float toInvert) { 134 | return new DateTime().withMillis((long) toInvert); 135 | } 136 | }; 137 | } 138 | 139 | @NonNull private Sales[] buildSales(int size) { 140 | Sales[] result = new Sales[size]; 141 | for (int i = 0; i < size; i++) { 142 | result[i] = new Sales( 143 | new DateTime().plusDays(i + 1), 144 | (int) (Math.random() * MAXIMUM_SALES), 145 | (int) (Math.random() * MAXIMUM_SALES), 146 | (int) (Math.random() * MAXIMUM_SALES) 147 | ); 148 | } 149 | return result; 150 | } 151 | 152 | static class Sales { 153 | @NonNull final DateTime date; 154 | final int apples; 155 | final int bananas; 156 | final int strawberries; 157 | 158 | private Sales( 159 | @NonNull DateTime date, int soldApples, int soldBananas, int soldStrawberries 160 | ) { 161 | this.date = date; 162 | apples = soldApples; 163 | bananas = soldBananas; 164 | strawberries = soldStrawberries; 165 | } 166 | } 167 | 168 | @Override protected void onResume() { 169 | super.onResume(); 170 | view.onResume(); 171 | } 172 | 173 | @Override protected void onPause() { 174 | super.onPause(); 175 | view.onPause(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/BoxPlotActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | import android.widget.TextView; 24 | 25 | import com.fabernovel.d3library.demo.R; 26 | import com.fabernovel.d3library.D3View; 27 | import com.fabernovel.d3library.action.OnClickAction; 28 | import com.fabernovel.d3library.axes.AxisOrientation; 29 | import com.fabernovel.d3library.axes.D3Axis; 30 | import com.fabernovel.d3library.axes.D3FloatFunction; 31 | import com.fabernovel.d3library.boxplot.D3BoxPlot; 32 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 33 | 34 | import org.joda.time.DateTime; 35 | 36 | import butterknife.BindView; 37 | import butterknife.ButterKnife; 38 | 39 | public class BoxPlotActivity extends Activity { 40 | private static final float MAXIMUM_SALES = 500F; 41 | private static final int DEFAULT_DATA_NUMBER = 4; 42 | 43 | @BindView(R.id.d3view) D3View view; 44 | @BindView(R.id.message) TextView message; 45 | 46 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.demo_message_activity); 49 | ButterKnife.bind(this); 50 | 51 | message.setText(getString(R.string.multiple_areas_activity_message)); 52 | 53 | final D3Axis salesAxis = 54 | new D3Axis<>(AxisOrientation.RIGHT, Float.class) 55 | .domain(new Float[]{0F, MAXIMUM_SALES}); 56 | 57 | final Sales[] sales = buildSales(DEFAULT_DATA_NUMBER, new Sales[0]); 58 | 59 | final D3BoxPlot applesBoxPlot = 60 | new D3BoxPlot<>(sales) 61 | .dataWidth(new D3FloatFunction() { 62 | @Override public float getFloat() { 63 | return view.getWidth() * 0.20F; 64 | } 65 | }) 66 | .offsetX(new D3FloatFunction() { 67 | @Override public float getFloat() { 68 | return view.getWidth() * 0.10F; 69 | } 70 | }) 71 | .dataMapper(new D3FloatDataMapperFunction() { 72 | @Override public float compute(Sales object, int position, Sales[] data) { 73 | return object.apples; 74 | } 75 | }) 76 | .scale(salesAxis.scale()); 77 | applesBoxPlot.paint().setColor(0xFF99CC00); 78 | 79 | final D3BoxPlot bananasBoxPlot = 80 | new D3BoxPlot<>(sales) 81 | .dataWidth(new D3FloatFunction() { 82 | @Override public float getFloat() { 83 | return view.getWidth() * 0.20F; 84 | } 85 | }) 86 | .offsetX(new D3FloatFunction() { 87 | @Override public float getFloat() { 88 | return view.getWidth() * 0.40F; 89 | } 90 | }) 91 | .dataMapper(new D3FloatDataMapperFunction() { 92 | @Override public float compute(Sales object, int position, Sales[] data) { 93 | return object.bananas; 94 | } 95 | }) 96 | .scale(salesAxis.scale()); 97 | bananasBoxPlot.paint().setColor(0xFFFFFF00); 98 | 99 | final D3BoxPlot strawberriesBoxPlot = 100 | new D3BoxPlot<>(sales) 101 | .dataWidth(new D3FloatFunction() { 102 | @Override public float getFloat() { 103 | return view.getWidth() * 0.20F; 104 | } 105 | }) 106 | .offsetX(new D3FloatFunction() { 107 | @Override public float getFloat() { 108 | return view.getWidth() * 0.70F; 109 | } 110 | }) 111 | .dataMapper(new D3FloatDataMapperFunction() { 112 | @Override public float compute(Sales object, int position, Sales[] data) { 113 | return object.strawberries; 114 | } 115 | }) 116 | .scale(salesAxis.scale()); 117 | strawberriesBoxPlot.paint().setColor(0xFFD20E07); 118 | 119 | applesBoxPlot.onClickAction(new OnClickAction() { 120 | @Override public void onClick(float X, float Y) { 121 | Sales[] data = applesBoxPlot.data(); 122 | Sales[] newData = buildSales(data.length + 1, data); 123 | applesBoxPlot.data(newData); 124 | applesBoxPlot.updateNeeded(); 125 | bananasBoxPlot.data(newData); 126 | bananasBoxPlot.updateNeeded(); 127 | strawberriesBoxPlot.data(newData); 128 | strawberriesBoxPlot.updateNeeded(); 129 | } 130 | }); 131 | 132 | view.add(applesBoxPlot); 133 | view.add(bananasBoxPlot); 134 | view.add(strawberriesBoxPlot); 135 | view.add(salesAxis); 136 | } 137 | 138 | @NonNull private Sales[] buildSales(int size, Sales[] first) { 139 | Sales[] result = new Sales[size]; 140 | for (int i = 0; i < first.length; i++) { 141 | result[i] = first[i]; 142 | } 143 | for (int i = first.length; i < size; i++) { 144 | result[i] = new Sales( 145 | new DateTime().plusDays(i), 146 | (int) (Math.random() * MAXIMUM_SALES / 2 + MAXIMUM_SALES / 4), 147 | (int) (Math.random() * MAXIMUM_SALES * 2 / 3 + MAXIMUM_SALES / 6), 148 | (int) (Math.random() * MAXIMUM_SALES) 149 | ); 150 | } 151 | return result; 152 | } 153 | 154 | static class Sales { 155 | @NonNull final DateTime date; 156 | final int apples; 157 | final int bananas; 158 | final int strawberries; 159 | 160 | private Sales( 161 | @NonNull DateTime date, int soldApples, int soldBananas, int soldStrawberries 162 | ) { 163 | this.date = date; 164 | apples = soldApples; 165 | bananas = soldBananas; 166 | strawberries = soldStrawberries; 167 | } 168 | } 169 | 170 | @Override protected void onResume() { 171 | super.onResume(); 172 | view.onResume(); 173 | } 174 | 175 | @Override protected void onPause() { 176 | super.onPause(); 177 | view.onPause(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/CustomArcsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.Nullable; 22 | 23 | import com.fabernovel.d3library.demo.R; 24 | import com.fabernovel.d3library.D3View; 25 | import com.fabernovel.d3library.arc.D3Arc; 26 | import com.fabernovel.d3library.axes.D3FloatFunction; 27 | 28 | import butterknife.BindView; 29 | import butterknife.ButterKnife; 30 | 31 | public class CustomArcsActivity extends Activity { 32 | private static final int DATA_LENGTH = 5; 33 | 34 | @BindView(R.id.d3view) D3View view; 35 | 36 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.demo_activity); 39 | ButterKnife.bind(this); 40 | 41 | Float[] data = new Float[DATA_LENGTH]; 42 | float[] weights = new float[DATA_LENGTH]; 43 | for (int i = 0; i < DATA_LENGTH; i++) { 44 | data[i] = (float) i + 1; 45 | weights[i] = (float) i + 1; 46 | } 47 | 48 | final D3Arc arc = new D3Arc<>(data) 49 | .weights(weights) 50 | .offsetX(new D3FloatFunction() { 51 | @Override public float getFloat() { 52 | return view.getHeight() <= view.getWidth() ? 53 | (view.getWidth() - view.getHeight()) * 2 / 3F : 54 | view.getWidth() / 6F; 55 | } 56 | }) 57 | .offsetY(new D3FloatFunction() { 58 | @Override public float getFloat() { 59 | return view.getWidth() <= view.getHeight() ? 60 | (view.getHeight() - view.getWidth()) * 2 / 3F : 61 | view.getHeight() / 6F; 62 | } 63 | }) 64 | .innerRadius(new D3FloatFunction() { 65 | @Override public float getFloat() { 66 | return Math.min(view.getWidth(), view.getHeight()) / 6F; 67 | } 68 | }) 69 | .outerRadius(new D3FloatFunction() { 70 | @Override public float getFloat() { 71 | return Math.min(view.getWidth(), view.getHeight()) * 2F / 6F; 72 | } 73 | }) 74 | .padAngle(0) 75 | .colors(new int[]{ 76 | 0xFF0066CC, 0xFF7F00FF, 0xFFCD7F32, 0xFFC0C0C0, 0xFFFFD700 77 | }) 78 | .labels(new String[]{"Label1", "Label2", "Label3", "Label4", "Label5"}); 79 | view.add(arc); 80 | } 81 | 82 | @Override protected void onResume() { 83 | super.onResume(); 84 | view.onResume(); 85 | } 86 | 87 | @Override protected void onPause() { 88 | super.onPause(); 89 | view.onPause(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/DrawPolygonActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | import android.widget.TextView; 24 | 25 | import com.fabernovel.d3library.demo.R; 26 | import com.fabernovel.d3library.D3View; 27 | import com.fabernovel.d3library.action.OnClickAction; 28 | import com.fabernovel.d3library.action.OnPinchAction; 29 | import com.fabernovel.d3library.action.OnScrollAction; 30 | import com.fabernovel.d3library.action.PinchType; 31 | import com.fabernovel.d3library.action.ScrollDirection; 32 | import com.fabernovel.d3library.polygon.D3Polygon; 33 | 34 | import butterknife.BindView; 35 | import butterknife.ButterKnife; 36 | 37 | public class DrawPolygonActivity extends Activity { 38 | @BindView(R.id.d3view) D3View view; 39 | @BindView(R.id.message) TextView message; 40 | 41 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.demo_message_activity); 44 | ButterKnife.bind(this); 45 | message.setText(getString(R.string.drawing_polygon_activity_message)); 46 | 47 | final D3Polygon polygon = new D3Polygon(new float[0]) 48 | .lazyRecomputing(false); 49 | polygon 50 | .onClickAction(new OnClickAction() { 51 | @Override public void onClick(float X, float Y) { 52 | AddPoint(X, Y, polygon); 53 | } 54 | }) 55 | .onScrollAction(new OnScrollAction() { 56 | private static final int FREQUENCY_TAKEN_POINT = 5; 57 | int count = 0; 58 | 59 | @Override public void onScroll( 60 | ScrollDirection direction, float coordinateX, float coordinateY, 61 | float dX, float dY 62 | ) { 63 | if (count == 0) { 64 | AddPoint(coordinateX, coordinateY, polygon); 65 | } 66 | count = (count + 1) % FREQUENCY_TAKEN_POINT; 67 | } 68 | }) 69 | .onPinchAction(new OnPinchAction() { 70 | @Override public void onPinch( 71 | PinchType pinchType, float coordinateStaticX, float coordinateStaticY, 72 | float coordinateMobileX, float coordinateMobileY, float dX, float dY 73 | ) { 74 | polygon.coordinates(new float[0]); 75 | } 76 | }); 77 | 78 | view.add(polygon); 79 | } 80 | 81 | private void AddPoint(float x, float y, @NonNull D3Polygon polygon) { 82 | float[] coordinates = polygon.coordinates(); 83 | float[] newCoordinates = new float[coordinates.length + 2]; 84 | for (int i = 0; i < coordinates.length; i++) { 85 | newCoordinates[i] = coordinates[i]; 86 | } 87 | newCoordinates[coordinates.length] = x; 88 | newCoordinates[coordinates.length + 1] = y; 89 | polygon.coordinates(newCoordinates); 90 | } 91 | 92 | @Override protected void onResume() { 93 | super.onResume(); 94 | view.onResume(); 95 | } 96 | 97 | @Override protected void onPause() { 98 | super.onPause(); 99 | view.onPause(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/GrowingLineChartActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.animation.ValueAnimator; 20 | import android.app.Activity; 21 | import android.os.Bundle; 22 | import android.support.annotation.NonNull; 23 | import android.support.annotation.Nullable; 24 | 25 | import com.fabernovel.d3library.demo.R; 26 | import com.fabernovel.d3library.D3View; 27 | import com.fabernovel.d3library.axes.AxisOrientation; 28 | import com.fabernovel.d3library.axes.D3Axis; 29 | import com.fabernovel.d3library.axes.D3FloatFunction; 30 | import com.fabernovel.d3library.axes.HorizontalAlignment; 31 | import com.fabernovel.d3library.line.D3Line; 32 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 33 | import com.fabernovel.d3library.scale.D3Converter; 34 | import com.fabernovel.d3library.scale.D3LabelFunction; 35 | 36 | import org.joda.time.DateTime; 37 | 38 | import butterknife.BindView; 39 | import butterknife.ButterKnife; 40 | 41 | public class GrowingLineChartActivity extends Activity { 42 | private static final int MAXIMUM_SALES = 500; 43 | private static final int FRUIT_NUMBER = 3; 44 | private static final int DEFAULT_DATA_NUMBER = 150; 45 | private static final int ANIMATION_TIME = 2500; 46 | 47 | @BindView(R.id.d3view) D3View view; 48 | 49 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | setContentView(R.layout.demo_activity); 52 | ButterKnife.bind(this); 53 | 54 | final D3Axis salesAxis = 55 | new D3Axis<>(AxisOrientation.RIGHT, Integer.class) 56 | .domain(new Integer[]{0, FRUIT_NUMBER * MAXIMUM_SALES}); 57 | 58 | final D3Axis timeAxis = 59 | new D3Axis(AxisOrientation.BOTTOM) 60 | .domain(new DateTime[]{ 61 | new DateTime().plusDays(DEFAULT_DATA_NUMBER / 3), 62 | new DateTime().plusDays(DEFAULT_DATA_NUMBER * 2 / 3) 63 | }) 64 | .converter(getDateTimeConverter()) 65 | .labelFunction(new D3LabelFunction() { 66 | String format = "dd/MM/yyyy hh:mm:ss"; 67 | 68 | @Override public String getLabel(DateTime object) { 69 | return object.toString(format); 70 | } 71 | }) 72 | .legendHorizontalAlignment(HorizontalAlignment.CENTER); 73 | 74 | Sales[] sales = buildSales(DEFAULT_DATA_NUMBER); 75 | D3Line line = 76 | new D3Line(sales) 77 | .x(new D3FloatDataMapperFunction() { 78 | @Override public float compute(Sales object, int position, Sales[] data) { 79 | return timeAxis.scale().value(object.date); 80 | } 81 | }) 82 | .y(new D3FloatDataMapperFunction() { 83 | @Override public float compute( 84 | Sales object, int position, Sales[] data 85 | ) { 86 | return salesAxis.scale().value( 87 | (int) object.strawberries.getAnimatedValue() 88 | + (int) object.apples.getAnimatedValue() 89 | + (int) object.bananas.getAnimatedValue() 90 | ); 91 | } 92 | }) 93 | .setClipRect( 94 | new D3FloatFunction() { 95 | @Override public float getFloat() { 96 | return 0.05f * view.getWidth(); 97 | } 98 | }, 99 | new D3FloatFunction() { 100 | @Override public float getFloat() { 101 | return 0F; 102 | } 103 | }, 104 | new D3FloatFunction() { 105 | @Override public float getFloat() { 106 | return view.getWidth(); 107 | } 108 | }, 109 | new D3FloatFunction() { 110 | @Override public float getFloat() { 111 | return view.getHeight() * 0.95f; 112 | } 113 | } 114 | ) 115 | .lazyRecomputing(false); 116 | line.paint().setColor(0xFF0066CC); 117 | view.add(line); 118 | view.add(salesAxis); 119 | view.add(timeAxis); 120 | } 121 | 122 | @NonNull private D3Converter getDateTimeConverter() { 123 | return new D3Converter() { 124 | @Override public float convert(DateTime toConvert) { 125 | return toConvert.getMillis(); 126 | } 127 | 128 | @Override public DateTime invert(float toInvert) { 129 | return new DateTime().withMillis((long) toInvert); 130 | } 131 | }; 132 | } 133 | 134 | @NonNull private Sales[] buildSales(int size) { 135 | Sales[] result = new Sales[size]; 136 | for (int i = 0; i < size; i++) { 137 | result[i] = new Sales( 138 | new DateTime().plusDays(i + 1), 139 | (int) (Math.random() * MAXIMUM_SALES), 140 | (int) (Math.random() * MAXIMUM_SALES), 141 | (int) (Math.random() * MAXIMUM_SALES) 142 | ); 143 | } 144 | return result; 145 | } 146 | 147 | static class Sales { 148 | @NonNull final DateTime date; 149 | final ValueAnimator apples; 150 | final ValueAnimator bananas; 151 | final ValueAnimator strawberries; 152 | 153 | private Sales( 154 | @NonNull DateTime date, int soldApples, int soldBananas, int soldStrawberries 155 | ) { 156 | this.date = date; 157 | apples = setupAnimator(soldApples); 158 | bananas = setupAnimator(soldBananas); 159 | strawberries = setupAnimator(soldStrawberries); 160 | } 161 | 162 | private static ValueAnimator setupAnimator(int apples) { 163 | ValueAnimator result = ValueAnimator.ofInt(0, apples); 164 | result.setDuration(ANIMATION_TIME); 165 | result.start(); 166 | return result; 167 | } 168 | } 169 | 170 | @Override protected void onResume() { 171 | super.onResume(); 172 | view.onResume(); 173 | } 174 | 175 | @Override protected void onPause() { 176 | super.onPause(); 177 | view.onPause(); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/MultipleBarChartsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | 24 | import com.fabernovel.d3library.demo.R; 25 | import com.fabernovel.d3library.D3View; 26 | import com.fabernovel.d3library.axes.AxisOrientation; 27 | import com.fabernovel.d3library.axes.D3Axis; 28 | import com.fabernovel.d3library.axes.D3FloatFunction; 29 | import com.fabernovel.d3library.axes.HorizontalAlignment; 30 | import com.fabernovel.d3library.barchart.D3StackBarChart; 31 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 32 | import com.fabernovel.d3library.scale.D3Converter; 33 | import com.fabernovel.d3library.scale.D3LabelFunction; 34 | 35 | import org.joda.time.DateTime; 36 | 37 | import java.util.ArrayList; 38 | import java.util.List; 39 | 40 | import butterknife.BindView; 41 | import butterknife.ButterKnife; 42 | 43 | public class MultipleBarChartsActivity extends Activity { 44 | private static final int MAXIMUM_SALES = 500; 45 | private static final int FRUIT_NUMBER = 3; 46 | private static final int DEFAULT_DATA_NUMBER = 4; 47 | 48 | @BindView(R.id.d3view) D3View view; 49 | 50 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.demo_activity); 53 | ButterKnife.bind(this); 54 | 55 | final D3Axis salesAxis = 56 | new D3Axis<>(AxisOrientation.RIGHT, Integer.class) 57 | .domain(new Integer[]{0, FRUIT_NUMBER * MAXIMUM_SALES}); 58 | 59 | final D3Axis timeAxis = 60 | new D3Axis(AxisOrientation.BOTTOM) 61 | .domain(new DateTime[]{new DateTime(), new DateTime().plusDays(5)}) 62 | .ticks(DEFAULT_DATA_NUMBER + 2) 63 | .converter(getDateTimeConverter()) 64 | .onScrollAction(null) 65 | .onPinchAction(null) 66 | .labelFunction(new D3LabelFunction() { 67 | String format = "dd/MM/yyyy"; 68 | 69 | @Override public String getLabel(DateTime object) { 70 | return object.toString(format); 71 | } 72 | }) 73 | .legendHorizontalAlignment(HorizontalAlignment.CENTER); 74 | 75 | List> heights = new ArrayList<>(); 76 | heights.add( 77 | new D3FloatDataMapperFunction() { 78 | @Override public float compute(Sales object, int position, Sales[] data) { 79 | return salesAxis.scale().value(0) - salesAxis.scale().value(object.bananas); 80 | } 81 | }); 82 | heights.add( 83 | new D3FloatDataMapperFunction() { 84 | @Override public float compute(Sales object, int position, Sales[] data) { 85 | return salesAxis.scale().value(0) - salesAxis.scale().value(object.apples); 86 | } 87 | }); 88 | heights.add( 89 | new D3FloatDataMapperFunction() { 90 | @Override public float compute(Sales object, int position, Sales[] data) { 91 | return salesAxis.scale().value(0) - 92 | salesAxis.scale().value(object.strawberries); 93 | } 94 | }); 95 | 96 | Sales[] sales = buildSales(DEFAULT_DATA_NUMBER); 97 | D3StackBarChart stackBarChart = 98 | new D3StackBarChart<>(sales, FRUIT_NUMBER) 99 | .x(new D3FloatDataMapperFunction() { 100 | @Override public float compute(Sales object, int position, Sales[] data) { 101 | return timeAxis.scale().value(object.date); 102 | } 103 | }) 104 | .y(new D3FloatDataMapperFunction() { 105 | @Override public float compute(Sales object, int position, Sales[] data) { 106 | return salesAxis.scale().value(0); 107 | } 108 | }) 109 | .dataWidth(new D3FloatFunction() { 110 | @Override public float getFloat() { 111 | float[] range = timeAxis.range(); 112 | return (range[1] - range[0]) / (1.25F * timeAxis.ticks()); 113 | } 114 | }) 115 | .colors(new int[][]{ 116 | new int[]{0xFFFFFF00}, 117 | new int[]{0xFF99CC00}, 118 | new int[]{0xFFD20E07} 119 | }) 120 | .setClipRect( 121 | new D3FloatFunction() { 122 | @Override public float getFloat() { 123 | return 0.05f * view.getWidth(); 124 | } 125 | }, 126 | new D3FloatFunction() { 127 | @Override public float getFloat() { 128 | return 0F; 129 | } 130 | }, 131 | new D3FloatFunction() { 132 | @Override public float getFloat() { 133 | return 0.95f * view.getWidth(); 134 | } 135 | }, 136 | new D3FloatFunction() { 137 | @Override public float getFloat() { 138 | return view.getHeight() * 0.95f; 139 | } 140 | } 141 | ) 142 | .dataHeight(heights); 143 | view.add(stackBarChart); 144 | view.add(salesAxis); 145 | view.add(timeAxis); 146 | } 147 | 148 | @NonNull private D3Converter getDateTimeConverter() { 149 | return new D3Converter() { 150 | @Override public float convert(DateTime toConvert) { 151 | return toConvert.getMillis(); 152 | } 153 | 154 | @Override public DateTime invert(float toInvert) { 155 | return new DateTime().withMillis((long) toInvert); 156 | } 157 | }; 158 | } 159 | 160 | @NonNull private Sales[] buildSales(int size) { 161 | Sales[] result = new Sales[size]; 162 | for (int i = 0; i < size; i++) { 163 | result[i] = new Sales( 164 | new DateTime().plusDays(i + 1), 165 | (int) (Math.random() * MAXIMUM_SALES), 166 | (int) (Math.random() * MAXIMUM_SALES), 167 | (int) (Math.random() * MAXIMUM_SALES) 168 | ); 169 | } 170 | return result; 171 | } 172 | 173 | static class Sales { 174 | @NonNull final DateTime date; 175 | final int apples; 176 | final int bananas; 177 | final int strawberries; 178 | 179 | private Sales( 180 | @NonNull DateTime date, int soldApples, int soldBananas, int soldStrawberries 181 | ) { 182 | this.date = date; 183 | apples = soldApples; 184 | bananas = soldBananas; 185 | strawberries = soldStrawberries; 186 | } 187 | } 188 | 189 | @Override protected void onResume() { 190 | super.onResume(); 191 | view.onResume(); 192 | } 193 | 194 | @Override protected void onPause() { 195 | super.onPause(); 196 | view.onPause(); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/ObjectArcsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | import android.widget.TextView; 24 | 25 | import com.fabernovel.d3library.demo.R; 26 | import com.fabernovel.d3library.D3View; 27 | import com.fabernovel.d3library.action.OnClickAction; 28 | import com.fabernovel.d3library.arc.D3Arc; 29 | import com.fabernovel.d3library.axes.D3FloatFunction; 30 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 31 | import com.fabernovel.d3library.mappers.D3IntDataMapperFunction; 32 | 33 | import butterknife.BindView; 34 | import butterknife.ButterKnife; 35 | 36 | public class ObjectArcsActivity extends Activity { 37 | @BindView(R.id.d3view) D3View view; 38 | @BindView(R.id.message) TextView message; 39 | 40 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.demo_message_activity); 43 | ButterKnife.bind(this); 44 | message.setText(getString(R.string.object_arcs_activity_message)); 45 | 46 | final FruitSale[] data = buildData(); 47 | 48 | final D3Arc arc = new D3Arc<>(data) 49 | .weights(new D3FloatDataMapperFunction() { 50 | @Override public float compute( 51 | FruitSale object, int position, FruitSale[] data 52 | ) { 53 | return object.sales; 54 | } 55 | }) 56 | .innerRadius(new D3FloatFunction() { 57 | @Override public float getFloat() { 58 | return Math.min(view.getWidth(), view.getHeight()) / 4F; 59 | } 60 | }) 61 | .padAngle(10) 62 | .colors(new D3IntDataMapperFunction() { 63 | @Override public int compute( 64 | FruitSale object, int position, FruitSale[] data 65 | ) { 66 | return object.color; 67 | } 68 | }) 69 | .lazyRecomputing(false); 70 | arc.onClickAction(new OnClickAction() { 71 | @Override public void onClick(float X, float Y) { 72 | FruitSale fruitSale = arc.dataFromPosition(X, Y); 73 | if (fruitSale == null) { 74 | int sale = (int) (Math.random() * 3); 75 | data[sale].sales += 5; 76 | } else { 77 | fruitSale.sales += 5; 78 | } 79 | } 80 | }); 81 | view.add(arc); 82 | } 83 | 84 | @NonNull private FruitSale[] buildData() { 85 | return new FruitSale[]{ 86 | new FruitSale("Banana", 0xFFFFFF00), 87 | new FruitSale("Apple", 0xFF99CC00), 88 | new FruitSale("Strawberry", 0xFFD20E07) 89 | }; 90 | } 91 | 92 | @Override protected void onResume() { 93 | super.onResume(); 94 | view.onResume(); 95 | } 96 | 97 | @Override protected void onPause() { 98 | super.onPause(); 99 | view.onPause(); 100 | } 101 | 102 | private static class FruitSale { 103 | private String fruitName; 104 | private int sales; 105 | private int color; 106 | 107 | FruitSale(String fruitName, int color) { 108 | this.fruitName = fruitName; 109 | this.sales = 10; 110 | this.color = color; 111 | } 112 | 113 | @Override public String toString() { 114 | return fruitName + " (" + sales + ")"; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/RectangleActionsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.annotation.Nullable; 22 | import android.widget.TextView; 23 | 24 | import com.fabernovel.d3library.demo.R; 25 | import com.fabernovel.d3library.D3View; 26 | import com.fabernovel.d3library.action.OnPinchAction; 27 | import com.fabernovel.d3library.action.OnScrollAction; 28 | import com.fabernovel.d3library.action.PinchType; 29 | import com.fabernovel.d3library.action.ScrollDirection; 30 | import com.fabernovel.d3library.axes.D3FloatFunction; 31 | import com.fabernovel.d3library.polygon.D3Polygon; 32 | 33 | import butterknife.BindView; 34 | import butterknife.ButterKnife; 35 | 36 | public class RectangleActionsActivity extends Activity { 37 | private static final int FPS = 40; 38 | private static final int TIME_PER_FRAME = 1000 / FPS; 39 | private static final float RECTANGLE_DIMENSION = 400F; 40 | @BindView(R.id.d3view) D3View view; 41 | @BindView(R.id.message) TextView message; 42 | 43 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.demo_message_activity); 46 | ButterKnife.bind(this); 47 | 48 | message.setText(getString(R.string.rectangle_actions_activity_message)); 49 | 50 | final float[] coordinatesX = new float[4]; 51 | setXCoordinates(coordinatesX, 0F, RECTANGLE_DIMENSION); 52 | final float[] coordinatesY = new float[4]; 53 | setYCoordinates(coordinatesY, 0F, RECTANGLE_DIMENSION); 54 | 55 | 56 | final Float[] offsetX = new Float[]{0F}; 57 | final Float[] offsetY = new Float[]{0F}; 58 | 59 | final D3Polygon polygon = new D3Polygon() 60 | .x(coordinatesX) 61 | .y(coordinatesY) 62 | .offsetX(new D3FloatFunction() { 63 | @Override public float getFloat() { 64 | return offsetX[0]; 65 | } 66 | }) 67 | .offsetY(new D3FloatFunction() { 68 | @Override public float getFloat() { 69 | return offsetY[0]; 70 | } 71 | }) 72 | .lazyRecomputing(false); 73 | polygon 74 | .onScrollAction(new OnScrollAction() { 75 | @Override public void onScroll( 76 | ScrollDirection direction, 77 | float coordinateX, 78 | float coordinateY, 79 | float dX, 80 | float dY 81 | ) { 82 | offsetX[0] += dX; 83 | offsetY[0] += dY; 84 | } 85 | }) 86 | .onPinchAction(new OnPinchAction() { 87 | private float leftCoordinate = 0F; 88 | private float rightCoordinate = RECTANGLE_DIMENSION; 89 | private float topCoordinate = 0F; 90 | private float bottomCoordinate = RECTANGLE_DIMENSION; 91 | 92 | @Override public void onPinch( 93 | PinchType pinchType, float coordinateStaticX, float coordinateStaticY, 94 | float coordinateMobileX, float coordinateMobileY, float dX, float dY 95 | ) { 96 | if (coordinateMobileX < coordinateStaticX) { 97 | leftCoordinate += dX; 98 | } else { 99 | rightCoordinate += dX; 100 | } 101 | if (coordinateMobileY < coordinateStaticY) { 102 | topCoordinate += dY; 103 | } else { 104 | bottomCoordinate += dY; 105 | } 106 | setXCoordinates(coordinatesX, leftCoordinate, rightCoordinate); 107 | setYCoordinates(coordinatesY, topCoordinate, bottomCoordinate); 108 | } 109 | }); 110 | 111 | view.add(polygon); 112 | view.setMinimumTimePerFrame(TIME_PER_FRAME); 113 | } 114 | 115 | private void setXCoordinates( 116 | float[] coordinatesX, float leftCoordinate, float rightCoordinate 117 | ) { 118 | coordinatesX[0] = leftCoordinate; 119 | coordinatesX[1] = rightCoordinate; 120 | coordinatesX[2] = rightCoordinate; 121 | coordinatesX[3] = leftCoordinate; 122 | } 123 | 124 | private void setYCoordinates( 125 | float[] coordinatesY, float topCoordinate, float bottomCoordinate 126 | ) { 127 | coordinatesY[0] = topCoordinate; 128 | coordinatesY[1] = topCoordinate; 129 | coordinatesY[2] = bottomCoordinate; 130 | coordinatesY[3] = bottomCoordinate; 131 | } 132 | 133 | @Override protected void onResume() { 134 | super.onResume(); 135 | view.onResume(); 136 | } 137 | 138 | @Override protected void onPause() { 139 | super.onPause(); 140 | view.onPause(); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/activities/TurningArcsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.activities; 18 | 19 | import android.animation.ValueAnimator; 20 | import android.app.Activity; 21 | import android.os.Bundle; 22 | import android.support.annotation.NonNull; 23 | import android.support.annotation.Nullable; 24 | import android.view.animation.LinearInterpolator; 25 | 26 | import com.fabernovel.d3library.demo.R; 27 | import com.fabernovel.d3library.D3View; 28 | import com.fabernovel.d3library.arc.D3Arc; 29 | import com.fabernovel.d3library.axes.D3FloatFunction; 30 | import com.fabernovel.d3library.mappers.D3StringDataMapperFunction; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | 35 | public class TurningArcsActivity extends Activity { 36 | private static final int ANIMATION_DURATION = 10000; 37 | private static final int DATA_LENGTH = 40; 38 | 39 | @BindView(R.id.d3view) D3View view; 40 | 41 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.demo_activity); 44 | ButterKnife.bind(this); 45 | 46 | final ValueAnimator animator = buildAnimator(); 47 | 48 | Float[] data = new Float[DATA_LENGTH]; 49 | float[] weights = new float[DATA_LENGTH]; 50 | for (int i = 0; i < DATA_LENGTH; i++) { 51 | data[i] = (float) i + 1; 52 | weights[i] = (float) i + 1; 53 | } 54 | 55 | D3Arc arc = 56 | new D3Arc<>(data) 57 | .weights(weights) 58 | .startAngle(new D3FloatFunction() { 59 | @Override public float getFloat() { 60 | return (float) animator.getAnimatedValue(); 61 | } 62 | }) 63 | .labels(new D3StringDataMapperFunction() { 64 | String noLabel = ""; 65 | 66 | @Override public String compute(Float object, int position, Float[] data) { 67 | /* Using a variable rather than returning "" avoids to reallocate a new 68 | * String each time the method is called. */ 69 | return noLabel; 70 | } 71 | }) 72 | .lazyRecomputing(false); 73 | 74 | view.add(arc); 75 | } 76 | 77 | @NonNull private ValueAnimator buildAnimator() { 78 | ValueAnimator startAngleAnimator = ValueAnimator.ofFloat(0F, 360F); 79 | startAngleAnimator.setRepeatMode(ValueAnimator.RESTART); 80 | startAngleAnimator.setRepeatCount(ValueAnimator.INFINITE); 81 | startAngleAnimator.setInterpolator(new LinearInterpolator()); 82 | startAngleAnimator.setDuration(ANIMATION_DURATION); 83 | startAngleAnimator.start(); 84 | return startAngleAnimator; 85 | } 86 | 87 | @Override protected void onResume() { 88 | super.onResume(); 89 | view.onResume(); 90 | } 91 | 92 | @Override protected void onPause() { 93 | super.onPause(); 94 | view.onPause(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/adapter/ActivityView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.adapter; 18 | 19 | import android.content.Context; 20 | import android.content.Intent; 21 | import android.support.annotation.Nullable; 22 | import android.util.AttributeSet; 23 | import android.view.View; 24 | import android.widget.FrameLayout; 25 | import android.widget.TextView; 26 | 27 | import com.fabernovel.d3library.demo.R; 28 | 29 | import butterknife.BindView; 30 | import butterknife.ButterKnife; 31 | 32 | public class ActivityView extends FrameLayout { 33 | @BindView(R.id.title) TextView title; 34 | 35 | public ActivityView(Context context) { 36 | super(context); 37 | init(); 38 | } 39 | 40 | public ActivityView( 41 | Context context, 42 | @Nullable AttributeSet attrs 43 | ) { 44 | super(context, attrs); 45 | init(); 46 | } 47 | 48 | private void init() { 49 | inflate(getContext(), R.layout.view_activity, this); 50 | ButterKnife.bind(this); 51 | } 52 | 53 | public void setTitle(String title) { 54 | this.title.setText(title); 55 | } 56 | 57 | public void setActivity(final Class activityClass) { 58 | setOnClickListener(new OnClickListener() { 59 | @Override public void onClick(View v) { 60 | Intent intent = new Intent(getContext(), activityClass); 61 | getContext().startActivity(intent); 62 | } 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/adapter/ActivityViewHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.adapter; 18 | 19 | import android.support.v7.widget.RecyclerView; 20 | import android.view.View; 21 | 22 | class ActivityViewHolder extends RecyclerView.ViewHolder { 23 | ActivityViewHolder(View itemView) { 24 | super(itemView); 25 | } 26 | 27 | void bindView(ActivityViewModel activityViewModel) { 28 | ((ActivityView) itemView).setTitle(activityViewModel.title()); 29 | ((ActivityView) itemView).setActivity(activityViewModel.activityClass()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/adapter/ActivityViewModel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.adapter; 18 | 19 | import io.norberg.automatter.AutoMatter; 20 | 21 | @AutoMatter 22 | public interface ActivityViewModel { 23 | String title(); 24 | Class activityClass(); 25 | } 26 | -------------------------------------------------------------------------------- /demo/src/main/java/com/fabernovel/d3library/demo/adapter/RecyclerAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.demo.adapter; 18 | 19 | import android.support.v7.widget.RecyclerView; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | 24 | import com.fabernovel.d3library.demo.R; 25 | 26 | import java.util.ArrayList; 27 | import java.util.Collection; 28 | import java.util.List; 29 | 30 | public class RecyclerAdapter extends RecyclerView.Adapter { 31 | private final List activities; 32 | private final LayoutInflater inflater; 33 | 34 | public RecyclerAdapter(LayoutInflater inflater) { 35 | this.inflater = inflater; 36 | activities = new ArrayList<>(); 37 | } 38 | 39 | public void setActivities(Collection collection) { 40 | activities.clear(); 41 | activities.addAll(collection); 42 | notifyDataSetChanged(); 43 | } 44 | 45 | public void addActivity(ActivityViewModel activityViewModel) { 46 | activities.add(activityViewModel); 47 | notifyDataSetChanged(); 48 | } 49 | 50 | @Override public ActivityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 51 | View view = inflater.inflate(R.layout.activity_view, parent, false); 52 | return new ActivityViewHolder(view); 53 | } 54 | 55 | @Override public void onBindViewHolder(ActivityViewHolder holder, int position) { 56 | holder.bindView(activities.get(position)); 57 | } 58 | 59 | @Override public int getItemCount() { 60 | return activities.size(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /demo/src/main/res/drawable/ic_right_chevron.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 25 | 26 | 36 | 37 | 42 | 43 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/activity_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 23 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/demo_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/demo_message_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 31 | 32 | 46 | 47 | -------------------------------------------------------------------------------- /demo/src/main/res/layout/view_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 24 | 25 | 34 | 35 | 42 | 43 | 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /demo/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | #3F51B5 20 | #303F9F 21 | #FF4081 22 | 23 | #FF1B80B3 24 | #FFFFFFFF 25 | #FF000000 26 | 27 | -------------------------------------------------------------------------------- /demo/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 8dp 20 | 16dp 21 | 24dp 22 | 23 | 4dp 24 | 25 | 4sp 26 | 8sp 27 | 12sp 28 | 16sp 29 | 20sp 30 | 24sp 31 | 28sp 32 | 33 | -------------------------------------------------------------------------------- /demo/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | D3Android 19 | D3Android - Demo 20 | Click on a fruit to increase its sales. Click elsewhere in the view to increase the sales of a random fruit. 21 | You can move and resize the rectangle 22 | Click to add generate a new random entry. 23 | Click to add a point at the end of the polygon. Scroll to add multiple points. Pinch to clean the polygon. 24 | 25 | -------------------------------------------------------------------------------- /demo/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /devApp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /devApp/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.fabernovel.d3library.d3_android" 8 | minSdkVersion 21 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile project(':library') 28 | compile 'com.android.support:appcompat-v7:25.2.0' 29 | compile 'net.danlew:android.joda:2.9.9' 30 | compile 'com.android.support.constraint:constraint-layout:1.0.1' 31 | testCompile 'junit:junit:4.12' 32 | } 33 | -------------------------------------------------------------------------------- /devApp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /devApp/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /devApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/devApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /devApp/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /devApp/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | D3_Android 3 | 4 | -------------------------------------------------------------------------------- /devApp/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Mar 28 12:21:32 CEST 2017 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-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | apply plugin: 'com.android.library' 18 | 19 | android { 20 | compileSdkVersion 25 21 | buildToolsVersion "25.0.2" 22 | 23 | defaultConfig { 24 | minSdkVersion 18 25 | targetSdkVersion 25 26 | versionCode 1 27 | versionName "1.0" 28 | 29 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 30 | 31 | } 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | } 39 | 40 | dependencies { 41 | compile fileTree(dir: 'libs', include: ['*.jar']) 42 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 43 | exclude group: 'com.android.support', module: 'support-annotations' 44 | }) 45 | compile 'com.android.support:appcompat-v7:25.2.0' 46 | testCompile 'junit:junit:4.12' 47 | } 48 | -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/action/OnClickAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.action; 18 | 19 | public interface OnClickAction { 20 | void onClick(float X, float Y); 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/action/OnPinchAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.action; 18 | 19 | public interface OnPinchAction { 20 | void onPinch( 21 | PinchType pinchType, 22 | float coordinateStaticX, 23 | float coordinateStaticY, 24 | float coordinateMobileX, 25 | float coordinateMobileY, 26 | float dX, 27 | float dY 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/action/OnScrollAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.action; 18 | 19 | public interface OnScrollAction { 20 | void onScroll( 21 | ScrollDirection direction, 22 | float coordinateX, 23 | float coordinateY, 24 | float dX, 25 | float dY 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/action/PinchType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.action; 18 | 19 | public enum PinchType { 20 | VERTICAL_INCREASE, 21 | VERTICAL_DECREASE, 22 | HORIZONTAL_INCREASE, 23 | HORIZONTAL_DECREASE 24 | } 25 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/action/ScrollDirection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.action; 18 | 19 | public enum ScrollDirection { 20 | TOP, 21 | RIGHT, 22 | BOTTOM, 23 | LEFT 24 | } 25 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/AngleBitmapValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.threading.BitmapValueRunnable; 22 | 23 | 24 | class AngleBitmapValueRunnable extends BitmapValueRunnable { 25 | @NonNull private final D3Arc arc; 26 | 27 | AngleBitmapValueRunnable(@NonNull D3Arc arc) { 28 | this.arc = arc; 29 | } 30 | 31 | @Override protected void computeValue() { 32 | value.eraseColor(0); 33 | D3ArcDrawer.drawArcs( 34 | canvas, arc.innerRadius(), arc.outerRadius(), arc.offsetX(), arc.offsetY(), 35 | arc.preComputedAngles.getValue(), arc.paint(), arc.colors() 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/Angles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | public class Angles { 22 | @NonNull float[] startAngles; 23 | @NonNull float[] drawAngles; 24 | 25 | Angles(int dataNumber) { 26 | startAngles = new float[dataNumber]; 27 | drawAngles = new float[dataNumber]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/AnglesValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.threading.ThreadPool; 22 | import com.fabernovel.d3library.threading.ValueRunnable; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.Executors; 28 | 29 | public class AnglesValueRunnable extends ValueRunnable { 30 | private static final String DATA_ERROR = "Data should not be null."; 31 | private static final String SUM_WEIGHT_ERROR = "Sum of weight must be different from 0"; 32 | private static final float CIRCLE_ANGLE = 360F; 33 | private final FirstHalfAnglesRunnable firstHalfAnglesRunnable; 34 | private final LastHalfAnglesRunnable lastHalfAnglesRunnable; 35 | 36 | @NonNull private final D3Arc arc; 37 | @NonNull private final List> tasks; 38 | 39 | public AnglesValueRunnable(@NonNull D3Arc arc) { 40 | this.arc = arc; 41 | tasks = new ArrayList<>(); 42 | firstHalfAnglesRunnable = new FirstHalfAnglesRunnable(); 43 | lastHalfAnglesRunnable = new LastHalfAnglesRunnable(); 44 | } 45 | 46 | void setDataLength(int length) { 47 | value = new Angles(length); 48 | } 49 | 50 | @Override protected void computeValue() { 51 | value = computeStartAngle(); 52 | } 53 | 54 | private Angles computeStartAngle() { 55 | if (arc.data == null) { 56 | throw new IllegalStateException(DATA_ERROR); 57 | } 58 | final float[] computedWeights = arc.weights(); 59 | float totalWeight = 0F; 60 | for (int i = 0; i < arc.data.length; i++) { 61 | totalWeight += computedWeights[i]; 62 | } 63 | if (totalWeight == 0F) { 64 | throw new IllegalStateException(SUM_WEIGHT_ERROR); 65 | } 66 | 67 | tasks.clear(); 68 | firstHalfAnglesRunnable.setParameters(computedWeights, value, totalWeight); 69 | tasks.add(Executors.callable(firstHalfAnglesRunnable)); 70 | lastHalfAnglesRunnable.setParameters(computedWeights, value, totalWeight); 71 | tasks.add(Executors.callable(lastHalfAnglesRunnable)); 72 | ThreadPool.executeOnSecondaryPool(tasks); 73 | return value; 74 | } 75 | 76 | private class FirstHalfAnglesRunnable implements Runnable { 77 | private float[] computedWeights; 78 | private Angles angles; 79 | private float totalWeight; 80 | 81 | private void setParameters( 82 | float[] computedWeights, Angles angles, float totalWeight 83 | ) { 84 | this.computedWeights = computedWeights; 85 | this.angles = angles; 86 | this.totalWeight = totalWeight; 87 | } 88 | 89 | @Override public void run() { 90 | if (arc.data == null) { 91 | throw new IllegalStateException(DATA_ERROR); 92 | } 93 | 94 | angles.startAngles[0] = (arc.startAngle.getFloat()) % CIRCLE_ANGLE; 95 | if (angles.startAngles[0] < 0.0F) { 96 | angles.startAngles[0] += CIRCLE_ANGLE; 97 | } 98 | angles.drawAngles[0] = (CIRCLE_ANGLE - arc.data.length * arc.padAngle) 99 | * computedWeights[0] / totalWeight; 100 | for (int i = 1; i < arc.data.length / 2; i++) { 101 | angles.startAngles[i] = (angles.startAngles[i - 1] + angles.drawAngles[i - 1] 102 | + arc.padAngle) % CIRCLE_ANGLE; 103 | if (angles.startAngles[i] < 0.0F) { 104 | angles.startAngles[i] += CIRCLE_ANGLE; 105 | } 106 | angles.drawAngles[i] = (CIRCLE_ANGLE - computedWeights.length * arc.padAngle) * 107 | computedWeights[i] / totalWeight; 108 | } 109 | } 110 | } 111 | 112 | private class LastHalfAnglesRunnable implements Runnable { 113 | private float[] computedWeights; 114 | private Angles angles; 115 | private float totalWeight; 116 | 117 | private void setParameters( 118 | float[] computedWeights, Angles angles, float totalWeight 119 | ) { 120 | this.computedWeights = computedWeights; 121 | this.angles = angles; 122 | this.totalWeight = totalWeight; 123 | } 124 | 125 | @Override public void run() { 126 | if (arc.data == null) { 127 | throw new IllegalStateException(DATA_ERROR); 128 | } 129 | 130 | angles.drawAngles[arc.data.length - 1] = (CIRCLE_ANGLE - arc.data.length * arc 131 | .padAngle) 132 | * computedWeights[arc.data.length - 1] / totalWeight; 133 | angles.startAngles[arc.data.length - 1] = (arc.startAngle.getFloat() - arc 134 | .padAngle - angles.drawAngles[arc.data.length - 1]) % CIRCLE_ANGLE; 135 | if (angles.startAngles[arc.data.length - 1] < 0.0F) { 136 | angles.startAngles[arc.data.length - 1] += CIRCLE_ANGLE; 137 | } 138 | for (int i = arc.data.length - 2; i >= arc.data.length / 2; i--) { 139 | angles.drawAngles[i] = (CIRCLE_ANGLE - computedWeights.length * arc.padAngle) * 140 | computedWeights[i] / totalWeight; 141 | 142 | angles.startAngles[i] = (angles.startAngles[i + 1] - angles.drawAngles[i] 143 | - arc.padAngle) % CIRCLE_ANGLE; 144 | if (angles.startAngles[i] < 0.0F) { 145 | angles.startAngles[i] += CIRCLE_ANGLE; 146 | } 147 | } 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/ColorsRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | 20 | import com.fabernovel.d3library.mappers.D3IntDataMapperFunction; 21 | import com.fabernovel.d3library.threading.ValueRunnable; 22 | 23 | class ColorsRunnable extends ValueRunnable { 24 | private final D3Arc arc; 25 | 26 | private D3IntDataMapperFunction mapper; 27 | private boolean areSetLabels; 28 | 29 | ColorsRunnable(D3Arc arc) { 30 | this.arc = arc; 31 | } 32 | 33 | void setDataLength(int length) { 34 | if (areSetLabels) { 35 | return; 36 | } 37 | value = new int[length]; 38 | } 39 | 40 | void setColors(int[] labels) { 41 | areSetLabels = true; 42 | value = labels; 43 | } 44 | 45 | void setDataMapper(D3IntDataMapperFunction mapper) { 46 | this.mapper = mapper; 47 | if (!areSetLabels) { 48 | return; 49 | } 50 | areSetLabels = false; 51 | setDataLength(arc.data == null ? 0 : arc.data.length); 52 | } 53 | 54 | @Override protected void computeValue() { 55 | if (areSetLabels) { 56 | return; 57 | } 58 | 59 | for (int i = 0; i < value.length; i++) { 60 | value[i] = mapper.compute(arc.data[i], i, arc.data); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/D3ArcDrawer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import android.graphics.Canvas; 20 | import android.graphics.Paint; 21 | import android.graphics.RectF; 22 | import android.support.annotation.NonNull; 23 | 24 | final class D3ArcDrawer { 25 | private static RectF rectangle = new RectF(); 26 | 27 | private D3ArcDrawer() {} 28 | 29 | static void drawArcs( 30 | @NonNull Canvas canvas, float innerRadius, float outerRadius, float offsetX, float offsetY, 31 | @NonNull Angles angles, @NonNull Paint paint, int[] colors 32 | ) { 33 | float diffRadius = outerRadius - innerRadius; 34 | paint.setStrokeWidth(diffRadius); 35 | paint.setStyle(Paint.Style.STROKE); 36 | 37 | for (int i = 0; i < angles.drawAngles.length; i++) { 38 | paint.setColor(colors[i % colors.length]); 39 | rectangle.left = offsetX + diffRadius / 2F; 40 | rectangle.top = offsetY + diffRadius / 2F; 41 | rectangle.right = offsetX + 2F * outerRadius - diffRadius / 2F; 42 | rectangle.bottom = offsetY + 2F * outerRadius - diffRadius / 2F; 43 | canvas.drawArc( 44 | rectangle, 45 | angles.startAngles[i], 46 | angles.drawAngles[i], 47 | false, 48 | paint 49 | ); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/InnerRadiusValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | public class InnerRadiusValueRunnable extends ValueRunnable { 22 | private final D3Arc arc; 23 | 24 | public InnerRadiusValueRunnable(D3Arc arc) { 25 | this.arc = arc; 26 | } 27 | 28 | @Override protected void computeValue() { 29 | value = arc.innerRadius.getFloat(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/LabelsCoordinates.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | class LabelsCoordinates { 20 | float[] coordinatesX; 21 | float[] coordinatesY; 22 | 23 | LabelsCoordinates(int dataLength) { 24 | coordinatesX = new float[dataLength]; 25 | coordinatesY = new float[dataLength]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/LabelsRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import com.fabernovel.d3library.mappers.D3StringDataMapperFunction; 20 | import com.fabernovel.d3library.threading.ValueRunnable; 21 | 22 | class LabelsRunnable extends ValueRunnable { 23 | private final D3Arc arc; 24 | 25 | private D3StringDataMapperFunction mapper; 26 | private boolean areSetLabels; 27 | 28 | LabelsRunnable(D3Arc arc) { 29 | this.arc = arc; 30 | } 31 | 32 | void setDataLength(int length) { 33 | if (areSetLabels) { 34 | return; 35 | } 36 | value = new String[length]; 37 | } 38 | 39 | void setLabels(String[] labels) { 40 | areSetLabels = true; 41 | value = labels; 42 | } 43 | 44 | void setDataMapper(D3StringDataMapperFunction mapper) { 45 | this.mapper = mapper; 46 | if (!areSetLabels) { 47 | return; 48 | } 49 | areSetLabels = false; 50 | setDataLength(arc.data == null ? 0 : arc.data.length); 51 | } 52 | 53 | @Override protected void computeValue() { 54 | if (areSetLabels) { 55 | return; 56 | } 57 | 58 | for (int i = 0; i < value.length; i++) { 59 | value[i] = mapper.compute(arc.data[i], i, arc.data); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/LabelsValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import android.graphics.Paint; 20 | import android.support.annotation.NonNull; 21 | 22 | import com.fabernovel.d3library.helper.TextHelper; 23 | import com.fabernovel.d3library.threading.ValueRunnable; 24 | 25 | class LabelsValueRunnable extends ValueRunnable { 26 | private static final String DATA_ERROR = "Data should not be null."; 27 | 28 | @NonNull private final D3Arc arc; 29 | @NonNull private final Paint paint; 30 | 31 | LabelsValueRunnable(@NonNull D3Arc arc, @NonNull Paint paint) { 32 | this.arc = arc; 33 | this.paint = paint; 34 | } 35 | 36 | void setDataLength(int length) { 37 | value = new LabelsCoordinates(length); 38 | } 39 | 40 | protected void computeValue() { 41 | if (arc.data == null) { 42 | throw new IllegalStateException(DATA_ERROR); 43 | } 44 | 45 | String[] labels = arc.labels(); 46 | 47 | Angles computedAngles = arc.preComputedAngles.getValue(); 48 | float outerRadius = arc.outerRadius(); 49 | float radius = (outerRadius + arc.innerRadius()) / 2F; 50 | float currentAngle; 51 | float radianAngle; 52 | float coordinateX; 53 | float coordinateY; 54 | 55 | for (int i = 0; i < arc.data.length; i++) { 56 | currentAngle = computedAngles.startAngles[i]; 57 | radianAngle = (float) Math.toRadians( 58 | -(currentAngle + computedAngles.drawAngles[i] / 2F) 59 | ); 60 | 61 | coordinateX = outerRadius + radius * (float) Math.cos(radianAngle); 62 | coordinateX -= paint.measureText(labels[i]) / 2F; 63 | coordinateY = outerRadius - radius * (float) Math.sin(radianAngle); 64 | coordinateY += TextHelper.getTextHeight(labels[i], paint) / 2F; 65 | value.coordinatesX[i] = coordinateX; 66 | value.coordinatesY[i] = coordinateY; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/OffsetXValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | public class OffsetXValueRunnable extends ValueRunnable { 22 | private final D3Arc arc; 23 | 24 | public OffsetXValueRunnable(D3Arc arc) { 25 | this.arc = arc; 26 | } 27 | 28 | @Override protected void computeValue() { 29 | value = arc.offsetX.getFloat(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/OffsetYValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | public class OffsetYValueRunnable extends ValueRunnable { 22 | private final D3Arc arc; 23 | 24 | public OffsetYValueRunnable(D3Arc arc) { 25 | this.arc = arc; 26 | } 27 | 28 | @Override protected void computeValue() { 29 | value = arc.offsetY.getFloat(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/arc/OuterRadiusValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.arc; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | public class OuterRadiusValueRunnable extends ValueRunnable { 22 | private final D3Arc arc; 23 | 24 | public OuterRadiusValueRunnable(D3Arc arc) { 25 | this.arc = arc; 26 | } 27 | 28 | @Override protected void computeValue() { 29 | value = arc.outerRadius.getFloat(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/area/AreaBitmapValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.area; 18 | 19 | import android.graphics.Path; 20 | import android.support.annotation.NonNull; 21 | 22 | import com.fabernovel.d3library.threading.BitmapValueRunnable; 23 | 24 | class AreaBitmapValueRunnable extends BitmapValueRunnable { 25 | private static final String GROUND_ERROR = "Ground should not be null"; 26 | private static final String DATA_ERROR = "Data should not be null"; 27 | 28 | @NonNull private final Path path; 29 | 30 | private final D3Area area; 31 | 32 | AreaBitmapValueRunnable(D3Area area) { 33 | this.area = area; 34 | path = new Path(); 35 | } 36 | 37 | @Override protected void computeValue() { 38 | T[] data = area.data(); 39 | if (data == null) { 40 | throw new IllegalStateException(DATA_ERROR); 41 | } 42 | if (data.length < 2) { 43 | return; 44 | } 45 | if (area.ground == null) { 46 | throw new IllegalStateException(GROUND_ERROR); 47 | } 48 | 49 | value.eraseColor(0); 50 | float computedGrounded = area.ground.getFloat(); 51 | float[] x = area.x(); 52 | float[] y = area.y(); 53 | 54 | path.rewind(); 55 | path.moveTo(x[0], y[0]); 56 | for (int i = 1; i < Math.min(x.length, y.length); i++) { 57 | path.lineTo(x[i], y[i]); 58 | } 59 | path.lineTo(x[x.length - 1], computedGrounded); 60 | path.lineTo(x[0], computedGrounded); 61 | 62 | canvas.drawPath(path, area.paint()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/area/D3Area.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.area; 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.Canvas; 21 | import android.graphics.Paint; 22 | import android.support.annotation.NonNull; 23 | import android.support.annotation.Nullable; 24 | 25 | import com.fabernovel.d3library.action.OnClickAction; 26 | import com.fabernovel.d3library.action.OnPinchAction; 27 | import com.fabernovel.d3library.action.OnScrollAction; 28 | import com.fabernovel.d3library.axes.D3FloatFunction; 29 | import com.fabernovel.d3library.line.D3Line; 30 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 31 | import com.fabernovel.d3library.scale.Interpolator; 32 | import com.fabernovel.d3library.threading.ValueStorage; 33 | 34 | public class D3Area extends D3Line { 35 | private static final String GROUND_ERROR = "Ground should not be null"; 36 | private static final String DATA_ERROR = "Data should not be null"; 37 | @Nullable D3FloatFunction ground; 38 | 39 | private final ValueStorage bitmapValueStorage = new ValueStorage<>(); 40 | private final AreaBitmapValueRunnable bitmapValueRunnable = 41 | new AreaBitmapValueRunnable<>(this); 42 | 43 | public D3Area() { 44 | super(); 45 | } 46 | 47 | public D3Area(@Nullable T[] data) { 48 | super(data); 49 | setupPaint(); 50 | } 51 | 52 | @Override public D3Area onClickAction(@Nullable OnClickAction onClickAction) { 53 | super.onClickAction(onClickAction); 54 | return this; 55 | } 56 | 57 | @Override public D3Area onScrollAction(@Nullable OnScrollAction onScrollAction) { 58 | super.onScrollAction(onScrollAction); 59 | return this; 60 | } 61 | 62 | @Override public D3Area onPinchAction(@Nullable OnPinchAction onPinchAction) { 63 | super.onPinchAction(onPinchAction); 64 | return this; 65 | } 66 | 67 | @Override public D3Area setClipRect( 68 | @NonNull D3FloatFunction leftLimit, 69 | @NonNull D3FloatFunction topLimit, 70 | @NonNull D3FloatFunction rightLimit, 71 | @NonNull D3FloatFunction bottomLimit 72 | ) { 73 | super.setClipRect(leftLimit, topLimit, rightLimit, bottomLimit); 74 | return this; 75 | } 76 | 77 | @Override public D3Area deleteClipRect() { 78 | super.deleteClipRect(); 79 | return this; 80 | } 81 | 82 | @Override public D3Area x(@NonNull D3FloatDataMapperFunction x) { 83 | super.x(x); 84 | return this; 85 | } 86 | 87 | @Override public D3Area y(@NonNull D3FloatDataMapperFunction y) { 88 | super.y(y); 89 | return this; 90 | } 91 | 92 | @Override public D3Area data(@NonNull T[] data) { 93 | super.data(data); 94 | return this; 95 | } 96 | 97 | @Override public D3Area interpolator(@NonNull Interpolator interpolator) { 98 | super.interpolator(interpolator); 99 | return this; 100 | } 101 | 102 | @Override public D3Area paint(@NonNull Paint paint) { 103 | super.paint(paint); 104 | paint.setStyle(Paint.Style.FILL); 105 | return this; 106 | } 107 | 108 | /** 109 | * Returns the ground of the area. 110 | */ 111 | public float ground() { 112 | if (ground == null) { 113 | throw new IllegalStateException(GROUND_ERROR); 114 | } 115 | return ground.getFloat(); 116 | } 117 | 118 | /** 119 | * Sets the ground of the area. 120 | */ 121 | public D3Area ground(@NonNull D3FloatFunction ground) { 122 | this.ground = ground; 123 | return this; 124 | } 125 | 126 | @Override protected void onDimensionsChange(float width, float height) { 127 | super.onDimensionsChange(width, height); 128 | bitmapValueRunnable.resizeBitmap(width, height); 129 | } 130 | 131 | @Override public void prepareParameters() { 132 | super.prepareParameters(); 133 | if (lazyRecomputing && calculationNeeded() == 0) { 134 | return; 135 | } 136 | bitmapValueStorage.setValue(bitmapValueRunnable); 137 | } 138 | 139 | @Override public void draw(@NonNull Canvas canvas) { 140 | canvas.drawBitmap(bitmapValueStorage.getValue(), 0F, 0F, null); 141 | } 142 | 143 | @Override public D3Area lazyRecomputing(boolean lazyRecomputing) { 144 | super.lazyRecomputing(lazyRecomputing); 145 | return this; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/AxisBitmapValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.threading.BitmapValueRunnable; 22 | 23 | class AxisBitmapValueRunnable extends BitmapValueRunnable { 24 | @NonNull private final D3AxisDrawer drawer; 25 | 26 | AxisBitmapValueRunnable(@NonNull D3AxisDrawer drawer) { 27 | this.drawer = drawer; 28 | } 29 | 30 | @Override protected void computeValue() { 31 | value.eraseColor(0); 32 | drawer.draw(canvas); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/AxisDefaultInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import com.fabernovel.d3library.scale.D3Converter; 20 | 21 | final class AxisDefaultInitializer { 22 | private AxisDefaultInitializer() { 23 | } 24 | 25 | static D3Converter getDefaultConverter(Class tClass) { 26 | if (tClass.equals(Float.class)) { 27 | return new D3Converter() { 28 | @Override public float convert(T toConvert) { 29 | return (Float) toConvert; 30 | } 31 | 32 | @Override public T invert(float toInvert) { 33 | return (T) new Float(toInvert); 34 | } 35 | }; 36 | } else if (tClass.equals(Integer.class)) { 37 | return new D3Converter() { 38 | @Override public float convert(T toConvert) { 39 | return (Integer) toConvert; 40 | } 41 | 42 | @Override public T invert(float toInvert) { 43 | return (T) Integer.valueOf((int) toInvert); 44 | } 45 | }; 46 | } 47 | return null; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/AxisOrientation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | public enum AxisOrientation { 20 | TOP, 21 | RIGHT, 22 | BOTTOM, 23 | LEFT 24 | } 25 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/D3AxisActionsInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.action.OnPinchAction; 22 | import com.fabernovel.d3library.action.OnScrollAction; 23 | import com.fabernovel.d3library.action.PinchType; 24 | import com.fabernovel.d3library.action.ScrollDirection; 25 | import com.fabernovel.d3library.scale.D3Converter; 26 | 27 | final class D3AxisActionsInitializer { 28 | private static final String CONVERTER_ERROR = "Converter should not be null"; 29 | private static final String DOMAIN_ERROR = "Domain should not be null"; 30 | private static final String RANGE_ERROR = "Range should not be null"; 31 | private static final float PINCH_MIN_SPACING = 100F; 32 | 33 | private final D3Axis axis; 34 | 35 | D3AxisActionsInitializer(D3Axis axis) { 36 | this.axis = axis; 37 | } 38 | 39 | @NonNull OnScrollAction getHorizontalOnScrollAction() { 40 | return new OnScrollAction() { 41 | @Override public void onScroll( 42 | ScrollDirection direction, float coordinateX, float coordinateY, float dX, float dY 43 | ) { 44 | D3Converter converter = axis.scale.converter(); 45 | if (converter == null) { 46 | throw new IllegalStateException(CONVERTER_ERROR); 47 | } 48 | T[] domain = axis.scale.domain(); 49 | if (domain == null) { 50 | throw new IllegalStateException(DOMAIN_ERROR); 51 | } 52 | converter.convert(domain[0]); 53 | float[] range = axis.scale.range(); 54 | if (range == null) { 55 | throw new IllegalStateException(RANGE_ERROR); 56 | } 57 | float sign = dY < 0F ? 1F : -1F; 58 | float absDy = Math.abs(dY); 59 | float offset = converter.convert(domain[0]) 60 | - converter.convert(axis.scale.invert(range[0] + absDy)); 61 | offset *= sign; 62 | domain[0] = converter.invert(converter.convert(domain[0]) - offset); 63 | domain[1] = converter.invert(converter.convert(domain[1]) - offset); 64 | axis.scale.domain(domain); 65 | axis.updateNeeded(); 66 | } 67 | }; 68 | } 69 | 70 | @NonNull OnPinchAction getHorizontalOnPinchAction() { 71 | return new OnPinchAction() { 72 | @Override public void onPinch( 73 | PinchType pinchType, float coordinateStaticX, float coordinateStaticY, 74 | float coordinateMobileX, float coordinateMobileY, float dX, float dY 75 | ) { 76 | if (pinchType == PinchType.HORIZONTAL_DECREASE || 77 | pinchType == PinchType.HORIZONTAL_INCREASE) { 78 | return; 79 | } 80 | resizeOnPinch(coordinateStaticY, coordinateMobileY, dY); 81 | axis.updateNeeded(); 82 | } 83 | }; 84 | } 85 | 86 | private void resizeOnPinch( 87 | float coordinateStatic, float coordinateMobile, float diffCoordinate 88 | ) { 89 | if (Math.abs(coordinateMobile - coordinateStatic) < PINCH_MIN_SPACING) { 90 | return; 91 | } 92 | 93 | float[] range = axis.range(); 94 | 95 | float coordinateMin = range[0]; 96 | float coordinateMax = range[1]; 97 | 98 | int inverted = 0; 99 | if (coordinateMin > coordinateMax) { 100 | inverted++; 101 | float tmp = coordinateMin; 102 | coordinateMin = coordinateMax; 103 | coordinateMax = tmp; 104 | } 105 | 106 | if ((coordinateMobile < coordinateMin || coordinateMobile > coordinateMax) 107 | || (coordinateStatic < coordinateMin || coordinateStatic > coordinateMax)) { 108 | return; 109 | } 110 | 111 | D3Converter converter = axis.scale.converter(); 112 | if (converter == null) { 113 | throw new IllegalStateException(CONVERTER_ERROR); 114 | } 115 | 116 | float newDomainMin = ((coordinateStatic - coordinateMobile) * coordinateMin - 117 | coordinateStatic * diffCoordinate) 118 | / (coordinateStatic - coordinateMobile - diffCoordinate); 119 | float newDomainMax = ((coordinateStatic - coordinateMobile) * coordinateMax - 120 | coordinateStatic * diffCoordinate) 121 | / (coordinateStatic - coordinateMobile - diffCoordinate); 122 | 123 | T[] domain = axis.domain(); 124 | if (converter.convert(domain[0]) > converter.convert(domain[1])) { 125 | inverted = (inverted + 1) % 2; 126 | } 127 | /* Two new bounds are computed before to assign the first value in order to not have 128 | * side effects. */ 129 | T result = axis.scale.invert(newDomainMin); 130 | domain[1 - inverted] = axis.scale.invert(newDomainMax); 131 | domain[inverted] = result; 132 | axis.domain(domain); 133 | } 134 | 135 | @NonNull OnScrollAction getVerticalOnScrollAction() { 136 | return new OnScrollAction() { 137 | @Override public void onScroll( 138 | ScrollDirection direction, float coordinateX, float coordinateY, float dX, float dY 139 | ) { 140 | D3Converter converter = axis.scale.converter(); 141 | if (converter == null) { 142 | throw new IllegalStateException(CONVERTER_ERROR); 143 | } 144 | T[] domain = axis.scale.domain(); 145 | if (domain == null) { 146 | throw new IllegalStateException(DOMAIN_ERROR); 147 | } 148 | float[] range = axis.scale.range(); 149 | if (range == null) { 150 | throw new IllegalStateException(RANGE_ERROR); 151 | } 152 | float sign = dX < 0F ? 1F : -1F; 153 | float absoluteDx = Math.abs(dX); 154 | float offset = converter.convert(domain[0]) 155 | - converter.convert(axis.scale.invert(range[0] + absoluteDx)); 156 | offset *= sign; 157 | domain[0] = converter.invert(converter.convert(domain[0]) - offset); 158 | domain[1] = converter.invert(converter.convert(domain[1]) - offset); 159 | axis.scale.domain(domain); 160 | axis.updateNeeded(); 161 | } 162 | }; 163 | } 164 | 165 | @NonNull OnPinchAction getVerticalOnPinchAction() { 166 | return new OnPinchAction() { 167 | @Override public void onPinch( 168 | PinchType pinchType, float coordinateStaticX, float coordinateStaticY, 169 | float coordinateMobileX, float coordinateMobileY, float dX, float dY 170 | ) { 171 | if (pinchType == PinchType.VERTICAL_DECREASE || 172 | pinchType == PinchType.VERTICAL_INCREASE) { 173 | return; 174 | } 175 | resizeOnPinch(coordinateStaticX, coordinateMobileX, dX); 176 | axis.updateNeeded(); 177 | } 178 | }; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/D3DomainFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | /** 22 | * Returns a range of T computed each time needed. 23 | */ 24 | public interface D3DomainFunction { 25 | @NonNull T[] getRange(); 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/D3FloatFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | /** 20 | * Returns a float computed each time needed. 21 | */ 22 | public interface D3FloatFunction { 23 | float getFloat(); 24 | } 25 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/D3RangeFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | /** 22 | * Returns a range of T computed each time needed. 23 | */ 24 | public interface D3RangeFunction { 25 | @NonNull float[] getRange(); 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/HorizontalAlignment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | public enum HorizontalAlignment { 20 | /*** 21 | * The legend is at the left of the tick. 22 | */ 23 | LEFT, 24 | /*** 25 | * The legend is center on the tick. 26 | */ 27 | CENTER, 28 | /*** 29 | * The legend is at the right of the tick (Default value). 30 | */ 31 | RIGHT 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/LegendProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import android.graphics.Color; 20 | import android.support.annotation.ColorInt; 21 | import android.support.annotation.NonNull; 22 | 23 | class LegendProperties { 24 | private static final float DEFAULT_TEXT_SIZE = 15F; 25 | 26 | @NonNull private VerticalAlignment verticalAlignment; 27 | @NonNull private HorizontalAlignment horizontalAlignment; 28 | 29 | private float offsetX = 0F; 30 | private float offsetY = 0F; 31 | 32 | private float textSizeInPixels = DEFAULT_TEXT_SIZE; 33 | 34 | @ColorInt private int color; 35 | 36 | public LegendProperties() { 37 | this(VerticalAlignment.TOP, HorizontalAlignment.RIGHT); 38 | } 39 | 40 | public LegendProperties(@NonNull VerticalAlignment verticalAlignment) { 41 | this(verticalAlignment, HorizontalAlignment.RIGHT); 42 | } 43 | 44 | public LegendProperties(@NonNull HorizontalAlignment horizontalAlignment) { 45 | this(VerticalAlignment.TOP, horizontalAlignment); 46 | } 47 | 48 | public LegendProperties( 49 | @NonNull VerticalAlignment verticalAlignment, 50 | @NonNull HorizontalAlignment horizontalAlignment 51 | ) { 52 | this.verticalAlignment = verticalAlignment; 53 | this.horizontalAlignment = horizontalAlignment; 54 | color = Color.rgb(0, 0, 0); 55 | } 56 | 57 | /** 58 | * Returns the vertical alignment of the LegendProperties. 59 | */ 60 | @NonNull public VerticalAlignment verticalAlignment() { 61 | return verticalAlignment; 62 | } 63 | 64 | /** 65 | * Sets the vertical alignment of the LegendProperties. 66 | */ 67 | public void verticalAlignment(@NonNull VerticalAlignment verticalAlignment) { 68 | this.verticalAlignment = verticalAlignment; 69 | } 70 | 71 | /** 72 | * Returns the horizontal alignment of the LegendProperties. 73 | */ 74 | @NonNull public HorizontalAlignment horizontalAlignement() { 75 | return horizontalAlignment; 76 | } 77 | 78 | /** 79 | * Sets the horizontal alignment of the LegendProperties. 80 | */ 81 | public void horizontalAlignement(@NonNull HorizontalAlignment horizontalAlignment) { 82 | this.horizontalAlignment = horizontalAlignment; 83 | } 84 | 85 | /** 86 | * Returns the horizontal offset of the LegendProperties. 87 | */ 88 | public float offsetX() { 89 | return offsetX; 90 | } 91 | 92 | /** 93 | * Sets the horizontal offset of the LegendProperties. 94 | */ 95 | public void offsetX(float paddingX) { 96 | this.offsetX = paddingX; 97 | } 98 | 99 | /** 100 | * Returns the vertical offset of the LegendProperties. 101 | */ 102 | public float offsetY() { 103 | return offsetY; 104 | } 105 | 106 | /** 107 | * Sets the vertical offset of the LegendProperties. 108 | */ 109 | public void offsetY(float paddingY) { 110 | this.offsetY = paddingY; 111 | } 112 | 113 | 114 | /** 115 | * Returns the size of the text of the LegendProperties. 116 | */ 117 | public float textSizeInPixels() { 118 | return textSizeInPixels; 119 | } 120 | 121 | /** 122 | * Sets the size of the text of the LegendProperties. 123 | */ 124 | public void textSizeInPixels(float textSizeInPixels) { 125 | this.textSizeInPixels = textSizeInPixels; 126 | } 127 | 128 | /** 129 | * Returns the color of the text of the LegendProperties. 130 | */ 131 | public int color() { 132 | return color; 133 | } 134 | 135 | /** 136 | * Sets the color of the text of the LegendProperties. 137 | */ 138 | public void color(@ColorInt int color) { 139 | this.color = color; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/TicksValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | class TicksValueRunnable extends ValueRunnable { 22 | private final D3Axis axis; 23 | 24 | private boolean areCustomLegends; 25 | 26 | TicksValueRunnable(D3Axis axis) { 27 | this.axis = axis; 28 | } 29 | 30 | void setCustomTicks(String[] legends) { 31 | areCustomLegends = true; 32 | value = legends; 33 | } 34 | 35 | void setTicksNumber(int ticksNumber) { 36 | areCustomLegends = false; 37 | value = new String[ticksNumber]; 38 | } 39 | 40 | int getTicksNumber() { 41 | return value.length; 42 | } 43 | 44 | @Override protected void computeValue() { 45 | if (areCustomLegends) { 46 | return; 47 | } 48 | 49 | axis.scale.ticksLegend(getTicksNumber(), value); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/axes/VerticalAlignment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.axes; 18 | 19 | public enum VerticalAlignment { 20 | /*** 21 | * The legend is above the tick (Default value). 22 | */ 23 | TOP, 24 | /*** 25 | * The legend is align with the tick. 26 | */ 27 | CENTER, 28 | /*** 29 | * The legend is under the tick. 30 | */ 31 | BOTTOM 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/barchart/FloatsValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.barchart; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 22 | import com.fabernovel.d3library.threading.ValueRunnable; 23 | 24 | class FloatsValueRunnable extends ValueRunnable { 25 | private static final String DATA_ERROR = "Data should not be null"; 26 | 27 | @NonNull private final D3BarChart barChart; 28 | @NonNull private D3FloatDataMapperFunction mapper; 29 | 30 | FloatsValueRunnable(@NonNull D3BarChart barChart) { 31 | this.barChart = barChart; 32 | } 33 | 34 | void setDataLength(int length) { 35 | value = new float[length]; 36 | } 37 | 38 | void setDataMapper(@NonNull D3FloatDataMapperFunction mapper) { 39 | this.mapper = mapper; 40 | } 41 | 42 | @Override protected void computeValue() { 43 | if (barChart.data == null) { 44 | throw new IllegalStateException(DATA_ERROR); 45 | } 46 | for (int i = 0; i < value.length; i++) { 47 | value[i] = mapper.compute(barChart.data[i], i, barChart.data); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/boxplot/Statistics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.boxplot; 18 | 19 | class Statistics { 20 | float min; 21 | float max; 22 | float median; 23 | float lowerQuartile; 24 | float upperQuartile; 25 | 26 | float minCoordinate; 27 | float maxCoordinate; 28 | float medianCoordinate; 29 | float lowerQuartileCoordinate; 30 | float upperQuartileCoordinate; 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/boxplot/StatisticsComputer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.boxplot; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import com.fabernovel.d3library.threading.ValueRunnable; 22 | 23 | class StatisticsComputer extends ValueRunnable { 24 | private static final String DATA_ERROR = "Data should not be null"; 25 | 26 | @NonNull private final D3BoxPlot boxPlot; 27 | private float[] floatData; 28 | 29 | StatisticsComputer(@NonNull D3BoxPlot boxPlot) { 30 | this.boxPlot = boxPlot; 31 | value = new Statistics(); 32 | } 33 | 34 | void setDataLength(int length) { 35 | floatData = new float[length]; 36 | } 37 | 38 | @Override protected void computeValue() { 39 | if (boxPlot.data == null) { 40 | throw new IllegalStateException(DATA_ERROR); 41 | } 42 | computeFloatData(); 43 | computeStatistics(); 44 | computeCoordinates(); 45 | } 46 | 47 | private void computeFloatData() { 48 | for (int i = 0; i < floatData.length; i++) { 49 | floatData[i] = boxPlot.dataMapper.compute(boxPlot.data[i], i, boxPlot.data); 50 | } 51 | } 52 | 53 | private void computeStatistics() { 54 | if (boxPlot.data.length == 0) { 55 | return; 56 | } 57 | int i = 0; 58 | float swap; 59 | while (i < boxPlot.data.length - 1) { 60 | if (floatData[i] > floatData[i + 1]) { 61 | swap = floatData[i]; 62 | floatData[i] = floatData[i + 1]; 63 | floatData[i + 1] = swap; 64 | i = Math.max(i - 1, 0); 65 | } else { 66 | i++; 67 | } 68 | } 69 | 70 | value.min = floatData[0]; 71 | value.max = floatData[floatData.length - 1]; 72 | value.median = floatData.length % 2 == 0 ? 73 | (floatData[floatData.length / 2 - 1] + floatData[floatData.length / 2]) / 2F : 74 | floatData[floatData.length / 2]; 75 | 76 | value.lowerQuartile = floatData[Math.round((float) (floatData.length - 1)/ 4F)]; 77 | value.upperQuartile = floatData[Math.round((float) (floatData.length - 1) * 3F / 4F)]; 78 | } 79 | 80 | private void computeCoordinates() { 81 | value.minCoordinate = boxPlot.scale().value(value.min); 82 | value.maxCoordinate = boxPlot.scale().value(value.max); 83 | value.medianCoordinate = boxPlot.scale().value(value.median); 84 | value.lowerQuartileCoordinate = boxPlot.scale().value(value.lowerQuartile); 85 | value.upperQuartileCoordinate = boxPlot.scale().value(value.upperQuartile); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/curve/D3Curve.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.curve; 18 | 19 | import android.graphics.Canvas; 20 | import android.graphics.Paint; 21 | import android.support.annotation.NonNull; 22 | import android.support.annotation.Nullable; 23 | 24 | import com.fabernovel.d3library.action.OnClickAction; 25 | import com.fabernovel.d3library.action.OnPinchAction; 26 | import com.fabernovel.d3library.action.OnScrollAction; 27 | import com.fabernovel.d3library.axes.D3FloatFunction; 28 | import com.fabernovel.d3library.line.D3Line; 29 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 30 | import com.fabernovel.d3library.scale.Interpolator; 31 | import com.fabernovel.d3library.threading.ValueStorage; 32 | 33 | public class D3Curve extends D3Line { 34 | private static final String DATA_ERROR = "Data should not be null"; 35 | private static final String TICKS_ERROR = 36 | "PrepareParameters should have be called to setup ticksX and ticksY"; 37 | private static final String TICKS_X_ERROR = "TicksX should not be null"; 38 | private static final int DEFAULT_POINT_NUMBER = 100; 39 | private static final int DEFAULT_INDEX_SIZE = 5; 40 | 41 | @NonNull final ValueStorage ticksX = new ValueStorage<>(); 42 | @NonNull private final GetTicksXRunnable ticksXRunnable = new GetTicksXRunnable<>(this); 43 | @NonNull final ValueStorage ticksY = new ValueStorage<>(); 44 | @NonNull private final GetTicksYRunnable ticksYRunnable = new GetTicksYRunnable<>(this); 45 | 46 | 47 | private int pointsNumber; 48 | 49 | public D3Curve() { 50 | super(); 51 | initInterpolator(); 52 | pointsNumber(DEFAULT_POINT_NUMBER); 53 | } 54 | 55 | public D3Curve(T[] data) { 56 | super(data); 57 | initInterpolator(); 58 | pointsNumber(DEFAULT_POINT_NUMBER); 59 | } 60 | 61 | private void initInterpolator() { 62 | interpolator = new Interpolator() { 63 | private int[] indexToUse; 64 | 65 | @Override 66 | public float interpolate( 67 | float x, 68 | float[] xData, 69 | float[] yData 70 | ) { 71 | if (indexToUse == null) { 72 | initIndex(yData.length); 73 | } 74 | return computeLagrangePolynomialInterpolation(x, xData, yData); 75 | } 76 | 77 | private float computeLagrangePolynomialInterpolation( 78 | float x, 79 | float[] xData, 80 | float[] yData 81 | ) { 82 | float result = 0F; 83 | for (int i = 0; i < indexToUse.length; i++) { 84 | float intermediary = 1F; 85 | for (int j = 0; j < indexToUse.length; j++) { 86 | if (i != j) { 87 | intermediary *= (x - xData[indexToUse[j]]) / 88 | (xData[indexToUse[i]] - xData[indexToUse[j]]); 89 | } 90 | } 91 | result += yData[indexToUse[i]] * intermediary; 92 | } 93 | return result; 94 | } 95 | 96 | private void initIndex(int indexSize) { 97 | if (indexSize <= DEFAULT_INDEX_SIZE) { 98 | indexToUse = new int[indexSize]; 99 | for (int i = 0; i < indexToUse.length; i++) { 100 | indexToUse[i] = i; 101 | } 102 | } else { 103 | indexToUse = new int[DEFAULT_INDEX_SIZE]; 104 | for (int i = 0; i < DEFAULT_INDEX_SIZE; i++) { 105 | indexToUse[i] = (indexSize - 1) * i / (DEFAULT_INDEX_SIZE - 1); 106 | } 107 | } 108 | } 109 | }; 110 | } 111 | 112 | @Override public float interpolateValue(float measuredX) { 113 | return interpolator.interpolate(measuredX, x(), y()); 114 | } 115 | 116 | /** 117 | * Returns the number of point used by the interpolation 118 | */ 119 | public int pointsNumber() { 120 | return pointsNumber; 121 | } 122 | 123 | /** 124 | * Sets the number of point used by the interpolation 125 | */ 126 | public D3Curve pointsNumber(int pointsNumber) { 127 | this.pointsNumber = pointsNumber; 128 | ticksXRunnable.onPointsNumberChange(pointsNumber); 129 | ticksYRunnable.onPointsNumberChange(pointsNumber); 130 | lines = new float[4 * (pointsNumber - 1)]; 131 | return this; 132 | } 133 | 134 | @Override public D3Curve paint(@NonNull Paint paint) { 135 | super.paint(paint); 136 | return this; 137 | } 138 | 139 | @Override public D3Curve x(@NonNull D3FloatDataMapperFunction x) { 140 | super.x(x); 141 | return this; 142 | } 143 | 144 | @Override public D3Curve y(@NonNull D3FloatDataMapperFunction y) { 145 | super.y(y); 146 | return this; 147 | } 148 | 149 | @Override public D3Curve data(@Nullable T[] data) { 150 | this.data = data; 151 | if (data == null) { 152 | setDataStorageDataLength(0); 153 | return this; 154 | } 155 | setDataStorageDataLength(data.length); 156 | return this; 157 | } 158 | 159 | @Override public D3Curve interpolator(@NonNull Interpolator interpolator) { 160 | super.interpolator(interpolator); 161 | return this; 162 | } 163 | 164 | @Override public D3Curve onClickAction(@Nullable OnClickAction onClickAction) { 165 | super.onClickAction(onClickAction); 166 | return this; 167 | } 168 | 169 | @Override public D3Curve onScrollAction(@Nullable OnScrollAction onScrollAction) { 170 | super.onScrollAction(onScrollAction); 171 | return this; 172 | } 173 | 174 | @Override public D3Curve onPinchAction(@Nullable OnPinchAction onPinchAction) { 175 | super.onPinchAction(onPinchAction); 176 | return this; 177 | } 178 | 179 | @Override public void draw(@NonNull Canvas canvas) { 180 | if (data == null) { 181 | throw new IllegalStateException(DATA_ERROR); 182 | } 183 | 184 | if (data.length < 2) { 185 | return; 186 | } 187 | 188 | float[] xDraw = ticksX.getValue(); 189 | float[] yDraw = ticksY.getValue(); 190 | 191 | for (int i = 0; i < pointsNumber - 1; i++) { 192 | lines[4 * i] = xDraw[i]; 193 | lines[4 * i + 1] = yDraw[i]; 194 | lines[4 * i + 2] = xDraw[i + 1]; 195 | lines[4 * i + 3] = yDraw[i + 1]; 196 | } 197 | canvas.drawLines(lines, paint); 198 | } 199 | 200 | @Override public void prepareParameters() { 201 | if (lazyRecomputing && calculationNeeded() == 0) { 202 | return; 203 | } 204 | super.prepareParameters(); 205 | ticksX.setValue(ticksXRunnable); 206 | ticksY.setValue(ticksYRunnable); 207 | } 208 | 209 | @Override public D3Curve setClipRect( 210 | @NonNull D3FloatFunction leftLimit, 211 | @NonNull D3FloatFunction topLimit, 212 | @NonNull D3FloatFunction rightLimit, 213 | @NonNull D3FloatFunction bottomLimit 214 | ) { 215 | super.setClipRect(leftLimit, topLimit, rightLimit, bottomLimit); 216 | return this; 217 | } 218 | 219 | @Override public D3Curve deleteClipRect() { 220 | super.deleteClipRect(); 221 | return this; 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/curve/GetTicksXRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.curve; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | class GetTicksXRunnable extends ValueRunnable { 22 | private final D3Curve curve; 23 | 24 | GetTicksXRunnable(D3Curve curve) { 25 | this.curve = curve; 26 | } 27 | 28 | void onPointsNumberChange(int pointsNumber) { 29 | value = new float[pointsNumber]; 30 | } 31 | 32 | @Override protected void computeValue() { 33 | float[] xData = curve.x(); 34 | value[0] = xData[0]; 35 | for (int i = 1; i < value.length - 1; i++) { 36 | value[i] = ((value.length - 1 - i) * xData[0] + i * xData[xData 37 | .length - 1]) / 38 | value.length; 39 | } 40 | value[value.length - 1] = xData[xData.length - 1]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/curve/GetTicksYRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.curve; 18 | 19 | import com.fabernovel.d3library.threading.ValueRunnable; 20 | 21 | class GetTicksYRunnable extends ValueRunnable { 22 | private final D3Curve curve; 23 | 24 | GetTicksYRunnable(D3Curve curve) { 25 | this.curve = curve; 26 | } 27 | 28 | void onPointsNumberChange(int pointsNumber) { 29 | value = new float[pointsNumber]; 30 | } 31 | 32 | @Override protected void computeValue() { 33 | float[] xData = curve.x(); 34 | float[] yData = curve.y(); 35 | float[] xDraw = curve.ticksX.getValue(); 36 | 37 | value[0] = curve.interpolator().interpolate(xDraw[0], xData, yData); 38 | 39 | for (int i = 1; i < value.length - 1; i++) { 40 | value[i] = curve.interpolator().interpolate(xDraw[i], xData, yData); 41 | } 42 | 43 | value[value.length - 1] = curve.interpolator().interpolate( 44 | xDraw[value.length - 1], xData, yData 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/helper/ArrayConverterHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.helper; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | public final class ArrayConverterHelper { 22 | private static final String CONTAINER_ARRAY_IS_TOO_SMALL = "Container array is too small"; 23 | 24 | private ArrayConverterHelper(){} 25 | 26 | public static float[] convertArray(@NonNull Float[] toConvert, @NonNull float[] resContainer) { 27 | if (resContainer.length < toConvert.length) { 28 | throw new IllegalStateException(CONTAINER_ARRAY_IS_TOO_SMALL); 29 | } 30 | for (int i = 0; i < toConvert.length; i++) { 31 | resContainer[i] = toConvert[i] == null ? 0F : toConvert[i]; 32 | } 33 | return resContainer; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/helper/ColorHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.helper; 18 | 19 | public final class ColorHelper { 20 | 21 | private static final int WHITE = 0XFF_FF_FF_FF; 22 | private static final int BLACK = 0XFF_00_00_00; 23 | 24 | private static final float COEFFICIENT_BLUE = 0.114F; 25 | private static final float COEFFICIENT_GREEN = 0.587F; 26 | private static final float COEFFICIENT_RED = 0.299F; 27 | private static final float LIMIT_VALUE = 0.5F; 28 | 29 | private ColorHelper() {} 30 | 31 | /*** 32 | * Return the most suitable color depending on the given background color 33 | * @param color color of the background 34 | * @return black or white 35 | */ 36 | public static int colorDependingOnBackground(int color) { 37 | int blue = color % 0x100; 38 | blue = blue < 0 ? blue + 256 : blue; 39 | int green = (color >> 8) % 0x100; 40 | green = green < 0 ? green + 256 : green; 41 | int red = (color >> 16) % 0x100; 42 | red = red < 0 ? red + 256 : red; 43 | float score = (COEFFICIENT_BLUE * blue 44 | + COEFFICIENT_RED * red 45 | + COEFFICIENT_GREEN * green) / 255F; 46 | return score > LIMIT_VALUE ? BLACK : WHITE; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/helper/TextHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.helper; 18 | 19 | import android.graphics.Paint; 20 | import android.graphics.Rect; 21 | 22 | public final class TextHelper { 23 | private final static Rect bounds = new Rect(); 24 | private TextHelper() {} 25 | 26 | public static float getTextHeight(String text, Paint textPaint) { 27 | textPaint.getTextBounds(text, 0, text.length(), bounds); 28 | return (float) bounds.height(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/line/CoordinatesValueStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.line; 18 | 19 | import android.support.annotation.NonNull; 20 | import android.support.annotation.Nullable; 21 | 22 | import com.fabernovel.d3library.mappers.D3FloatDataMapperFunction; 23 | import com.fabernovel.d3library.threading.ThreadPool; 24 | import com.fabernovel.d3library.threading.ValueRunnable; 25 | 26 | import java.util.ArrayList; 27 | import java.util.List; 28 | import java.util.concurrent.Callable; 29 | import java.util.concurrent.Executors; 30 | 31 | public class CoordinatesValueStorage extends ValueRunnable { 32 | private static final String DATA_ERROR = "Data should not be null"; 33 | 34 | @NonNull private final D3Line line; 35 | @NonNull private final List> tasks; 36 | @NonNull private final List runnables; 37 | 38 | @Nullable private D3FloatDataMapperFunction mapper; 39 | 40 | CoordinatesValueStorage(@NonNull D3Line line) { 41 | this.line = line; 42 | tasks = new ArrayList<>(); 43 | runnables = new ArrayList<>(); 44 | for (int i = 0; i < ThreadPool.CORES_NUMBER; i++) { 45 | runnables.add(new ComputeValueRunnable(i)); 46 | } 47 | } 48 | 49 | void setDataLength(int length) { 50 | value = new float[length]; 51 | } 52 | 53 | void setMapper(@NonNull D3FloatDataMapperFunction mapper) { 54 | this.mapper = mapper; 55 | } 56 | 57 | @Override protected void computeValue() { 58 | value = compute(mapper); 59 | } 60 | 61 | float[] compute(@NonNull D3FloatDataMapperFunction mapper) { 62 | if (line.data == null) { 63 | throw new IllegalStateException(DATA_ERROR); 64 | } 65 | tasks.clear(); 66 | for (int k = 0; k < ThreadPool.CORES_NUMBER; k++) { 67 | tasks.add(Executors.callable(runnables.get(k))); 68 | } 69 | ThreadPool.executeOnSecondaryPool(tasks); 70 | return value; 71 | } 72 | 73 | private class ComputeValueRunnable implements Runnable { 74 | int k; 75 | 76 | public ComputeValueRunnable(int offset) { 77 | k = offset; 78 | } 79 | 80 | @Override public void run() { 81 | if (line.data == null) { 82 | throw new IllegalStateException(DATA_ERROR); 83 | } 84 | for (int i = k; i < value.length; i += ThreadPool.CORES_NUMBER) { 85 | value[i] = mapper.compute(line.data[i], i, line.data); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/mappers/D3FloatDataMapperFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.mappers; 18 | 19 | /** 20 | * Maps a float value to each value of an array. 21 | */ 22 | public interface D3FloatDataMapperFunction { 23 | /** 24 | * @param object The object to consider. 25 | * @param position The position of the object. 26 | * @param data The array of data. 27 | */ 28 | float compute(T object, int position, T[] data); 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/mappers/D3IntDataMapperFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.mappers; 18 | 19 | /** 20 | * Maps an int value to each value of an array. 21 | */ 22 | public interface D3IntDataMapperFunction { 23 | /** 24 | * @param object The object to consider. 25 | * @param position The position of the object. 26 | * @param data The array of data. 27 | */ 28 | int compute(T object, int position, T[] data); 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/mappers/D3StringDataMapperFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.mappers; 18 | 19 | /** 20 | * Maps a String to each value of an array. 21 | */ 22 | public interface D3StringDataMapperFunction { 23 | /** 24 | * @param object The object to consider. 25 | * @param position The position of the object. 26 | * @param data The array of data. 27 | */ 28 | String compute(T object, int position, T[] data); 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/polygon/OffsetRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.polygon; 18 | 19 | import com.fabernovel.d3library.axes.D3FloatFunction; 20 | import com.fabernovel.d3library.threading.ValueRunnable; 21 | 22 | class OffsetRunnable extends ValueRunnable { 23 | private D3FloatFunction function; 24 | 25 | void setOffsetFunction(D3FloatFunction function) { 26 | this.function = function; 27 | } 28 | 29 | @Override protected void computeValue() { 30 | value = function.getFloat(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/polygon/PolygonBitmapValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.polygon; 18 | 19 | import android.graphics.Path; 20 | import android.support.annotation.NonNull; 21 | 22 | import com.fabernovel.d3library.threading.BitmapValueRunnable; 23 | 24 | class PolygonBitmapValueRunnable extends BitmapValueRunnable { 25 | @NonNull private final D3Polygon polygon; 26 | @NonNull private final Path path; 27 | 28 | 29 | PolygonBitmapValueRunnable(@NonNull D3Polygon polygon) { 30 | this.polygon = polygon; 31 | path = new Path(); 32 | path.setFillType(Path.FillType.WINDING); 33 | } 34 | 35 | @Override protected void computeValue() { 36 | value.eraseColor(0); 37 | 38 | if (polygon.x.length == 0) { 39 | return; 40 | } 41 | 42 | path.rewind(); 43 | 44 | float computedOffsetX = polygon.offsetX(); 45 | float computedOffsetY = polygon.offsetY(); 46 | 47 | if (polygon.proportional) { 48 | float width = polygon.width(); 49 | float height = polygon.height(); 50 | 51 | path.moveTo( 52 | (polygon.x[0] + computedOffsetX) * width, 53 | (polygon.y[0] + computedOffsetY) * height 54 | ); 55 | for (int i = 1; i < polygon.x.length; i++) { 56 | path.lineTo( 57 | (polygon.x[i] + computedOffsetX) * width, 58 | (polygon.y[i] + computedOffsetY) * height 59 | ); 60 | } 61 | } else { 62 | path.moveTo(polygon.x[0] + computedOffsetX, polygon.y[0] + computedOffsetY); 63 | for (int i = 1; i < polygon.x.length; i++) { 64 | path.lineTo(polygon.x[i] + computedOffsetX, polygon.y[i] + computedOffsetY); 65 | } 66 | } 67 | canvas.drawPath(path, polygon.paint()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/scale/D3Converter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.scale; 18 | 19 | public interface D3Converter { 20 | float convert(T toConvert); 21 | T invert(float toInvert); 22 | } 23 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/scale/D3LabelFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.scale; 18 | 19 | public interface D3LabelFunction { 20 | String getLabel(T object); 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/scale/Interpolator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.scale; 18 | 19 | public interface Interpolator { 20 | float interpolate( 21 | float initialValue, float[] initialScope, float[] destinationScope 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/scale/LinearInterpolator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.scale; 18 | 19 | public class LinearInterpolator implements Interpolator { 20 | @Override public float interpolate( 21 | float initialValue, float[] initialScope, float[] destinationScope 22 | ) { 23 | if (destinationScope[0] == destinationScope[1]) { 24 | return destinationScope[0]; 25 | } 26 | float proportion = (initialValue - initialScope[0]) / (initialScope[1] - initialScope[0]); 27 | return (1 - proportion) * destinationScope[0] + proportion * destinationScope[1]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/scale/WrapperDomainFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.scale; 18 | 19 | import com.fabernovel.d3library.axes.D3DomainFunction; 20 | 21 | class WrapperDomainFunction implements D3DomainFunction { 22 | private T[] data; 23 | 24 | WrapperDomainFunction(T[] data) { 25 | setData(data); 26 | } 27 | 28 | void setData(T[] data) { 29 | this.data = data; 30 | } 31 | 32 | @Override public T[] getRange() { 33 | return data; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/threading/BitmapValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.threading; 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.Canvas; 21 | import android.support.annotation.NonNull; 22 | 23 | public abstract class BitmapValueRunnable extends ValueRunnable { 24 | @NonNull protected final Canvas canvas; 25 | 26 | protected BitmapValueRunnable() { 27 | canvas = new Canvas(); 28 | resizeBitmap(1F, 1F); 29 | } 30 | 31 | public void resizeBitmap(float width, float height) { 32 | synchronized (key) { 33 | value = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888); 34 | canvas.setBitmap(value); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/threading/ThreadPool.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.threading; 18 | 19 | import java.util.List; 20 | import java.util.concurrent.Callable; 21 | import java.util.concurrent.ExecutorService; 22 | import java.util.concurrent.Executors; 23 | 24 | public final class ThreadPool { 25 | private static final int MIN_THREADS_NUMBER = 5; 26 | public static final int CORES_NUMBER = Runtime.getRuntime().availableProcessors(); 27 | private static ExecutorService executor = Executors.newFixedThreadPool( 28 | Math.max(CORES_NUMBER + 1, MIN_THREADS_NUMBER) 29 | ); 30 | /** 31 | * This second thread pool should be used when threads from the first pool launch a blocking 32 | * call. This avoids deadlocks. 33 | */ 34 | private static ExecutorService secondaryExecutor = Executors.newFixedThreadPool( 35 | Math.max(CORES_NUMBER + 1, MIN_THREADS_NUMBER) 36 | ); 37 | 38 | private ThreadPool() { 39 | } 40 | 41 | public static void execute(List> todo) { 42 | try { 43 | executor.invokeAll(todo); 44 | } catch (InterruptedException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | 49 | public static void execute(Runnable runnable) { 50 | executor.execute(runnable); 51 | } 52 | 53 | 54 | /** 55 | * See {@link #secondaryExecutor}. 56 | */ 57 | public static void executeOnSecondaryPool(List> todo) { 58 | try { 59 | secondaryExecutor.invokeAll(todo); 60 | } catch (InterruptedException e) { 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | /** 66 | * See {@link #secondaryExecutor}. 67 | */ 68 | public static void executeOnSecondaryPool(Runnable runnable) { 69 | secondaryExecutor.execute(runnable); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/threading/ValueRunnable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.threading; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | import java.util.concurrent.Semaphore; 22 | 23 | public abstract class ValueRunnable { 24 | @NonNull protected final Semaphore semaphore = new Semaphore(0, true); 25 | @NonNull protected final Object key = new Object(); 26 | 27 | protected T value; 28 | 29 | public T getValue() { 30 | return value; 31 | } 32 | 33 | public final Semaphore getSemaphore() { 34 | return semaphore; 35 | } 36 | 37 | public final void run() { 38 | synchronized (key) { 39 | computeValue(); 40 | semaphore.release(); 41 | } 42 | } 43 | 44 | protected abstract void computeValue(); 45 | } 46 | -------------------------------------------------------------------------------- /library/src/main/java/com/fabernovel/d3library/threading/ValueStorage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017, Fabernovel Technologies 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.fabernovel.d3library.threading; 18 | 19 | public class ValueStorage { 20 | private T storedValue; 21 | private final Object synchronisationKey; 22 | private final SetValueRunnable runnable; 23 | private boolean initialized; 24 | 25 | public ValueStorage() { 26 | synchronisationKey = new Object(); 27 | initialized = false; 28 | runnable = new SetValueRunnable(); 29 | } 30 | 31 | public void setValue(final ValueRunnable valueRunnable) { 32 | synchronized (synchronisationKey) { 33 | initialized = true; 34 | storedValue = null; 35 | } 36 | runnable.setRunnable(valueRunnable); 37 | ThreadPool.execute(runnable); 38 | } 39 | 40 | public T getValue() { 41 | try { 42 | synchronized (synchronisationKey) { 43 | if (!initialized) { 44 | throw new IllegalStateException("Not initialized"); 45 | } 46 | while (storedValue == null) { 47 | synchronisationKey.wait(); 48 | } 49 | return storedValue; 50 | } 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | return null; 54 | } 55 | } 56 | 57 | private class SetValueRunnable implements Runnable { 58 | private ValueRunnable runnable; 59 | 60 | private void setRunnable(ValueRunnable runnable) { 61 | this.runnable = runnable; 62 | } 63 | 64 | @Override public void run() { 65 | try { 66 | runnable.run(); 67 | runnable.getSemaphore().acquire(); 68 | synchronized (ValueStorage.this.synchronisationKey) { 69 | storedValue = runnable.getValue(); 70 | synchronisationKey.notifyAll(); 71 | } 72 | } catch (InterruptedException e) { 73 | e.printStackTrace(); 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /library/src/main/res/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | D3Library 19 | 20 | -------------------------------------------------------------------------------- /screenshots/arc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/arc.png -------------------------------------------------------------------------------- /screenshots/area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/area.png -------------------------------------------------------------------------------- /screenshots/barchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/barchart.png -------------------------------------------------------------------------------- /screenshots/boxplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/boxplot.png -------------------------------------------------------------------------------- /screenshots/line.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/line.gif -------------------------------------------------------------------------------- /screenshots/line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/line.png -------------------------------------------------------------------------------- /screenshots/polygon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/polygon.gif -------------------------------------------------------------------------------- /screenshots/stackbarchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/stackbarchart.png -------------------------------------------------------------------------------- /screenshots/turningarcs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applidium/D3Android/65312a626267a2fda29398c718bb3cf6c0e52184/screenshots/turningarcs.gif -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':devApp', ':library', ':demo' 2 | --------------------------------------------------------------------------------