package org.commcare.graph.model;
import org.commcare.graph.util.GraphException;
import org.commcare.graph.view.c3.AxisConfiguration;
import org.commcare.graph.view.c3.DataConfiguration;
import org.commcare.graph.view.c3.GridConfiguration;
import org.commcare.graph.view.c3.LegendConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Hashtable;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
/**
* Contains all of the fully-evaluated data to draw a graph: a type, set of series, set of text annotations, and key-value map of configuration.
*
* @author jschweers
*/
public class GraphData implements ConfigurableData {
private String mType;
private final Vector<SeriesData> mSeries;
private final Hashtable<String, String> mConfiguration;
private final Vector<AnnotationData> mAnnotations;
public GraphData() {
mSeries = new Vector<>();
mConfiguration = new Hashtable<>();
mAnnotations = new Vector<>();
}
public String getType() {
return mType;
}
public void setType(String type) {
mType = type;
}
public Vector<SeriesData> getSeries() {
return mSeries;
}
public void addSeries(SeriesData s) {
mSeries.addElement(s);
}
public void addAnnotation(AnnotationData a) {
mAnnotations.addElement(a);
}
public Vector<AnnotationData> getAnnotations() {
return mAnnotations;
}
@Override
public void setConfiguration(String key, String value) {
mConfiguration.put(key, value);
}
@Override
public String getConfiguration(String key) {
return mConfiguration.get(key);
}
@Override
public String getConfiguration(String key, String defaultValue) {
String value = getConfiguration(key);
if (value == null) {
return defaultValue;
}
return value;
}
/**
* @return The full HTML page that will comprise this graph (including head, body, and all
* script and style tags)
*/
public String getGraphHTML(String title) throws GraphException {
SortedMap<String, String> variables = new TreeMap<>();
JSONObject config = new JSONObject();
StringBuilder html = new StringBuilder();
try {
// Configure data first, as it may affect the other configurations
DataConfiguration data = new DataConfiguration(this);
config.put("data", data.getConfiguration());
AxisConfiguration axis = new AxisConfiguration(this);
config.put("axis", axis.getConfiguration());
GridConfiguration grid = new GridConfiguration(this);
config.put("grid", grid.getConfiguration());
LegendConfiguration legend = new LegendConfiguration(this);
config.put("legend", legend.getConfiguration());
variables.put("type", "'" + this.getType() + "'");
variables.put("config", config.toString());
// For debugging purposes, note that most minified files have un-minified equivalents in the same directory.
// To use them, switch affix to "max" and get rid of the ignoreAssetsPattern in build.gradle that
// filters them out of the APK.
String affix = "min";
html.append(
"<html>" +
"<head>" +
"<link rel='stylesheet' type='text/css' href='file:///android_asset/graphing/c3.min.css'></link>" +
"<link rel='stylesheet' type='text/css' href='file:///android_asset/graphing/graph." + affix + ".css'></link>" +
"<script type='text/javascript' src='file:///android_asset/graphing/d3.min.js'></script>" +
"<script type='text/javascript' src='file:///android_asset/graphing/c3." + affix + ".js' charset='utf-8'></script>" +
"<script type='text/javascript'>try {\n");
html.append(getVariablesHTML(variables, null));
html.append(getVariablesHTML(data.getVariables(), "data"));
html.append(getVariablesHTML(axis.getVariables(), "axis"));
html.append(getVariablesHTML(grid.getVariables(), "grid"));
html.append(getVariablesHTML(legend.getVariables(), "legend"));
String titleHTML = "<div id='chart-title'>" + title + "</div>";
String errorHTML = "<div id='error'></div>";
String chartHTML = "<div id='chart'></div>";
html.append(
"\n} catch (e) { displayError(e); }</script>" +
"<script type='text/javascript' src='file:///android_asset/graphing/graph." + affix + ".js'></script>" +
"</head>" +
"<body>" + titleHTML + errorHTML + chartHTML + "</body>" +
"</html>");
} catch (JSONException e) {
e.printStackTrace();
throw new GraphException(e.getMessage());
}
return html.toString();
}
/**
* Generate HTML to declare given variables in WebView.
*
* @param variables OrderedHashTable where keys are variable names and values are JSON
* representations of values.
* @param namespace Optional. If provided, instead of declaring a separate variable for each
* item in variables, one object will be declared with namespace for a name
* and a property corresponding to each item in variables.
* @return HTML string
*/
private static String getVariablesHTML(SortedMap<String, String> variables, String namespace) {
StringBuilder html = new StringBuilder();
if (namespace != null && !namespace.equals("")) {
html.append("var ").append(namespace).append(" = {};\n");
}
for (String name : variables.keySet()) {
if (namespace == null || namespace.equals("")) {
html.append("var ").append(name);
} else {
html.append(namespace).append(".").append(name);
}
html.append(" = ").append(variables.get(name)).append(";\n");
}
return html.toString();
}
}