tools overlay
tools overlay
hi,
can i somehow overlay graphic elements without changing the source code? i think of cursors, lines and other things ...
thanks in advance
can i somehow overlay graphic elements without changing the source code? i think of cursors, lines and other things ...
thanks in advance
Yes, you can.
XYPlot allows you to set secondary datasets, with their own renderers. For example, to add a line to the plot, you could add a secondary dataset and set its renderer to StandardXYItemRenderer. Then add a series with two items (one for the start- and one for the end-point) for each line you want overlaid.
XYPlot allows you to set secondary datasets, with their own renderers. For example, to add a line to the plot, you could add a secondary dataset and set its renderer to StandardXYItemRenderer. Then add a series with two items (one for the start- and one for the end-point) for each line you want overlaid.
performance would be toooo slow
this solution is ok to add lines in a static chart, but what if i want to ta add lines underneath the cursor? adding and removing lines whenever i move the mouse is no solution ... auto-scaling and all those (annoying and cool at the same time) features make it very slow.
I need to add items directly into the rendering pipeline of jfreechart ...
I need to add items directly into the rendering pipeline of jfreechart ...
Basically, JFreeChart always redraws everything. I've been working on some optimisations to make "redrawing everything" happen significantly faster, but when a large set of data is being shown it still happens too slowly for real-trime drawing of tools (lines, etc.) to be feasible. One thing you could try is xoring shapes onto the component's Graphics, so you don't need to redraw the whole chart. This is the approach taken for the trace lines and the zoom rectangle in ChartPanel.
The ChartPanel already does the rendering of the chart directly to the Graphics object. For a simple XYPlot, it goes something like this (simplified):
<code>
ChartPanel.paintComponent() ->
|- Create the Graphics2D object
|- Handle buffering
|- Work out scaling
|- JFreeChart.draw() ->
|- Set rendering hints
|- Handle clipping
|- Render chart background, border and title
|- XYPlot.draw() ->
|- Render plot background
|- Render axes
|- XYRenderer.draw(Domain|Range)TickBands()
|- XYRenderer.draw(Domain|Range)Gridlines()
|- for each data item: XYRenderer.drawItem()
</code>
As for specifying which timespan to draw, use "setRange()" on your domain axis (which presumably is a DateAxis).
<code>
ChartPanel.paintComponent() ->
|- Create the Graphics2D object
|- Handle buffering
|- Work out scaling
|- JFreeChart.draw() ->
|- Set rendering hints
|- Handle clipping
|- Render chart background, border and title
|- XYPlot.draw() ->
|- Render plot background
|- Render axes
|- XYRenderer.draw(Domain|Range)TickBands()
|- XYRenderer.draw(Domain|Range)Gridlines()
|- for each data item: XYRenderer.drawItem()
</code>
As for specifying which timespan to draw, use "setRange()" on your domain axis (which presumably is a DateAxis).
(Reposted since I messed up the BBCode, sorry - Preview is your friend)
The ChartPanel already does the rendering of the chart directly to the Graphics object. For a simple XYPlot, it goes something like this (simplified):
As for specifying which timespan to draw, use "setRange()" on your domain axis (which presumably is a DateAxis).
The ChartPanel already does the rendering of the chart directly to the Graphics object. For a simple XYPlot, it goes something like this (simplified):
Code: Select all
ChartPanel.paintComponent() ->
|- Create the Graphics2D object
|- Handle buffering
|- Work out scaling
|- JFreeChart.draw() ->
|- Set rendering hints
|- Handle clipping
|- Render chart background, border and title
|- XYPlot.draw() ->
|- Render plot background
|- Render axes
|- XYRenderer.draw(Domain|Range)TickBands()
|- XYRenderer.draw(Domain|Range)Gridlines()
|- for each data item: XYRenderer.drawItem()
setRange() is a member of org.jfree.chart.axis.ValueAxis (i.e.) - sorry to be so lame, but i can't get a grip on how to set the range for my data or chart. i can't find a setAxis/setRange inkingguppy wrote:(Reposted since I messed up the BBCode, sorry - Preview is your friend)
As for specifying which timespan to draw, use "setRange()" on your domain axis (which presumably is a DateAxis).
JFreeChart chart; TimeSeriesCollection xyseries=new TimeSeriesCollection(); TimeSeries x1; or ChartPanel chartPanel;
can you tell me where i can find it?
about the other thing of drawing, i guess i'll simply enable the markers and draw the chart onto a jpanel manually - with grabbing the mouse events and handing them (if necesary) to the underlying chartPanel - it makes most sense to me - the clicks i think i can convert through this convert function i found in chartpanel ....
Can you please post your chart creation code? I guess you're using some constructors that automatically create axes, etc. (which is fine, but I don't know where your Plot is created).
The ChartPanel does some useful things with the mouse events (such as zooming and crosshairs). It also determines which "ChartEntity" is under the pointer, which can be very useful (once you've drawn your lines, I'm guessing you're going to want to be able to click on them to manipulate them). Subclassing ChartPanel might be the way to go. Indidently, I extended the mouse input support throughout JFreeChart, I'm getting a load of patches together to submit to David in the near future.
The ChartPanel does some useful things with the mouse events (such as zooming and crosshairs). It also determines which "ChartEntity" is under the pointer, which can be very useful (once you've drawn your lines, I'm guessing you're going to want to be able to click on them to manipulate them). Subclassing ChartPanel might be the way to go. Indidently, I extended the mouse input support throughout JFreeChart, I'm getting a load of patches together to submit to David in the near future.
that's the main chart class ...
Code: Select all
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.text.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.time.FixedMillisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.*;
import plugin.*;
public class ChartWindow extends JInternalFrame implements DataRecipient{
String symbol=""; //contains the symbol for this chartwindow
Starter s; // the pointer to Start
JPanel toolbar; //a panel supposed to be a toolbar
JComboBox jcb; //the dropdown containing the symbols
JComboBox timerange; //the dropdown for the complete timerange
JComboBox compression; //the dropdown for the duration
JFreeChart chart;
//JFreeChart datasets
TimeSeriesCollection xyseries=new TimeSeriesCollection(); // XYSeriesCollection (see ttp://www.jfree.org/jfreechart/javadoc/org/jfree/data/XYSeriesCollection.html)
TimeSeries x1;
TimeSeries bollinger_top;
TimeSeries bollinger_bottom;
TimeSeries average1;
TimeSeries average2;
Vector components=new Vector(); //contains plugin components
//helper variables
int av1=5;
/**
* constructor. Constructs the chart window.
* @param s
* @param symbol
*/
public ChartWindow(Starter s, String symbol){
super(symbol, true, true, true, true);
this.symbol=symbol;
this.s=s;
//build a toolbar
toolbar=new JPanel();
this.getContentPane().add(toolbar, BorderLayout.NORTH);
buildToolbar(toolbar);
//
x1=new TimeSeries("symbol", FixedMillisecond.class);
average1=new TimeSeries("av1", FixedMillisecond.class);
xyseries.addSeries(x1);
xyseries.addSeries(average1);
System.out.println("Populated.");
//
JFreeChart chart = createChart(xyseries);
System.out.println("constr.");
chart.getXYPlot().setOrientation(PlotOrientation.VERTICAL);
chart.setAntiAlias(false);
chart.setBackgroundPaint(new Color(255,255,255));
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
//
this.getContentPane().add(chartPanel, BorderLayout.CENTER);
s.desktop.add(this);
System.out.println("add");
setVisible(true);
setSize(new Dimension(400,300));
chartPanel.setPopupMenu(buildPopupMenu());
chartPanel.setMouseZoomable(true);
chartPanel.setHorizontalAxisTrace(true);
chartPanel.setVerticalAxisTrace(true);
//initialize some plugins
RSI rsi=new RSI();
components.add(rsi);
this.getContentPane().add(rsi.visualComponent(), BorderLayout.SOUTH);
}
/**
* builds and returns the popup menu
* @return
*/
public JPopupMenu buildPopupMenu(){
JPopupMenu m=new JPopupMenu();
//the averages menu
JMenu a=new JMenu("Averages");
JMenu a1=new JMenu("Average 1");
JMenuItem a11=a1.add("5 units");
a11.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setAV1(5);
}
});
JMenuItem a12=a1.add("10 units");
a12.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setAV1(10);
}
});
JMenuItem a13=a1.add("50 units");
a13.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
setAV1(50);
}
});
a.add(a1);
JMenu a2=new JMenu("Average 2");
JMenuItem a21=a2.add("5 units");
JMenuItem a22=a2.add("10 units");
JMenuItem a23=a2.add("50 units");
a.add(a2);
m.add(a);
//Indicator menu
return m;
}
public void setAV1(int d){
av1=d;
}
/**
* temporal helper function
*
* @param dataset
* @return
*/
private JFreeChart createChart(TimeSeriesCollection dataset) {
chart = ChartFactory.createTimeSeriesChart(
symbol,
"",
"",
dataset,
false, false, false
);
return chart;
}
/**
* populates toolbar
*
* @author uls
*
*/
void buildToolbar(JPanel t){
//set up the layout ground
GridBagLayout gbl=new GridBagLayout();
GridBagConstraints gbc=new GridBagConstraints();
t.setLayout(gbl);
int i=0;
gbc.gridy=0;
gbc.fill=GridBagConstraints.BOTH;
gbc.anchor=GridBagConstraints.NORTHWEST;
//populate the bar
//add the float/defloat button
gbc.gridx=i;
gbc.weightx=0;
JButton floa=new JButton("float");
gbl.setConstraints(floa, gbc);
toolbar.add(floa);
//add the cymbol chooser
i++;
gbc.gridx=i;
gbc.weightx=1;
jcb=new JComboBox(new Object[]{"^GDAXI", "MUVGN.DE"});
jcb.setEditable(true);
gbl.setConstraints(jcb, gbc);
toolbar.add(jcb);
//add the set button
i++;
JButton set=new JButton("set");
gbc.gridx=i;
gbc.weightx=0;
gbl.setConstraints(set, gbc);
toolbar.add(set);
set.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String s=(String)jcb.getSelectedItem();
chart.setTitle(s);
symbol=s;
populate();
}
});
//add the print button
i++;
JButton print=new JButton("print");
gbc.gridx=i;
gbc.weightx=0;
gbl.setConstraints(print, gbc);
toolbar.add(print);
//add a drop down with to set the time range
timerange=new JComboBox(new Object[]{"2 d", "5 d", "10 d", "1 m", "3 m", "6 m", "1 y", "2 y", "5 y", "max"});
i++;
gbc.gridx=i;
gbc.weightx=0;
gbl.setConstraints(timerange, gbc);
toolbar.add(timerange);
//add a drop down with to set the compression
compression=new JComboBox(new Object[]{"ticks", "1 min", "5 min", "15 min", "30 min", "60 min", "daily", "weekly", "monthly"});
i++;
gbc.gridx=i;
gbc.weightx=0;
gbl.setConstraints(compression, gbc);
toolbar.add(compression);
}
// data recipient interfaces
/**w
* implements DataRecipients data function
* @see jahangir.DataRecipient#data(jahangir.Tick)
*/
int i=0;
public void data(Tick t){
// Date d=new Date();
x1.add(new FixedMillisecond(t.date), t.value);
calcAverage1(0,t.date);
for(int i=0;i<components.size();i++){
Plugin p=(Plugin)components.elementAt(i);
p.data(t);
}
i++;
}
/**
* implements DataRecipient's getSymbol function
* @see jahangir.DataRecipient#getSymbol()
*
*/
public String getSymbol(){
return symbol;
}
/**
* reads the settings from the jcomboboxes timerange and compression and
* populates the chart.
*
*/
public void populate(){
int n=timerange.getSelectedIndex();
int comp=compression.getSelectedIndex();
String startdate="";
String symbol=(String)jcb.getSelectedItem();
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
GregorianCalendar cal = new GregorianCalendar() ;
switch(n){
case 0:
//two day range
cal.add(cal.DATE, -2) ;
break;
case 1:
//five day range
cal.add(cal.DATE, -5) ;
break;
case 2:
//ten day range
cal.add(cal.DATE, -10) ;
break;
case 3:
//one month
cal.add(cal.MONTH, -1);
break;
case 4:
//three month
cal.add(cal.MONTH, -3);
break;
case 5:
//six month
cal.add(cal.MONTH, -6);
break;
case 6:
//one year
cal.add(cal.YEAR, -1);
break;
case 7:
//two year
cal.add(cal.YEAR, -2);
break;
case 8:
//five year
cal.add(cal.YEAR, -5);
break;
case 9:
//max range
cal.add(cal.YEAR, -1000);
break;
default:
break;
}
startdate=sdf.format(cal.getTime());
Vector v=s.dal.getTicks(symbol, startdate, "");
Tick t;
try{
for(int i=0;i<v.size();i++){
t=(Tick)v.elementAt(i);
//System.out.println(t.timestamp);
x1.add(new FixedMillisecond(sdf.parse(t.timestamp)), t.value);
calcAverage1(0, sdf.parse(t.timestamp));
}
}
catch(Exception e){
}
}
public void calcAverage1(int d, Date timestamp){
try{
double v=0;
List l1=x1.getItems();
for(int i=d;i<d+av1;i++){
v+=x1.getValue(x1.getItemCount()-(av1-i)).doubleValue();
}
average1.add(new FixedMillisecond(timestamp), v/av1);
}
catch(Exception e){
e.printStackTrace();
//System.out.println(timestamp.toString());
}
}
/**
* actually recalculates the first average (necessary when we change the average settings)
* @param d
*/
public void recalculateAverage1(int d){
average1.delete(0, average1.getItemCount());
}
public void addMiniChart(Plugin p){
}
}