w2ui

前回の記事「w2uiサイドツリーをPHPで出力」でツリー表示するアイテム数が17,000個を超えていたため、表示にかなり時間が掛かってしまいました。

ですので今回、表示までの時間を短縮できるように修正していきたいと思います。

初期表示用のPHPを作成する

初期状態では、全ての子要素は閉じられていて見えない状態で表示するようにします。

ですので第一階層のみ表示することと、イベント処理などを返却する初期表示用のPHP「data/side/initside.php」を作成します。

<?php

define('DB_HOST', 'MySQLホスト');
define('DB_NAME', 'データベース名');
define('DB_USER', 'ユーザー名');
define('DB_PASS', 'パスワード');
define('DB_TABLE', 'テーブル名');


setlocale(LC_ALL,'ja_JP.UTF-8');
//HTTP出力文字コードの設定
mb_http_output('UTF-8');
date_default_timezone_set('Asia/Tokyo');
header('Content-Type: text/html; charset=UTF-8');

$tableName = DB_TABLE;

$dsn = 'mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8;';
$pdo = null;

try {
	$pdo = new PDO($dsn, DB_USER, DB_PASS);
	$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);          
	$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

}
catch (PDOException $e) {
	die($e->getMessage());
}

//サイドツリー取得SQL
$sql = <<<EOF
	SELECT
		A.ID AS id
		,A.Name as text
		,'icon-page' as img
		,EXISTS(SELECT * FROM {$tableName} AS B WHERE B.ParentID=A.ID) AS flg
	FROM 
		{$tableName} AS A
	WHERE 
		A.ParentID=:ParentID
	ORDER BY 
		A.Disp
EOF;
		
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':ParentID','0',PDO::PARAM_STR);
$rows = array();
if($stmt->execute()) {
	$cnt = 0;
	while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		if($row['flg']) {
			//子要素があればダミーを作成する
			$row['nodes'][] = array('id'=>'D'.$row['id'],'text'=>'');
		}
		$rows[] = $row;			
		$cnt++;
	}
}
$cnt=0;
$ParentID = 0;

//テーブルからサイドツリー要素を作成
$json['nodes'] = $rows;
//サイドバー名
$json['name'] = 'sidebar';

//イベント関数
$java=<<<EOF
function(event){
	console.log(event);
	var child = this.find(event.target,{}).forEach(function( value ) {
		w2ui['sidebar'].remove(value.id);
	 });
	w2ui.sidebar.insert(event.target, null, [
		{ id: event.target+'-4', text: 'New Item 4', icon: 'w2ui-icon-check' },
		{ id: event.target+'-5', text: 'New Item 5', icon: 'w2ui-icon-check' },
		{ id: event.target+'-6', text: 'New Item 6', icon: 'w2ui-icon-check' }
	]);
}
EOF;
$json['onExpand'] = $java;

header("Content-Type: application/json;charset=utf-8");
echo json_encode($json);


 

今回のソースのポイントは、選択されている行の3か所になります。

 

1.子要素があるか?判別する項目「flg」を追加

サブクエリーを使って取得したレコードのIDに紐付く、子要素が存在するか?を取得しています。

 

2.子要素があれば、ダミー要素を設定する

子要素がデータ上確認できるのであれば、ダミーで項目を追加しておきます。

こうしないとツリーの左にプラス「+」が表示されなくなってしまいますので、設定しておきます。

w2uiで設定するidは、必ずユニーク(重複しない値)にする必要があるため、取得レコードのid先頭に「D」という文字列を付けて設定しています。

 

3.onExpandイベント処理を作成

onExpandイベントでは、子要素が表示されたときに発生するイベントになります。

行っていることとしては、findメソッドで子要素を取得し削除し、テストで項目を追加しています。

※後ほどダミー要素のみ削除する処理に変更します。

 

初期表示用のPHPをJavaスクリプトに設定

「js/script.js」のサイドツリー読み込み部分を、追加したPHPに変更します。

$(function () {
	var wheight=$(window).height()-15;
	$("#main").css("height",wheight);
	w2utils.locale('locale/ja-jp.json');
        
	$('#main').w2layout(layout);

	$().w2grid(grid);
	w2ui.layout.content('main', w2ui['grid']);
	w2ui.layout.lock('left', 'Loading....', true);

	//サイドツリーの読み込み
	getJson('data/side/initside.php').then(value => {
		var sidebar = value;
		$().w2sidebar(sidebar);	 
		w2ui['layout'].content('left', w2ui['sidebar']);
		w2ui.layout.unlock('left');
	 });
	 
	//ウィンドウリサイズ時
	$(window).resize(function() {
		if ($(document.body).hasClass('print')==false ) {
			//現在のウィンドウ高さを取得し、要素に設定
			var wheight=$(window).height()-15;
			$("#main").css("height",wheight);
		}
	});	
});

//パネルスタイル
var pstyle = 'border: 1px solid #dfdfdf; padding: 5px;';

// レイアウト設定
var layout = {
        name: 'layout',
        padding: 4,
        panels: [
            { type: 'left', size: 200, resizable: true, style: pstyle, content: '' },
            { type: 'main', style: pstyle, content: '' }
        ]
};

// グリッド設定
var grid = { 
        name: 'grid', 
        url: 'data/list.json',
        method: 'GET', 
        columns: [                
            { field: 'fname', caption: 'First Name', size: '30%' },
            { field: 'lname', caption: 'Last Name', size: '30%' },
            { field: 'email', caption: 'Email', size: '40%' },
            { field: 'sdate', caption: 'Start Date', size: '120px' }
        ]
};
 
/**
 * JSONデータを取得する
 */
async function getJson(url) {
	var json 
	await fetch(url).then(function(response) {
		return response.text();
	}).then(function(text) {
		var parser = function reviver(k, v) {
			if (typeof v === 'string' && v.match(/^function/)) {
				return Function.call(this, 'return ' + v)();
			}
			return v;
		};
		json = JSON.parse(text, parser);

	});
	return json;
}

 

ここまで行うと、下の画面のように子要素を表示すると要素が3つ追加され表示されるかと思います。

 

子要素を取得するPHPを作成

子要素が表示されたときに、紐付く子要素を取得するPHP「data/side/getChild.php」を作成します。

親要素のidをGETパラメータで受け取ることを想定しています。(17行~20行)

返却するJsonは、nodeの部分のみとなっています。

<?php

define('DB_HOST', 'MySQLホスト');
define('DB_NAME', 'データベース名');
define('DB_USER', 'ユーザー名');
define('DB_PASS', 'パスワード');
define('DB_TABLE', 'テーブル名');


setlocale(LC_ALL,'ja_JP.UTF-8');
//HTTP出力文字コードの設定
mb_http_output('UTF-8');
date_default_timezone_set('Asia/Tokyo');
header('Content-Type: text/html; charset=UTF-8');

//GETパラメータ「id」で親IDを取得する
$id = (isset($_GET['id'])?$_GET['id']:null);
if($id == null) {
	exit();
}

$tableName = DB_TABLE;

$dsn = 'mysql:dbname=' . DB_NAME . ';host=' . DB_HOST . ';charset=utf8;';
$pdo = null;

try {
	$pdo = new PDO($dsn, DB_USER, DB_PASS);
	$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);          
	$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

} catch (PDOException $e) {
	die($e->getMessage());
}

//サイドツリー取得SQL
$sql = <<<EOF
	SELECT
		A.ID AS id
		,A.Name as text
		,'icon-page' as img
		,EXISTS(SELECT * FROM {$tableName} AS B WHERE B.ParentID=A.ID) AS flg
	FROM 
		{$tableName} AS A
	WHERE 
		A.ParentID=:ParentID
	ORDER BY 
		A.Disp
EOF;
		
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':ParentID',$id,PDO::PARAM_STR);
$rows = array();
if($stmt->execute()) {
	while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
		if($row['flg']) {
			//子要素があればダミーを作成する
			$row['nodes'][] = array('id'=>'D'.$row['id'],'text'=>'');
		}
		$rows[] = $row;			
	}
}
//テーブルからサイドツリー要素を作成
$json['nodes'] = $rows;

header("Content-Type: application/json;charset=utf-8");
echo json_encode($json);


 

onExpandイベント処理修正

「data/side/initside.php」のonExpandイベント処理を下記の通りに修正しました。

//イベント関数
$java=<<<EOF
function(event){
	console.log(event);
	var child = this.find(event.target,{});
	if(child[0].text.length == 0) {
		getJson('data/side/getChild.php?id='+event.target).then(value => {
			w2ui['sidebar'].insert(event.target, null, value.nodes);
		 });				
		w2ui['sidebar'].remove(child[0].id);
	}
}
EOF;
$json['onExpand'] = $java;

 

w2uiのfindメソッドを利用すると、指定したID以下の子要素を全て取得してしまいます。

ダミーとして設定している要素は、必ず各親要素以下に1つのみですので、child[0]と指定しています。(5~6行)

6行でtextが設定されていないこと=ダミー要素と判別しています。

ダミー要素が残っている場合は、まだ正しい子要素の読み込みがされていないため、7行で親IDを指定して子要素を取得しています。

8行で、取得した子要素を追加しています。

9行でダミーで追加してあった要素を削除しています。

 

ここまで行うと、下記のような画面表示を行うことができました。

 

まとめ

アイテム数17,000のサイドツリーでしたが、上記の方法でストレス無く読み込みができるようになりました。

他にも方法はあるかと思いますので、もっと良い方法があれば教えてくださいm(_ _)m

 

今回の記事で取り扱ったソース一式は下記からダウンロードできます。

[wpdm_package id=’757′]

 

 

By にど寝

もともと名古屋でシステムエンジニアをしてましたが、現在は地元に帰省してネットショップの社内システムエンジニアをしてます。  

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です