js-xlsx で js で excel のファイルを生成する
Excel ファイルの生成、めんどくさいですよね。CSV の生成めんどくさいですよね。HTML を出力した上でさらにやるのはだるい、というわけで、HTML の DOM を解析して JS で XLSX 生成してダウンロードさせたらいいんじゃね?と思ってそういうのやれるやつ探したら、js-xlsx ってのがあった。 これをつかって、HTML のレポートから XLSX を生成するコードを書いた。なかなかうまく動く感じしてる。
http://tokuhirom.github.io/js-xlsx-demo/
td タグに class を指定すると数字カラムになる、みたいな感じになってるのがいいかんじです。
js-xlsx で生成したXLSXは、FileSaver.js で保存させてます。
デモで利用している JS は以下のようなものである。簡単でしょ。
"use strict";
var data = [
{date:'2014-06-11', num:2300},
{date:'2014-06-10', num:11300},
{date:'2014-06-09', num:300},
{date:'2014-06-08', num:3400},
{date:'2014-06-07', num:4300},
{date:'2014-06-06', num:8300},
{date:'2014-06-05', num:3300},
{date:'2014-06-04', num:331300},
{date:'2014-06-03', num:300},
{date:'2014-06-02', num:3700},
{date:'2014-06-01', num:8300}
];
function ReportCtrl($scope) {
$scope.data = data;
function downloadCSV() {
function datenum(v, date1904) {
if(date1904) v+=1462;
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {};
var range = {s: {c:10000000, r:10000000}, e: {c:0, r:0 }};
for(var R = 0; R != data.length; ++R) {
for(var C = 0; C != data[R].length; ++C) {
if(range.s.r > R) range.s.r = R;
if(range.s.c > C) range.s.c = C;
if(range.e.r < R) range.e.r = R;
if(range.e.c < C) range.e.c = C;
var cell = {v: data[R][C] };
if(cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({c:C,r:R});
if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.t = 'n'; cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if(range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
return ws;
}
var data = [];
$('.report tr').each(function (i, tr) {
var row = [];
$(tr).find('th,td').each(function (j, td) {
var o = ''+td.innerHTML;
if ($(td).hasClass("report-num")) {
o = parseInt(o, 10);
}
row.push(o);
});
data.push(row);
});
console.log(data);
function Workbook() {
if(!(this instanceof Workbook)) return new Workbook();
this.SheetNames = [];
this.Sheets = {};
}
var key = XLSX.utils.encode_cell({c:0,r:0});
var ws = sheet_from_array_of_arrays(data);
var workbook = new Workbook();
workbook.SheetNames.push("売上");
workbook.Sheets["売上"] = ws;
var wbout = XLSX.write(workbook, {
bookType:'xlsx',
bookSST:true,
type:'binary'
});
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
saveAs(new Blob([s2ab(wbout)],{type:""}), "report.xlsx");
}
$scope.downloadCSV = function () {
downloadCSV();
};
$scope.uriage = function (row) {
return row.num * 1000;
};
$scope.tax = function (uriage) {
return uriage * 0.08;
};
}
この方法だと、
- 生成される XLSX が環境によってずれたりしたら最悪
- ユーザーの環境で動かなかったら最悪
- 重くなったら最悪 っていうのが懸念されますが、そのへんがパスできるなら便利だと思います。