JFreeChart自学整理

来源:互联网 发布:佳能dpp下载mac版 编辑:程序博客网 时间:2024/05/21 22:42

(JFreeChart我就不多介绍了,用过的人都知道它是什么。网上关于这方面的博客也是多得数不胜数,不过感觉多数都是互相抄袭,这点真是不好,浪费后来人的时间,想找点有用的真是难啊,所幸的是还是多少有些有用的,至少教会我在开始阶段如何画出一个漂亮图形出来。这里贴一些网上没有找到的,我看源码总结出来的东西,希望对后来人有所助益,同时也是对自己的理解进行一次剖析和检查,纯属个人自学总结,错误在所难免,欢迎指教,共同探讨)

首先一个图要表达某个意思最重要的肯定是数据,下面就先从数据开始分析:

0维键值对:KeyedValue继承于Value,添加了一个对应的关键字(Key)。默认实现DefaultKeyedValue中具有私有成员Comparable key和Number value,这中对应关系不多说了。1维数值:Values拥有一个一维数值型数组,从这些数据里我们没法知道这些数据所代表的意义是什么。我们可以把它想象成一个List<Number>,但不要认为它就是一个List,它只是一个接口,没有任何实现。1维键值对:KeyedValues继承于Values,为每个Value增加了对应的关键字(Keys),此时我们能够明白每个数据值对应的意义(即Key)。它是个什么东西呢?它也是个接口。如果为了理解的方便,暂且也可以把它想象成一个HashMap<Key, Value>,但也请一定记得它绝对不是HashMap,甚至它的实现类的实现方式和HashMap的实现方式完全不一样。可以看到它的默认实现DefaultKeyedValues中,分别用了一个ArrayList 来保存keys 和values ,甚至还另外添加了一个HashMap来专门保存key值及其索引(这个在编者我看来是怎么也想不通的,感觉真的没有必要,key都保存在了List里,索引自然也是可以根据indexOf方法获取,如果说是因为HashMap里有key值唯一性,List没有,那样也是可以用indexOf方法先去找达到相同的效果的,想不通,想不通了???)2维数值:Values2D此时相当于一个二维数组,有行有列,可以获取行数和列数,并且可以根据给定行列值获取对应数据值。这里的二维怎么表示呢?用二维数组?当然可以实现,可是会不会方便呢?2维键值对:KeyedValues2D同样,继承于Values2D的它自然也是有了键值对,不多啰嗦,看它默认实现。在DefaultKeyedValues2D中三个私有List和一个用于判断是否排列关键字的bool值(这个暂时别管了)。它是如何实现二维键值对的呢?当然是靠这三个List,想想KeyedValues的实现方式,它们肯定神似。不卖关子了,它是用一个List保存rowKeys,用另一个保存KeyedValues(KeyedValues可以有columnKeys和Values的对应关系),成了。不要怀疑还有一个List哪去了,那个List用来保存columnKeys了。Dataset数据集,字面翻译过来就这样叫。这个可称得上最底层的接口做了什么呢?它就标明所有的图表数据集都必须有一个事件监听器和一个数据集ID...根据数据类型生成不一样的图数据集,与KeyedValue生成的默认的类DefaultKeyedValueDataset私有成员就是一个KeyedValue;与KeyedValues生成的默认的类DefaultKeyedValuesDataset就直接派生于DefaultPieDataset,DefaultPieDataset中的私有成员就是一个DefaultKeyedValues(饼图的数据确实是一维键值对,很符合这种数据类型,可是插在这里让我感到很不解,按理放在DefaultKeyedValuesDataset不是让人更好理解吗?);而DefaultKeyedValues2DDataset则派生于DefaultCategoryDataset,DefaultCategoryDataset中的私有成员则是一个DefaultKeyedValues2D(还是一样的,又有插队的……)不同的数据类型适合不同类型的图,DefaultKeyedValueDataset只有一个数据我还真的想不出适合什么图,或许可以作为一般的说明图,直接在图旁边标识;而DefaultKeyedValuesDataset适合的图当然是饼图了,而最后一种适合的就是柱状图。肯定有朋友会问折线图的数据类型了,折线图的确太普遍了,很多地方都用(先不管X唯一不唯一),同样我们可以用一个List保存X值,另一个List保存Y值,似乎可以,同样的多折线图,可以用KeyedValues2D对应的方法,一个List保存折线键值,另一个List保存一条折线的数据,是不是真的没有问题?是不是真的是这样实现的呢?有没有问题我不知道,我可以告诉你的是它不是这样实现的,而是换了一种思维(这样看来我的思维还是太死板了,不会变通)。它是如何实现的呢?从最底层,‘DataItem系列’,其实没有这个类或者接口,但有相关的类,如XYDataItem、TimeSeriesDataItem……XYDataItem中两个数值型私有成员,分别用来保存X、Y值,而TimeSeriesDataItem一个RegularTimePeriod类型,一个Number类型,分别用来保存时间和数值。(RegularTimePeriod的子类有Year, Quarter, Month, Week, Day, Minute, Hour, Minute, Second, Millisecond, FixedMillisecond, 具体实现再研究吧)这样用‘DataItem’就可以保存一个点了,再用一个List来保存'DataItem'就可以保存一条折线上的数据了。不要以为这里又用另一个List来保存多条折线了,这里没有那样做,我也没弄明白不那样做的原因。这里用的是Series类保存一条折线,一个Series里总包含有一个key值,然后就是数据List了,如XYSeries, TimeSeries ...Series配合Dataset就形成了‘SeriesCollection’就是所谓折线图了,如XYSeriesCollection, TimeSeriesCollection.Series:私有成员:Comparable key唯一标识一条折现;String description 描述这条折现,默认为null.其子类XYSeries:私有成员:List data 保存XYDataItem; int maximumItemCount:设置最大数据个数,调用set方法设置; boolean autoSort 是否自动排序,默认为true; boolean allowDuplicateXValue 是否允许重复X值(意思即一个X值对应多个Y值);(这两个boolean默认都为true,只可以通过构造方法设置)TimeSeries:私有成员:String domain 描述横坐标,默认”Time”; String range 描述纵坐标,默认”Value”;(domain和range都不会在图片中表现出来) Class timePeriodClass 保存时间类型; List data 保存TimeSeriesDataItem; int maxmumItemCount 设置最大数据个数

分析了数据,接下来就开始正式的图形与数据之间的关系了,因为要对号入座,图形用错了数据类型自然会报异常,我就列出它们之间的一些继承关系,从名字上应该也能或多或少有些理解。

Dataset -> AbstractDataset  SeriesDataset -> AbstractSeriesDataset ( XYDataset ) ->  AbstractXYDatasetDataset -> AbstractDatasetDataset KeyedValue ->  KeyedValueDataset AbstractDataset KeyedValueDataset -> DafaultKeyedValueDatasetDataset -> AbstractDatasetDataset KeyedValues -> PieDatasetPieDataset -> KeyedValuesDataset (二者并无不同)AbstractDataset PieDataset  -> DefaultPieDatasetDefaultPieDataset KeyedValuesDataset -> DefaultKeyedValuesDatasetDataset -> AbstractDatasetDataset -> CategoryDatasetAbstractDataset CategoryDataset -> DefaultCategoryDatasetDataset -> AbstractDatasetDataset -> SeriesDatasetSeriesDataset -> XYDatasetXYDataset -> IntervalXYDatasetAbstractDataset SeriesDataset -> AbstractSeriesDatasetAbstractSeriesDataset XYDataset -> AbstractXYDatasetAbstractXYDataset IntervalXYDataset -> AbstractIntervalXYDatasetAbstractIntervalXYDataset -> TimeSeriesCollection XYSeriesCollection

好了,有些心急的童鞋估计都等得不耐烦了,说了这么多还没有说到底该如何用。其实到底如何用,网上这方面的资料多得很,多啰嗦只是对各位的时间的浪费。有兴趣的就接着往下看。

首先当然是下载包了,需要的有"gnujaxp.jar","jcommon.jar","jfreechart.jar",加到项目里……

如果你是web项目,当然还得配置下Servlet,当然啦,有能力的可以自己写Servlet.

        在web.xml中添加

        <servlet><servlet-name>DisplayChart</servlet-name><servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class></servlet><servlet-mapping><servlet-name>DisplayChart</servlet-name><url-pattern>/servlet/DisplayChart</url-pattern></servlet-mapping>
        或者自己写Servlet如下:(配置就不写了)

package com.esen.servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.jfree.chart.JFreeChart;import com.keypoint.PngEncoder;public class ChartViewer extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpSession session = request.getSession();JFreeChart chart = (JFreeChart)session.getAttribute("chart");if(chart == null)return;session.removeAttribute("chart");response.setContentType("image/png");PngEncoder encoder = new PngEncoder(chart.createBufferedImage(760, 360, null), false, 0, 9);response.getOutputStream().write(encoder.pngEncode());}public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}}
ok,现在可以开始JFreeChart的画图了,没有特殊需求的话,一般都可以调用JFreeChart提供的ChartFactory的静态方法来产生相应的图。
例子:

     //饼图       ChartFactory.createPieChart(title, dataset, legend, tooltips, urls);   // (参数介绍:title - String类型,图标题;dataset - PieDataset,还不知道的,看上面的介绍; legend - boolean类型,是否产生说明信息; tooltips - boolean类型,是否产生工具提示; urls - boolean类型,是否产生链接;tooltips 和 urls 均用于web项目中的操作,如果不是Web项目,可以设置为false)     //柱图       ChartFactory.createBarChart(title, categoryAxisLabel, valueAxisLabel, dataset, orientation, legend, tooltips, urls);   //  (参数介绍: categoryAxisLabel - String 类型,横坐标标签; valueAxisLabel - String 类型,纵坐标标签, orientation - PlotOrientation类型,有PlotOrientation.HORIZONTAL和PlotOrientation.VERTICAL两种类型,分别标识图形方向为垂直和水平,其它参数同上)    //线图       ChartFactory.createLineChart(title, categoryAxisLabel, valueAxisLabel, dataset, orientation, legend, tooltips, urls)    //时间序列图       ChartFactory.createTimeSeriesChart(title, timeAxisLabel, valueAxisLabel, dataset, legend, tooltips, urls);  //  (参数介绍:  timeAxisLabel - String 横坐标标签; 其它参数同上)

      ……

创建好图之后,如果不是Web项目,直接调用ChartUtilities.writeChartAsJPEG(outputStream, chart, width, height);就可以画出图片来了

否则,就先调用

ServletUtilities.saveChartAsJPEG(chart, width, height, session); 

保存图片到Session里,然后在页面里调用

<img src=" <%=request.getContextPath() + ‘/servlet/DisplayChart?filename=’ + filename%>

打开页面就可以显示所创建的图片了,当然这里的Servlet如果是自己写的,路径得相应的作下修改。

但是, 这样画出来的图片只是简单的图片,没有任何的交互性可言,也就是没有任何事件与该图片关联。学过DOM的都知道img有个map,可以产生相应的事件,这就要用到前面介绍的参数中的tooltips和urls了,urls是产生相应的点击链接事件,而tooltips则可以产生HTML中的TITLE显示信息,或者产生onMouseOver和onMouseOut事件。怎么用?上代码:

        ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());String filename = ServletUtilities.saveChartAsPNG(chart, width, height, info, session);//注意多了个info,这个info用来保存所有的MAP信息ChartUtilities.writeImageMap(out, filename, info, true);//out当然是页面的out,最后一个参数为true是就是阐述onMouse事件,否则产生TITLE提示
成了,不信可以去看看……



下面就讲些常用的设置吧(以柱状图为例),毕竟设置不对,效果很不好,比如最常用的就是字体,JFreeChart默认字体好像不支持中文,不设置的话会乱码,至少我所用的版本是这样的。

        //设置图片标题        TextTitle title = chart.getTitle();        title.setText("图片示例");//设置标题文本        title.setPaint(Color.black);//设置标题字体颜色        title.setBackgroundPaint(Color.cyan);//设置背景颜色        title.setExpandToFitSpace(true);//设置标题宽度自动适应为图片宽度        title.setHeight(20);//设置标题高度        title.setToolTipText("这是一个提示");//设置标题提示,和tooltips真假有关系,用于Web        title.setURLText("http://www.csdn.com");//设置标题链接,和urls有关,用于Web        title.setFont(new Font("黑体", Font.BOLD, 18));//设置标题字体
        //设置轴字体        CategoryAxis domainAxis = plot.getDomainAxis();//横轴        domainAxis.setLabelFont(new Font("楷体", Font.PLAIN, 12));        domainAxis.setTickLabelFont(new Font("宋体", Font.CENTER_BASELINE, 14));        ValueAxis rangeAxis = plot.getRangeAxis();//纵轴        rangeAxis.setLabelFont(new Font("楷体", Font.PLAIN, 12));        rangeAxis.setTickLabelFont(new Font("宋体", Font.CENTER_BASELINE, 14));
 
        //设置图例说明字体        LegendTitle legend = chart.getLegend();        legend.setItemFont(new Font("宋体", Font.ITALIC, 12));
       //设置图片renderer        CategoryItemRenderer renderer = plot.getRenderer();                //设置标签显示        renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{1}:({0},{2})", NumberFormat.getInstance()));        renderer.setBaseItemLabelsVisible(true);        renderer.setBaseItemLabelFont(new Font("宋体", Font.PLAIN, 12));        renderer.setBaseItemLabelPaint(Color.WHITE);        ItemLabelPosition position = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.TOP_CENTER);        renderer.setBasePositiveItemLabelPosition(position);                //设置图片链接        CategoryURLGenerator generator = new StandardCategoryURLGenerator("index.html", "param1", "param2");        renderer.setBaseItemURLGenerator(generator);                //设置工具提示(网页项目中的title效果)        CategoryToolTipGenerator generatorToolTip = new StandardCategoryToolTipGenerator("{0}{1}{2}", NumberFormat.getInstance(Locale.ENGLISH));        renderer.setBaseToolTipGenerator(generatorToolTip);

附加:(对于图片链接及工具提示的一些详解)

URLCategoryURLGeneratorURL for CategoryDatasetStandardCategoryURLGenerator标准Category数据集URL生成器私有成员:String prefix 前缀,即网址部分,默认“index.html”; String seriesParameterName 系列参数名,默认“series”; String categoryParameterName 类别参数名,默认“category”;通过构造函数进行设置。最后生成的URL是“index.html?series=’rowKey’&category=’columnKeys’”CustomCategoryURLGenerator自定义Category数据集URL生成器私有成员:ArrayList urlSeries 保存一系列List,每个List都保存有相应Series的所有url,具体用法有待研究。XYURLGeneratorURL  for XYDatasetStandardXYURLGenerator标准XY数据集URL生成器私有成员:String prefix 前缀,默认“index.html”; String seriesParameterName 系列参数名,默认“series”; String itemParameterName item参数名,默认“item”;通过构造函数设置。同StandardCategoryURLGenerator.CustomXYURLGenerator自定义XY数据集URL生成器 同CustomCategoryURLGeneratorTimeSeriesURLGenerator时间序列数据集URL生成器私有成员:DateFormat dateFormat 时间格式; 接下来三个同StandardXYURLGeneratorLabel CategoryAbstractCategoryItemLabelGenerator私有成员:String labelFormat 标签格式; String nullValueString 替代value为空时的值; NumberFormat numberFormat 数值格式; DateFormat dateFormat 日期格式; NumberFormat percentFormat 百分数格式。{0}=rowKey, {1} = columnKey, {2} = value, {3} = value所占百分数StandardCategoryItemLabelGenerator标准Category标签生成器继承自AbstractCategoryItemLabelGenerator, 默认的标签格式为”{2}”.IntervalCategoryItemLabelGenerator间隔Category标签生成器继承自StandardCategoryItemLabelGenerator, 默认标签格式”({0}, {1}) = {3} – {4}”{0} = rowKey; {1} = columnKey; {2} = value; {3} = startValue; {4} = endValue.ToolTipCategoryCategoryToolTipGeneratorStandardCategoryToolTipGenerator标准Category工具提示生成器继承自AbstractCategoryItemLabelGenerator,默认的工具提示格式为”({0}, {1} ={2})”IntervalCategoryToolTipGenerator间隔Category工具提示生成器默认的工具提示格式为”({0}, {1}) = {3} – {4}”LabelXYAbstractXYItemLabelGenerator私有成员:String formatString 字符串格式; NumberFormat xFormat 数值型x值格式; DateFormat xDateFormat 日期型y值格式; NumberFormat yFormat 数值型y值格式; DateFormat yDateFormat 日期型y值格式; String nullYString y值为空时的替换字符串,默认“null”{0} = seriesKey, {1} = rowValue, {2} = columnValueStandardXYItemLabelGenerator标准XY标签生成器继承自AbstractXYItemLabelGenerator, 默认标签格式为”{2}”IntervalXYItemLabelGenerator间隔XY标签生成器继承自AbstractXYItemLabelGenerator, 默认标签格式为”{5} – {6}”{0} = seriesKey; {1} = xValue; {2} = xStart; {3} = yEnd; {4} = yValue; {5} = yStart; {6} = yEnd.ToolTip XYXYToolTipGeneratorStandardXYToolTipGenerator默认的提示格式为”{0}: ({1}, {2})”.



(还在研究阶段,有新的理解会及时添加进来,有错误的地方,还请看到的朋友友善指正)




原创粉丝点击