/*
* Created on Oct 13, 2005
*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package jsystem.framework.graph;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.transform.TransformerException;
import jsystem.framework.report.Reporter;
import junit.framework.SystemTestCase;
import org.apache.xpath.XPathAPI;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
/**
* @author guy.arieli
*
*/
public class Graph {
String name;
String yAxiesName;
String xAxiesName = "Second";
String graphName = "graph";
NumberTickUnit xAxisTickUnit = null;
NumberTickUnit yAxisTickUnit = null;
Font textFont = new Font("sansserif", Font.PLAIN, 14);
Font tickFont = new Font("sansserif", Font.PLAIN, 8);
Range xAxisRange = null;
Range yAxisRange = null;
HashMap<String, XYSeries> series = new HashMap<String, XYSeries>();
/**
* Get the Graph's name that will appear as Graph's head line
*
* @return : name as String
*/
public String getName() {
return name;
}
/**
* Set the Graph's name that will appear as Graph's head line
*
* @param name :
* as String
*/
public void setName(String name) {
this.name = name;
}
/**
* Get the X Axis name that will appear as X Axis head line
*
* @return : name as String
*/
public String getXAxiesName() {
return xAxiesName;
}
/**
* Set the X Axis name that will appear as X Axis head line
*
* @param axiesName :
* as String
*/
public void setXAxiesName(String axiesName) {
xAxiesName = axiesName;
}
/**
* Get the Y Axis name that will appear as Y Axis head line
*
* @return : name as String
*/
public String getYAxiesName() {
return yAxiesName;
}
/**
* Set the Y Axis name that will appear as Y Axis head line
*
* @param axiesName :
* as String
*/
public void setYAxiesName(String axiesName) {
yAxiesName = axiesName;
}
/**
* Ctor for Graph
*
* @param name
* (String) the Graph's name that will appear as Graph's head
* line
* @param yAxiesName
* (String) the Y Axis name that will appear as Y Axis head line
*/
public Graph(String name, String yAxiesName) {
this.name = name;
this.yAxiesName = yAxiesName;
}
/**
* Ctor for Graph
*
* @param name
* (String) the Graph's name that will appear as Graph's head
* line
* @param yAxiesName
* (String) the Y Axis name that will appear as Y Axis head line
* @param graphName
* (String) a name to be added to the Graph's file-name for
* uniqeness
*/
public Graph(String name, String yAxiesName, String graphName) {
this.name = name;
this.yAxiesName = yAxiesName;
this.graphName = graphName;
}
/**
* Add a new value (point on the graph) to the Graph on a specific series
*
* @param seriesName
* (String) the name of the series ("line" in the graph)
* @param time
* (long) the X Axis value
* @param value
* (double) the Y Axis value
*/
public void add(String seriesName, long time, double value) {
if (seriesName == null) {
seriesName = "Y";
}
XYSeries s = (XYSeries) series.get(seriesName);
if (s == null) {
s = new XYSeries(seriesName);
series.put(seriesName, s);
}
s.add(time, value);
}
/**
* Remove a graph (line)
*
* @param seriesName the graph name
*/
public void removeGraph(String seriesName){
series.remove(seriesName);
}
/**
* Add a new value (point on the graph) to the Graph on a specific series
* will add the X Axis as the system's current time millis
*
* @param seriesName
* (String) the name of the series ("line" in the graph)
* @param value
* (double) the Y Axis value
*/
public void add(String seriesName, double value) {
add(seriesName, System.currentTimeMillis(), value);
}
/**
* Sets the X Axis ticks to be integers with the requestad gap example:
* setXAxisNumberTickUnitInteger(5): will appear as (0,5,10...)
*
* @param tickUnit -
* the requestad gap between two ticks
*/
public void setXAxisNumberTickUnitInteger(int tickUnit) {
xAxisTickUnit = new NumberTickUnit(tickUnit, NumberFormat.getIntegerInstance());
}
/**
* Sets the Y Axis ticks to be integers with the requestad gap example:
* setYAxisNumberTickUnitInteger(5): will appear as (0,5,10...)
*
* @param tickUnit -
* the requestad gap between two ticks
*/
public void setYAxisNumberTickUnitInteger(int tickUnit) {
yAxisTickUnit = new NumberTickUnit(tickUnit, NumberFormat.getIntegerInstance());
}
/**
* Sets the range for the the X Axis example: setXAxisBounds(-5,5): the
* range will be(-5,-4...4,5)
*
* @param lowBound -
* the lowest value for the X Axis
* @param highBound -
* the highest value for the X Axis
*/
public void setXAxisBounds(double lowBound, double highBound) {
if (lowBound != highBound) {
if (highBound < lowBound) {
double d = lowBound;
lowBound = highBound;
highBound = d;
}
xAxisRange = new Range(lowBound, highBound);
}
}
/**
* Sets the range for the the Y Axis example: setYAxisBounds(-5,5): the
* range will be(-5,-4...4,5)
*
* @param lowBound -
* the lowest value for the Y Axis
* @param highBound -
* the highest value for the Y Axis
*/
public void setYAxisBounds(double lowBound, double highBound) {
if (lowBound != highBound) {
if (highBound < lowBound) {
double d = lowBound;
lowBound = highBound;
highBound = d;
}
yAxisRange = new Range(lowBound, highBound);
}
}
public void show() throws Exception {
show(SystemTestCase.report);
}
/**
* build, renders, save graph as file and add a link in the report
*
* @param reporter
* the "Reporter" object as declared in the tests
* @throws Exception
*/
public void show(Reporter reporter) throws Exception {
XYSeriesCollection dataset = new XYSeriesCollection();
Iterator<XYSeries> iter = series.values().iterator();
while (iter.hasNext()) {
dataset.addSeries(iter.next());
}
NumberAxis xAxis = new NumberAxis(xAxiesName);
xAxis.setLabelFont(textFont);
xAxis.setTickLabelFont(tickFont);
if (xAxisTickUnit != null) {
xAxis.setTickUnit(xAxisTickUnit);
}
xAxis.setAutoRange(true);
if (xAxisRange != null) {
xAxis.setRange(xAxisRange);
}
NumberAxis yAxis = new NumberAxis(yAxiesName);
yAxis.setLabelFont(textFont);
yAxis.setTickLabelFont(tickFont);
if (yAxisTickUnit != null) {
yAxis.setTickUnit(yAxisTickUnit);
}
if (yAxisRange != null) {
yAxis.setRange(yAxisRange);
}
XYItemRenderer renderer = new XYLineAndShapeRenderer(true, false);
renderer.setBaseItemLabelFont(textFont);
renderer.setItemLabelFont(textFont);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setOrientation(PlotOrientation.VERTICAL);
renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
JFreeChart chart = new JFreeChart(name, textFont, plot, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ChartUtilities.writeChartAsPNG(out, chart, 600, 450, false, 9);
String file = graphName + "." + (System.currentTimeMillis() % 1000) + ".png";
reporter.saveFile(file, out.toByteArray());
reporter.addLink(name, file);
}
public byte[] getImageAsByteArray() throws IOException {
XYSeriesCollection dataset = new XYSeriesCollection();
Iterator<XYSeries> iter = series.values().iterator();
while (iter.hasNext()) {
dataset.addSeries(iter.next());
}
JFreeChart chart = ChartFactory.createXYLineChart(name, xAxiesName, yAxiesName, dataset,
PlotOrientation.VERTICAL, true, true, false);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ChartUtilities.writeChartAsPNG(out, chart, 600, 450);
return out.toByteArray();
}
/**
* turn graph into xml Element and add it to a given document.
*
* @param doc
* @throws TransformerException
*/
public void addGraphToDocument(Document doc) throws TransformerException {
Iterator<XYSeries> iter = series.values().iterator();
Element graphElem = doc.createElement("graph");
graphElem.setAttribute("name", this.getName());
while (iter.hasNext()) {
XYSeries currentSeries = iter.next();
for (int i = 0; i < currentSeries.getItemCount(); i++) {
Element xAxis = doc.createElement("xAxis");
Element yAxis = doc.createElement("yAxis");
xAxis.setAttribute("series", (String) (currentSeries.getKey()));
yAxis.setAttribute("series", (String) (currentSeries.getKey()));
Text xValue = doc.createTextNode(((XYDataItem) currentSeries.getItems().get(i)).getX().toString());
Text yValue = doc.createTextNode(((XYDataItem) currentSeries.getItems().get(i)).getY().toString());
xAxis.appendChild(xValue);
yAxis.appendChild(yValue);
graphElem.appendChild(xAxis);
graphElem.appendChild(yAxis);
}
}
Element rootElem = (Element) XPathAPI.selectSingleNode(doc, "/testGraphs");
rootElem.appendChild(graphElem);
}
public Font getTextFont() {
return textFont;
}
public void setTextFont(Font textFont) {
this.textFont = textFont;
}
public Font getTickFont() {
return tickFont;
}
public void setTickFont(Font tickFont) {
this.tickFont = tickFont;
}
}