Axiu Blog
e,然后通过给`ChartFactory`工厂传入`Dataset`来创建图表对象,当然最麻烦的就是外观显示了,这部分可以参考`org.jfree.chart.plot`里的一众实现。 有个需求是这样:绘制一个曲线图,对于其中的每个点x,限定最大值k,即大于k的时候,按k画图,同时标签显示准确的值x。 原始图形 ![jFreeChart](https:
在非B/S结构的java程序中,要绘制图形,普遍使用的就是jFreeChart。相对于highChart的纯JS实现(highChart官方例子也很多),绘制jFreeChart可能不是那么容易。通常需要自定义一个map存放key和value,然后通过给`ChartFactory`工厂传入`Dataset`来创建图表对象,当然最麻烦的就是外观显示了,这部分可以参考`org.jfree.chart.
在非B/S结构的java程序中,要绘制图形,普遍使用的就是jFreeChart。相对于highChart的纯JS实现(highChart官方例子也很多),绘制jFreeChart可能不是那么容易。通常需要自定义一个map存放key和value,然后通过给`ChartFactory`工厂传入`Dataset`来创建图表对象,当然最麻烦的就是外观显示了,这部分可以参考`org.jfree.chart.
jFreeChart限定最大显示值
Max

在非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());
                ......
            }
        }
    }
    ......

}

}

Comments