2016년 3월 5일 토요일

서버에서 동적으로 차트 이미지를 만들자

차트의 썸네일을 클릭해서 선택한 차트를 크게 보여주는 페이지가 있다. 차트의 유형이 고정적으로 정해져 있어서 썸네일 이미지를 특정한 경우의 차트 모양을 캡쳐하여 이미지로 소스저장소에 저장해서 사용하고 있었다. 이 썸네일 이미지를 실제 차트로 보여질 데이터의 모양으로 보여달라는 기능을 구현해야 해서 찾아본 내용을 공유한다.

1.
썸네일이미지를 만들지 말고 실제 차트를 썸네일 크기로 만드는 방법도 검토했다. 그런데 작은 공간에 수많은 div들과 svg들이 들어가게 되는 것이 좀 꺼림칙했다. 그리고 페이지가 스크롤되거나 윈도우 사이즈가 변경될 때 썸네일차트들이 잘 렌더링될지도 걱정이 되었다.

2.
썸네일이미지를 동적으로 만드는 방법도 검토했다. "generate chart image response java"와 같은 검색어로 검색도 해보고, java chart library를 찾아보기도 했다. 이 방면에서 가장 유명한 라이브러리는 jfreechart인 것 같다. 흥미로운 것은 FAQ에서 다른 차트 라이브러리를 소개하고 있다.

3.
xchart가 적당한 수준의  기능이 구현된 것 같아서선택하여 구현했다. 기본적으로 swing을 이용해서 차트를 띄울 수 있어서 테스트해가면서 차트의 모양을 확인하기가 편했다. 그리고 완성차트의 이미지 바이트배열을 제공하므로 http response로 보낼수도 있었다.

double[] yData = new double[] { 2.0, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7, 1.0, 1.7 };

// Create Chart
Chart_XY chart = new Chart_XY(85 * 2, 44 * 2);
chart.getStyler().setChartBackgroundColor(Color.WHITE);
chart.getStyler().setChartTitleVisible(false);
chart.getStyler().setChartTitleBoxVisible(false);
chart.getStyler().setPlotGridLinesVisible(false);
chart.getStyler().setLegendVisible(false);
chart.getStyler().setAxisTicksVisible(false);
chart.getStyler().setAxisTitlesVisible(false);

Series_XY series = chart.addSeries(" ", null, yData);
series.setLineColor(Color.BLUE);
series.setMarker(SeriesMarkers.NONE);
series.setLineStyle(SeriesLines.SOLID);

byte[] img = BitmapEncoder.getBitmapBytes(chart, BitmapFormat.PNG);

4. 
리턴이 이미지파일이므로 response에 적절한 헤더와 함께 담아야 한다. 그런데 Spring의 RequestMapping의 produces 속성에 이미지파일형식만 선언해서, 간단히 byte[]만 리턴하면 되게 할 수 도 있다.

@Controller
public class ImageController {
@RequestMapping(value="/", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
public @ResponseBody byte[] index() throws IOException {
return BitmapEncoder.getBitmapBytes(chart, BitmapFormat.PNG);
}
}

5.
이렇게 만들면 간단하게 <img> 태그의 주소만 변경해서 썸네일스러운 이미지를 동적으로 만들 수 있다. 실제 파일이 생성되는 것이 아니므로 스토리지에 대한 부담도 없다. 대략 아래와 같이 썸네일 스러운 이미지를 만들 수 있다.