股票的K线图是所有Chart图中最复杂的一种,把一个K线图拆分开来我们可以发现,K线图的上半截实际上是由阴阳线(阴阳线可以表示开盘价,收盘价,最高价,最低价)、和若干条随时间变化的若干条均线组成;下半截则由与阴阳线对应的成交量柱形图和若干条随时间变化的成交量均线组成。如下图:
了解这一点之后,对照JFreeChart我们发现所有的单个Chart它都已经提供了,我们所需要做的就是把这些Chart进行组合,进而形成一张K线图。
股票中的阴阳线,我们可以用OHLCDataset(蜡烛图)来实现,均线可以用IntervalXYDataset来实现,对于与阴阳线对应的成交量的值我们同样可以用OHLCDataset来实现,只是在编程的时候注意些技艺就可以实现了。
表示阴阳线的(蜡烛图)OHLCDataset如下图:
表示均线的IntervalXYDataset图如下:
对于K线图的上半部分我们可以用JFreeChart中的蜡烛图与时间线图的叠加来完成,下半部分我们同样可以用JFreeChart中的蜡烛图与时间线图的叠加来完成。完成之后我们只需要将上下两部分Chart用CombinedDomainXYPlot进行组合,得到的结果就是我们想要的K线图。知道中明确了这些信息之后我们就可以动手来做JFreeChart版的K线图啦。
这里我们采用JFreeChart的最新版jfreechart-1.0.6来实现。为了方便我们把做好的K线图放到网页当中我们采用Applet来作为载体。同时为了不让Applet直接去访问数据库我们利用Bstek公司的J2EE前端展现产品Dorado5来在客户端为K线图的Applet传递数据,接下来我们就来一步一步实现我们的K线图JFreeChart版。
1) 构造一个为K线图提供数据的表,表结构如下 :
create table k_line_data( stock_name varchar(100),--股票名称 issue_date date,//日期 open_value double,//开盘价 high_value double,//最高价 low_value double,//最低价 close_value double,//收盘价 volume_value double,//成交量 avg5 double,//5日均价 avg10 double,//10日均价 avg20 double,20日均价 avg60 double,//60日均价 vol_avg5 double,//5日成交量均价 vol_avg10 double//10日成交量均价 ) |
接下来我们需要虚拟一些数据出来提供给K线图使用,我们用Dorado5展现的效果如下:
我们要实现的效果是在客户端通过Dorado5中的Dataset通过JS来调用Applet里的方法,为Applet里的K线图提供数据,这样做就避免了我们在Applet里直接去访问服务器端的数据库里的数据。
2) Applet代码如下:
package test.applet;
import java.awt.Color; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map;
import javax.swing.JApplet; import javax.swing.JPanel;
import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickUnit; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.block.BlockBorder; import org.jfree.chart.block.BlockContainer; import org.jfree.chart.block.BorderArrangement; import org.jfree.chart.labels.StandardXYToolTipGenerator; import org.jfree.chart.plot.CombinedDomainXYPlot; import org.jfree.chart.plot.Plot; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.CandlestickRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.title.LegendTitle; import org.jfree.data.general.Dataset; import org.jfree.data.time.Day; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.DefaultHighLowDataset; import org.jfree.data.xy.IntervalXYDataset; import org.jfree.data.xy.OHLCDataset; import org.jfree.ui.HorizontalAlignment; import org.jfree.ui.RectangleEdge;
public class TestApplet extends JApplet { List ls = new ArrayList();//定义一个用来保存数据的集合类List
Map map = null;//用来表示一条记录
public TestApplet() {//将Chart在 Applet中显示 JPanel jpanel = createDemoPanel(); setContentPane(jpanel); }
public void clearList(){//清空保存数据的集合类List ls.clear(); }
private JFreeChart createCombinedChart() { Map m = createDatasetMap();//从数据对象里取出各种类型的对象,主要是用来表示均线的时间线(IntervalXYDataset)对象和用来表示阴阳线和成交量的蜡烛图对象(OHLCDataset) IntervalXYDataset avg_line5 = (IntervalXYDataset) m.get("avg_line5"); IntervalXYDataset avg_line10 = (IntervalXYDataset) m.get("avg_line10"); IntervalXYDataset avg_line20 = (IntervalXYDataset) m.get("avg_line20"); IntervalXYDataset avg_line60 = (IntervalXYDataset) m.get("avg_line60"); IntervalXYDataset vol_avg_line5 = (IntervalXYDataset) m .get("vol_avg_line5"); IntervalXYDataset vol_avg_line10 = (IntervalXYDataset) m .get("vol_avg_line10"); OHLCDataset k_line = (OHLCDataset) m.get("k_line"); OHLCDataset vol = (OHLCDataset) m.get("vol"); String stock_name = (String) m.get("stock_name");
//设置若干个时间线的Render,目的是用来让几条均线显示不同的颜色,和为时间线加上鼠标提示 XYLineAndShapeRenderer xyLineRender = new XYLineAndShapeRenderer(true, false); xyLineRender.setBaseToolTipGenerator(new StandardXYToolTipGenerator( "{0}: ({1}, {2})", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0.00"))); xyLineRender.setSeriesPaint(0, Color.red);
XYLineAndShapeRenderer xyLineRender1 = new XYLineAndShapeRenderer(true, false); xyLineRender1.setBaseToolTipGenerator(new StandardXYToolTipGenerator( "{0}: ({1}, {2})", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0.00"))); xyLineRender1.setSeriesPaint(0, Color.BLACK);
XYLineAndShapeRenderer xyLineRender2 = new XYLineAndShapeRenderer(true, false); xyLineRender1.setBaseToolTipGenerator(new StandardXYToolTipGenerator( "{0}: ({1}, {2})", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0.00"))); xyLineRender1.setSeriesPaint(0, Color.blue);
XYLineAndShapeRenderer xyLineRender3 = new XYLineAndShapeRenderer(true, false); xyLineRender1.setBaseToolTipGenerator(new StandardXYToolTipGenerator( "{0}: ({1}, {2})", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0.00"))); xyLineRender1.setSeriesPaint(0, Color.darkGray);
//定义K线图上半截显示的Plot XYPlot volPlot = new XYPlot(vol_avg_line5, null, new NumberAxis( "股票价格情况"), xyLineRender);
//定义一个CandlestickRenderer给蜡烛图对象使用,目的是对蜡烛图对象的显示进行调整,这里主要是调整它显示的宽度并加上鼠标提示 CandlestickRenderer candlesRender = new CandlestickRenderer(); candlesRender.setCandleWidth(4D); candlesRender.setBaseToolTipGenerator(new StandardXYToolTipGenerator( "{0}: ({1}, {2})", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0.00")));
//把其它的几个Dataset加到上半截要显示的Plot里,并同时设置它们所采用的Render,以形成一个叠加显示的效果 volPlot.setDataset(1, vol_avg_line10); volPlot.setRenderer(1, xyLineRender1); volPlot.setDataset(2, vol); volPlot.setRenderer(2, candlesRender); XYPlot candlePlot = new XYPlot(k_line, null, new NumberAxis( ""), candlesRender); candlePlot.setDataset(1, avg_line5); candlePlot.setRenderer(1, xyLineRender1); candlePlot.setDataset(2, avg_line10); candlePlot.setRenderer(2, xyLineRender2); candlePlot.setDataset(3, avg_line20); candlePlot.setRenderer(3, xyLineRender3); candlePlot.setDataset(4, avg_line60); candlePlot.setRenderer(4, xyLineRender); DateAxis dateaxis = new DateAxis("K线图"); dateaxis.setTickUnit(new DateTickUnit(1, 1, new SimpleDateFormat( "MM/yy")));//设置日期格式及显示日期的间隔 dateaxis.setLowerMargin(0.0D); dateaxis.setUpperMargin(0.02D);
//定义一个复合类型的Plot,目的是为了把Chart的上半截和下半截结合起来,形成一张完整的K线图 CombinedDomainXYPlot combineXY = new CombinedDomainXYPlot(dateaxis); //把上下两个Plot都加到复合Plot里,并设置它们在图中所占的比重 combineXY.add(candlePlot, 3); combineXY.add(volPlot, 1); combineXY.setGap(8D); combineXY.setDomainGridlinesVisible(true); JFreeChart jfreechart = new JFreeChart(stock_name, JFreeChart.DEFAULT_TITLE_FONT, combineXY, false); jfreechart.setBackgroundPaint(Color.white);
//为Chart图添加一个图例,这里我们可以定义需要显示的一些信息,及图例放置的位置,我们选择的顶部 LegendTitle legendtitle = new LegendTitle(candlePlot); BlockContainer blockcontainer = new BlockContainer( new BorderArrangement()); blockcontainer.setFrame(new BlockBorder(0.10000000000000001D, 0.10000000000000001D, 0.10000000000000001D, 0.10000000000000001D)); BlockContainer blockcontainer1 = legendtitle.getItemContainer(); blockcontainer1.setPadding(2D, 10D, 5D, 2D); blockcontainer.add(blockcontainer1); legendtitle.setWrapper(blockcontainer); legendtitle.setPosition(RectangleEdge.TOP); legendtitle.setHorizontalAlignment(HorizontalAlignment.CENTER); jfreechart.addSubtitle(legendtitle); return jfreechart; }
///该方法主要是为WEB端的JS调用,定义一个新的Map,插入一行空的记录 public void insertRecord() { map = new HashMap(); }
///该方法主要是为WEB端的JS调用,为当前记录设置值 public void setValue(String key, String value) { map.put(key, value); }
///该方法主要是为WEB端的JS调用,把当前记录添加到记录集List里 public void postRecord() { ls.add(map); }
public Map createDatasetMap() {
//从每一行记录里取出特定值,用来开成各种类型的均线和阴阳线图 Map m = new HashMap(); TimeSeries avg_lin5 = new TimeSeries("5日均线", org.jfree.data.time.Day.class); TimeSeries avg_lin10 = new TimeSeries("10日均线", org.jfree.data.time.Day.class); TimeSeries avg_lin20 = new TimeSeries("20日均线", org.jfree.data.time.Day.class); TimeSeries avg_lin60 = new TimeSeries("60日均线", org.jfree.data.time.Day.class); TimeSeries vol_avg_lin5 = new TimeSeries( "5日成交量均线", org.jfree.data.time.Day.class); TimeSeries vol_avg_lin10 = new TimeSeries( "10日成交量均线", org.jfree.data.time.Day.class);
int count = ls.size(); Date adate[] = new Date[count]; double high[] = new double[count]; double low[] = new double[count]; double close[] = new double[count]; double open[] = new double[count]; double volume[] = new double[count]; Date adate1[] = new Date[count]; double high1[] = new double[count]; double low1[] = new double[count]; double close1[] = new double[count]; double open1[] = new double[count]; double volume1[] = new double[count];
String stock_name = null; Calendar cal = Calendar.getInstance();
for (int j = 0; j < ls.size(); j++) { Map vMap = (Map) ls.get(j);
stock_name = (String) vMap.get("stock_name"); Date issue_date = new Date(Long.parseLong(vMap.get("issue_date") .toString())); double open_value = Double.parseDouble(vMap.get("open_value") .toString()); double high_value = Double.parseDouble(vMap.get("high_value") .toString()); double low_value = Double.parseDouble(vMap.get("low_value") .toString()); double close_value = Double.parseDouble(vMap.get("close_value") .toString()); double avg5 = Double.parseDouble(vMap.get("avg5").toString()); double avg10 = Double.parseDouble(vMap.get("avg10").toString()); double avg20 = Double.parseDouble(vMap.get("avg20").toString()); double avg60 = Double.parseDouble(vMap.get("avg60").toString()); double volume_value = Double.parseDouble(vMap.get("volume_value") .toString()); double vol_avg5 = Double.parseDouble(vMap.get("vol_avg5") .toString()); double vol_avg10 = Double.parseDouble(vMap.get("vol_avg10") .toString()); cal.setTime(issue_date);
if (avg5 > 0.0D) avg_lin5.addOrUpdate(new Day(cal.get(5), cal.get(2) + 1, cal.get(1)), avg5); if (avg10 > 0.0D) avg_lin10.addOrUpdate(new Day(cal.get(5), cal.get(2) + 1, cal.get(1)), avg10); if (avg20 > 0.0D) avg_lin20.addOrUpdate(new Day(cal.get(5), cal.get(2) + 1, cal.get(1)), avg20); if (avg60 > 0.0D) avg_lin60.addOrUpdate(new Day(cal.get(5), cal.get(2) + 1, cal.get(1)), avg60); if (vol_avg5 > 0.0D) vol_avg_lin5.addOrUpdate( new Day(cal.get(5), cal.get(2) + 1, cal.get(1)), vol_avg5); if (vol_avg10 > 0.0D) vol_avg_lin10.addOrUpdate(new Day(cal.get(5), cal.get(2) + 1, cal .get(1)), vol_avg10); adate[j] = issue_date; high[j] = high_value; low[j] = low_value; close[j] = close_value; open[j] = open_value; volume[j] = 0.0D; adate1[j] = issue_date; high1[j] = 0.0D; low1[j] = 0.0D; close1[j] = 0.0D; open1[j] = 0.0D;
//这里是我们用蜡烛图来构造与阴阳线对应的成交量图,我们主要是通过判断开盘价与收盘价相比较的值来决定到底是在表示成交量的蜡烛图的开盘价设置值还是收盘价设置值,设置之前我们把它们全部都设置为0 if (open_value < close_value) close1[j] = volume_value; else open1[j] = volume_value; volume1[j] = 0.0D; } DefaultHighLowDataset k_line = new DefaultHighLowDataset("", adate, high, low, close, open, volume); DefaultHighLowDataset vol = new DefaultHighLowDataset( "", adate1, high1, low1, close1, open1, volume1); //把各种类型的图表对象放到Map里,以为其它方法提供使用 m.put("k_line", k_line); m.put("vol", vol); m.put("stock_name", stock_name); m.put("avg_line5", new TimeSeriesCollection(avg_lin5)); m.put("avg_line10", new TimeSeriesCollection(avg_lin10)); m.put("avg_line20", new TimeSeriesCollection(avg_lin20)); m.put("avg_line60", new TimeSeriesCollection(avg_lin60)); m.put("vol_avg_line5", new TimeSeriesCollection(vol_avg_lin5)); m.put("vol_avg_line10", new TimeSeriesCollection(vol_avg_lin10));
return m; }
//该方法主要是为WEB端的JS调用,用来动态改变K线图 public void changeApplet() { Map m = createDatasetMap(); IntervalXYDataset avg_line5 = (IntervalXYDataset) m.get("avg_line5"); IntervalXYDataset avg_line10 = (IntervalXYDataset) m.get("avg_line10"); IntervalXYDataset avg_line20 = (IntervalXYDataset) m.get("avg_line20"); IntervalXYDataset avg_line60 = (IntervalXYDataset) m.get("avg_line60"); IntervalXYDataset vol_avg_line5 = (IntervalXYDataset) m .get("vol_avg_line5"); IntervalXYDataset vol_avg_line10 = (IntervalXYDataset) m .get("vol_avg_line10"); OHLCDataset k_line = (OHLCDataset) m.get("k_line"); OHLCDataset vol = (OHLCDataset) m.get("vol");
ChartPanel panel = (ChartPanel) getContentPane(); JFreeChart chart = panel.getChart(); CombinedDomainXYPlot plot = (CombinedDomainXYPlot) chart.getPlot(); List list=plot.getSubplots(); XYPlot candlePlot = (XYPlot)list.get(0); candlePlot.setDataset(0, k_line); candlePlot.setDataset(1, avg_line5); candlePlot.setDataset(2, avg_line10); candlePlot.setDataset(3, avg_line20); candlePlot.setDataset(4, avg_line60);
XYPlot volPlot = (XYPlot)list.get(1); volPlot.setDataset(0,vol); volPlot.setDataset(1,vol_avg_line5); volPlot.setDataset(2,vol); volPlot.setDataset(3,vol_avg_line10);
repaint(); } public JPanel createDemoPanel() { JFreeChart jfreechart = createCombinedChart(); return new ChartPanel(jfreechart); } } |
接下来我们需要将该Applet放入JSP里,JSP代码如下:
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib uri="http://www.bstek.com/dorado" prefix="d" %> <html> <head> <title></title> </head> <body> <d:View config="test.applet.TestView"> <d:DataTable id="table1" /> <d:Button id="buttonAdd" /> <d:Button id="buttonDel" /> <APPLET name="klineApplet" CODE="test.applet.TestApplet" archive="/k-line/source/jcommon-1.0.10.jar,/k-line/source/jfreechart-1.0.6.jar" codebase="/k-line/source/" width="100%" height="600" MAYSCRIPT> </APPLET>
</d:View> </body> </html> |
同时,我们还要写一段JS来调用Applet,并为Applet里的K线图填充数据,JS函数如下:
function changeKLine(){ var applet=document.klineApplet; var record = datasetStock.getFirstRecord(); var start=new Date(); applet.clearList(); while (record) { applet.insertRecord(); var stock_name=record.getValue("stock_name"); applet.setValue("stock_name",stock_name);
var issue_date=record.getValue("issue_date").getTime(); applet.setValue("issue_date",issue_date);
var open_value=record.getValue("open_value"); applet.setValue("open_value",open_value);
var high_value=record.getValue("high_value"); applet.setValue("high_value",high_value);
var low_value=record.getValue("low_value"); applet.setValue("low_value",low_value);
var close_value=record.getValue("close_value"); applet.setValue("close_value",close_value);
var volume_value=record.getValue("volume_value"); applet.setValue("volume_value",volume_value);
var avg5=record.getValue("avg5"); applet.setValue("avg5",avg5);
var avg10=record.getValue("avg10"); applet.setValue("avg10",avg10);
var avg20=record.getValue("avg20"); applet.setValue("avg20",avg20);
var avg60=record.getValue("avg60"); applet.setValue("avg60",avg60);
var vol_avg5=record.getValue("vol_avg5"); applet.setValue("vol_avg5",vol_avg5);
var vol_avg10=record.getValue("vol_avg5"); applet.setValue("vol_avg10",vol_avg10);
record = record.getNextRecord();
applet.postRecord(); }
applet.changeApplet(); } |
同时,我们要在Dorado5的View里Dataset不同的事件里调用该JS函数,View的源代码如下:
<?xml version="1.0" encoding="UTF-8"?> <view> <Datasets> <Datasetid="datasetStock" type="Wrapper" wrappedType="AutoSql"dataSource="doradosample" originTable="K_LINE_DATA" pageSize="0"> <Joins /> <Fields> <Field name="STOCK_NAME" originField="STOCK_NAME" table="K_LINE_DATA" dataType="string" group="false" label="股票名称"> <Properties /> <Validator type="Required" /> </Field> <Field name="ISSUE_DATE" originField="ISSUE_DATE" table="K_LINE_DATA" dataType="date" group="false" label="时间"> <Properties /> <Validator type="Required" /> </Field> <Field name="OPEN_VALUE" originField="OPEN_VALUE" table="K_LINE_DATA" dataType="double" group="false" label="开盘价" defaultValue="0"> <Properties /> <Validator type="Required" /> </Field> <Field name="HIGH_VALUE" originField="HIGH_VALUE" table="K_LINE_DATA" dataType="double" group="false" label="最高价" defaultValue="0"> <Properties /> <Validator type="Required" /> </Field> <Field name="LOW_VALUE" originField="LOW_VALUE" table="K_LINE_DATA" dataType="double" group="false" label="最低价" defaultValue="0"> <Properties /> <Validator type="Required" /> </Field> <Field name="CLOSE_VALUE" originField="CLOSE_VALUE" table="K_LINE_DATA" dataType="double" group="false" label="收盘价" defaultValue="0"> <Properties /> <Validator type="Required" /> </Field> <Field name="VOLUME_VALUE" originField="VOLUME_VALUE" table="K_LINE_DATA" dataType="double" group="false" label="成交量" defaultValue="0"> <Properties /> <Validator type="Required" /> </Field> <Field name="AVG5" originField="AVG5" table="K_LINE_DATA" dataType="double" group="false" label="五日均价" defaultValue="0"> <Properties /> </Field> <Field name="AVG10" originField="AVG10" table="K_LINE_DATA" dataType="double" group="false" label="十日均价" defaultValue="0"> <Properties /> </Field> <Field name="AVG20" originField="AVG20" table="K_LINE_DATA" dataType="double" group="false" label="二十日均价" defaultValue="0"> <Properties /> </Field> <Field name="AVG60" originField="AVG60" table="K_LINE_DATA" dataType="double" group="false" label="六十日均价" defaultValue="0"> <Properties /> </Field> <Field name="VOL_AVG5" originField="VOL_AVG5" table="K_LINE_DATA" dataType="double" group="false" label="成交量五日均价" defaultValue="0"> <Properties /> </Field> <Field name="VOL_AVG10" originField="VOL_AVG10" table="K_LINE_DATA" dataType="double" group="false" label="成交量十日均价" defaultValue="0"> <Properties /> </Field> </Fields> <MatchRules /> <SortRules /> <MasterLink /> <Parameters /> <Properties /> <Events> <Event name="afterDelete">changeKLine()</Event> <Event name="afterPost">changeKLine()</Event> </Events> </Dataset> </Datasets> <Controls> <Control id="table1" type="DataTable" dataset="datasetStock" height="500" width="100%"> <Column name="STOCK_NAME" field="STOCK_NAME" /> <Column name="ISSUE_DATE" field="ISSUE_DATE" /> <Column name="OPEN_VALUE" field="OPEN_VALUE" /> <Column name="HIGH_VALUE" field="HIGH_VALUE" /> <Column name="LOW_VALUE" field="LOW_VALUE" /> <Column name="CLOSE_VALUE" field="CLOSE_VALUE" /> <Column name="VOLUME_VALUE" field="VOLUME_VALUE" /> <Column name="AVG5" field="AVG5" /> <Column name="AVG10" field="AVG10" /> <Column name="AVG20" field="AVG20" /> <Column name="AVG60" field="AVG60" /> <Column name="VOL_AVG5" field="VOL_AVG5" /> <Column name="VOL_AVG10" field="VOL_AVG10" /> </Control> <Control id="buttonAdd" type="Button" value=" 添加一条记录 "> <Events> <Event name="onClick">datasetStock.insertRecord();</Event> </Events> </Control> <Control id="buttonDel" type="Button" value=" 删除当前记录 "> <Events> <Event name="onClick">datasetStock.deleteRecord();</Event> </Events> </Control> </Controls> <Properties /> <Events> <Event name="functions">function changeKLine(){ var applet=document.klineApplet; var record = datasetStock.getFirstRecord(); var start=new Date(); applet.clearList(); while (record) { applet.insertRecord(); var stock_name=record.getValue("stock_name"); applet.setValue("stock_name",stock_name);
var issue_date=record.getValue("issue_date").getTime(); applet.setValue("issue_date",issue_date);
var open_value=record.getValue("open_value"); applet.setValue("open_value",open_value);
var high_value=record.getValue("high_value"); applet.setValue("high_value",high_value);
var low_value=record.getValue("low_value"); applet.setValue("low_value",low_value);
var close_value=record.getValue("close_value"); applet.setValue("close_value",close_value);
var volume_value=record.getValue("volume_value"); applet.setValue("volume_value",volume_value);
var avg5=record.getValue("avg5"); applet.setValue("avg5",avg5);
var avg10=record.getValue("avg10"); applet.setValue("avg10",avg10);
var avg20=record.getValue("avg20"); applet.setValue("avg20",avg20);
var avg60=record.getValue("avg60"); applet.setValue("avg60",avg60);
var vol_avg5=record.getValue("vol_avg5"); applet.setValue("vol_avg5",vol_avg5);
var vol_avg10=record.getValue("vol_avg5"); applet.setValue("vol_avg10",vol_avg10);
record = record.getNextRecord();
applet.postRecord(); }
applet.changeApplet(); }</Event> <Event name="onLoad">changeKLine()</Event> </Events> </view>
|
启动工程,浏览我们的JSP,我们看到如下效果:
这时我们可以尝试对Dorado5表格中的任一数据做修改,我们发现在下面的Applet里的K线图也会做相应的变化,而且这一变化是在页面没有刷新的情况下实现的。