#GWC UI Library : Tree
웹 UI 라이브러리인 GWC에서 제공하는 Tree 컴포넌트에 대한 예제 코드입니다.
먼저 DOM 구성은 다음과 같습니다.
그리고 CSS 구성은 다음과 같구요.
.center {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 1em;
}
gwc-vscrollview {
width: 22em;
height: 30em;
background: rgba(0,0,0,0.3);
border: 1px solid black;
}
gwc-tree {
width: 100%;
padding: 0.5em 0.5em;
}
.h-center {
display: fex;
justify-content: center;
align-items: center;
}
js 코드는 다음과 같습니다.
window.onload = () => {
// 최상위 폴더(root)
const rootFolder = tree.rootFolder;
// 폴더 추가
const gaFolder = rootFolder.addFolder("아카이브");
const docFolder = rootFolder.addFolder("문서").open();
rootFolder.addFolder("프로그램");
const programFolder = rootFolder.getFolder("프로그램");
const humanGeoFolder = gaFolder.addFolder("인문공간데이터");
const adminGeoFolder = gaFolder.addFolder("행정경계");
// 폴더에 파일 추가
humanGeoFolder.addFile("인구통계.zip", "url(../examples/images/icon7.png)");
humanGeoFolder.addFile("유동인구.zip", "url(../examples/images/icon7.png)");
humanGeoFolder.addFile("유아통계.zip", "url(../examples/images/icon7.png)");
const koreaFolder = adminGeoFolder.addFolder("대한민국");
koreaFolder.addFile("시도.zip", "url(../examples/images/icon3.png)");
koreaFolder.addFile("시군구.zip", "url(../examples/images/icon3.png)");
koreaFolder.addFile("읍면동.zip", "url(../examples/images/icon3.png)");
adminGeoFolder.addFile("서울특별시.zip", "url(../examples/images/icon3.png)");
adminGeoFolder.addFile("경기도.zip", "url(../examples/images/icon3.png)");
docFolder.addFile("레포트1.pdf", "url(../examples/images/icon6.png)");
docFolder.addFile("레포트2.pdf", "url(../examples/images/icon6.png)");
docFolder.addFile("레포트3.pdf", "url(../examples/images/icon6.png)");
programFolder.addFile("VisualSudio.Code.zip", "url(../examples/images/icon5.png)")
programFolder.addFile("PhotoShop.zip", "url(../examples/images/icon5.png)")
programFolder.addFile("리터널_PS5.zip", "url(../examples/images/icon5.png)")
// 폴더 열고 닫기
btnProgramOpenClose.addEventListener("click", () => {
const folder = tree.rootFolder.getFolder("아카이브");
if(folder.isOpen()) folder.close();
else folder.open();
});
// 특정 폴더에 파일 추가
btnAddFile.addEventListener("click", () => {
const folder = tree.rootFolder.getFolder("문서");
const file = folder.getFile("NEW 레포트.pdf");
if(file) {
file.remove();
} else {
const file = folder.addFile("NEW 레포트.pdf", "url(../examples/images/icon6.png)");
// 파일 또는 폴더에 사용자 정의 데이터 추가
file.setData("생성일자", "2022년 2월 10일");
console.log(file.getData("생성일자"));
}
});
// 파일(폴더+파일)에 대한 클릭 이벤트
tree.addEventListener("fileClick", (event) => {
const file = event.detail.file;
const parentFolderName = file.parentFolder.name;
const bFolder = file.isFolder();
const bOpen = file.isOpen();
label.content = `
이름: ${file.name}
부모폴더: ${parentFolderName?parentFolderName:"없음"}
종류: ${bFolder?"폴더":"파일"}
${bFolder?`상태: ${bOpen?"열림":"닫힘"}`:""}
`;
vscrollview.refresh(); // 폴더 열기로 인한 트리 컴포넌트 크기 변경에 따른 스크롤뷰 업데이트
});
// 트리 컴포넌트의 크기가 가변이므로 스크롤뷰를 업데이트 해줌
vscrollview.refresh();
GeoServiceWebComponentManager.instance.update();
};
실행 결과는 다음과 같습니다.
트리의 항목에 대한 팝업 메뉴 기능을 적용할 때에 대한 코드입니다.
// PopupMenu 생성 시작
const popupMenu = gwcCreatePopupMenu();
popupMenu.addMenuItem("menu1", {
text: "생성",
_icon: "images/icon1.png",
onClick: (menuId) => {
gwcMessage(`폴더 생성(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu2", {
text: "이름 변경",
_icon: "images/icon2.png",
onClick: (menuId) => {
gwcMessage(`${popupMenu.fileData.name} 이름 변경(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu3", {
text: "삭제",
_icon: "images/icon3.png",
onClick: (menuId) => {
gwcMessage(`${popupMenu.fileData.name} 삭제(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu4", {
text: "잘라내기",
_icon: "images/icon4.png",
onClick: (menuId) => {
gwcMessage(`${popupMenu.fileData.name} 잘라내기(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu5", {
text: "붙여넣기",
_icon: "images/icon5.png",
onClick: (menuId) => {
gwcMessage(`${popupMenu.fileData.name}에 붙여넣기(${menuId})`);
popupMenu.hide();
}
});
// PopupMenu 생성 완료
// 파일(폴더+파일)에 대한 클릭 이벤트
tree.addEventListener("fileClick", (event) => {
const file = event.detail.file;
const contextMenu = event.detail.contextMenu;
if(contextMenu) {
console.log(event.detail.originalEvent);
popupMenu.fileData = file; // fileData는 임의로 부여한 속성으로 팝업 메뉴 실행 시에 참조됨
popupMenu.show(event.detail.originalEvent.clientX, event.detail.originalEvent.clientY);
}
});
위의 코드에 대한 실행 결과는 다음과 같습니다.
트리를 구성하는 항목에 대해서 선택된 항목이라는 피드백을 줄 수 있습니다. 다음 코드를 참고하기 바랍니다.
tree.clearSelection(); // 일단 기존의 선택된 항목에 대해 선택 해제
tree.rootFolder.getFolder("아카이브").selected = true; // 폴더를 얻고 해당 폴더를 선택된 상태로 표시
폴더 또는 파일 항목의 우측에 Tag 정보를 표시할 수 있습니다. 즉, getFolder 또는 getFile을 통해 얻은 item 객체의 tag 속성(get, set)을 설정하면 됩니다. 아래는 파일항목의 우측에 파일의 크기를 표시하는 예시입니다.

tree 컴포넌트는 동일한 계층에 동일한 이름을 가진 항목을 추가할 수 없습니다. 이때 label 속성을 이용해 이름은 다르지만 표시되는 제목만을 변경해 줄 수 있습니다. 코드 예시는 다음과 같습니다.
data.forEach(item => {
const rootFolder = this.#tree.rootFolder;
rootFolder.addFile(item.id, "url(../images/layers.svg)").label = item.title;
});
#GWC UI Library : Memo
웹 UI 라이브러리인 GWC에서 제공하는 Memo 컴포넌트에 대한 예제 코드입니다.
먼저 DOM 구성은 다음과 같습니다. gwc-resizable-panel 태그로 감싸서 크기 조정이 가능하도록 했습니다. 이는 옵션입니다.
그리고 CSS 구성은 다음과 같구요.
.center {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 0.5em;
}
.vcenter {
display: flex;
align-items: center;
gap: 0.3em;
}
.hcenter {
flex-direction: column;
display: flex;
_align-items: center;
}
gwc-memo {
width: 100%;
height: 100%;
}
js 코드는 다음과 같습니다.
window.onload = () => {
button1.onclick = () => {
memo.value = "메모에 대한 내용은 코드로 변경할 수 있어요.\n줄 바꿈도 가능하답니다.";
}
button2.onclick = () => {
gwcMessage(memo.value);
}
button3.onclick = () => {
console.log(memo.disabled);
memo.disabled = !memo.disabled;
}
button4.onclick = () => {
console.log(memo.readonly);
memo.readonly = !memo.readonly;
}
memo.addEventListener("change", (event) => {
labelEvent.content = `${memo.value.length}자가 입력됨 (입력가능 문자수 ${memo.maxLength})`;
})
GeoServiceWebComponentManager.instance.update();
};
실행 결과는 다음과 같습니다.
gwc-memo 태그 선언을 통해 value 속성에 문자열을 지정할 때 문자열에 쌍따옴표가 있을 경우 변환이 필요합니다.
<gwc-memo value="${params.content.replaceAll("\"", """)}"></gwc-memo>
#GWC UI Library : PopupMenu
웹 UI 라이브러리인 GWC에서 제공하는 PopupMenu 컴포넌트에 대한 예제 코드입니다.
큰 의미는 없으나 DOM 구성은 다음과 같습니다.
그리고 CSS 구성은 다음과 같구요.
.center {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
gap: 1em;
}
js 코드는 다음과 같습니다.
window.onload = () => {
const popupMenu = gwcCreatePopupMenu();
popupMenu.addMenuItem("menu1", {
text: "녹음 시작",
icon: "images/icon1.png",
onClick: (menuId) => {
gwcMessage(`녹음 시작 클릭(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu2", {
text: "WiFi 활성화",
icon: "images/icon2.png",
checked: false,
onClick: (menuId) => {
const bChecked = popupMenu.getMenuChecked(menuId);
popupMenu.setMenuChecked(menuId, !bChecked);
}
});
popupMenu.addMenuItem("menu3", {
text: "꿈꾸기",
icon: "images/icon3.png",
onClick: (menuId) => {
gwcMessage(`상세화하기(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu4", {
text: "구체화하기",
icon: "images/icon4.png",
onClick: (menuId) => {
gwcMessage(`구체화하기(${menuId})`);
popupMenu.hide();
}
});
popupMenu.addMenuItem("menu5", {
text: "실현하기",
icon: "images/icon5.png",
onClick: (menuId) => {
gwcMessage(`실현하기(${menuId})`);
popupMenu.hide();
}
});
const popupMenuZone = document.querySelector(".center");
popupMenuZone.addEventListener("click", (event) => {
if(popupMenu.isShown()) {
popupMenu.hide();
return;
}
if(event.target === popupMenuZone) {
// 팝업창의 표시를 위해
// event.currentTarget.getBoundingClientRect()의 결과값에 대한 left, top을 사용하는 것이 좋음
popupMenu.show(event.offsetX, event.offsetY);
}
});
};
실행 결과는 다음과 같습니다.
PopupMenu를 표시하기 전에 어떤 메뉴 항목을 감추거나 다시 표시해야 할 필요가 있습니다. 이에 대한 이벤트는 showing인데요. 예제 코드는 다음과 같습니다.
popupMenu.addEventListener("showing", (event) => {
popupMenu.setMenuVisible("menu1", true);
popupMenu.setMenuVisible("menu2", false);
// event.cancel = true; -> 이 코드가 작동하면 팝업 메뉴가 표시되지 않음
});
gwcCreatePopupMenu를 응용해서 일반적인 메뉴를 구성할 수 있는데, 이때 서브 메뉴에 대한 구성도 가능합니다. 아래는 코드 예시과 그 결과 이미지입니다.
const menu = gwcCreatePopupMenu();
const shpCsvMenu = gwcCreatePopupMenu();
shpCsvMenu.addMenuItem("menu-shp2csv", {
text: "SHP 데이터를 CSV로 변환",
icon: "images/change.svg",
onClick: (menuId) => {}
});
shpCsvMenu.addMenuItem("menu-xycsv2shp", {
text: "경위도 좌표 데이터(CSV)를 SHP으로 변환",
icon: "images/change.svg",
onClick: (menuId) => {}
});
menu.addSubMenu("menu-shpcsv", shpCsvMenu, { text: "SHP/CSV 변환" })

gwcCreateModalDialog의 resizing 코드 예 (gwc-card에도 적용됨)
하나의 모달 대화상자를 gwcCreateModalDialog 함수를 이용해 만들때 class 단위로 만들면 전체적인 시스템의 UI 기능이 효과적으로 분리됩니다. 먼저 모달 대화상자에 대한 코드를 class로 만듭니다.
class ArchiveManagerDialog {
constructor() {
const dlg = gwcCreateModalDialog("아카이브 관리자");
dlg.content = `
`;
dlg.width = "50em";
dlg.resizablePanel.resizableLeft = true;
dlg.resizablePanel.resizableRight = true;
dlg.resizablePanel.resizableTop = true;
dlg.resizablePanel.resizableBottom = true;
dlg.resizablePanel.minWidth = 450;
dlg.resizablePanel.minHeight = 300;
dlg.resizablePanel.addEventListener("change", (event) => {
if(event.target === dlg.resizablePanel) {
const { mode, oldHeight, newHeight } = event.detail;
if(mode === "BOTTOM" || mode == "TOP") {
const domScrollView = dlg.content.querySelector("gwc-vscrollview");
const height = parseFloat(window.getComputedStyle(domScrollView).getPropertyValue("height"));
domScrollView.style.height = `${height - (oldHeight - newHeight)}px`;
domScrollView.refresh();
}
}
});
dlg.show();
GeoServiceWebComponentManager.instance.update();
}
}
CSS에 대한 코드는 다음과 같습니다.
.vertical-linear-layout {
display: flex;
flex-direction: column;
gap: 0.3em;
}
.horizontal-linear-layout {
display: flex;
gap: 0.3em;
flex-direction: row;
_padding: 0 1em;
}
.v-center {
align-items: center;
}
.h-center {
justify-content: center;
}
.v-space {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.archive-manager-dialog {
padding: 0.5em 0.5em 0.5em 0.5em;
}
.archive-manager-dialog gwc-textinput {
width: 10em;
}
.archive-manager-dialog .search-part {
margin-left: auto;
}
.archive-manager-dialog gwc-vscrollview {
height: 30em; /* js 코드로 크기를 조정해야 함 */
margin: 0 0.2em;
background: rgba(0,0,0,0.3);
box-shadow: inset -0.6px -0.6px 0.6px rgba(255,255,255,0.4),
inset 0.6px 0.6px 0.6px rgba(0,0,0,0.5);
border-radius: 0.5em;
}
.archive-manager-dialog gwc-tree {
width: 100%;
padding: 0.5em 0.5em 0.5em 0.5em;
_border: 1px solid red;
}
실행 결과는 다음과 같습니다.
