com.day.cq.graphics.Graph Maven / Gradle / Ivy
/*
* Copyright 1997-2004 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.graphics;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.graphics.chart.Axis;
import com.day.cq.graphics.chart.Chart;
import com.day.cq.graphics.chart.Data;
import com.day.cq.graphics.chart.Grid;
import com.day.cq.graphics.chart.Metrics;
import com.day.image.Layer;
/**
* The Graph
class implements the basic functionality for the
* chart host object. This class is based on the former rgba/rgba_graph.c
* code.
*
* The Graph
object is the top level container of a chart graphic.
* It contains all the elements such as the axis, the data and the chart itself.
*
* This object is not truly unmutable, but it is mostly write-once. That is, as
* soon as a property has been defined through its setter method, it cannot be
* changed again. It is completely in the responsability of the client not to
* tamper with any values after having calculated the graph. Moreover it is
* the clients duty to ensure complete setting of the graph and its component
* prior to drawing the chart. The results may not be as desired if failing to
* do so.
*
* @author fmeschbe
*/
public class Graph {
//---------- statics -------------------------------------------------------
/** Default logging */
private final static Logger log = LoggerFactory.getLogger(Graph.class);
/** The default background color. May be changed once. */
private static final Color DEFAULT_BGCOLOR = Color.white;
/** Flag to indicate the chart to fit the extent. */
public static final int FLAGS_FIT = 0x01;
/** Flag to indicate non-anti-aliased drawing */
public static final int FLAGS_NON_ANTI_ALIASED = 0x10;
/**
* Internal flag value indicating unset flags. If the flags value is set,
* it is masked with the negative of this. That is the high bit is
* guaranteed to only be set, if the flags field is undefined.
*/
private static final int FLAGS_UNDEFINED = 0x8000;
/**
* The default grid, which may be replaced and merely serves as a
* placeholder. Note: This is not really a good use as we depend on this
* instance to not draw anything and also for the constructor not to
* through if called with null
values.
*/
private static final Grid DEFAULT_GRID = new Grid(null, null);
//---------- fields --------------------------------------------------------
/**
* The background color of the chart. By default the background is white.
* This default may be changed by calling {@link #setBgColor(Color)} once.
*/
private Color bgcolor = DEFAULT_BGCOLOR;
/**
* The chart of the type defined at construction time. This object is set
* at construction time and can only be retrieved from the graph.
*/
private final Chart chart;
/**
* The data is defined by one of the initGraphSamples()
* methods. If the data is set, these methods may not be called anymore and
* the graph can only be drawn, if the data is defined. So clients must
* ensure to call any of the initGraphSamples()
methods prior
* to calling {@link #draw(boolean)}.
*/
private Data data;
/**
* The intented extent of the graph chart. This is defined upon creation
* time. The resulting layer of the {@link #draw(boolean)} call should have this
* size.
*/
private final Rectangle extent;
/**
* The flags for this graph. This may only be set once.
*/
private int flags = FLAGS_UNDEFINED;
/**
* The grid to draw on the background of the chart. The default grid does
* not draw anything but prevents NullPointerExceptions if the grid is not
* set by the client.
*/
private Grid grid = DEFAULT_GRID;
/**
* The maximum number of columns of the data to obey. This value only has
* an effect during sample data initialization if set to anything greater
* than zero.
*/
private int maxcols = 0;
/**
* The maximum number of rows of the data to obey. This value only has
* an effect during sample data initialization if set to anything greater
* than zero.
*/
private int maxrows = 0;
/**
* The metrics data container, which is created during construction and
* filled by the chart implementation object during chart calculation.
*/
private final Metrics metrics;
/**
* The X Axis of the graph chart. This can be set by the setter method,
* only if not set yet. This is also set by the getter method, if not set
* yet. That is, calling the setter after the getter will not replace the
* X Axis object.
*/
private Axis x;
/**
* The Y Axis of the graph chart. This can be set by the setter method,
* only if not set yet. This is also set by the getter method, if not set
* yet. That is, calling the setter after the getter will not replace the
* Y Axis object.
*/
private Axis y;
//---------- Constructors --------------------------------------------------
/**
* Creates a graph chart of the given width, height and type. The type
* parameter is used to create the chart object and depends on the
* {@link Chart#getInstance(String)} method. See there for a definition of
* this parameter.
*
* @param width The desired overall width of the graph chart
* @param height The desired overall height of the graph chart
* @param type The type of chart to draw. The value of this parameter
* is defined by {@link Chart#getInstance(String)}.
*/
public Graph(int width, int height, String type) {
this.chart = Chart.getInstance(type);
this.extent = new Rectangle(width, height);
this.metrics = new Metrics();
}
//---------- Methods -------------------------------------------------------
/**
* @see com.day.cq.graphics.Graph#initGraphSamples(java.lang.String[], java.lang.String[], double[][])
*/
public void initGraphSamples(String[] labels, String[] legends,
double[][] samples) {
// Check for empty data before continuing
if (data != null) {
log.info("initGraphSamples: Samples have already been defined");
return;
}
// check parameters
if (samples == null || samples.length == 0 || samples[0] == null ||
samples[0].length == 0) {
log.warn("initGraphSamples: Missing sample data");
return;
}
if (labels == null) labels = new String[0];
if (legends == null) legends = new String[0];
// get the number of columns and rows
int numrows = samples.length;
int numcols = samples[0].length;
if (maxrows > 0 && numrows > maxrows) numrows = maxrows;
if (maxcols > 0 && numcols > maxcols) numcols = maxcols;
data = new Data(numrows, numcols);
data.setSamples(samples);
data.setLabels(labels);
data.setLegends(legends);
}
/**
* @see com.day.cq.graphics.Graph#initGraphSamples(java.lang.String[][], boolean, boolean)
*/
public void initGraphSamples(String[][] dataTable, boolean nocateg,
boolean nolabels) {
// Check for empty data before continuing
if (data != null) {
log.info("initGraphSamples: Samples have already been defined");
return;
}
// split the string on tabs and lf
int numRows = dataTable.length;
int numCols = dataTable[0].length;
int rowOff = 0; // sample data starts here
int colOff = 0; // sample data starts here
String[] labels = null;
String[] legends = null;
// first get the number straight ...
if (!nolabels) {
numRows--; // don't count label row
rowOff = 1; // data starts on second row
}
if (!nocateg) {
numCols--; // don't count legend column
colOff = 1; // data start on second column
}
// get labels if existing
if (!nolabels) {
labels = new String[numCols];
System.arraycopy(dataTable[0], colOff, labels, 0, labels.length);
}
// get categories (that is legends) if existing
if (!nocateg) {
legends = new String[numRows];
for (int i=0,j=rowOff; i= 0) this.maxcols = maxcols;
}
/**
* @see com.day.cq.graphics.Graph#getMaxcols()
*/
public int getMaxcols() {
return maxcols;
}
/**
* @see com.day.cq.graphics.Graph#setMaxrows(int)
*/
public void setMaxrows(int maxrows) {
if (maxrows >= 0) this.maxrows = maxrows;
}
/**
* @see com.day.cq.graphics.Graph#getMaxrows()
*/
public int getMaxrows() {
return maxrows;
}
/**
* @see com.day.cq.graphics.Graph#getMetrics()
*/
public Metrics getMetrics() {
return metrics;
}
/**
* @see com.day.cq.graphics.Graph#setXAxis(com.day.cq.graphics.chart.Axis)
*/
public void setXAxis(Axis x) {
this.x = x;
}
/**
* @see com.day.cq.graphics.Graph#getXAxis()
*/
public Axis getXAxis() {
if (x == null) x = Axis.getInstance(this);
return x;
}
/**
* @see com.day.cq.graphics.Graph#setYAxis(com.day.cq.graphics.chart.Axis)
*/
public void setYAxis(Axis y) {
this.y = y;
}
/**
* @see com.day.cq.graphics.Graph#getYAxis()
*/
public Axis getYAxis() {
if (y == null) y = Axis.getInstance(this);
return y;
}
}