통합 문서 뷰어

이 샘플은 xlsx 파일 내용을 로드하고 페이지에 표시하는 간단한 Excel 통합 문서 뷰어를 구현합니다.

샘플은 통합 문서 인스턴스를 만들고, Workbook.load 메서드를 사용하여 xlsx 파일 내용을 통합 문서 인스턴스에 로드합니다. 그런 다음, WorkSheet 클래스에서 제공하는 현재 통합 문서 시트의 콘텐츠를 검색하고 콘텐츠를 시각화하는 HTML 표를 만듭니다.

통합 문서 시트 간에 전환할 수 있도록 탭도 만듭니다. Workbook.sheets 컬렉션을 반복하는 ng-repeat 지시문이 적용된 <li> 요소의 스타일 지정과 비슷한 BootstrapJS 탭을 사용하여 탭을 구현합니다.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import * as wjcCore from '@grapecity/wijmo'; import * as wjcXlsx from '@grapecity/wijmo.xlsx'; import './styles.css'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { let workbook; // document.querySelector('#importFile').addEventListener('change', () => { loadWorkbook(); }); // document.querySelector('#sheetNav').addEventListener('click', (e) => { e.preventDefault(); // let navEle = e.target.parentElement; let activeIndex = toggleNavActiveStatus(navEle); if (activeIndex !== -1) { drawSheet(activeIndex); } }); // function loadWorkbook() { let reader = new FileReader(); // reader.onload = (e) => { let tmp = new wjcXlsx.Workbook(); tmp.loadAsync(reader.result, (result) => { workbook = result; drawSheetNav(workbook.activeWorksheet || 0); drawSheet(workbook.activeWorksheet || 0); }); }; // let file = document.getElementById('importFile').files[0]; if (file) { reader.readAsDataURL(file); } } // function drawSheet(sheetIndex) { let drawRoot = document.getElementById('tableHost'); drawRoot.textContent = ''; drawWorksheet(workbook, sheetIndex, drawRoot, 200, 100); } // function drawSheetNav(activeIndex) { let contianer = document.querySelector('#sheetNav'); contianer.innerHTML = ''; let navItem = ''; for (let i = 0; i < workbook.sheets.length; i++) { let sheet = workbook.sheets[i]; navItem += `<li role="presentation" class="${i === activeIndex ? 'active' : ''}"><a href="#">${sheet.name}</a></li>`; } contianer.innerHTML = navItem; } // function drawWorksheet(workbook, sheetIndex, rootElement, maxRows, maxColumns) { //NOTES: //Empty cells' values are numeric NaN, format is "General" // //Excessive empty properties: //fill.color = undefined // // netFormat should return '' for ''. What is 'General'? // font.color should start with '#'? // Column/row styles are applied to each cell style, this is convenient, but Column/row style info should be kept, // for column/row level styling // formats conversion is incorrect - dates and virtually everything; netFormat - return array of formats? // ?row heights - see hello.xlsx if (!workbook || !workbook.sheets || sheetIndex < 0 || workbook.sheets.length == 0) { return; } // sheetIndex = Math.min(sheetIndex, workbook.sheets.length - 1); // if (maxRows == null) { maxRows = 200; } // if (maxColumns == null) { maxColumns = 100; } // // Namespace and XlsxConverter shortcuts. let sheet = workbook.sheets[sheetIndex], defaultRowHeight = 20, defaultColumnWidth = 60, tableEl = document.createElement('table'); // tableEl.border = '1'; tableEl.style.borderCollapse = 'collapse'; // let maxRowCells = 0; for (let r = 0; sheet.rows && r < sheet.rows.length; r++) { if (sheet.rows[r] && sheet.rows[r].cells) { maxRowCells = Math.max(maxRowCells, sheet.rows[r].cells.length); } } // // add columns let columns = sheet.columns || [], invisColCnt = columns.filter(col => col.visible === false).length; // if (sheet.columns) { maxRowCells = Math.min(Math.max(maxRowCells, columns.length), maxColumns); // for (let c = 0; c < maxRowCells; c++) { let col = columns[c]; // if (col && !col.visible) { continue; } // let colEl = document.createElement('col'); tableEl.appendChild(colEl); let colWidth = defaultColumnWidth + 'px'; if (col) { importStyle(colEl.style, col.style); if (col.autoWidth) { colWidth = ''; } else if (col.width != null) { colWidth = col.width + 'px'; } } colEl.style.width = colWidth; } } // // generate rows let rowCount = Math.min(maxRows, sheet.rows.length); for (let r = 0; sheet.rows && r < rowCount; r++) { let row = sheet.rows[r], cellsCnt = 0; // including colspan // if (row && !row.visible) { continue; } // let rowEl = document.createElement('tr'); tableEl.appendChild(rowEl); // if (row) { importStyle(rowEl.style, row.style); if (row.height != null) { rowEl.style.height = row.height + 'px'; } // for (let c = 0; row.cells && c < row.cells.length; c++) { let cell = row.cells[c], cellEl = document.createElement('td'), col = columns[c]; // if (col && !col.visible) { continue; } // cellsCnt++; // rowEl.appendChild(cellEl); if (cell) { importStyle(cellEl.style, cell.style); let value = cell.value; // if (!(value == null || value !== value)) { // TBD: check for NaN should be eliminated if (wjcCore.isString(value) && value.charAt(0) == "'") { value = value.substr(1); } let netFormat = ''; if (cell.style && cell.style.format) { netFormat = wjcXlsx.Workbook.fromXlsxFormat(cell.style.format)[0]; } let fmtValue = netFormat ? wjcCore.Globalize.format(value, netFormat) : value; cellEl.innerHTML = wjcCore.escapeHtml(fmtValue); } // if (cell.colSpan && cell.colSpan > 1) { cellEl.colSpan = getVisColSpan(columns, c, cell.colSpan); cellsCnt += cellEl.colSpan - 1; c += cell.colSpan - 1; } // if (cell.note) { wjcCore.addClass(cellEl, 'cell-note'); cellEl.title = cell.note.text; } } } } // // pad with empty cells let padCellsCount = maxRowCells - cellsCnt - invisColCnt; for (let i = 0; i < padCellsCount; i++) { rowEl.appendChild(document.createElement('td')); } // if (!rowEl.style.height) { rowEl.style.height = defaultRowHeight + 'px'; } } // // do it at the end for performance rootElement.appendChild(tableEl); } // function getVisColSpan(columns, startFrom, colSpan) { let res = colSpan; // for (let i = startFrom; i < columns.length && i < startFrom + colSpan; i++) { let col = columns[i]; if (col && !col.visible) { res--; } } // return res; } // function importStyle(cssStyle, xlsxStyle) { if (!xlsxStyle) { return; } // if (xlsxStyle.fill) { if (xlsxStyle.fill.color) { cssStyle.backgroundColor = xlsxStyle.fill.color; } } // if (xlsxStyle.hAlign && xlsxStyle.hAlign != wjcXlsx.HAlign.Fill) { cssStyle.textAlign = wjcXlsx.HAlign[xlsxStyle.hAlign].toLowerCase(); } // let font = xlsxStyle.font; if (font) { if (font.family) { cssStyle.fontFamily = font.family; } if (font.bold) { cssStyle.fontWeight = 'bold'; } if (font.italic) { cssStyle.fontStyle = 'italic'; } if (font.size != null) { cssStyle.fontSize = font.size + 'px'; } if (font.underline) { cssStyle.textDecoration = 'underline'; } if (font.color) { cssStyle.color = font.color; } } } // function toggleNavActiveStatus(navEle) { let activeIndex = -1; let navEles = document.querySelectorAll('#sheetNav li'); for (let i = 0; i < navEles.length; i++) { let currentItem = navEles[i]; wjcCore.removeClass(currentItem, 'active'); if (currentItem === navEle) { wjcCore.addClass(currentItem, 'active'); activeIndex = i; } } return activeIndex; } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MESCIUS Wijmo Workbook Viewer</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <div class="row"> <input type="file" class="form-control" id="importFile" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel.sheet.macroEnabled.12" style="width:300px" /> </div> <!-- Sheet tabs --> <ul id="sheetNav" class="nav nav-tabs" style="margin-top:40px"> </ul> <!-- Current sheet view --> <div id="tableHost"></div> </div> </body> </html>
.cell-note { position: relative; } .cell-note:after { content: ""; position: absolute; display: block; top: 0; right: 0; border-left: 7px solid transparent; border-top: 7px solid red; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@grapecity/wijmo': 'npm:@grapecity/wijmo/index.js', '@grapecity/wijmo.input': 'npm:@grapecity/wijmo.input/index.js', '@grapecity/wijmo.styles': 'npm:@grapecity/wijmo.styles', '@grapecity/wijmo.cultures': 'npm:@grapecity/wijmo.cultures', '@grapecity/wijmo.chart': 'npm:@grapecity/wijmo.chart/index.js', '@grapecity/wijmo.chart.analytics': 'npm:@grapecity/wijmo.chart.analytics/index.js', '@grapecity/wijmo.chart.animation': 'npm:@grapecity/wijmo.chart.animation/index.js', '@grapecity/wijmo.chart.annotation': 'npm:@grapecity/wijmo.chart.annotation/index.js', '@grapecity/wijmo.chart.finance': 'npm:@grapecity/wijmo.chart.finance/index.js', '@grapecity/wijmo.chart.finance.analytics': 'npm:@grapecity/wijmo.chart.finance.analytics/index.js', '@grapecity/wijmo.chart.hierarchical': 'npm:@grapecity/wijmo.chart.hierarchical/index.js', '@grapecity/wijmo.chart.interaction': 'npm:@grapecity/wijmo.chart.interaction/index.js', '@grapecity/wijmo.chart.radar': 'npm:@grapecity/wijmo.chart.radar/index.js', '@grapecity/wijmo.chart.render': 'npm:@grapecity/wijmo.chart.render/index.js', '@grapecity/wijmo.chart.webgl': 'npm:@grapecity/wijmo.chart.webgl/index.js', '@grapecity/wijmo.chart.map': 'npm:@grapecity/wijmo.chart.map/index.js', '@grapecity/wijmo.gauge': 'npm:@grapecity/wijmo.gauge/index.js', '@grapecity/wijmo.grid': 'npm:@grapecity/wijmo.grid/index.js', '@grapecity/wijmo.grid.detail': 'npm:@grapecity/wijmo.grid.detail/index.js', '@grapecity/wijmo.grid.filter': 'npm:@grapecity/wijmo.grid.filter/index.js', '@grapecity/wijmo.grid.search': 'npm:@grapecity/wijmo.grid.search/index.js', '@grapecity/wijmo.grid.grouppanel': 'npm:@grapecity/wijmo.grid.grouppanel/index.js', '@grapecity/wijmo.grid.multirow': 'npm:@grapecity/wijmo.grid.multirow/index.js', '@grapecity/wijmo.grid.transposed': 'npm:@grapecity/wijmo.grid.transposed/index.js', '@grapecity/wijmo.grid.transposedmultirow': 'npm:@grapecity/wijmo.grid.transposedmultirow/index.js', '@grapecity/wijmo.grid.pdf': 'npm:@grapecity/wijmo.grid.pdf/index.js', '@grapecity/wijmo.grid.sheet': 'npm:@grapecity/wijmo.grid.sheet/index.js', '@grapecity/wijmo.grid.xlsx': 'npm:@grapecity/wijmo.grid.xlsx/index.js', '@grapecity/wijmo.grid.selector': 'npm:@grapecity/wijmo.grid.selector/index.js', '@grapecity/wijmo.grid.cellmaker': 'npm:@grapecity/wijmo.grid.cellmaker/index.js', '@grapecity/wijmo.nav': 'npm:@grapecity/wijmo.nav/index.js', '@grapecity/wijmo.odata': 'npm:@grapecity/wijmo.odata/index.js', '@grapecity/wijmo.olap': 'npm:@grapecity/wijmo.olap/index.js', '@grapecity/wijmo.rest': 'npm:@grapecity/wijmo.rest/index.js', '@grapecity/wijmo.pdf': 'npm:@grapecity/wijmo.pdf/index.js', '@grapecity/wijmo.pdf.security': 'npm:@grapecity/wijmo.pdf.security/index.js', '@grapecity/wijmo.viewer': 'npm:@grapecity/wijmo.viewer/index.js', '@grapecity/wijmo.xlsx': 'npm:@grapecity/wijmo.xlsx/index.js', '@grapecity/wijmo.undo': 'npm:@grapecity/wijmo.undo/index.js', '@grapecity/wijmo.interop.grid': 'npm:@grapecity/wijmo.interop.grid/index.js', '@grapecity/wijmo.touch': 'npm:@grapecity/wijmo.touch/index.js', '@grapecity/wijmo.cloud': 'npm:@grapecity/wijmo.cloud/index.js', '@grapecity/wijmo.barcode': 'npm:@grapecity/wijmo.barcode/index.js', '@grapecity/wijmo.barcode.common': 'npm:@grapecity/wijmo.barcode.common/index.js', '@grapecity/wijmo.barcode.composite': 'npm:@grapecity/wijmo.barcode.composite/index.js', '@grapecity/wijmo.barcode.specialized': 'npm:@grapecity/wijmo.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);