[Web Chart系列之六] canvas Chart 導出圖文件

前言

 

博主正在參加CSDN2013年度博客之星評選,若是這篇文章對您有用,請投他一票:javascript

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

不勝感激^^

 

 

 

[Web Chart系列之六] canvas Chart 導出圖文件

 

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

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 傳入)

相關文章
相關標籤/搜索