! 제품 버전을 정확하게 입력해 주세요.
제품 버전이 정확하게 기재되어 있지 않은 경우,
최신 버전을 기준으로 안내 드리므로
더욱 빠르고 명확한 안내를 위해
제품 버전을 정확하게 입력해 주세요!

[FlexSheet] 서로 다른 멀티헤더 형식을 가진 다중 시트를 엑셀로 저장 > 블로그 & Tips

본문 바로가기

[FlexSheet] 서로 다른 멀티헤더 형식을 가진 다중 시트를 엑셀로 저장

페이지 정보

작성자 GrapeCity 작성일 2020-12-30 15:59 조회 4,800회 댓글 0건

본문

Wijmo(위즈모)의 FlexSheet(플렉스시트)는 Excel(엑셀)과 같은 느낌으로, 데이터를 유연하게 컨트롤 하고자 할 때 사용하면 좋은 컨트롤 입니다.

해당 포스팅에서는 FlexSheet(플렉스시트)를 이용하여, 서로 다른 컬럼 헤더(병합된 멀티헤더)와 고정된 행을 가지고 있는 시트를 생성하고, 이를 최종 사용자가 버튼 클릭을 통해 Excel 파일로 내려받을 수 있도록 구현해보고자 합니다.


아래는 최종 결과물로 실제 소스코드와 함께 실행해보실 수 있습니다.



이번 주제는 많은 고객분이 개발하시면 문의하셨던 내용을 바탕으로 만들여 졌으며, 이를 통해 위즈모의 컨트롤의 유연함과 강력함을 여러분이 개발하시는 데 적용하실 수 있기를 기대해봅니다.


HTML DOM 코드 작성

아래와 같이 "Excel 저장" 버튼과 FlexSheet를 위한 div 요소를 선언하여 줍니다.

<button 
  class="button is-primary" 
  id="exportExcel">Excel 저장
</button>    
​
<div id="sheet"></div>  


FlexSheet 객체 생성 및 컬럼 헤더 병합 속성 설정

wijmo.grid.sheet.FlexSheet 인스턴스를 생성하여 "sheet"라는 id를 가진 HTML 요소에 추가해줍니다. allowingMerging 속성에 Column 헤더를 추가하여 열의 헤더가 병합될 수 있도록 합니다.

var flex = new wijmo.grid.sheet.FlexSheet("#sheet", {
   allowMerging: wijmo.grid.AllowMerging.ColumnHeaders,
});


데이터 바인딩

FlexSheet에 addBoundSheet 메서드를 통해 FlexSheet에서 시트를 바운드해줍니다. 예제에서는 "Data","Data2","Data3"라는 이름을 가진 3가지 시트에 데이터의 소스로 랜덤 데이터인 getData()를 연결하여 만듭니다. (실제 개발시에는 getDate대신 다양한 사용자 정의함수를 만드셔서, 서로 다른 데이터를 바인딩하실 수 있습니다.)

flex.addBoundSheet("Data", getData(20)); // 데이터 이름과 source 바운드
flex.addBoundSheet("Data2", getData(20));
flex.addBoundSheet("Data3", getData(20));
​
//랜덤 데이터 생성
function getData(count) {
 var countries = "US,Germany,UK,Japan,Italy,Greece".split(","),
   data = [];
 for (var i = 0; i < count; i++) {
   data.push({
     id: i,
     country: countries[i % countries.length],
     date: new Date(2014, i % 12, i % 28),
     amount: Math.random() * 10000,
     active: i % 4 == 0,
  });
}
 return new wijmo.collections.CollectionView(data);
}



사용자 정의 컬럼 헤더를 위한 함수 선언


위의 addBoundSheet를 통해 순차적으로 시트를 추가하면, 화면에는 마지막으로 추가한 세번째 시트가 선택되고 포커싱된 상태가 됩니다.

즉, 현재 포커스가 되어 있는 시트는 가장 마지막에 만들어진 "Data3"라는 이름을 가진 시트입니다.

위즈모는 기본적으로 강력한 퍼포먼스를 위해 Virtual로 화면을 그려주기 때문에, 우선적으로 사용자에게 먼저 보여지는 가장 마지막에 추가된 시트를 기준으로 "병합된 멀티헤더"를 그려주고자 합니다.

이를 위해, 아래과 같이 미리 정의한 updateColumnHeaders 함수를 통해 원하는 모양의 멀티헤더를 구현하고자 합니다.

updateColumnHeaders(flex, flex.selectedSheet.name); // 가장 마지막에 호출된 시트의 데이터가 전달됨


updateColumnHeaders 함수 작성

우선, updateColumnHeaders 함수에서는 아래와 같은 작업을 해줄 것입니다.


  • 기존에 시트에 설정되어 있는 열과 행의 속성들을 초기화시켜줍니다. . 시트 별로 사용자가 원하는 스타일의 열 헤더와 스타일을 적용해 주기 위해서는, 먼저 기존에 디폴트로 저장된 설정들을 초기화해준 다음, 원하시는 속성들을 할당해주어야 합니다. . 이를 통해 원하지 않는 스타일이 다른 시트에 적용되는 것을 방지할 수 있습니다.

  • 시트별로 서로 다른 헤더의 모양과 스타일을 설정해 주기 위한 함수를 호출합니다. . Switch 문을 통해, 시트명에 따라 다른 헤더를 만들어줄 각각의 setColumnMerge() 함수를 호출합니다.


이때 FlexSheet에서는 beginUpdate 메서드를 사용하여 endUpdate 메서드가 호출될 때까지 변화 감지를 지연시킵니다.

endUpdate 메서드는 beginUpdate 메서드에 의해 지연되었던 알림(변화 감지)를 재개하며, 이는 최종 사용자에게 빠른 스타일 렌더링 할 수 있도록 지원합니다.

시트 초기화 단계에서는,

먼저, columnHeaders의 행에 들어 있는 데이터 배열, 즉 헤더에 들어 있는 데이터를 splice 메서드를 통해 제거/초기화합니다.

또한, 기존의 행/열 틀 고정 또한 0으로 할당하여 초기화한 뒤, columnheaders의 병합에 대한 설정도 false로 지정해줍니다.


*분기별, setCulumMerge()에 대한 함수를 다음 섹션에서 자세하게 설명하겠습니다.

function updateColumnHeaders(flex, sheetname){
 flex.beginUpdate();
 // 행과 업데이트 상황 초기화
 flex.columnHeaders.rows.splice(1, flex.columnHeaders.rows.length - 1);
 flex.frozenRows = 0;
 flex.frozenColumns = 0;
 flex.columnHeaders.columns.forEach((r) => (r.allowMerging = false));
 flex.columnHeaders.rows.forEach((r) => (r.allowMerging = false));
​
 // 열 구조 업데이트
 switch(sheetname){
   case "Data": setColumnMerge(flex); break;
   case "Data2": setColumnMerge2(flex); break;
   case "Data3": setColumnMerge3(flex); break;
   default: break;
}
​
 flex.endUpdate();
}


사용자 정의 헤더 만들기


setColumnMerge() 함수 작성

setColumnMerge 함수에서는 "Data" 라는 이름을 가진 시트에 대해서,

  • push() 메소드를 통해, 열 헤더에 새롭게 추가된 행을 추가합니다.

  • frozenRows/frozenColumns로 원하는 행과 열을 고정합니다.

  • 헤더에 열/행에 병합 속성인 allowMerging를 true 할당합니다. . 위와 같이 설정해주면, 인접한 동일 문자열에 대해서 자동으로 병합을 해줍니다.

  • setCellData를 통해 헤더 텍스트를 넣어 줍니다. . 병합하고 하는 헤더는 인접한 곳에 동일한 문자열을 넣어 주면, 자동으로 병합이 됩니다.


 

함수에 대한 상세 코드는 아래와 같습니다.

function setColumnMerge(flex){
 flex.columnHeaders.rows.push(new wijmo.grid.Row());
 flex.frozenRows = 2;
 flex.frozenColumns = 1
 flex.columnHeaders.columns.forEach((r) => (r.allowMerging = true));
 flex.columnHeaders.rows.forEach((r) => (r.allowMerging = true));
​
 
 flex.columnHeaders.setCellData(0, 0, "Col A");
 flex.columnHeaders.setCellData(0, 1, "Col B");
 flex.columnHeaders.setCellData(0, 2, "Main Col");
 flex.columnHeaders.setCellData(0, 3, "Main Col");
 flex.columnHeaders.setCellData(0, 4, "Main Col E");
 flex.columnHeaders.setCellData(1, 0, "Col A");
 flex.columnHeaders.setCellData(1, 1, "Col B");
 flex.columnHeaders.setCellData(1, 2, "Col C");
 flex.columnHeaders.setCellData(1, 3, "Col D");
 flex.columnHeaders.setCellData(1, 4, "Col E");
​
}


setColumnMerge2() 함수 작성

setColumnMerge2 함수는, "Data2"라는 이름의 시트의 헤더 세팅을 위한 함수로, 단일 헤더에 병합이 없는 일반적인 시트를 만들줍니다.

  • 해당 시트에는 단일 헤더를 사용할 것이기 때문에 , 별도의 헤더 행은 추가 하지 않습니다.

  • 원하시는 행 또는 열 고정이 있을 경우, frozenRow와 frozenColum을 통해서 수행해줍니다.

  • setCellData를 통해, 원하시는 헤더 텍스트를 입력합니다.



 

함수에 대한 상세 코드는 아래와 같습니다.

function setColumnMerge2(flex){
 flex.frozenRows = 0;
 flex.frozenColumns = 1
​
 flex.columnHeaders.setCellData(0, 0, "Col A");
 flex.columnHeaders.setCellData(0, 1, "Col B");
 flex.columnHeaders.setCellData(0, 2, "Col C");
 flex.columnHeaders.setCellData(0, 3, "Col D");
 flex.columnHeaders.setCellData(0, 4, "Col E");
}


setColumnMerge3() 함수 작성

setColumnMerge3 함수는 위의 setColumnMerge()과 비슷하지만, 다른 모양의 헤더를 생성하게 됩니다.

이에, setColumnMerge3 함수는 "Data3" 라는 이름을 가진 시트에 대해서,

  • push() 메소드를 통해, 열 헤더에 새롭게 추가된 행을 추가합니다.

  • frozenRows/frozenColumns로 원하는 행과 열을 고정합니다.

  • 헤더에 열/행에 병합 속성인 allowMerging를 true 할당합니다. . 위와 같이 설정해주면, 인접한 동일 문자열에 대해서 자동으로 병합을 해줍니다.

  • setCellData를 통해 헤더 텍스트를 넣어 줍니다. . 병합하고 하는 헤더는 인접한 곳에 동일한 문자열을 넣어 주면, 자동으로 병합이 됩니다.(다만 고정이 되어 있는 열)



 

함수에 대한 상세 코드는 아래와 같습니다.

function setColumnMerge3(flex){
 flex.columnHeaders.rows.push(new wijmo.grid.Row());   
 flex.frozenRows = 2;
 flex.frozenColumns = 0;
 flex.columnHeaders.columns.forEach((r) => (r.allowMerging = true));
 flex.columnHeaders.rows.forEach((r) => (r.allowMerging = true));
​
 
 flex.columnHeaders.setCellData(0, 0, "Super Col");
 flex.columnHeaders.setCellData(0, 1, "Super Col");
 flex.columnHeaders.setCellData(0, 2, "Main Col");
 flex.columnHeaders.setCellData(0, 3, "Main Col");
 flex.columnHeaders.setCellData(0, 4, "Main Col E");
   
 flex.columnHeaders.setCellData(1, 0, "Col A");
 flex.columnHeaders.setCellData(1, 1, "Col B");
 flex.columnHeaders.setCellData(1, 2, "Col C");
 flex.columnHeaders.setCellData(1, 3, "Col D");
 flex.columnHeaders.setCellData(1, 4, "Col E");
​
}



selectedSheetChanged 이벤트 선언

Wijmo의 FlexSheet에서 여러 시트에 사용자가 임의로 서로 다른 스타일의 헤더를 추가하고자 할 경우에는, selectedSheetChanged 이벤트를 사용해야 합니다.

(단일 시트의 경우, 시트 선언 시, 위에서 만든 함수의 내용을 바로 적용하시면 됩니다.)

selectedSheetChanged 이벤트는 현재 보고 있는 시트의 인덱스가 변경될 때마다 발생합니다.

즉, 최종 사용자가 시트의 탭을 통해 시트를 변경하여 클릭할 때, 헤더를 원하는 모양으로 그려주게 됩니다.

이는 위즈모(Wijmo)의 특성 상, 성능을 최대화 위해 보이는 뷰에 대해서만 가상으로 렌더링을 해주기 때문입니다.

그러기 때문에, 멀티 시트의 멀티 헤더에 대해서는 각각의 헤더의 정보를 FlexSheet에서 가지고 있지 않기 때문에, 필요에 따라 화면을 그려 주어야 합니다.

결과적으로, 시트가 변경될 때마다 selectedSheetChanged 이벤트를 사용하여,

현재 선택한 시트에 대한 정보를 가지고 updateColumnHeaders 함수를 호출하여 시트별 다양한 헤더를 그려주게 됩니다.


선언 방법은 아래와 같습니다:

 flex.selectedSheetChanged.addHandler((s) => {
   updateColumnHeaders(s, s.selectedSheet.name);
});


Excel 내보내기/저장 함수 만들기


엑셀로 내보내기를 하기 위해서 버튼을 클릭할 때, exportToExcel 함수가 호출됩니다.

워크북의 틀 고정 설정을 가져오거나 조절하는 frozenPane 속성을 통해 엑셀로 내보낼 때에도 열과 행의 틀 고정을 지정할 수 있습니다.

(열과 행의 틀 고정을 지정하기 이전에 현재 시트의 인덱스 설정을 해주는 selectedSheetIndex 속성을 먼저 지정해줘야 각 시트에 올바른 틀 고정이 적용됩니다.)

여기서, 중요한 것은 함수가 호출될 때, FlexSheet의 설정을 담을 빈 워크북을 만든 다음에, addHeaders 함수를 호출하여, Excel 시트에 사용자가 만든 헤더를 삽입하는 과정을 거쳐야 합니다.

자세한 내용은 다음 섹션에서 공유드리겠습니다.


상세 코드는 아래와 같습니다:

function exportToExcel(flex) {
 //빈 워크북을 만듭니다.
 var wb = flex.saveAsync("");
 var selectedSheetIndex = flex.selectedSheetIndex;
 //시트별로 설정된 속성 값을 워크북에 저장
 for(var i = 0; i < wb.sheets.length; i++){
   flex.selectedSheetIndex = i;
     
   wb.sheets[i].froznePane.rows = flex.frozenRows;
   wb.sheets[i].froznePane.columns = flex.frozenColumns;
 
   // 시트 업데이트
   
   addHeaders(wb.sheets[i],flex.columnHeaders)
}
 
(..)
}


addHeaders 함수를 통해, 엑셀 시트에 헤더 행을 추가

addHeaders에서 열의 헤더에 대한 데이터를 수동적으로 지정해주어야 합니다.

기본적으로 Wijmo FlexSheet에서 엑셀 내보기를 할 때는, 시트 내부에 있는 데이터들만 엑셀 파일로 내보내게 됩니다. 이는 아시는 것 처럼 MS Excel에서 기본적으로 열과 행의 해더에는 값을 넣을 수 없기 떄문입니다.

그렇기 때문에, 해당 샘플의 경우, 내보낼 시트에 사용자 정의 헤더를 넣을 행을 추가하고, 기존 FlexSheet의 헤더의 데이터와 병합 그리고 스타일을 적용해 주는 작업을 해줍니다.

상세 코드는 아래와 같습니다.

function addHeaders(sheet, colHeaders) {
 var totalExtraRows = colHeaders.rows.length;
 var flex = colHeaders.grid;
​
 for (var i = 0; i < totalExtraRows; i++) {
   sheet.rows.splice(0, 0, new wijmo.xlsx.WorkbookRow());
}
​
 for (var row = 0; row < colHeaders.rows.length; row++) {
   var sheetRow = sheet.rows[row]; 
   for (var col = 0; col < colHeaders.columns.length; col++) {
    
     var cell = new wijmo.xlsx.WorkbookCell(); // 워크북 셀
     var rng =
       flex.getMergedRange(colHeaders, row, col) ||
       new wijmo.grid.CellRange(row, col);
  
     cell.rowSpan = rng.rowSpan;
     cell.colSpan = rng.columnSpan;
  
     cell.value = colHeaders.getCellData(rng.row, rng.col); // FlexSheet의 셀의 데이터 값을 가져와 할당
     
     cell.style = new wijmo.xlsx.WorkbookStyle(); // 워크북 스타일
     cell.style.fill = new wijmo.xlsx.WorkbookFill(); // 워크북 셀 스타일
     cell.style.fill.color = '#eee'; //셀 채우기 색깔
     cell.style.font = new wijmo.xlsx.WorkbookFont(); //워크북 글씨 설정
     cell.style.font.color = '#444'; // 글씨체 색깔
     cell.style.font.bold = true; // 글씨체 굵게
     cell.style.hAlign = wijmo.xlsx.HAlign.Center; // 가로 중앙 정렬 
     cell.style.vAlign = wijmo.xlsx.VAlign.Center; // 세로 중앙 정렬 

     sheetRow.cells.push(cell);
  }
}
}


SaveAsync로 Excel 저장

위에서 열 헤더에 대한 설정이 끝났으면, 다음으로 flex.selectedSheetIndex에 시트 번호를 입력해줍니다.

이를 통해, 최종 사용자가 내려 받은 엑셀을 오픈했을 때, 특정 시트를 먼저 보여지게 할 수 있습니다.

그 뒤 설정된 워크북에 saveAsync 메서드를 사용하여 엑셀로 내보내기를 완료하면 됩니다.


상세 코드는 아래와 같습니다:

function exportToExcel(flex) {
(..)
 // 현재 사용자가 FlexSheet에서 보고 있는 시트의 인덱스 입력
 // ex) flex.selectedSheetIndex = 0; // 첫번째 시트가 열림 
 flex.selectedSheetIndex = selectedSheetIndex;
 wb.saveAsync("FlexSheet.xlsx");
}


위의 코드를 활용하여, 다양한 방법으로 사용자들에게 Excel 느낌의 그리드와 Excel 내보내기 기능을 제공하실 수 있습니다.



Wijmo(위즈모)FlexSheet(플렉스시트)는 파워풀한 위즈모의 FlexGrid를 기반으로, 조금 더 엑셀과 비슷한 형식과 느낌으로 만들어 달라는 사용자분의 요청으로 추가된 스프레드시트 컨트롤 입니다.

최종 사용자에게 기존의 그리드가 아닌, 엑셀과 비슷하게 데이터를 더욱 유연하게 컨트롤 할 수 있도록 제공하여 주고자 할 때 사용하면 좋은 컨트롤 입니다.

엑셀과 같이 시트를 추가하거나, 필터링, 정렬과 같은 기능을 기본 제공하며, 약 100개 정도의 엑셀 기본수식 수식도 함께 제공합니다.


추전 제품: 완전한 Excel 컨트롤이 필요하다면 ?!

SpreadJS - JavaScript Excel UI 컨트롤

만약, MS Excel과 완벽하게 호환되는 자바스크립트 Excel UI 컨트롤를 찾으신다면, SpreadJS 사용을 고려해보세요. - SpreadJS 바로가기

. 450 + 의 엑셀 수식지원 . 차트, 테이블, 슬라이서, 도형, 이미지 등 거의 모든 Excel 기능지원 . 조건부서식, 다양한 셀타입 지원

 

  • 페이스북으로 공유
  • 트위터로  공유
  • 링크 복사
  • 카카오톡으로 보내기

댓글목록

등록된 댓글이 없습니다.

메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기

태그1

인기글

더보기
  • 인기 게시물이 없습니다.
메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기
이메일 : sales-kor@mescius.com | 전화 : 1670-0583 | 경기도 과천시 과천대로 7길 33, 디테크타워 B동 1107호 메시어스(주) 대표자 : 허경명 | 사업자등록번호 : 123-84-00981 | 통신판매업신고번호 : 2013-경기안양-00331 ⓒ 2024 MESCIUS inc. All rights reserved.