Created
February 2, 2019 21:39
-
-
Save vasyl91/0bc4ceb7b1fd78a2623fc3ae980f0be8 to your computer and use it in GitHub Desktop.
GraphView React-Native CSV reader module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.Color; | |
import com.facebook.react.bridge.ReadableArray; | |
import com.facebook.react.bridge.ReadableMap; | |
import com.facebook.react.modules.core.DeviceEventManagerModule; | |
import com.facebook.react.uimanager.SimpleViewManager; | |
import com.facebook.react.uimanager.ThemedReactContext; | |
import com.facebook.react.uimanager.annotations.ReactProp; | |
import com.jjoe64.graphview.GraphView; | |
import com.jjoe64.graphview.GridLabelRenderer; | |
import com.jjoe64.graphview.helper.DateAsXAxisLabelFormatter; | |
import com.jjoe64.graphview.series.DataPoint; | |
import com.jjoe64.graphview.series.LineGraphSeries; | |
import com.jjoe64.graphview.Viewport; | |
import com.univocity.parsers.csv.CsvParser; | |
import com.univocity.parsers.csv.CsvParserSettings; | |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileFilter; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.text.ParseException; | |
import java.text.SimpleDateFormat; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import javax.annotation.Nullable; | |
import org.apache.commons.lang3.time.DurationFormatUtils; | |
import org.apache.commons.io.comparator.LastModifiedFileComparator; | |
import org.apache.commons.io.filefilter.WildcardFileFilter; | |
// Created by Vasyl 25/01/2019 | |
/* | |
** NOTE: Even though I implemented fastest csv parser on the market, GraphView still struggles to display correctly data greater than 200-300 lines. | |
** Optimally save to .csv not often than every 3 minutes (assuming really long night sleep: 20 logs per hour x 10 hours of sleep = 200 lines) | |
*/ | |
// If you want to use it with RN add this file as module. | |
public class CSVGraph extends SimpleViewManager<GraphView> { | |
private final static String REACT_CLASS = "CSV_GRAPH"; | |
public @Nullable int number; | |
ThemedReactContext appContext; | |
// Count files in provided directory | |
public int getFilesCount(File file) { | |
File[] files = file.listFiles(); | |
int count = 0; | |
for (File f : files) | |
if (f.isDirectory()) | |
count += getFilesCount(f); | |
else | |
count++; | |
return count; | |
} | |
@Override | |
public String getName() { | |
return REACT_CLASS; | |
} | |
@Override | |
public GraphView createViewInstance(ThemedReactContext reactContext) { | |
appContext = reactContext; | |
GraphView graphView = new GraphView(reactContext); | |
return graphView; | |
} | |
private void sendData(String eventName, String fileData) { | |
appContext | |
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) | |
.emit(eventName, fileData); | |
} | |
@ReactProp(name = "graphNumber") | |
public void setData(GraphView graphView, @Nullable int number){ | |
// Get chosen .csv file and if it exists and is not empty, read two first columns: timestamp,value | |
// Depending on 'graphNumber' in JS file: the newest file - 0; second - 1; third - 2; ...tenth - 9 | |
String directoryString = "/storage/emulated/0/SleepTracker/nights/"; | |
File directory = new File(directoryString); | |
graphView.removeAllSeries(); | |
if (getFilesCount(directory) > 0) { | |
FileFilter fileFilter = new WildcardFileFilter("*.csv"); | |
File[] files = directory.listFiles(fileFilter); | |
Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE); | |
String stringFile = directoryString + files[number].getName(); | |
File file = new File(stringFile); | |
if (file.length() > 0) { | |
List<String[]> data = new ArrayList<>(); | |
String[] content = null; | |
CsvParserSettings settings = new CsvParserSettings(); | |
CsvParser parser = new CsvParser(settings); | |
String[] rows; | |
parser.beginParsing(file); | |
String[] firstRow = parser.parseNext(); | |
while ((rows = parser.parseNext()) != null) { | |
String lastRow = rows[0]; | |
content = rows; | |
data.add(content); | |
DataPoint[] points = new DataPoint[data.size()]; | |
for (int i = 0; i < data.size(); i++){ | |
rows = data.get(i); | |
points[i] = new DataPoint(Long.parseLong(rows[0]), Integer.parseInt(rows[1])); | |
} | |
LineGraphSeries<DataPoint> series = new LineGraphSeries<>(points); | |
graphView.getViewport().setXAxisBoundsManual(true); | |
graphView.getViewport().setMinX(Long.parseLong(firstRow[0])); | |
graphView.getViewport().setMaxX(Long.parseLong(lastRow)); | |
SimpleDateFormat hoursFormat = new SimpleDateFormat("HH':00'"); | |
graphView.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(appContext, hoursFormat)); | |
graphView.getGridLabelRenderer().setNumHorizontalLabels(4); | |
graphView.getGridLabelRenderer().setHorizontalLabelsAngle(135); | |
graphView.getViewport().setScalableY(true); | |
series.setColor(Color.parseColor("#587F4A")); | |
graphView.addSeries(series); | |
// Change time format depending on scale | |
graphView.getViewport().setOnXAxisBoundsChangedListener(new Viewport.OnXAxisBoundsChangedListener() { | |
@Override | |
public void onXAxisBoundsChanged(double minX, double maxX, Viewport.OnXAxisBoundsChangedListener.Reason reason) { | |
maxX = graphView.getViewport().getMaxX(false); | |
minX = graphView.getViewport().getMinX(false); | |
Long view = (Double.valueOf(maxX).longValue() / 1000) - (Double.valueOf(minX).longValue() / 1000); | |
SimpleDateFormat hoursFormat; | |
if (view < 100) { | |
hoursFormat = new SimpleDateFormat("HH:mm"); | |
} else { | |
hoursFormat = new SimpleDateFormat("HH':00'"); | |
} | |
graphView.getGridLabelRenderer().setLabelFormatter(new DateAsXAxisLabelFormatter(appContext, hoursFormat)); | |
} | |
}); | |
// Send data info | |
String eventName = "INFO_" + String.valueOf(number); | |
String duration = DurationFormatUtils.formatDuration((Long.parseLong(lastRow) - Long.parseLong(firstRow[0])), "HH'h' mm'm'"); | |
sendData(eventName, duration); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment