博主正在參加CSDN2013年度博客之星評選,若是這篇文章對您有用,請投他一票:javascript
投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/oscar999html
Chart 導出的原理很基本方法,在上一篇已經有介紹過。前端
對於Extjs 來講,在 Ext.chart.Chart 這個類直接有提供一個 save( [config] ) 的方法, 調用這個方法, 就能夠在browser 下載當前這個chart 的對應格式的圖形文件。java
chart.save({ type: 'image/png' });
這裏使用的技術是把數據傳遞到服務器端, 由服務器端產生圖再傳到前端。web
因此, 在調用save 這個方法的時候, 你會發現, 請求會訪問http://svg.sencha.io/ 這個地址。apache
曾經, 大概在 2013 的年中的時候, 這個地址均可以訪問, 當時不知什麼時候, 這個地址的訪問就會報 503 (Service Unavailable)的錯誤了。canvas
這樣的話, 本來能夠work 的chart 導出功能, 如今就不行了。 瀏覽器
網上搜索一下, 是說部分版本已經不提供這個服務了。 服務器
無論如何, 講本身的服務放在別的地方, 總也不踏實, 是否能夠開發出這種服務呢?app
首先看一看, chart.save 時,前端傳遞了那些參數:
參數有四個:
width 和 height 應該是圖片的大小
type 應該是圖的保存格式
svg 傳遞的就是xml方式的svg 格式的數據。
因此問題歸結爲一點: 在服務端如何解析這個svg 格式的數據並生成圖片文件?
看懂這些svg 數據, 並使用基本API生成一個圖片不失爲一種解法?
可是對java 語言來講, 是否已經存在第三方包來幫咱們直接作這種事呢?
答案之一就是:
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 傳入)