概述:
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生成图片的代码如下:
代码语言:javascript复制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的编写代码如下:
代码语言:javascript复制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:ntParameter [svg]: The DOM Element to be converted."
"ntParameter [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的配置如下:
代码语言:javascript复制 <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>
在前台,调用的方式如下:
代码语言:javascript复制 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的方式传给后台,代码如下:
代码语言:javascript复制 $("#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