概述:
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