倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

GroovyChart と戯れて (6) : ChartBuilder が構築するのは JFreeChart のラッパー

GroovyChart の ChartBuilder は JFreeChart (JFreeChart のチャートを表す型)オブジェクトを構築するのではなく、そのラッパークラスを構築します。 これは、それほど気にすることでもありませんが、JFrame などに埋め込むために ChartPanel を生成しようとすると、ビルダーの構築結果のオブジェクトに対して「chart プロパティ」にアクセスして JFreeChart オブジェクトを取得する必要があります(以前の記事参照)。

まぁ、「そういうものだ」と思って使い方を覚えてしまってもいいんですが、やはり直感的にはビルダーの構築結果が JFreeChart オブジェクトであった方が自然な感じがします。

今回は、ChartBuilder のサブクラスでちょこっとメソッドをオーバライドすることによって、これを実現する方法を見ていきます。 GroovyChart がどうこうというより、ビルダー実装の演習みたいな回です。

JFreeChart を返す ChartBuilder のサブクラスを作ってみる


ノードを構築した結果返されるオブジェクトを操作したい場合は、postNodeCompletion() メソッドをオーバーライドすると良さそうです(nodeCompletion() メソッドは返り値が void なので、今回の目的には合いません)。

GroovyChart では JFreeChart のラッパークラスは BaseChart クラス*1のようなので、引数 node がこのオブジェクトの時に、chart プロパティを取得して返すようにします。 それ以外の時はスーパークラスの処理そのままにします:

class MyChartBuilder extends ChartBuilder{

    @Override
    protected Object postNodeCompletion(parent, node) {
        def result = super.postNodeCompletion(parent, node)

        if(node instanceof BaseChart)
            return result.chart
        else
            return result
    }
}

実装はこれだけ。

使い方


で、実際にこのクラスを使ってみると

def builder = new MyChartBuilder()
def chart = builder.xyareachart(
        title:'BMI Index Graph', XAxisLabel: 'weight (Kg)', YAxisLabel: 'height (m)',
        orientation:PlotOrientation.VERTICAL) {
    
    xyseries {
        for(int weight = 0; weight < 150; weight += 10) {
            point('Overweight', x: weight, y: sqrt(weight / 35.0d))
            point('Normal', x: weight, y: sqrt(weight / 25.0d))
            point('Underweight', x: weight, y: sqrt(weight / 18.0d))
        }
    }

    xyplot {
        foregroundAlpha(1.0f)
    }
}

assert chart instanceof JFreeChart    // chart は JFreeChart インスタンス
def chartPanel = new ChartPanel(chart)

という感じで、ビルダーの構築結果が JFreeChart オブジェクトになってます。 めでたし、めでたし。

Groovyイン・アクション

Groovyイン・アクション

*1:XYAreaChart の継承関係は「BeanBuilder ← BaseChart ← BasicChart ← XYChart ← XYAreaChart」となっているようです。