/*
Copyright 2006 by Sean Luke
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.util.media.chart;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.util.*;
import sim.util.gui.*;
// From JFreeChart (jfreechart.org)
import org.jfree.data.xy.*;
import org.jfree.chart.*;
import org.jfree.chart.event.*;
import org.jfree.chart.plot.*;
import org.jfree.data.general.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.general.*;
/** A SeriesAttributes used for user control pf time series created with TimeSeriesCharGenerator.
This is done largely through the
manipulation of XYSeries objects and features of the XYPlot class. */
public class TimeSeriesAttributes extends SeriesAttributes
{
/** A dash */
static final float DASH = 6;
/** A dot */
static final float DOT = 1;
/** A short space */
static final float SPACE = 3;
/** A long space */
static final float SKIP = DASH;
static final public int PATTERN_DASH = 0;
static final public int PATTERN_DASH_SKIP = 1;
static final public int PATTERN_DASH_SPACE = 2;
static final public int PATTERN_DASH_SPACE_DASH_SPACE_DOT_SPACE = 3;
static final public int PATTERN_DASH_SPACE_DOT_SPACE = 4;
static final public int PATTERN_DASH_SPACE_DOT_SPACE_DOT_SPACE = 5;
static final public int PATTERN_DOT_SPACE =6;
static final public int PATTERN_DOT_SKIP = 7;
/** Nine dash combinations that the user might find helpful. */
static final float[][] dashPatterns =
{
{ DASH, 0.0f }, // --------
{ DASH * 2, SKIP },
{ DASH, SKIP } , // - - -
{ DASH, SPACE } , // - - - -
{ DASH, SPACE, DASH, SPACE, DOT, SPACE }, // - - . - - .
{ DASH, SPACE, DOT, SPACE, }, // - . - .
{ DASH, SPACE, DOT, SPACE, DOT, SPACE }, // - . . - . .
{ DOT, SPACE }, // . . . .
{ DOT, SKIP } // . . . .
};
/** How much we should stretch the dashPatterns listed above. 1.0 is normal. */
float stretch;
NumberTextField stretchField;
/** Line thickness. */
float thickness;
NumberTextField thicknessField;
/** Line dash pattern (one of the dashPatterns above). */
float[] dashPattern;
JComboBox dashPatternList;
/** Line color. */
Color strokeColor;
ColorWell strokeColorWell;
public void setThickness(float value) { thicknessField.setValue(thicknessField.newValue(value)); }
public float getThickness() { return (float)(thicknessField.getValue()); }
public void setStretch(float value) { stretchField.setValue(stretchField.newValue(value)); }
public float getStretch() { return (float)(stretchField.getValue()); }
public void setDashPattern(int value)
{
if (value >= 0 && value < dashPatterns.length)
{
dashPatternList.setSelectedIndex(value);
dashPattern = dashPatterns[value];
}
}
public float getDashPattern() { return dashPatternList.getSelectedIndex(); }
public void setStrokeColor(Color value) { strokeColorWell.setColor(strokeColor = value);}
public Color getStrokeColor() { return strokeColor; }
/** The time series in question. */
public XYSeries series;
public void setSeriesName(String val) { series.setKey(val); }
public String getSeriesName() { return "" + series.getKey(); }
/** Builds a TimeSeriesAttributes with the given generator, series, and index for the series. */
public TimeSeriesAttributes(ChartGenerator generator, XYSeries series, int index)
{
super(generator, "" + series.getKey(), index); this.series = series;
}
public void rebuildGraphicsDefinitions()
{
float[] newDashPattern = new float[dashPattern.length];
for(int x=0;x<dashPattern.length;x++)
if (stretch*thickness > 0)
newDashPattern[x] = dashPattern[x] * stretch * thickness; // include thickness so we dont' get overlaps -- will this confuse users?
XYItemRenderer renderer = getRenderer();
renderer.setSeriesStroke(getSeriesIndex(),
new BasicStroke(thickness, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,0,newDashPattern,0));
renderer.setSeriesPaint(getSeriesIndex(),strokeColor);
repaint();
}
public void buildAttributes()
{
// The following three variables aren't defined until AFTER construction if
// you just define them above. So we define them below here instead.
dashPattern = dashPatterns[0];
stretch = 1.0f;
thickness = 2.0f;
// strokeColor = Color.black; // rebuildGraphicsDefinitions will get called by our caller afterwards
XYItemRenderer renderer = getRenderer();
//Paint paint = renderer.getSeriesPaint(getSeriesIndex());
//In jfc 1.0.6 getSeriesPaint returns null!!!
//You need lookupSeriesPaint(), but that's not backward compatible.
//The only thing consistent in all versions is getItemPaint
//(which looks like a gross miss-use, but gets the job done)
Paint paint = renderer.getItemPaint(getSeriesIndex(), -1);
strokeColor = (Color)paint;
strokeColorWell = new ColorWell(strokeColor)
{
public Color changeColor(Color c)
{
strokeColor = c;
rebuildGraphicsDefinitions();
return c;
}
};
addLabelled("Color",strokeColorWell);
thicknessField = new NumberTextField(2.0,true)
{
public double newValue(double newValue)
{
if (newValue < 0.0)
newValue = currentValue;
thickness = (float)newValue;
rebuildGraphicsDefinitions();
return newValue;
}
};
addLabelled("Width",thicknessField);
dashPatternList = new JComboBox();
dashPatternList.setEditable(false);
dashPatternList.setModel(new DefaultComboBoxModel(new java.util.Vector(Arrays.asList(
new String[] { "Solid", "__ __ __", "_ _ _ _", "_ _ _ _ _", "_ _ . _ _ .",
"_ . _ . _ .", "_ . . _ . .", ". . . . . . .", ". . . . ." }))));
dashPatternList.setSelectedIndex(0);
dashPatternList.addActionListener(new ActionListener()
{
public void actionPerformed ( ActionEvent e )
{
dashPattern = dashPatterns[dashPatternList.getSelectedIndex()];
rebuildGraphicsDefinitions();
}
});
addLabelled("Dash",dashPatternList);
stretchField = new NumberTextField(1.0,true)
{
public double newValue(double newValue)
{
if (newValue < 0.0)
newValue = currentValue;
stretch = (float)newValue;
rebuildGraphicsDefinitions();
return newValue;
}
};
addLabelled("Stretch",stretchField);
}
}