Here comes how I implemented the input mentioned above. It is more a beginning than a fully fledged example of how to include labels in HighLowCharts.
Code: Select all
/*
* Some parts of this example are copied from HighLowChartDemo1.java.
*/
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.labels.StandardXYItemLabelGenerator;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.CrosshairState;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.HighLowRenderer;
import org.jfree.chart.renderer.xy.XYItemRendererState;
import org.jfree.data.xy.DefaultHighLowDataset;
import org.jfree.data.xy.OHLCDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RefineryUtilities;
/**
* A demo showing a high-low-open-close chart.
*/
public class HLOCChartWithOwnRendering2 extends ApplicationFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* A demonstration application showing a high-low-open-close chart.
*
* @param title the frame title.
*/
public HLOCChartWithOwnRendering2(String title) {
super(title);
JPanel chartPanel = createDemoPanel();
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
private static JFreeChart createChart(OHLCDataset dataset) {
JFreeChart chart = ChartFactory.createHighLowChart(
"High-Low-Open-Close Demo", "Time", "Price", dataset, true);
XYPlot plot = (XYPlot) chart.getPlot();
// plug in my own renderer
plot.setRenderer(new MyHighLowRenderer2());
MyHighLowRenderer2 r = (MyHighLowRenderer2) plot.getRenderer();
r.setHLOCItemPaint(Color.black);
// To set Labels
XYItemLabelGenerator generator = new StandardXYItemLabelGenerator();
r.setBaseItemLabelGenerator(generator);
r.setBaseItemLabelsVisible(true);
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
yAxis.setNumberFormatOverride(new DecimalFormat("$0.00"));
return chart;
}
private static final Calendar calendar = Calendar.getInstance();
/**
* Returns a date using the default locale and timezone.
*
* @param y the year (YYYY).
* @param m the month (1-12).
* @param d the day of the month.
* @param hour the hour of the day.
* @param min the minute of the hour.
*
* @return A date.
*/
private static Date createDate(int y, int m, int d, int hour, int min) {
calendar.clear();
calendar.set(y, m - 1, d, hour, min);
return calendar.getTime();
}
/**
* Creates a sample high low dataset.
*
* @return a sample high low dataset.
*/
public static OHLCDataset createDataset() {
Date[] date = new Date[14];
double[] high = new double[14];
double[] low = new double[14];
double[] open = new double[14];
double[] close = new double[14];
double[] volume = new double[14];
int jan = 1;
date[0] = createDate(2001, jan, 4, 12, 0);
high[0] = 54.00;
low[0] = 51.00;
open[0] = 52.00;
close[0] = 53.00;
volume[0] = 100.0;
date[1] = createDate(2001, jan, 5, 12, 0);
high[1] = 56.50;
low[1] = 51.80;
open[1] = 53.50;
close[1] = 56.00;
volume[1] = 150.0;
date[2] = createDate(2001, jan, 6, 12, 0);
high[2] = 57.00;
low[2] = 52.00;
open[2] = 56.00;
close[2] = 54.50;
volume[2] = 70.0;
date[3] = createDate(2001, jan, 7, 12, 0);
high[3] = 58.00;
low[3] = 54.00;
open[3] = 54.50;
close[3] = 57.50;
volume[3] = 200.0;
date[4] = createDate(2001, jan, 8, 12, 0);
high[4] = 58.50;
low[4] = 55.00;
open[4] = 57.50;
close[4] = 55.50;
volume[4] = 120.0;
date[5] = createDate(2001, jan, 9, 12, 0);
high[5] = 57.80;
low[5] = 53.00;
open[5] = 56.00;
close[5] = 53.00;
volume[5] = 110.0;
date[6] = createDate(2001, jan, 10, 12, 0);
high[6] = 55.0;
low[6] = 51.50;
open[6] = 53.50;
close[6] = 54.00;
volume[6] = 20.0;
date[7] = createDate(2001, jan, 11, 12, 0);
high[7] = 54.50;
low[7] = 51.80;
open[7] = 54.00;
close[7] = 52.00;
volume[7] = 30.0;
date[8] = createDate(2001, jan, 12, 12, 0);
high[8] = 52.50;
low[8] = 49.00;
open[8] = 52.00;
close[8] = 51.70;
volume[8] = 100.0;
date[9] = createDate(2001, jan, 13, 12, 0);
high[9] = 52.00;
low[9] = 48.90;
open[9] = 51.00;
close[9] = 49.00;
volume[9] = 50.0;
date[10] = createDate(2001, jan, 14, 12, 0);
high[10] = 49.30;
low[10] = 46.00;
open[10] = 49.00;
close[10] = 46.00;
volume[10] = 80.0;
date[11] = createDate(2001, jan, 15, 12, 0);
high[11] = 47.10;
low[11] = 45.90;
open[11] = 46.00;
close[11] = 47.00;
volume[11] = 90.0;
date[12] = createDate(2001, jan, 16, 12, 0);
high[12] = 47.10;
low[12] = 44.90;
open[12] = 46.80;
close[12] = 45.00;
volume[12] = 20.0;
date[13] = createDate(2001, jan, 17, 12, 0);
high[13] = 46.80;
low[13] = 43.10;
open[13] = 45.20;
close[13] = 44.50;
volume[13] = 70.0;
return new DefaultHighLowDataset("Series 1", date, high, low, open, close, volume);
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart(createDataset());
return new ChartPanel(chart);
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
HLOCChartWithOwnRendering2 demo = new HLOCChartWithOwnRendering2(
"JFreeChart: HighLowChartDemo1.java");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
class MyHighLowRenderer2 extends HighLowRenderer {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* The paint used for the the HLOC-Items (modification).
*/
private transient Paint hlocItemPaint;
/**
* The paint used for the open ticks (if <code>null</code>, the series
* paint is used instead).
*/
private transient Paint openTickPaint;
/**
* The paint used for the close ticks (if <code>null</code>, the series
* paint is used instead).
*/
private transient Paint closeTickPaint;
/**
* Newly introduced method.
*
* Returns the paint used to draw the HLOC items.
*
* @return The paint used to draw the HLOC items.
*
* @see #setHLOCItemPaint(Paint)
*/
public Paint getHLOCItemPaint() {
return this.hlocItemPaint;
}
/**
* Newly introduced method.
*
* Sets the paint used to draw HLOC items and sends a
* {@link RendererChangeEvent} to all registered listeners.
*
* @param paint the paint (<code>null</code> permitted).
*
* @see #getHLOCPaint()
*/
public void setHLOCItemPaint(Paint paint) {
this.hlocItemPaint = paint;
fireChangeEvent();
}
/**
* Overwritten version of jfree.org.
*
* @param g2 the graphics device.
* @param state the renderer state.
* @param dataArea the area within which the plot is being drawn.
* @param info collects information about the drawing.
* @param plot the plot (can be used to obtain standard color
* information etc).
* @param domainAxis the domain axis.
* @param rangeAxis the range axis.
* @param dataset the dataset.
* @param series the series index (zero-based).
* @param item the item index (zero-based).
* @param crosshairState crosshair information for the plot
* (<code>null</code> permitted).
* @param pass the pass index.
*/
public void drawItem(Graphics2D g2,
XYItemRendererState state,
Rectangle2D dataArea,
PlotRenderingInfo info,
XYPlot plot,
ValueAxis domainAxis,
ValueAxis rangeAxis,
XYDataset dataset,
int series,
int item,
CrosshairState crosshairState,
int pass) {
double x = dataset.getXValue(series, item);
if (!domainAxis.getRange().contains(x)) {
return; // the x value is not within the axis range
}
double xx = domainAxis.valueToJava2D(x, dataArea,
plot.getDomainAxisEdge());
// setup for collecting optional entity info...
Shape entityArea = null;
EntityCollection entities = null;
if (info != null) {
entities = info.getOwner().getEntityCollection();
}
PlotOrientation orientation = plot.getOrientation();
RectangleEdge location = plot.getRangeAxisEdge();
Paint itemPaint = getItemPaint(series, item);
// if-block is a modification of jfree.org version.
if (this.hlocItemPaint != null) {
itemPaint = this.hlocItemPaint;
}
Stroke itemStroke = getItemStroke(series, item);
g2.setPaint(itemPaint);
g2.setStroke(itemStroke);
if (dataset instanceof OHLCDataset) {
OHLCDataset hld = (OHLCDataset) dataset;
double yHigh = hld.getHighValue(series, item);
double yLow = hld.getLowValue(series, item);
if (!Double.isNaN(yHigh) && !Double.isNaN(yLow)) {
double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea,
location);
double yyLow = rangeAxis.valueToJava2D(yLow, dataArea,
location);
if (orientation == PlotOrientation.HORIZONTAL) {
g2.draw(new Line2D.Double(yyLow, xx, yyHigh, xx));
entityArea = new Rectangle2D.Double(Math.min(yyLow, yyHigh),
xx - 1.0, Math.abs(yyHigh - yyLow), 2.0);
}
else if (orientation == PlotOrientation.VERTICAL) {
g2.draw(new Line2D.Double(xx, yyLow, xx, yyHigh));
entityArea = new Rectangle2D.Double(xx - 1.0,
Math.min(yyLow, yyHigh), 2.0,
Math.abs(yyHigh - yyLow));
}
}
double delta = getTickLength();
if (domainAxis.isInverted()) {
delta = -delta;
}
if (getDrawOpenTicks()) {
double yOpen = hld.getOpenValue(series, item);
if (!Double.isNaN(yOpen)) {
double yyOpen = rangeAxis.valueToJava2D(yOpen, dataArea,
location);
if (this.openTickPaint != null) {
g2.setPaint(this.openTickPaint);
}
else {
g2.setPaint(itemPaint);
}
if (orientation == PlotOrientation.HORIZONTAL) {
g2.draw(new Line2D.Double(yyOpen, xx + delta, yyOpen,
xx));
}
else if (orientation == PlotOrientation.VERTICAL) {
g2.draw(new Line2D.Double(xx - delta, yyOpen, xx,
yyOpen));
}
}
}
if (getDrawCloseTicks()) {
double yClose = hld.getCloseValue(series, item);
if (!Double.isNaN(yClose)) {
double yyClose = rangeAxis.valueToJava2D(
yClose, dataArea, location);
if (this.closeTickPaint != null) {
g2.setPaint(this.closeTickPaint);
}
else {
g2.setPaint(itemPaint);
}
if (orientation == PlotOrientation.HORIZONTAL) {
g2.draw(new Line2D.Double(yyClose, xx, yyClose,
xx - delta));
}
else if (orientation == PlotOrientation.VERTICAL) {
g2.draw(new Line2D.Double(xx, yyClose, xx + delta,
yyClose));
}
}
}
}
else {
// not a HighLowDataset, so just draw a line connecting this point
// with the previous point...
if (item > 0) {
double x0 = dataset.getXValue(series, item - 1);
double y0 = dataset.getYValue(series, item - 1);
double y = dataset.getYValue(series, item);
if (Double.isNaN(x0) || Double.isNaN(y0) || Double.isNaN(y)) {
return;
}
double xx0 = domainAxis.valueToJava2D(x0, dataArea,
plot.getDomainAxisEdge());
double yy0 = rangeAxis.valueToJava2D(y0, dataArea, location);
double yy = rangeAxis.valueToJava2D(y, dataArea, location);
if (orientation == PlotOrientation.HORIZONTAL) {
g2.draw(new Line2D.Double(yy0, xx0, yy, xx));
}
else if (orientation == PlotOrientation.VERTICAL) {
g2.draw(new Line2D.Double(xx0, yy0, xx, yy));
}
}
}
if (entities != null) {
addEntity(entities, entityArea, dataset, series, item, 0.0, 0.0);
}
/* The following if-Block is more or less a quick and dirty copy and past of
* some code out of function drawSecondaryPass out of class XYLineAndShapeRenderer (Version 1.0.13).
* The code in the if block does not exist in HighLowRenderer.
* */
if (isItemLabelVisible(series, item)) {
// get the data point...
double x1 = dataset.getXValue(series, item);
double y1 = dataset.getYValue(series, item);
if (Double.isNaN(y1) || Double.isNaN(x1)) {
return;
}
RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
xx = transX1;
double yy = transY1;
yy = 100.0;
System.out.println(xx+" "+yy);
drawItemLabel(g2, orientation, dataset, series, item, xx, yy,
(y1 < 0.0));
}
}
}