[Javascript] jsTree 사용법 및 Tree 자료구조

jsTree는 jquery 기반으로, HTML 또는 JSON 데이터를 Tree 콘트롤로 웹에 출력해 주는 자바스트립트 라이브러리이다.
홈페이지는 이곳 ==> https://www.jstree.com/

사용한 예는 다음과 같다.
캡처-jsTree-실행예

먼저 jsTree 라이브러리를 불러온다.


	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.2/themes/default/style.min.css" />
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.2/jstree.min.js"></script>

<!-- (...중략...) -->
<div id="layerTree"></div>

이후 HTML 또는 JSON 데이터를 생성해 jstree()를 실행시킨다.

// jsTree 생성
$('#layerTree').jstree({
	"plugins" : [ "wholerow", "checkbox", "changed" ],
	'core' : { 'data' : treeJson }
});

데이터 정의는 HTML과 JSON 두가지가 있는데, 위 코드는 JSON 방식이다.
HTML의 경우, ‘ul’과 ‘li’ 태그를 이용하여 계층을 표현한다.

예제를 따라서, 구현을 들어갔는데 HTML 출력이 원하는대로 되지 않아서, JSON 방식으로 구현했다.
오히려 더 깔끔하고, Tree 자료구조 그대로 삽입할 수 있어서 더 나은 선택이 되었다.

** JSON 자료구조
참고: https://www.jstree.com/docs/json/


// jsTree의 Node 자료구조
{
  id          : "string" // will be autogenerated if omitted
  text        : "string" // node text
  icon        : "string" // string for custom
  state       : {
    opened    : boolean  // is the node open
    disabled  : boolean  // is the node disabled
    selected  : boolean  // is the node selected
  },
  children    : []  // array of strings or objects
  li_attr     : {}  // attributes for the generated LI node
  a_attr      : {}  // attributes for the generated A node
}

// jsTree 사용예
$('#using_json').jstree({
  'core' : {
    'data' : [
       'Simple root node',           // 단독으로 text만 넣거나
       {                             // 자료구조를 지켜서 넣거나
         'text' : 'Root node 2',
         'state' : {
           'opened' : true,
           'selected' : true
         },
         'children' : [              // 자식노드들은 Array에 넣어야 한다
           { 'text' : 'Child 1' },
           'Child 2'
         ]
      }
    ]
} });

이를 위해 사용자가 정의한 데이터로부터 jsTree와 호환되는 Tree 자료구조를 구현해야 하는데
다음과 같이 코드를 작성하였다.


/**
 ** ****************************************************
 ** 레이어 리스트 Tree 생성
 ** ****************************************************
 */

var treeCtrl = treeCtrl || (function(){

	var Node = function( nodeName ){
		return {
			text: nodeName,
			state: { 'opened' : false, 'selected' : false },
			data: null,			// @type: ol.Layer
			children: []
		};
	};

	var _root = new Node('ROOT','group');

	var findChild = function( parent, nodeName ){

		for( var i=0; i<parent.children.length; i++ ){
			var child = parent.children[i];
			if( child.text == nodeName ){
				return child;
			}
		}

		return null;
	};

	// find parent which save item
	var getParent = function( parent, group, opt_make ){

		opt_make = ( typeof opt_make === 'undefined' ) ? true : false;

		for( var i=0; i<group.length; i++ ){
			var child = findChild( parent, group[i] );
			// 없으면 Node 생성
			if( !child ){
				if( !opt_make ) return null;

				child = new Node( group[i] );
				parent.children.push( child );
			}
			parent = child;
		}

		return parent;
	}

	// group에 layer 아이템 저장
	var _set = function( key, item ){
		var group = key.split('-');
		var parent = getParent( _root, group );

		var child = new Node( item.name, 'item' );
		child.data = item;

		parent.children.push( child );

		return child;
	};

	// item인 node들만 반환 (=layer)
	var _get = function( key ){
		var group = key.split('-');
		var parent = getParent( _root, group );

		return parent.children.filter(function( node ){
			return node.type == 'item'
		});
	};

	var _clear = function(){
		_root.children = [];
	};

	var _setState = function( key, state ){
		var group = key.split('-');
		var node = getParent( _root, group, false );
		if( !node ) return false;

		node['state'] = state;
		return true;
	};

	var _toTreeJson = function(){
		return _root.children;
	};

	return {
		'root'  	: _root,
		'set'   	: _set,
		'get'   	: _get,
		'setState'  : _setState,
		'toTreeJson': _toTreeJson,
		'clear' 	: _clear,
	};

})(treeCtrl);

// wfsData 읽어들이기
for( var key in wfsData ){
	var node = treeCtrl.set( wfsData[key].group, wfsData[key] );
}
// 법정경계 펼치고, 선택하기
treeCtrl.setState( '주제도-법정경계', { 'opened' : true, 'selected' : true } );
var treeJson = treeCtrl.toTreeJson();
//console.log( treeJson );

Node의 트리 위치는 set() 함수의 ‘key’로 정의되는데, ‘-‘ 분리자로 계층을 표현하였다.
예를 들어, ‘주제도-법정경계’라면 ‘주제도’ 아래에 ‘법정경계’ 노드를 가리킨다.

이에 대한 트리 생성과 이벤트 처리는 다음과 같이 한다.

** 생성 옵션: “wholerow”, “checkbox”, “changed”
** 이벤트 : ‘changed’에 대해 ‘selected’와 ‘deselected’를 처리


// jsTree 생성
$('#layerTree').jstree({
	"plugins" : [ "wholerow", "checkbox", "changed" ],
	'core' : { 'data' : treeJson }
});

// jsTree 클릭 이벤트 : 레이어 setVisible
$('#layerTree').on("changed.jstree", function (e, data) {
	// 선택된 레이어 보이기
	var i, j, r = [];
	for(i = 0, j = data.changed.selected.length; i < j; i++) {
		var node = data.instance.get_node( data.changed.selected[i] );
		if( node.data !== null && node.data.hasOwnProperty('layer') ){
			wfsLayers[ node.data.layer ].setVisible( true );
			r.push( node.data.layer );
		}
	}
	console.log( 'selected Layer: ' + r.join(', ') );

	// 선택해제된 레이어 감추기
	r = [];
	for(i = 0, j = data.changed.deselected.length; i < j; i++) {
		var node = data.instance.get_node( data.changed.deselected[i] );
		if( node.data !== null && node.data.hasOwnProperty('layer') ){
			wfsLayers[ node.data.layer ].setVisible( false );
			r.push( node.data.layer );
		}
	}
	console.log( 'deselected Layer: ' + r.join(', ') );
});

jsTree 선택에 의한 조작 대상은 OpenLayer3의 layer의 setVisible() 이다.

더 자세한 설정은 jsTree 홈페이지를 참조하시길..
구글링으로도 예제코드들이 잘 나온다. (마음에 드는게 안나와서 기록하는 거지만)

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: