<< [안내] Sun Tech Day 2008 | | Top 125 Blogs for Development Managers >>

jfreechart로 차트 기능 구현

1. jfreechart 다운 로드
 - http://www.jfree.org/jfreechart/
 - jfreechart-X.X.X.jar, jcommon-X.X.X.jar를 어플리케이션 밑의 /WEB-INF/lib 폴더에 복사해 줌.

2. 환경 설정

  <servlet>
   <servlet-name>DisplayChart</servlet-name>
   <servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
 </servlet>
 <servlet-mapping>
   <servlet-name>DisplayChart</servlet-name>
  <url-pattern>/DisplayChart</url-pattern>
 </servlet-mapping>

 

3. 구현 코드

 - Chart.java

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.servlet.ServletUtilities;
public class Chart
{
 protected String type;
 protected String title;
 protected String yaxis;
 protected String varId;
 protected int id = -1;
 protected boolean displayChart;
 protected boolean savetofile;
 protected JFreeChart _chart;
 protected Log log = LogFactory.getLog(this.getClass());
 public Chart(String type, String title, String yaxis, String varId,
    boolean displayChart, boolean savetofile) {
  this.type = type; //차트 종류
  this.title = title; // 차트 제목
  this.yaxis = yaxis; //y범례title
  this.varId = varId; //x범례title
  this.displayChart = displayChart;
  this.savetofile = savetofile;
 }
 public String getType() {
  return type;
 }
 public JFreeChart getChart () {
  return _chart;
 }
 public void initXYSeries (String variableid, int variableindex, int flag) {
  // The XY charts need to implement this
 }
 public void addValue (double tpsd, String variableid,
    String variableindex, int flag) {
  // All charts need to implement this
 }
 public void addSeries(int flag)  {
  // The XY charts need to implement this
 }
 public void createChart() {
  // All charts need to implement this
 }
// 파일로 저장한 차트
 public String saveChart(String outfileprefix, int width, int height)
 {
  String filename = null;
  String fullpath = "/www/test";
  
  try {
   if (_chart == null) {
    log.info("Chart.saveChart: Chart has not been created");
    filename = "public_error_700x300.png";
    return filename;
   }
   if (savetofile && outfileprefix != null) {
    filename = fullpath + File.separator + outfileprefix + "." + type + ".jpg";
    File imgfile = new File (filename);
    ChartUtilities.saveChartAsJPEG(imgfile,
_chart, width, height);
   }
  } catch (Exception e) {
   e.printStackTrace();
   log.error(e);
  }
  return filename;
}
  //response chart 결과 출력
 public void displayChart(HttpServletResponse response, int width, int height)
 {
  BufferedImage image = null;
  ByteArrayOutputStream stream = null;
  OutputStream os = null;
   
  try {
   if (displayChart && _chart != null) {
    image  = _chart.createBufferedImage(width, height);
    stream = new ByteArrayOutputStream();
    ChartUtilities.writeBufferedImageAsJPEG(stream, image);
    response.setDateHeader("Expires", 1);
             byte[] data = stream.toByteArray();
             response.setContentLength(data.length);
             response.setContentType("image/jpeg");
             os = response.getOutputStream();
             os.write(data);
     }
  } catch (Exception e) {
   e.printStackTrace();
   log.error(e);
  } finally {
   try {
    if (os != null) {
     os.flush();
     os.close();
    }
   } catch (Throwable t) {
    // ignore
   }
    }
   }
  
   // session에 결과 출력
 public String displayChart(HttpSession session, PrintWriter pw,
int width, int height)
 {
  ChartRenderingInfo info = null;
  String filename = null;
   
  try {
     if (displayChart && _chart != null) {
      info = new ChartRenderingInfo(new StandardEntityCollection());
      filename = ServletUtilities.saveChartAsJPEG(_chart, width, height,
info, session);
     }
    } catch (Exception e) {
     e.printStackTrace();          
     log.error(e);
           filename = "public_error_700x300.png";
    } finally {
     info = null;
    }
    return filename;
   }
}

 - ChartFactory.java

public class ChartFactory 
{
 public static String[] SUPPORTED_CHARTS = {"BarChart3D", "XYLine", "XYScatter",
    "RatioBarChart3D", "RatioXYLine", "RatioXYScatter", "Line"};
 private static final int BARCHART3D = 0;
 private static final int XYLINE = 1;
 private static final int XYSCATTER = 2;
 private static final int RATIOBARCHART3D = 3;
 private static final int RATIOXYLINE = 4;
 private static final int RATIOXYSCATTER = 5;
 private static final int LINECHART = 6;
 public static Chart createChart (String type,
String title, String yaxis, String varId,
    boolean displayChart, boolean savetofile) {
  int id = 0;
  for (int i=0; i<SUPPORTED_CHARTS.length; i++) {
   if (type.equalsIgnoreCase (SUPPORTED_CHARTS[i])) {
    id = i;
    break;
   }
  }
  switch (id) {
   case BARCHART3D:
    return new BarChart3D (type, title, yaxis, varId, displayChart,
savetofile);
   case RATIOBARCHART3D:
    return new RatioBarChart3D (type, title, yaxis, varId,
displayChart, savetofile);
      case XYLINE:
      return new XYLineChart (type, title, yaxis, varId,
displayChart, savetofile);
      case XYSCATTER:
      return new XYScatterChart (type, title, yaxis, varId,
displayChart, savetofile);
      case RATIOXYLINE:
      return new RatioXYLineChart (type, title, yaxis, varId,
displayChart, savetofile);
      case RATIOXYSCATTER:
      return new RatioXYScatterChart (type, title, yaxis, varId,
displayChart, savetofile);
      case LINECHART:
       return new LineChart(type, title, yaxis, varId,
displayChart, savetofile);
  }
  return null;
 }
}

 - LineChart.java

import java.awt.Color;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
public class LineChart extends Chart
{
 protected DefaultCategoryDataset dataset;
 
 public LineChart(String type, String title, String yaxis/*y범례title*/,
    String varId/*x범례title*/, boolean displayChart, boolean savetofile) {
  super (type, title, yaxis, varId, displayChart, savetofile);
  dataset = new DefaultCategoryDataset();
 }

 public void addValue (double tpsd, String variableid, String variableindex,
   int flag) {
  dataset.addValue(tpsd/* y */, variableid, variableindex/* x */);
 }
 
 public void createChart()
 {
  CategoryPlot categoryplot = null;
  NumberAxis numberaxis = null;
  LineAndShapeRenderer lineandshaperenderer = null;
  
  try {
   _chart = org.jfree.chart.ChartFactory.createLineChart(title, varId, yaxis,
    (CategoryDataset)dataset, PlotOrientation.VERTICAL/*라인orientation*/,
     true/*범례설정여부*/, true/*도움말설정여부*/, false/*urls설정여부*/);
   _chart.setBackgroundPaint(Color.white);
   
   _chart.setAntiAlias(true);
   categoryplot = (CategoryPlot) _chart.getPlot();
   categoryplot.setRangeGridlinePaint(Color.lightGray);
   numberaxis = (NumberAxis) categoryplot.getRangeAxis();
   numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
   numberaxis.setAutoRangeIncludesZero(false);
   numberaxis.setUpperMargin(0.12D);
   lineandshaperenderer = (LineAndShapeRenderer) categoryplot.getRenderer();
   lineandshaperenderer.setBaseShapesVisible(true);
   lineandshaperenderer.setDrawOutlines(true);
   lineandshaperenderer.setUseFillPaint(true);
   lineandshaperenderer.setBaseFillPaint(Color.white);
   lineandshaperenderer.setBaseItemLabelsVisible(true);
   lineandshaperenderer.setBaseItemLabelGenerator(
          new StandardCategoryItemLabelGenerator());//속도 안나옴
  } catch (Exception e) {
   log.error(e);
  }
 }
}

 - Controller에 위 클래스 사용 예

  public ModelAndView handleRequest(HttpServletRequest req, 
     HttpServletResponse resp) throws Exception
 {
  ModelAndView mv = null;
  String fromdate = null;
  String todate = null;
  DateUtil du = null;
  Chart charts = null;
  PrintWriter pw = null;
  String filename = null;
  String graphURL = null;
  
  try {
   fromdate = StringUtils.defaultIfEmpty(
      req.getParameter("fromdate"), StringUtils.EMPTY);
   todate = StringUtils.defaultIfEmpty(req.getParameter("todate"),
     StringUtils.EMPTY);
   if (StringUtils.isEmpty(fromdate) || StringUtils.isEmpty(todate)) {
    du = new DateUtil();
    fromdate = du.addDays(du.getShortDateString(), -8, "yyyyMMdd");
    todate = du.addDays(du.getShortDateString(), -1, "yyyyMMdd");
   }
   charts = ChartFactory.createChart("Line", "일별 가입자 수 통계", "가입자 수",
      "가입 일자", false, true);
   charts.addValue(5, "성년 가입자수", "2008.09.09", 1);
   charts.addValue(2, "미성년 가입자수", "2008.09.09", 1);
   charts.addValue(9, "성년 가입자수", "2008.09.10", 1);
   charts.addValue(1, "미성년 가입자수", "2008.09.10", 1);
   charts.addValue(4, "성년 가입자수", "2008.09.11", 1);
   charts.addValue(3, "미성년 가입자수", "2008.09.11", 1);
   charts.addValue(7, "성년 가입자수", "2008.09.12", 1);
   charts.addValue(3, "미성년 가입자수", "2008.09.12", 1);
   charts.addValue(7, "성년 가입자수", "2008.09.13", 1);
   charts.addValue(4, "미성년 가입자수", "2008.09.13", 1);
   charts.addValue(2, "성년 가입자수", "2008.09.14", 1);
   charts.addValue(5, "미성년 가입자수", "2008.09.14", 1);
   charts.addValue(10, "성년 가입자수", "2008.09.15", 1);
   charts.addValue(1, "미성년 가입자수", "2008.09.15", 1);
   charts.addValue(18, "성년 가입자수", "2008.09.16", 1);
   charts.addValue(1, "미성년 가입자수", "2008.09.16", 1);
   charts.createChart();
   filename = charts.saveChart("Signup", 700, 300);
   graphURL = "/upload_img/" + filename;
   log.info(graphURL);
   mv = new ModelAndView();
  mv.addObject("graphurl", graphURL);
   mv.addObject("filename", "#" + filename);  
   mv.setViewName("register-statistics");
  } catch (Exception e) {
   e.printStackTrace();
   log.error(e);
  } finally {
  }
  return mv;
 }

 - vm(Velocity)파일에서 사용 예

  <div id="bodyWrapper">
      <p class="more"><img src="$!{graphurl}"
width=700 height=300 border=0 usemap="$!{filename}"></p>
  </div>

4. 구현 결과 화면

5. 팁
 - http://mimul.com/examples/jfree/jfreechart-1.0.10-demo.jnlp을 다운 받아서 실행하면 샘플 예제들과 소스를 확인 할 수 있어 개발하는 데 많은 도움을 받을 수 있습니다.

 -  DisplayChart를 활용해서 이미지를 렌더링 할 경우 차트의 속성을 자세하게 설정하고 데이터를 차트에 할당 할 경우 이미지 로딩 속도가 현저하게 떨어지는 경우가 있습니다. 이럴 경우는 차트이미지를 파일로 만들어서 로딩하면 됩니다. 아직 성능 이슈가 좀 있긴 하네요.

태그 :



코멘트 달기 Send a TrackBack