본문으로 건너뛰기

OrganizationView

이 컨트롤은 무엇인가요?

OrganizationView는 부모-자식 관계를 가진 계층형 데이터를 박스와 연결선으로 이루어진 "조직도(org chart)" 형태로 그려주는 컨트롤입니다. 내부적으로는 dabeng/OrgChart jQuery 플러그인을 감싸서 syn.uicontrols.$organization 싱글턴 객체로 제공합니다.

TreeView도 같은 "계층형 데이터"를 다루지만 둘의 쓰임새는 다릅니다.

TreeViewOrganizationView
표현 방식들여쓰기된 목록(리스트)을 펼치고 접는 형태상자(노드)를 선으로 연결한 다이어그램 형태
어울리는 데이터메뉴/프로그램 목록, 폴더 구조처럼 항목 수가 많은 데이터부서/직위처럼 "구조 자체"를 한눈에 보여줘야 하는 데이터
드래그로 계층 변경지원 안 함draggable: true로 노드를 드래그해 조직 구조를 바로 바꿀 수 있음
확대/축소, 화면 이동없음zoom/pan 옵션으로 지원

즉, "이 항목이 몇 단계 아래에 있는지"보다 "누가 누구 밑에 있는지 그림으로" 보여줘야 할 때 OrganizationView를 사용합니다.

언제 사용하나요?

  • 회사/부서 조직도, 결재라인, 보고 체계처럼 상하 관계를 시각적으로 보여줘야 할 때
  • 사용자가 노드를 드래그해서 소속(상위 조직)을 직접 바꿀 수 있게 하고 싶을 때 (draggable: true + nodedrop 이벤트)
  • 노드 개수가 많아 화면에 다 들어가지 않을 때 (zoom/pan 옵션으로 확대·축소·이동)
  • 노드를 우클릭해서 "하위 조직 생성", "구성원 보기" 같은 메뉴를 띄워야 할 때 — OrganizationView 자체에는 우클릭 메뉴 기능이 없으므로, ContextMenu 컨트롤과 함께 사용합니다. target에 조직도 컨테이너 셀렉터(#조직도ID)를, delegate에 노드 셀렉터(div.node)를 지정하는 방식입니다.

빠른 시작

<syn_organization id="orgChartView" syn-options="{
height: '360px',
draggable: true,
nodeTitle: 'name',
nodeContent: 'title',
reduceMap: { key: 'ProgramID', title: 'ProgramName', parentID: 'ParentID' }
}" syn-events="['nodedrop', 'select', 'click']"></syn_organization>
'use strict';
let $samplePage = {
event: {
orgChartView_select(evt, node) {
// node는 클릭된 노드의 jQuery 객체입니다.
syn.$l.eventLog('orgChartView_select', node.find('.title').text());
}
}
}

값을 채워 넣을 때는 setValue에 평평한(flat) 배열을 그대로 넘기면 됩니다. 각 항목은 reduceMap에 지정한 컬럼명(ProgramID, ProgramName, ParentID)을 가지고 있어야 합니다.

syn.uicontrols.$organization.setValue('orgChartView', [
{ ProgramID: 'ROOT', ProgramName: '전체 조직', ParentID: null },
{ ProgramID: 'A01', ProgramName: '인사팀', ParentID: 'ROOT' },
{ ProgramID: 'A0101', ProgramName: '홍길동', ParentID: 'A01' }
]);

핵심 포인트:

  • 마크업은 <syn_organization> 커스텀 태그로 작성하고, syn-optionsreduceMap/nodeTitle/nodeContent/draggable 등을 JSON으로 넣습니다.
  • 페이지에 <script src="/js/syn.loader.js"></script> 한 줄만 있으면 OrgChart 플러그인을 포함한 나머지 CSS/JS는 자동으로 로드됩니다. 별도의 pageLoadFiles 설정이 필요 없습니다.
  • getValue/setValue는 TreeView와 마찬가지로 항상 "평평한 배열"을 주고받습니다. 조직도 안에서만 계층(중첩) 구조로 다뤄지고, 컨트롤 밖으로 나올 때는 평평한 형태로 변환됩니다.
  • 최상위(루트) 노드에는 기본적으로 top-level 클래스가 붙어 초록색으로, 그 외 노드는 파란색(middle-level)으로 표시됩니다(OrganizationView.css 참고). 원본 데이터에 className 컬럼을 넣어 노드별로 색을 다르게 줄 수도 있습니다.

예제 실행하기

example/ 폴더의 각 HTML 파일을 handstack의 wwwroot 정적 서버(예: rdy 프로젝트) 경로 아래에 두고 브라우저로 열면 바로 동작을 확인할 수 있습니다.

  • basic.html : 기본 조직도 표시 + getValue/setValue/clear/getControl 기능 확인
  • contextmenu.html : ContextMenu와 결합해서 노드 우클릭 메뉴(하위조직 생성 등)를 띄우는 예제
  • events.html : nodedrop(드래그로 조직 이동)/select/click 이벤트와 getRelatedNodes를 함께 확인하는 예제

각 예제는 화면 하단 로그 영역(syn.$l.eventLog 출력)에서 이벤트 발생 순서와 전달값을 확인할 수 있습니다.

더 알아보기

  • API 상세는 같은 폴더의 API.md를 참고하세요.
  • 실제 소스: wwwroot/uicontrols/OrganizationView/OrganizationView.js, OrganizationView.css
  • 기존 샘플: wwwroot/sample/uicontrol/organization.html, organization.js
  • 실사용 예: qcn.groupware의 조직도 화면 — nodeTemplate/createNode로 노드 안에 아이콘을 추가하고, 그 아이콘 클릭 시 syn.uicontrols.$contextmenu.open(...)으로 메뉴를 여는 패턴, nodedrop 이벤트에서 getRelatedNodes(elID, dropZone, 'children')로 드롭된 노드의 하위 조직을 다시 조회하는 흐름을 참고할 수 있습니다.
  • ContextMenu와 함께 쓰는 방법: ../ContextMenu/README.md, ../ContextMenu/API.md
  • OrgChart 원본 문서: https://github.com/dabeng/OrgChart

실전 예제 페이지

/uicontrols/OrganizationView/example/ 경로의 예제를 아래 iframe에서 바로 확인할 수 있습니다.

basic.html

contextmenu.html

events.html

소스와 로드 파일

항목내용
컨트롤OrganizationView
전역 별칭syn.uicontrols.$organization
버전v2025.10.1
소스uicontrols/OrganizationView/OrganizationView.js
스타일uicontrols/OrganizationView/OrganizationView.css

API 참조

싱글턴 객체: syn.uicontrols.$organization 소스 파일: wwwroot/uicontrols/OrganizationView/OrganizationView.js, wwwroot/uicontrols/OrganizationView/OrganizationView.css 내부 라이브러리: dabeng/OrgChart (jQuery 플러그인)

마크업

<syn_organization id="orgChartView" syn-options="{
height: '360px',
draggable: true,
nodeTitle: 'name',
nodeContent: 'title',
pan: true,
zoom: true,
verticalLevel: 5,
itemID: 'key',
parentItemID: 'parentID',
childrenID: 'children',
reduceMap: { key: 'ProgramID', title: 'ProgramName', parentID: 'ParentID' },
nodeTemplate: '$this.event.orgChartView_nodeTemplate',
createNode: '$this.event.orgChartView_createNode'
}" syn-events="['nodedrop', 'select', 'click']"></syn_organization>
  • id는 페이지 내에서 유일해야 하며, syn.uicontrols.$organization의 각종 메서드에서 이 id(elID)를 사용합니다.
  • controlLoad 실행 시 원래 태그는 {elID}_hidden으로 이름이 바뀌며 display:none 처리되고, 같은 위치에 실제 OrgChart가 그려질 <div id="{elID}">를 감싼 래퍼(div.organization-container 또는 className 옵션으로 지정한 클래스)가 새로 추가됩니다.
  • width/height는 마크업 요소의 인라인 style.width/style.height가 지정되어 있으면 그 값이 syn-options보다 우선합니다.
  • nodeTemplate/createNode는 마크업에서 '$this.event.함수명' 형태의 문자열로 지정하면 controlLoad 시점에 eval되어 실제 함수로 바뀝니다. 페이지 스크립트의 event 객체에 해당 이름의 함수를 정의해 두어야 합니다.

Options (defaultSetting)

속성타입기본값설명
widthstring'100%'조직도 컨테이너 너비
heightstring'300px'조직도 컨테이너 높이(넘치면 스크롤)
itemIDstring'id'평평한(flat) 데이터에서 각 행의 고유 키 컬럼명. getValue/setValue가 조직도 ↔ flat 배열 변환 시 사용합니다.
parentItemIDstring'parentID'flat 데이터에서 부모 키 컬럼명
childrenIDstring'children'중첩(nested) 구조로 변환할 때 자식 배열을 담을 속성명
reduceMapobject객체 설정조직도 내부 필드(key/title/parentID)와 실제 데이터 컬럼명을 매핑
nodeTitlestring'name'노드 상단(제목 영역)에 표시할 원본 데이터 컬럼명
nodeContentstring'title'노드 하단(내용 영역)에 표시할 원본 데이터 컬럼명
directionstring't2b'조직도가 뻗어나가는 방향. 't2b'(위→아래), 'b2t', 'l2r', 'r2l'
panbooleanfalse마우스 드래그로 조직도 전체를 이동(팬)할 수 있는지 여부
zoombooleanfalse마우스 휠로 확대/축소할 수 있는지 여부
zoominLimitnumber2zoom이 켜졌을 때 최대 확대 배율
zoomoutLimitnumber0.8zoom이 켜졌을 때 최대 축소 배율
draggablebooleanfalse노드를 드래그해서 다른 노드 밑으로 옮길 수 있는지 여부. true로 하면 nodedrop 이벤트가 의미를 가집니다.
classNamestring'top-level'조직도 최상위 래퍼(div)에 붙는 CSS 클래스. 지정하지 않으면 'organization-container'가 사용됩니다.
verticalLevelnumber4이 값 이하의 깊이까지는 세로(수직) 레이아웃 대신 OrgChart의 계층 접기 규칙을 따르는 기준 레벨(원본 OrgChart의 verticalLevel 옵션)
nodeTemplatefunction | stringnull노드 내부 HTML을 직접 그리는 함수 (data) => htmlString. 마크업에서는 '$this.event.함수명' 문자열로 지정합니다.
createNodefunction | stringnull노드 DOM이 생성된 직후 호출되는 함수 ($node, data). 아이콘 추가, 클릭 핸들러 부착 등 커스텀 처리에 사용합니다. 마크업에서는 '$this.event.함수명' 문자열로 지정합니다.
dataTypestring'string'다른 컨트롤과 형식을 맞추기 위한 공통 속성
belongID / getter / setter / controlText / validators / transactConfig / triggerConfig-null/falsesyn.uicontrols 공통 옵션(값 바인딩·유효성검사·트랜잭션 연동용)

reduceMap

getValue/setValue가 조직도 노드(key/title/parentID)와 원본 데이터 컬럼을 서로 바꿔치기할 때 쓰는 매핑 테이블입니다.

속성기본값설명
key'id'노드 고유 키에 대응하는 실제 데이터 컬럼명
title'title'조직도 내부에서 다루는 타이틀 값에 대응하는 컬럼명(화면 표시는 nodeTitle/nodeContent가 별도로 담당)
parentID'parentID'부모 노드 키에 대응하는 컬럼명

주의: 화면에 실제로 보이는 텍스트는 nodeTitle/nodeContent 옵션이 가리키는 컬럼이고, reduceMap.titlegetValue/setValue 변환에만 관여하는 별개의 값입니다. 둘을 같은 컬럼명으로 맞추지 않으면 "표시되는 값"과 "getValue로 꺼낸 값"이 다르게 보일 수 있습니다.

메서드

syn.uicontrols.$organization.<메서드명>(...) 형태로 호출합니다.

메서드설명
getControl(elID)등록된 컨트롤 정보(객체 설정)를 반환. orgchart가 실제 OrgChart 플러그인 인스턴스입니다.
getValue(elID, meta)조직도 전체를 reduceMap 기준의 평평한(flat) 배열로 변환해서 반환합니다.
setValue(elID, value, meta)reduceMap 컬럼명을 가진 평평한(flat) 배열을 받아 중첩 구조로 변환한 뒤 조직도를 다시 그립니다(orgchart.init).
clear(elID, isControlLoad)조직도 내용을 비웁니다(orgchart.init({ data: null })).
init(elID, newOptions)조직도를 새 옵션/데이터로 다시 초기화합니다(OrgChart의 init 그대로 위임).
getHierarchy(elID, includeNodeData)현재 조직도를 중첩(nested) 구조 그대로 반환합니다. includeNodeDatatrue면 각 노드의 원본 데이터도 포함합니다.
addParent(elID, data)최상위 노드 위에 새 부모 노드를 추가합니다.
addSiblings(elID, node, data)주어진 node와 같은 레벨에 형제 노드를 추가합니다.
addChildren(elID, node, data)주어진 node 아래에 자식 노드를 추가합니다.
removeNodes(elID, node)주어진 node(와 그 하위 노드 전체)를 제거합니다.
hideParent(elID, node) / showParent(elID, node)주어진 node의 상위 계층을 숨기거나 다시 보여줍니다.
hideSiblings(elID, node, direction) / showSiblings(elID, node, direction)주어진 node의 형제 노드들을 방향(direction)에 따라 숨기거나 보여줍니다.
showChildren(elID, node)주어진 node의 하위 계층을 펼쳐 보여줍니다.
getNodeState(elID, node, relation)node를 기준으로 relation('parent'|'children'|'siblings', 기본 'children') 방향 노드들의 표시 상태(펼침/숨김 등)를 반환합니다.
getRelatedNodes(elID, node, relation)node를 기준으로 relation('parent'|'children'|'siblings', 기본 'children') 방향의 관련 노드(jQuery 컬렉션)를 반환합니다. 드래그로 노드를 옮긴 뒤 변경된 하위 조직을 다시 조회할 때 유용합니다.
setChartScale(elID, node, newScale)조직도의 확대/축소 배율을 직접 지정합니다(zoom: true일 때 의미가 있습니다).
export(elID, fileName, fileExtension)현재 조직도를 이미지/PDF 등으로 내보냅니다. fileName을 생략하면 임의 문자열(syn.$l.random())이 사용됩니다.
setLocale(elID, translations, control, options)다국어 텍스트 적용 훅(OrganizationView는 별도 구현 없음, 빈 함수)

controlLoad(elID, setting)은 컨트롤이 마크업을 실제 OrgChart로 초기화하는 내부 진입점으로, 프레임워크가 자동으로 호출합니다. 직접 호출할 일은 거의 없습니다.

이벤트 (syn-events)

syn-events 배열에 이름을 넣으면 페이지 스크립트의 event 객체에서 {elID}_{이벤트명} 함수를 자동으로 연결해 줍니다.

중요: 아래 eventHooks(nodedrop/select/click) 목록에 있는 이름만 실제로 동작합니다. 목록에 없는 이름을 syn-events에 적어도 에러는 나지 않지만 아무 핸들러도 연결되지 않습니다.

이벤트명발생 시점핸들러 시그니처
nodedropdraggable: true인 상태에서 노드를 드래그해 다른 노드 위에 놓았을 때(evt, params)params.draggedNode(옮겨진 노드), params.dragZone(원래 부모), params.dropZone(새 부모)이 모두 jQuery 객체로 전달됩니다.
select조직도 안의 아무 노드(.node)를 클릭했을 때(evt, node)node는 클릭된 노드의 jQuery 객체입니다.
click조직도 영역(.orgchart) 어디든 클릭했을 때(evt, focusNodes)focusNodes는 클릭 지점이 노드 위였는지를 나타내는 개수(0 또는 1 이상)입니다.

핸들러 등록 예:

let $samplePage = {
event: {
orgChartView_nodedrop(evt, params) {
syn.$l.eventLog('orgChartView_nodedrop',
params.draggedNode.children('.title').text() + ' -> ' + params.dropZone.children('.title').text());
},
orgChartView_select(evt, node) {
syn.$l.eventLog('orgChartView_select', node.find('.title').text());
},
orgChartView_click(evt, focusNodes) {
syn.$l.eventLog('orgChartView_click', 'focusNodes=' + focusNodes);
}
}
}

참고

  • 내부적으로 jQuery의 .orgchart(setting) 호출을 그대로 감싼 구조이므로, 옵션/메서드의 더 자세한 원본 설명은 OrgChart 문서를 참고하세요: https://github.com/dabeng/OrgChart

  • 노드를 우클릭했을 때 메뉴를 띄우려면 OrganizationView 자체가 아니라 ContextMenu를 함께 사용합니다. target에 조직도 컨테이너 셀렉터(#조직도ID)를, delegate'div.node'를 지정하면 노드를 우클릭했을 때 메뉴가 뜹니다.

    <syn_organization id="orgChartView" syn-options="{...}" syn-events="['click']"></syn_organization>
    <syn_contextmenu id="ctxTreeItem" syn-options="{
    target: '#orgChartView', delegate: 'div.node', menu: [...]
    }" syn-events="['beforeOpen', 'select']"></syn_contextmenu>

    또는 createNode 콜백에서 노드 안에 아이콘을 추가하고, 그 아이콘 클릭 시 syn.uicontrols.$contextmenu.open('ctxTreeItem', this)로 메뉴를 직접 여는 방식도 자주 쓰입니다(우클릭 대신 아이콘 클릭으로 메뉴를 여는 패턴).

  • getValue/setValue는 항상 flat 배열 기준입니다. 조직도 내부 계층 변환은 syn.$l.flat2Nested / syn.$l.nested2Flat 유틸리티가 담당합니다(TreeView와 동일한 유틸리티를 공유합니다).

  • draggable: true로 노드를 옮긴 뒤에는 nodedrop 핸들러에서 getRelatedNodes(elID, params.dropZone, 'children')을 호출해 변경된 하위 조직 목록을 다시 조회하는 패턴이 자주 쓰입니다.