IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    jFreeChart限定最大显示值

    axiu发表于 2016-05-18 13:18:15
    love 0

    在非B/S结构的java程序中,要绘制图形,普遍使用的就是jFreeChart。相对于highChart的纯JS实现(highChart官方例子也很多),绘制jFreeChart可能不是那么容易。通常需要自定义一个map存放key和value,然后通过给ChartFactory工厂传入Dataset来创建图表对象,当然最麻烦的就是外观显示了,这部分可以参考org.jfree.chart.plot里的一众实现。

    有个需求是这样:绘制一个曲线图,对于其中的每个点x,限定最大值k,即大于k的时候,按k画图,同时标签显示准确的值x。

    原始图形

    jFreeChart

    首先想到的是,直接附加一个label属性,然后把value值按最大值k来取,最后画图就可以了。但是看一下代码,就会发现,这个label是根据dataSet的属性生成的,函数原型是

    DefaultCategoryDataset.addValue(Number value, Comparable rowKey, Comparable columnKey)

    就是说,只可以添加value和对应的key,以及这对值属于哪个row。所以想通过遍历DataSet或者类似方式,都会导致两个对象全部变化,达不到要求。

    而且,继续看的话,会发现Plot相关的renderer(用于外观展示)也没有提供什么有用的API,想要达到这个效果,只能硬编码,改变一下实际显示的图表内容函数了~~

    首先,挨个函数看一下,发现工程里的Render(这里使用的LineAndShapeRendere)长的比较像管这个的,其中还有个drawItem函数,打上断点看一下,没错就是它了。

    新建一个类,继承LineAndShapeRenderer,这样,就可以在plot里通过setRenderer来指定我们要用的这个对象。然后,对这个函数稍加改装(这里设计的阈值为0.01)

    double value = v.doubleValue() > 0.01 ? 0.01 : v.doubleValue();

    运行一下,发现输出了第一个图表,但是有点歪扭

    jFreeChart

    看起来,每个点的绘制,都是需要和前面一个点相关联的,接着看代码,改一下

    double previous = previousValue.doubleValue() > 0.01 ? 0.01 : previousValue.doubleValue();

    然后调整一下plot里的范围等效地方,最后输出图形

    jFreeChart

    代码:

    /**
     * Rewrite {@code drawItem} method, mainly set value limit to 0.01,
     * if value > 0.01, draw 0.01, else draw original value 
     * @see LineAndShapeRenderer
     *
     */
    public class LimitValueRenderer extends LineAndShapeRenderer {
        
        public void drawItem(Graphics2D g2, CategoryItemRendererState state,
                Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis,
                ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
                int pass) {
    
            ......
            double value = v.doubleValue() > 0.01 ? 0.01 : v.doubleValue();
            double y1 = rangeAxis.valueToJava2D(value, dataArea,
                    plot.getRangeAxisEdge());
            
            if (pass == 0 && getItemLineVisible(row, column)) {
                if (column != 0) {
                    Number previousValue = dataset.getValue(row, column - 1);
                    if (previousValue != null) {
                        // previous data point...
                        double previous = previousValue.doubleValue() > 0.01 ? 0.01 : previousValue.doubleValue();
                        double x0;
                        if (this.getUseSeriesOffset()) {
                            x0 = domainAxis.getCategorySeriesMiddle(
                                    column - 1, dataset.getColumnCount(),
                                    visibleRow, visibleRowCount,
                                    this.getItemMargin(), dataArea,
                                    plot.getDomainAxisEdge());
                        }
                        else {
                            x0 = domainAxis.getCategoryMiddle(column - 1,
                                    getColumnCount(), dataArea,
                                    plot.getDomainAxisEdge());
                        }
                        double y0 = rangeAxis.valueToJava2D(previous, dataArea,
                                plot.getRangeAxisEdge());
                        ......
                    }
                }
            }
            ......
    
        }
    }

    转载请注明来源:jFreeChart限定最大显示值
    本文链接地址:http://axiu.me/coding/jfreechart-limit-max-value/


沪ICP备19023445号-2号
友情链接