在純JaveScript中實現報表導出:從“PDF”到“JPG”

我們在前端報表中完成了各種工作數據的輸入或內容處理之後,需要做什麼?

數據的導出!

這些數據的常用導出格式有:PDF、Excel、HTML和圖片幾大類型。

但總有一些實際應用場景,需要的不僅僅是將現有內容導出,還需要我們對一些內容的格式進行轉化。

就在前幾天,葡萄剛上班,就看到客戶發來下圖,發生了以下對話

-葡萄,這一頁可以導出嗎?

-當然可以,PDF、Excel、HTML都可以。

-可是我想把這一頁導出圖片。

這時候問題就出現了,在我們的前端電子報表中並沒有默認圖片保存的格式,那這時候我們如何用已有功能進一步擴展,來實現這個功能呢?

一、確定實現思路

巧婦難爲無米之炊,首先我們先整理一下手中素材。

通過閱讀文檔瞭解我們可以自定義添加按鈕:

同時我們還可以在action屬性中,給按鈕定義點擊後觸發的事件:

順着這個思路,我們可以在工具欄添加一個導出按鈕,將按鈕的動作設置爲"點擊這個按鈕時實現導出圖片的功能"。ARJS本身支持導出PDF,並且也提供了直接調用導出PDF的接口:export,所以我們可以先通過接口導出PDF,然後再將PDF轉換爲圖片,最終實現導出圖片的功能。

這下子,我們的最終問題就變成了是如何 ** PDF **轉換爲圖片並導出

PDF.js是一款使用HTML5 Canvas安全地渲染PDF文件以及遵從網頁標準的網頁瀏覽器渲染PDF文件的JavaScript庫。我們可以通過PDF.js庫將導出的PDF通過Canvas在網頁上渲染出來,然後通過Canvas的toDataURL方法返回一個包含圖片展示的 data URL。拿到這個URL就好辦了,可以利用a標籤的download屬性直接對其進行下載,最終實現在ARJS中導出圖片的功能。

總結,整體實現思路如下:

  • 添加導出圖片按鈕
  • 實現導出PDF
  • 將 PDF 通過 PDF.js 庫渲染成
  • 通過a標籤的download屬性將保存爲圖片

二、代碼實戰
簡單起見,本示例不使用任何框架集成ARJS,選擇在純JaveScript中集成報表,大家可以閱讀相關文檔:在純JavaScript項目中集成報表 Viewer。另外,爲了在document中插入canvas元素,事先可以建立一個div元素,以便之後在該節點下插入canvas元素;同時爲了界面中只有報表查看器,可以隱藏該div。最終的頁面結構如下:

	<body>
	        <div id="viewer-host"></div>
	        <div id="imgDiv" style="display: none"></div>
	</body>

添加導出圖片按鈕

1.	    let exportImageButton = {
2.	        key: '$exportImage',
3.	        icon:{
4.	            type: 'svg',
5.	            content:'<svg role="img" xmlns="http://www.w3.org/2000/svg" width="21px" height="21px" viewBox="0 0 24 24" aria-labelledby="imageIconTitle" stroke="#205F78" stroke-width="2.2857142857142856" stroke-linecap="square" stroke-linejoin="miter" fill="none" color="#205F78"> <title id="imageIconTitle">Image</title> <rect width="18" height="18" x="3" y="3"/> <path stroke-linecap="round" d="M3 14l4-4 11 11"/> <circle cx="13.5" cy="7.5" r="2.5"/> <path stroke-linecap="round" d="M13.5 16.5L21 9"/> </svg>',
6.	            size: 'small'
7.	        },
8.	        enabled: true,
9.	        title:'導出圖片',
10.	        action: function() {
11.	            //定義導出圖片按鈕點擊事件
12.	        }
13.	    };
14.	    viewer.toolbar.addItem(exportImageButton);

接口文檔:addItem
(提示:以上在icon 的content的屬性中,使用了一個svg,這個示例代碼中的svg來自網站:ikonate 。如果大家有需要可自行下載,如果作爲商用需要注意版權 )

以上代碼添加之後,我們就可以在報表預覽界面的工具欄看到這樣一個按鈕:

實現導出PDF

在exportImageButton的action中定義一個exportImage方法,在這個方法中首先實現導出PDF,導出的結果包含一個PDF文件的blob對象,大家可自行打印出來看一下導出結果:

	    function exportImage() {
	        const settings = { title: 'Active Reports JS' };
	        viewer.export('PDF', settings).then((result) =>{
	                //這個result包含一個所導出PDF的blob對象
	                console.log(result);
	        });
	    }

將PDF通過PDF.js庫渲染成canvas

首先我們需要去PDF.js官網下載相關文件引入到項目中,我這裏的示例通過cdn的方式引入:

1.	  <script src="https://cdnjs.cloudflare.com/ajax/libs/PDF.js/2.10.377/PDF.min.js"></script>

引入之後,我們就可以對上一步得到的blob對象進行操作,將PDF渲染成&lt;canvas&gt;:

	    function pageToCanvasObj(page) {
	        const viewport = page.getViewport({scale: 1});
	        const canvas = document.createElement('canvas');
	        const context = canvas.getContext('2d');
	        canvas.height = viewport.height;
	        canvas.width = viewport.width;
	        canvas.style.width = "100%";
	        canvas.style.height = "100%";
	        imgDiv.append(canvas);
	        return {
	            canvas,
	            renderContext: {
	                canvasContext: context,
	                viewport
	            }
	        }
	    }
	
	    function exportImage() {
	        const settings = { title: 'Active Reports JS' };
	        viewer.export('PDF', settings).then((result) =>{
	            //核心代碼
	           //通過FileReader的接口將blob轉換爲ArrayBuffer
	            const fileReader = new FileReader();
	            fileReader.readAsArrayBuffer(result.data);
	            fileReader.onload = function() {
	                //爲了讀寫ArrayBuffer對象,建立typedArray視圖
	                const typedArrayResult = new Uint8Array(fileReader.result);
	                //PDF.js讀取文檔後渲染canvas
	                PDFjsLib.getDocument(typedArrayResult).promise.then(function(PDF) {
	                    if (PDF) {
	                        const pageNum = PDF.numPages;
	                        for (let i = 1; i <= pageNum; i++) {
	                            PDF.getPage(i).then((page) => {
	                                //創建canvas,並且返回相關數據
	                                const canvasObj = pageToCanvasObj(page);
	                                //<canvas>渲染
	                                page.render(canvasObj.renderContext).promise.then(() => {
	                                   //通過canvas對象的toDataURL得到圖片鏈接
	                                    const imgUrl = canvasObj.canvas.toDataURL();
	                                })
	                            })
	                        }
	                    }
	                },(error) => {
	                    alert(error);
	                });
	            };
	        });
	    }

通過a標籤的download屬性將canvas保存爲圖片
將上一步得到的imgURL通過a標籤下載:

   function saveImage(index, url) {
	        const link = document.createElement("a");
	        link.href = url;
	        link.download = `image${index}`;
	        link.click();
	        link.remove();
	    }

這下就實現了在在前端報表中完整將報表內容作爲圖片導出。在此附上示例完整demo代碼文件:

https://gcdn.grapecity.com.cn/forum.php?mod=attachment&aid=MTY0Njg4fGNlMzM5MTkwfDE2MzM2NjU4MzB8NjI2NzZ8MTMyNDM3
導出效果:

到這裏,已經完全解決了本次提到的問題~

後續也會爲大家帶來更多有趣或嚴肅的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章