Drill-down is the act of clicking on a region of a chart image and being directed to an URL that
presents additional information related to the clicked area. The URL can even bring another chart
image, and drill-down can be carried out across multiple levels.
A servlet can implement drill-down using JetChart image encoding feature in conjunction with image
mapping. JetChart implements the method AbstractSerie.getSerieMap(String[ ] urls,int type,String target),
which returns a map of a series data points as a collection of coordinates. The coordinates can be arranged
using three different formats for image mapping on the client side or on the server side.
For more information regarding the method above, please refer to the JetChart API documentation.
The servlet below encodes a bar chart into a PNG binary stream, outputting it to a file. The bar series is
then mapped and the resulting code is embedded into html code containing an <image> tag that points
to the PNG file location. After submitting a request and a mapped image is displayed, click any bar to be
directed to a predefined URL.
This servlet also starts a cleaner thread to remove old files from the files folder, as described in the
previous topic.
import javax.servlet.*; import javax.servlet.http.*; import java.awt.*; import com.jinsight.jetchart.*; import java.io.*; import java.awt.image.BufferedImage; import java.util.Locale; import com.sun.media.jai.codec.*; public class Example6 extends HttpServlet { String writeDir; String fileExtension; int expiryTime,checkTime; FileCheckThread fct; public void init() { // The folder where the png files are saved. Change it accordingly. writeDir="/usr/local/jakarta/webapps/examples/images/"; // The check time and file expiry time to be passed to the cleaner thread. checkTime=1; // 1 minute. Thread awakes every 1 minute. expiryTime=5; // 5 minutes. All files that are more than 5 minutes old are deleted. fileExtension="png"; // Creates the cleaner thread and starts it. fct=new FileCheckThread(writeDir,expiryTime,checkTime,fileExtension); fct.start(); } public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException,ServletException { // Sets the response content type. res.setContentType("text/html"); PrintWriter pw=res.getWriter(); // Creates the chart context. Graph graph=new Graph(); graph.setLabels(new String[]{"Google","MSN","Yahoo","Altavista","Hotbot","Overture","AOL"}); graph.setHorizontalGraphEnabled(true); graph.set3DEnabled(true); graph.setTitle(new String[]{"The JetChart Library","A drill-down example"}); // Sets the size of the chart context and enables offscreen graph generation. These two methods must // always be invoked when using JetChart with servlets. graph.setSize(500,400); graph.setOffScreenGraphEnabled(true); // Some JetChart classes place calls to the method Graph.getLocale(), which only returns // a valid Locale object if the Graph object has been laid out on a container, like a // Frame or JFrame object. If the Graph object has not a parent, an exception is then // raised when the Graph.paint(Graphics g) method is invoked to paint chart on the // BufferedImage, telling that Graph must have a parent in order to determine its // locale. If we set the Graph object locale as below, the exception is not raised. graph.setLocale(Locale.getDefault()); // If a BufferedImage object is used to generate offscreen images, the method below // must always be set to true. graph.setBufferedImageEnabled(true,BufferedImage.TYPE_INT_RGB); // Enables the grid. GraphSet graphSet=graph.getGraphSet(0); Grid grid=graphSet.getGrid(); grid.setEnabled(true); grid.setColor(Color.gray); grid.setStyle(Grid.DASHED); double[] values={220,180,250,140,100,200,210}; Color[] colors={Color.red,Color.blue,Color.yellow,Color.green,Color.magenta,Color.orange,Color.cyan}; // Creates a bar series. BarSerie bs=new BarSerie(values,"Bar series"); bs.setWidth(20); bs.setColors(colors); bs.setBorderEnabled(false); // Disables series legend bs.setLegendEnabled(false); // Enables series data points legends. bs.setMarkLegendEnabled(true); // Adds the series to the chart context. graph.addSerie(bs); // The BufferedImage object dimension has to be equal to the Graph object dimension. BufferedImage bi=new BufferedImage(500,400,BufferedImage.TYPE_INT_RGB); Graphics2D g=bi.createGraphics(); // Enables antialiasing. Antialiasing eliminates the jagged edges. g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); // Paints chart on the offscreen image. graph.paint(g); // Creates an object that encapsulates the common functionalities of PNG encoding. // This method is found in the JAI package. PNGEncodeParam png=PNGEncodeParam.getDefaultEncodeParam(bi); // At this point we create a file to output the png encoded image. The file has to // be created in a folder within the website directory structure, so it can be // accessed from a client browser. This servlet also must have write access to the // image folder. // To prevent the client browser from getting the png image from the local cache, // we assign unique names to the file created appending the current time in // miliseconds and the IP address of the remote machine. // A drawback to this file naming method is that the images folder will become // larger in size across time, because a new file is created each time a new request // arrives to this servlet. The FileCheckThread class is a thread that implements // a mechanism to periodically delete the png files. It is started in the init() // method of this servlet. String fileName=req.getRemoteAddr()+System.currentTimeMillis()+".png"; // The png stream is outputted to a file. Change the directory accordingly. FileOutputStream out=new FileOutputStream("/usr/local/jakarta/webapps/examples/images/"+fileName); // Gets a PNG encoder. ImageEncoder encoder=ImageCodec.createImageEncoder ("PNG", out,png); // Encodes the BufferedImage object. encoder.encode(bi); out.close(); // After creating the png image file, the image map is generated. String[] urls={"http://www.google.com","http://www.msn.com","http://www.yahoo.com", "http://www.altavista.com","http://www.hotbot.com","http://www.overture.com", "http://www.aol.com"}; String html="<html><body bgcolor=white><center>\n"; html+="<map name='map'>\n"; // Gets the series map. String imageMap=bs.getSerieMap(urls,AbstractSerie.CLIENT_SIDE,null); // Embed the series map into the html string. html+=imageMap+"\n</map>\n"; // The file name and location is passed to the 'src' attribute of the <image> tag. html+="<image src=../images/"+fileName+" usemap=#map border=0></center></body></html>"; // Sends the html stream back to the client browser. pw.println(html); pw.close(); } }