[Web Chart系列之六] canvas Chart 导出图文件

时间:2023-03-03 08:35:26

前言

博主正在参加CSDN2013年度博客之星评选,如果这篇文章对您有用,请投他一票:

投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/oscar999

不胜感激^^

[Web Chart系列之六] canvas Chart 导出图文件

Chart 导出的原理很基本方法,在上一篇已经有介绍过。

对于Extjs 来说,在 Ext.chart.Chart 这个类直接有提供一个 save( [config] ) 的方法, 调用这个方法, 就可以在browser 下载当前这个chart 的对应格式的图形文件。

chart.save({
type: 'image/png'
});

这里使用的技术是把数据传递到服务器端, 由服务器端产生图再传到前端。

所以, 在调用save 这个方法的时候, 你会发现, 请求会访问http://svg.sencha.io/ 这个地址。

曾经, 大概在 2013 的年中的时候, 这个地址都可以访问, 当时不知何时, 这个地址的访问就会报 503 (Service Unavailable)的错误了。

aaarticlea/png;base64,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" alt="" />

这样的话, 原本可以work 的chart 导出功能, 现在就不行了。

网上搜索一下, 是说部分版本已经不提供这个服务了。

不管如何, 讲自己的服务放在别的地方, 总也不踏实, 是否可以开发出这种服务呢?

原理

首先看一看, chart.save 时,前端传递了那些参数:

aaarticlea/png;base64,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" alt="" />

参数有四个:

width 和 height 应该是图片的大小

type 应该是图的保存格式

svg  传递的就是xml方式的svg 格式的数据。

所以问题归结为一点: 在服务端如何解析这个svg 格式的数据并生成图片文件?

解决方法

看懂这些svg 数据, 并使用基本API生成一个图片不失为一种解法?

但是对java 语言来说, 是否已经存在第三方包来帮我们直接做这种事呢?

答案之一就是:

Batik

Batik是使用
svg格式图片来实现各种功能的应用程序以及Applet提供的一个基于java的工具包。

它是属于 Apache软件基金会 的一个项目, 应该是值得信赖的。

项目主页:  http://xmlgraphics.apache.org/batik/

下载地址:http://mirrors.cnnic.cn/apache/xmlgraphics/batik/

开发步骤:

1. 下载batik-1.7.zip ( 目前的最新版) 并解压

2. 把根目录, lib 和 extensions 目录下的所有lib 包拷入项目的web lib 中。(可以选择)

3. 写一个servlet   ImageExportService.java

/**
* author:oscar999
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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 ImageExportService extends HttpServlet { /**
*
*/
private static final long serialVersionUID = 1L; /**
* Post File to Client
* Input Parameters:
* type(image type, as png, jpeg),
* svg(svg string, post by extjs),
* filename(save file name)
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException { String type = request.getParameter("type");
String svg = request.getParameter("svg");
String filename = "chart";
if( request.getParameter("filename")!=null&&request.getParameter("filename").length()>0)
{
filename = request.getParameter("filename");
} String postfix;
if ("image/jpeg".equals(type)) {
response.setContentType("image/jpeg");
postfix = "jpg";
} else {
response.setContentType("image/png");
postfix = "png";
}
response.setHeader("Content-Disposition", "attachment; filename=" + filename + "." + postfix); StringReader stringReader = new StringReader(svg);
OutputStream out = response.getOutputStream(); try {
TranscoderInput input = new TranscoderInput(stringReader);
TranscoderOutput output = new TranscoderOutput(out); if ("image/jpeg".equals(type)) {
new JPEGTranscoder().transcode(input, output);
} else {
new PNGTranscoder().transcode(input, output);
} } catch (TranscoderException e) {
throw new ServletException(e);
}
} }

4.  在 web.xml 中配置此servlet 的请求路径

  <servlet>
<servlet-name>ImageExportService</servlet-name>
<servlet-class>com.XXX.ImageExportService</servlet-class>
</servlet>
  <servlet-mapping>
      <servlet-name>ImageExportService</servlet-name>
      <url-pattern>/ImageExportService</url-pattern>
  </servlet-mapping>

5.  让Extjs 的Chart.save 切换到新的服务器。

Ext.draw.engine.ImageExporter.defaultUrl = 'ImageExportService';

(注意, 这部分是写在web端的, 可以放在 Ext.onReady 里面)

6. 全部完成, 写个例子测试一下

//author: oscar999
<script type="text/javascript">
var chart;
var panel1;
Ext.require(['*']);
Ext.onReady(function() { Ext.draw.engine.ImageExporter.defaultUrl = '/'+WEB_PROJECT_NAME+'/ImageExportService'; var store = Ext.create('Ext.data.JsonStore', {
fields: ['name', 'data'],
data: [
{ 'name': 'metric one', 'data':100000 },
{ 'name': 'metric two', 'data': 7 },
{ 'name': 'metric three', 'data': 5 },
{ 'name': 'metric four', 'data': 2 },
{ 'name': 'metric five', 'data':27 }
]
}); var chart = Ext.create('Ext.chart.Chart', {
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate: true,
store: store,
axes: [{
type: 'Numeric',
position: 'bottom',
fields: ['data'],
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
title: 'Sample Values',
grid: true,
minimum: 0
}, {
type: 'Category',
position: 'left',
fields: ['name'],
title: 'Sample Metrics'
}],
series: [{
type: 'bar',
axis: 'bottom',
highlight: true,
tips: {
trackMouse: true,
width: 140,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data') + ' views');
}
},
label: {
display: 'insideEnd',
field: 'data',
renderer: Ext.util.Format.numberRenderer('0'),
orientation: 'horizontal',
color: '#333',
'text-anchor': 'middle'
},
xField: 'name',
yField: 'data'
}]
}); Ext.MessageBox.confirm('Confirm Download', 'Would you like to download the chart as an image?', function(choice){
if(choice == 'yes'){
chart.save({
type: 'image/png',
filename:'testfile'
});
}
}); });
</script>

跨浏览器处理

可能想到会有一个问题, IE 的低版本还只是支持vml 绘图, 那在这些版本的IE中, 导出图是否就不行了呢?

其实不用担心, Extjs 已经帮我们处理好了, 即使在这些版本的IE中, 传递到服务器的也是 svg  格式的数据。

(另外发现的一点是, 如果要传入自己定义的参数, 比如filename 等, 直接从save 中可能不行,可以考虑从呼叫url 传入)