x-spreadsheet demo merges and formulae [ci skip]

Co-authored-by: SheetJS <dev@sheetjs.com>
This commit is contained in:
ThibautSF 2021-10-13 06:43:07 +02:00
parent e110fe8952
commit 5c02c819f6
2 changed files with 141 additions and 70 deletions

@ -35,56 +35,21 @@ var grid = x_spreadsheet(document.getElementById("gridctr"));
The following function converts data from SheetJS to x-spreadsheet:
```js
function stox(wb) {
var out = [];
wb.SheetNames.forEach(function(name) {
var o = {name:name, rows:{}};
var ws = wb.Sheets[name];
var aoa = XLSX.utils.sheet_to_json(ws, {raw: false, header:1});
aoa.forEach(function(r, i) {
var cells = {};
r.forEach(function(c, j) { cells[j] = ({ text: c }); });
o.rows[i] = { cells: cells };
})
out.push(o);
});
return out;
}
/* load data */
grid.loadData(stox(workbook_object));
```
`stox` is defined in [xlsxspread.js](./xlsxspread.js)
## Editing
`x-spreadsheet` handles the entire edit cycle. No intervention is necessary.
`x-spreadsheet` handles the entire edit cycle. No intervention is necessary.
## Saving Data
`grid.getData()` returns an object that can be converted back to a worksheet:
```js
function xtos(sdata) {
var out = XLSX.utils.book_new();
sdata.forEach(function(xws) {
var aoa = [[]];
var rowobj = xws.rows;
for(var ri = 0; ri < rowobj.len; ++ri) {
var row = rowobj[ri];
if(!row) continue;
aoa[ri] = [];
Object.keys(row.cells).forEach(function(k) {
var idx = +k;
if(isNaN(idx)) return;
aoa[ri][idx] = row.cells[k].text;
});
}
var ws = XLSX.utils.aoa_to_sheet(aoa);
XLSX.utils.book_append_sheet(out, ws, xws.name);
});
return out;
}
/* build workbook from the grid data */
var new_wb = xtos(xspr.getData());
@ -92,6 +57,8 @@ var new_wb = xtos(xspr.getData());
XLSX.writeFile(new_wb, "SheetJS.xlsx");
```
`stox` is defined in [xlsxspread.js](./xlsxspread.js)
## Additional Features
This demo barely scratches the surface. The underlying grid component includes

@ -1,37 +1,141 @@
/*! xlsxspread.js (C) SheetJS LLC -- https://sheetjs.com/ */
/* eslint-env browser */
/*global XLSX */
/*exported stox, xtos */
/**
* Converts data from SheetJS to x-spreadsheet
*
* @param {Object} wb SheetJS workbook object
*
* @returns {Object[]} An x-spreadsheet data
*/
function stox(wb) {
var out = [];
wb.SheetNames.forEach(function(name) {
var o = {name:name, rows:{}};
var ws = wb.Sheets[name];
var aoa = XLSX.utils.sheet_to_json(ws, {raw: false, header:1});
aoa.forEach(function(r, i) {
var cells = {};
r.forEach(function(c, j) { cells[j] = ({ text: c }); });
o.rows[i] = { cells: cells };
})
out.push(o);
});
return out;
var out = [];
wb.SheetNames.forEach(function (name) {
var o = { name: name, rows: {} };
var ws = wb.Sheets[name];
var range = XLSX.utils.decode_range(ws['!ref']);
// sheet_to_json will lost empty row and col at begin as default
range.s = { r: 0, c: 0 };
var aoa = XLSX.utils.sheet_to_json(ws, {
raw: false,
header: 1,
range: range
});
aoa.forEach(function (r, i) {
var cells = {};
r.forEach(function (c, j) {
cells[j] = { text: c };
var cellRef = XLSX.utils.encode_cell({ r: i, c: j });
if ( ws[cellRef] != null && ws[cellRef].f != null) {
cells[j].text = "=" + ws[cellRef].f;
}
});
o.rows[i] = { cells: cells };
});
o.merges = [];
(ws["!merges"]||[]).forEach(function (merge, i) {
//Needed to support merged cells with empty content
if (o.rows[merge.s.r] == null) {
o.rows[merge.s.r] = { cells: {} };
}
if (o.rows[merge.s.r].cells[merge.s.c] == null) {
o.rows[merge.s.r].cells[merge.s.c] = {};
}
o.rows[merge.s.r].cells[merge.s.c].merge = [
merge.e.r - merge.s.r,
merge.e.c - merge.s.c
];
o.merges[i] = XLSX.utils.encode_range(merge);
});
out.push(o);
});
return out;
}
/**
* Converts data from x-spreadsheet to SheetJS
*
* @param {Object[]} sdata An x-spreadsheet data object
*
* @returns {Object} A SheetJS workbook object
*/
function xtos(sdata) {
var out = XLSX.utils.book_new();
sdata.forEach(function(xws) {
var aoa = [[]];
var rowobj = xws.rows;
for(var ri = 0; ri < rowobj.len; ++ri) {
var row = rowobj[ri];
if(!row) continue;
aoa[ri] = [];
Object.keys(row.cells).forEach(function(k) {
var idx = +k;
if(isNaN(idx)) return;
aoa[ri][idx] = row.cells[k].text;
});
}
var ws = XLSX.utils.aoa_to_sheet(aoa);
XLSX.utils.book_append_sheet(out, ws, xws.name);
});
return out;
}
var out = XLSX.utils.book_new();
sdata.forEach(function (xws) {
var ws = {};
var rowobj = xws.rows;
for (var ri = 0; ri < rowobj.len; ++ri) {
var row = rowobj[ri];
if (!row) continue;
var minCoord, maxCoord;
Object.keys(row.cells).forEach(function (k) {
var idx = +k;
if (isNaN(idx)) return;
var lastRef = XLSX.utils.encode_cell({ r: ri, c: idx });
if (minCoord == null) {
minCoord = { r: ri, c: idx };
} else {
if (ri < minCoord.r) minCoord.r = ri;
if (idx < minCoord.c) minCoord.c = idx;
}
if (maxCoord == undefined) {
maxCoord = { r: ri, c: idx };
} else {
if (ri > maxCoord.r) maxCoord.r = ri;
if (idx > maxCoord.c) maxCoord.c = idx;
}
var cellText = row.cells[k].text, type = "s";
if (!cellText) {
cellText = "";
type = "z";
} else if (!isNaN(parseFloat(cellText))) {
cellText = parseFloat(cellText);
type = "n";
} else if (cellText.toLowerCase() === "true" || cellText.toLowerCase() === "false") {
cellText = Boolean(cellText);
type = "b";
}
ws[lastRef] = { v: cellText, t: type };
if (type == "s" && cellText[0] == "=") {
ws[lastRef].f = cellText.slice(1);
}
if (row.cells[k].merge != null) {
if (ws["!merges"] == null) ws["!merges"] = [];
ws["!merges"].push({
s: { r: ri, c: idx },
e: {
r: ri + row.cells[k].merge[0],
c: idx + row.cells[k].merge[1]
}
});
}
});
ws["!ref"] = XLSX.utils.encode_range({
s: { r: minCoord.r, c: minCoord.c },
e: { r: maxCoord.r, c: maxCoord.c }
});
}
XLSX.utils.book_append_sheet(out, ws, xws.name);
});
return out;
}