Using jFreeChart via a Chart Service Tuesday, April 9, 2013

Using ZKGrails I wanted to use its built-in chart tags. However, since the last time I used ZK (3 years ago) they no longer provide charts in their free version.

FYI, ZKGrails no longer supports having zscript code in the .zul pages, so the process of trying to get a dynamically rendered image embedded into a .zul page was that much more difficult. All the code must be the ZKGrails composer class, so rapid prototyping is out.

The difficulty was compounded by an optional ZKGrails Groovy Builder code supported inside the ZKGrails composers. The builder creates a JQuery like syntax for selecting ZK components from the .zul view. Since it provides a "Groovyer" syntax I wanted to use it, but it did add some mental overhead.

So using jFreeChart I created a Grails service, which just statically returns a jFreeChart. The chart is just a static chart I found in one of the jFreechart demos.

package com.lcr.audit

import org.jfree.chart.ChartFactory
import org.jfree.chart.ChartPanel
import org.jfree.chart.JFreeChart
import org.jfree.chart.plot.PlotOrientation
import org.jfree.chart.plot.XYPlot
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer
import org.jfree.ui.ApplicationFrame
import org.jfree.ui.RefineryUtilities
import org.jfree.data.category.DefaultCategoryDataset


class ChartService {
    static transactional = false

    def getChart() {
        def dataset = createDataset()
        def chart = createChart(dataset)
        return chart
    }
    
    def createDataset(){
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        dataset.addValue(212, "Classes", "JDK 1.0");
        dataset.addValue(504, "Classes", "JDK 1.1");
        dataset.addValue(1520, "Classes", "SDK 1.2");
        dataset.addValue(1842, "Classes", "SDK 1.3");
        dataset.addValue(2991, "Classes", "SDK 1.4");
        return dataset
    }
    
    def createChart(dataset){
            JFreeChart chart = ChartFactory.createLineChart(
            "Java Standard Class Library", // chart title
            "Release", // domain axis label
            "Class Count", // range axis label
            dataset, // data
            PlotOrientation.VERTICAL, // orientation
            false, // include legend
            true, // tooltips
            false // urls
        )
        
        return chart
    }
}

This returns a chart that looks like this:









This image is a jFreechart "chart" object, which provides a method that converts it to a buffered image class. After a great deal of trial and error and searching the web, I found a ZK example that I partially got to work, proving I could render a dynamic image, and the code only needed a buffered image as input.

ZK Demo Dynamic Images


Here is a basic .zul page which will work to render the single dynamic chart from the above chart service:


    
        
            
        
    

The important line is:

The "id" of "img" is what we will use to select this image component and set its content to our chart buffered image.

Now, let's look at the ZKGrails Composer:

package com.lcr.audit

import org.zkoss.zk.grails.composer.*

import org.zkoss.zk.ui.select.annotation.Wire
import org.zkoss.zk.ui.select.annotation.Listen

class DomBillAuditToolComposer extends GrailsComposer {
    def chartService
    def img
    
    def afterCompose = { window ->
        // initialize components here
        def chart = chartService.getChart()
        def bufferImg = chart.createBufferedImage(700, 200)
        img.setContent(bufferImg)
    }
}
This composer is not coded using the ZKGrails Builder JQuery syntax. This was the how I first got it to work. Later, I got help from to get the ZKGrails Builder code to work.

Google Groups: ZKGrails User Group

Lines 10 and 16 are important. "def img" is how we select the ZK Image component from the .zul page. Now, the variable img can be used as it is in line 16 to call the "setContent()" method, so we can pass in our buffered image.

Using the ZKGrails builder code we could do something like this:
$('#img').append{
    def chart = chartService.getChart()
    def bufferImg = chart.createBufferedImage(700, 200)
    def img = $('#chart01') // Or: def img = $('#chart01')[0]
    img.setContent(bufferImg)
}

This is how the ZK image component is selected:
$('#img')

Because we are not appending anything to the "img" ZK Image component, maybe we don't need to select the component like this:
$('#img').append{}

Because notice we are "selecting" the component again in this line.
def img = $('#chart01')
This is similar to what we did in the first composer code above, which uses the older style.

Note: if you have no JQuery background, you may find the JQuery style of having a dollar sign and parentheses $(blah), strange, and very non-Groovy. When I first saw it I had no idea what it was. It is optional, as you can always use the first composer syntax.

0 comments: