#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 : Tree”에 대한 2개의 댓글

  1. 안녕하세요. GWC UI Library라는건 혹시 본인이 만드신건가요? 구현이 깔끔해서 저도 한번 써보고싶은데, 깃헙 등에 소스가 공개되어있는지 궁금합니다!

    1. 안녕하세요. 직접 개발한 것입니다. 저희 서비스 개발을 위한 UI로 사용될 목적으로 개발 중입니다. 공개는 저희 서비스 개발에 적용하고 안정성과 사용성이 충분히 확인된 후에 할 예정입니다. 관심 감사합니다~!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다