概述:
Highcharts是在做項目涉及到統計圖的時候大家的首選,同時也會用到highcharts的export功能,將統計圖導出爲圖片,剛好,最近也遇到了這樣的事情,總結出來,以備後用。
導出方式:
highcharts導出圖片實現有三種:highcharts服務器導出、局域網服務器導出、本地後臺導出。
首先,highcharts服務器導出是默認的導出方式,不需要任何操作,只需在chart中配置export參數即可,但是這種導出方式需要聯網;
其次,局域網服務器導出,需要在局域網內配置導出的服務器,可參考http://www.highcharts.com/docs/export-module/setting-up-the-server進行配置;
最後,本地後臺導出,既不需要聯網,也不需要局域網服務器,直接在後臺寫對應的servlet即可,是本文講解的重點內容。
導出原理:
Highcharts圖表導出(或下載)本質上是將SVG代碼轉換爲不同文件格式的過程,用到的工具是batik,所以所謂導出服務器,只不過是調用batik,將SVG代碼轉換並下載。參見下圖:
在Java中通過SVG生成圖片的代碼如下:
package com.lzugis.demo; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.StringReader; import org.apache.batik.transcoder.Transcoder; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; public class CreateImg { public static void main(String[] args) throws Exception { String svg = "<svg height=\"200\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"10,10 75,150 150,60\" style=\"fill:#63BCF7;stroke:black;stroke-width:3\"/></svg>"; String type="image/png"; String filename="svg"; if (null != type && null != svg) { svg = svg.replaceAll(":rect", "rect"); String ext = ""; Transcoder t = null; if (type.equals("image/png")) { ext = "png"; t = new PNGTranscoder(); } else if (type.equals("image/jpeg")) { ext = "jpg"; t = new JPEGTranscoder(); } if (null != t) { OutputStream out = new FileOutputStream("D:\\"+filename+"."+ext); TranscoderInput input = new TranscoderInput(new StringReader(svg)); TranscoderOutput output = new TranscoderOutput(out); try{ t.transcode(input, output); System.out.println("out"); } catch (TranscoderException e) { e.printStackTrace(); } } } } }
生成後圖片效果如下:
在web中,servlet的編寫代碼如下:
package com.lzugis.demo; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringReader; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.batik.transcoder.Transcoder; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; public class SaveAsImage extends HttpServlet { private static final long serialVersionUID = 1L; public SaveAsImage() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8");//設置編碼,解決亂碼問題 String type = request.getParameter("type"); String svg = request.getParameter("svg"); String filename = request.getParameter("filename"); filename = filename==null?"chart":filename; ServletOutputStream out = response.getOutputStream(); if (null != type && null != svg) { svg = svg.replaceAll(":rect", "rect"); String ext = ""; Transcoder t = null; if (type.equals("image/png")) { ext = "png"; t = new PNGTranscoder(); } else if (type.equals("image/jpeg")) { ext = "jpg"; t = new JPEGTranscoder(); } else if(type.equals("image/svg+xml")) ext = "svg"; response.addHeader("Content-Disposition", "attachment; filename="+ filename + "."+ext); response.addHeader("Content-Type", type); if (null != t) { TranscoderInput input = new TranscoderInput(new StringReader(svg)); TranscoderOutput output = new TranscoderOutput(out); try { t.transcode(input, output); } catch (TranscoderException e) { out.print("Problem transcoding stream. See the web logs for more details."); e.printStackTrace(); } } else if (ext.equals("svg")) { OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); writer.append(svg); writer.close(); } else out.print("Invalid type: " + type); } else { response.addHeader("Content-Type", "text/html"); out.println("Usage:\n\tParameter [svg]: The DOM Element to be converted." + "\n\tParameter [type]: The destination MIME type for the elment to be transcoded."); } out.flush(); out.close(); } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } }
web.xml中的servlet的配置如下:
<servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <servlet-name>SaveAsImage</servlet-name> <servlet-class>com.foxconn.highcharts.demo.SaveAsImage</servlet-class> </servlet> <servlet-mapping> <servlet-name>SaveAsImage</servlet-name> <url-pattern>/SaveAsImage</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>basic_line.jsp</welcome-file> </welcome-file-list>
在前臺,調用的方式如下:
var chart; $(document).ready(function(){ Highcharts.setOptions({ lang: { printChart:"打印圖表", downloadJPEG: "下載JPEG 圖片" , downloadPDF: "下載PDF文檔" , downloadPNG: "下載PNG 圖片" , downloadSVG: "下載SVG 矢量圖" , exportButtonTitle: "導出圖片" } }); chart = new Highcharts.Chart({ chart: { renderTo: 'container', defaultSeriesType: 'line', marginRight: 130, marginBottom: 25 }, title: { text: 'Monthly Average Temperature', x: -20 //center }, subtitle: { text: '測試中文亂碼', x: -20 }, xAxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] }, yAxis: { title: { text: 'Temperature (°C)' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }, exporting:{ enabled:true, filename:'class-booking-chart', url:'http://localhost:8081/HighChartsDemo/SaveAsImage' }, tooltip: { formatter: function(){ return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y + '°C'; } }, legend: { layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0 }, series: [{ name: 'Tokyo', data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6] },{ name: 'New York', data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5] },{ name: 'Berlin', data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0] },{ name: 'London', data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8] }] });
同樣,如果不想將導出按鈕不顯示在圖片上的話,你可以通過chart.getSVG()函數來獲取到chart的svg元素,並以ajax的方式傳給後臺,代碼如下:
$("#export").click(function(){ var svg = chart.getSVG(); $.ajax({ type: "post", url: 'http://localhost:8081/HighChartsDemo/SaveAsImage', data:{ type:"image/png", filename:"chart", svg:svg }, success: function(data){ console.log("success"); } }); });
batik的lib包下載地址:http://pan.baidu.com/s/1dDwEvqL