var PATHNUM = 0;
var MAXDEPTH = 0;
var TREESPACE = 0;
var NODEHEIGHT = 50;
var DRAWHEIGHT = 0;
var endpoint = "";
var startclass= "";
var endclass = "";
var defendpoint = "";
var defstartclass= "";
var defendclass = "";
var jsontext = "";
var pathobj = "";
var pathlimit = 10;
// ページ読み込みが完了次第実行
$(function(){
// ページのパーツ部分を追加
initparts();
getParameter();
if(defendpoint != "" && defstartclass != "" && defendclass != ""){
openSPARQLBuilder();
}
});
function initparts(){
var sbdiv = $('div#SPARQLBUILDER');
if(sbdiv.find('div').length == 0){
var sbtop = '
Tutorial for SPARQL Builder GUI is
here.
';
var sbmodal = '';
sbdiv.html(sbtop);
$('body').append(sbmodal);
}
$('.SBModalView').click(function(){
$(this).fadeOut(700);
});
$('.SBModalContents').click(function(event){
event.stopPropagation();
});
loadEndPointList();
$(".SBEndPointSelect").change(function() {
changeEndPoint();
});
$(".SBStartClassSelect").change(function() {
startClass = $(".SBStartClassSelect").val();
loadEndClassList();
});
$(".SBEndClassSelect").change(function() {
endClass = $(".SBEndClassSelect").val();
loadPathList();
});
}
function getParameter()
{
if( 1 < window.location.search.length )
{
var query = window.location.search.substring( 1 );
var parameters = query.split( '&' );
for( var i = 0; i < parameters.length; i++ )
{
var element = parameters[ i ].split( '=' );
if(decodeURIComponent( element[ 0 ] ) == "ep"){
defendpoint = decodeURIComponent( element[ 1 ] )
}else if(decodeURIComponent( element[ 0 ] ) == "st"){
defstartclass = decodeURIComponent( element[ 1 ] )
}else if(decodeURIComponent( element[ 0 ] ) == "en"){
defendclass = decodeURIComponent( element[ 1 ] )
}
}
}
}
function openSPARQLBuilder(){
$('.SBModalView').css('top', $(window).scrollTop()).css('height', window.innerHeight).fadeIn();
resizeModalView();
$(".SBEndPointSelect").select2();
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
if(defendpoint != "" && defstartclass != "" && defendclass != ""){
$('.SBStartClassSelect').on('lsccomplete', function(){
$('.SBStartClassSelect').val(defstartclass);
defstartclass = "";
$(".SBEndPointSelect").select2();
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
$('.SBStartClassSelect').unbind('lsccomplete');
loadEndClassList();
});
$('.SBEndClassSelect').on('leccomplete', function(){
$('.SBEndClassSelect').val(defendclass);
defendclass = "";
$(".SBEndPointSelect").select2();
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
$('.SBEndClassSelect').unbind('leccomplete');
});
loadPathList();
var eplist = $('.SBEndPointSelect option');
if(eplist.length == 0){
$('.SBEndPointSelect').on('epcomplete', function(){
$('.SBEndPointSelect').val(defendpoint);
defendpoint = "";
loadStartClassList();
$('.SBEndPointSelect').unbind('epcomplete');
});
}else{
$('.SBEndPointSelect').val(defendpoint);
defendpoint = "";
loadStartClassList();
}
}
}
function resizeModalView(){
if($('.SBModalView').css('display') == 'block'){
var mvw = $('.SBModalContents').width();
var mvh = $('.SBModalContents').height();
$('.SBModalContents .SBForms').css('width', (mvw - 201) + 'px').css('height', 56 + 'px');
$('.SBModalContents .SBMessage').css('width', 200 + 'px').css('height', 56 + 'px');
$('.SBModalContents .SBGraph').css('width', (mvw - 201) + 'px').css('height', (mvh - 57) + 'px');
$('.SBModalContents .SBPath').css('width', 180 + 'px').css('height', (mvh - 77 - 26) + 'px');
$('.SBModalContents .SBModalButtons').css('width', 200 + 'px').css('height', '26px');
var formw = $('.SBModalContents .SBForms').width();
var selw = Math.floor(formw - 120);
if(selw % 2 == 1){
selw--;
}
$('.SBModalContents .SBSelects').css('width', selw);
$('.SBModalContents .SBPermaLink').css('width', Math.floor(formw - selw));
}
}
function openSample(ep, st, en){
defendpoint = ep;
defstartclass = st;
defendclass = en;
openSPARQLBuilder();
}
function openPermalink(){
var baseurl = location.href;
var spliturl = baseurl.split('?');
var url = spliturl[0] + "?ep=" + encodeURIComponent(endpoint) + "&st=" + encodeURIComponent(startclass) + "&en=" + encodeURIComponent(endclass);
window.open(url);
}
function closeSPARQLBuilder(){
$('.SBModalView').fadeOut();
}
function switchLoadIcon(mode) {
if(mode == "view"){
$('.SBAjaxLoad').show();
}else{
$('.SBAjaxLoad').hide();
}
};
function loadEndPointList(){
$('.SBPermaLinkButton').attr('disabled', true);
var url = 'http://www.sparqlbuilder.org/api/eplist';
$.ajax({
url: url,
success: function(data) {
var list = eval(data);
$(".SBEndPointSelect").empty();
$(".SBEndPointSelect").append('');
for (var i = 0; i < list.length; ++i) {
$(".SBEndPointSelect").append('');
switchLoadIcon("hide");
if($('.SBModalView').attr('display') == 'block'){
$(".SBEndPointSelect").select2();
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
}
}
$(".SBEndPointSelect").trigger(new $.Event('epcomplete'));
},
});
}
changeEndPoint = function() {
endpoint = $(".SBEndPointSelect").val();
if(endpoint != "SBDefault"){
loadStartClassList();
}
};
loadStartClassList = function() {
$('.SBPermaLinkButton').attr('disabled', true);
var url = "http://www.sparqlbuilder.org/api/clist?ep=" + encodeURIComponent(endpoint);
$.ajax({
type : "GET",
url : url,
async : false,
success : function(data) {
var list = eval(data);
$(".SBStartClassSelect").empty();
$(".SBEndClassSelect").empty();
$(".SBStartClassSelect").append('');
for (var i = 0; i < list.length; ++i) {
$(".SBStartClassSelect").append('');
}
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
$(".SBStartClassSelect").trigger(new $.Event('lsccomplete'));
}
});
};
loadEndClassList = function() {
$('.SBPermaLinkButton').attr('disabled', true);
var url = "http://www.sparqlbuilder.org/api/clist?ep=" + encodeURIComponent(endpoint) + '&class=' + encodeURIComponent($(".SBStartClassSelect").val());
$.ajax({
type : "GET",
url : url,
async : false,
success : function(data) {
var list = eval(data);
$(".SBEndClassSelect").empty();
$(".SBEndClassSelect").append('');
for (var i = 0; i < list.length; ++i) {
$(".SBEndClassSelect").append('');
}
$(".SBStartClassSelect").select2();
$(".SBEndClassSelect").select2();
$(".SBEndClassSelect").trigger(new $.Event('leccomplete'));
}
});
};
loadPathList = function() {
startclass = $(".SBStartClassSelect").val();
endclass = $(".SBEndClassSelect").val();
if(defendpoint != "" && defstartclass != "" && defendclass != ""){
endpoint = defendpoint;
startclass = defstartclass;
endclass = defendclass;
}
$('.SBSaveESE').attr('disabled', true);
if (startclass == null || endclass == null || startclass == "SBDefault" || endclass == "SBDefault"){
return;
}
pathlimit = 10;
$('.SBResult').hide();
$('.SBViewAll').hide();
$('.SBSelectedPath').html('Please select a leaf node and click to generate a SPARQL
');
var url = "http://www.sparqlbuilder.org/api/plist?ep=" + encodeURIComponent(endpoint)
+ "&startclass=" + encodeURIComponent(startclass)
+ "&endclass=" + encodeURIComponent(endclass);
switchLoadIcon("view");
setTimeout(function(){
$.ajax({
type : "GET",
url : url,
//async : false,
timeout : 1000000,
success : function(data) {
jsontext = data;
view_map();
switchLoadIcon("hide");
$('.SBPermaLinkButton').attr('disabled', false);
},
error: function(data){
switchLoadIcon("hide");
alert("error: ", data);
}
});
}, 100);
};
function viewAll(){
pathlimit = 0;
view_map();
}
generateSPARQL = function() {
var path = JSON.stringify(pathobj);
var url = 'http://www.sparqlbuilder.org/api/sparql?path=' + encodeURIComponent(path);
$.ajax({
type: "GET",
url : url,
dataType: 'text',
async: false,
success : function(data) {
$(".SBSparqlArea").val(data);
closeSPARQLBuilder();
}
});
};
function sendSPARQL(){
var sendep = $(".SBEndPointSelect").val();
var query = $(".SBSparqlArea").val();
if(sendep == "SBDefault" || query == ""){
return;
}
query = encodeURIComponent(query);
openpage = sendep + "?format=text%2Fhtml&query=" + query;
window.open(openpage);
}
function downloadResult(){
var sendep = $(".SBEndPointSelect").val();
var query = $(".SBSparqlArea").val();
if(sendep == "SBDefault" || query == ""){
return;
}
qr = sendQuery(sendep,query);
qr.fail(
function (xhr, textStatus, thrownError) {
alert("Error: A '" + textStatus+ "' occurred.");
}
);
qr.done(
function (d) {
downloadCSV(d.results.bindings);
}
);
}
function downloadCSV(data){
if (data instanceof Array) {
var result_txt ="";
var i=0;
for ( var key in data[0]) {
if(i>0){result_txt +=",";}
result_txt += key;
i++;
}
result_txt += "\n";
for (var d = 0; d < data.length; d++) {
var i = 0;
for ( var key in data[d]) {
if(i>0){result_txt +=",";}
result_txt += data[d][key].value;
i++;
}
result_txt += '\n';
}
var blob = new Blob( [result_txt], {type: 'text/plain'} )
var link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'result' + '.csv'
document.body.appendChild(link) // for Firefox
link.click()
document.body.removeChild(link) // for Firefox
}
};
// グラフ描画部分
view_map = function(){
// make_dataメソッドの結果を取得
var json = make_data();
// パス数が0でなければ
if(json['nodes'].length != 0){
// 出来上がった結果を渡してマップ上の座標をセット
set_map_location(0, json['nodes'], json['links']);
// SVGの幅と高さ用に描画領域のサイズを取得
var width = $('.SBGraph').width();
var height = $('.SBGraph').height();
// SVG内のグラフ部分高さ(パス数に応じる)をセット
var graphheight = ((NODEHEIGHT * 1.5) * PATHNUM) + (NODEHEIGHT / 2);
// スコア表示のマージン
var scoreleftmargin = NODEHEIGHT * 1.5;
var scrollsvg = function(delta){
// 現在のビューボックスの状態を取得
var vb = svg.attr("viewBox");
// スペースで区切り各値に分解
var spvb = vb.split(" ");
// ビューボックスのyの値から今回のホイールイベントの差分を引く
var vby = (parseInt(spvb[1]) - parseInt(delta));
// 0を割っていたら0に
if(vby < 0){
vby = 0;
// スクロール上限(グラフサイズ引く表示領域サイズ)を超えていたら補正
}else if(vby > (graphheight - height)){
vby = (graphheight - height);
// 補正した結果0を割っていたら0に
if(vby < 0){
vby = 0;
}
}
// ここまででできたyをセットしビューボックスを更新
svg.attr("viewBox", "0 " + vby + " " + width + " " + height);
}
// SVGの削除
d3.select(".SBGraph svg").remove();
// 画面サイズに合わせSVGの追加
var svg = d3.select(".SBGraph").append("svg")
.attr("width", width)
.attr("height", height)
// ビューボックスのセット
.attr("viewBox", "0 0 " + width + " " + height);
// SVGがスクロールされた時のイベントをブラウザに応じてセット
var mousewheelevent = 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll';
$(".SBGraph svg").on(mousewheelevent,function(e){
// ブラウザに応じてスクロールの値を取得
var delta = e.originalEvent.deltaY ? -(e.originalEvent.deltaY) : e.originalEvent.wheelDelta ? e.originalEvent.wheelDelta : -(e.originalEvent.detail);
// FireFoxだとスクロール速度が非常に遅い場合があるので補正
if(delta < 0 && delta > -100){
delta = -100;
}else if(0 < delta && delta < 100){
delta = 100;
}
// スクロールのデフォルトの動作とバブリングをキャンセル
e.preventDefault();
e.stopPropagation();
// 値を渡してスクロール
scrollsvg(delta);
});
// 背景の追加(高さ以外は描画領域そのまま)
var bg = svg
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", function(){
// グラフ部分の高さが描画領域の高さを割っていたら(パスが少なければ)描画領域の高さを返す
if(graphheight < height){
return height;
}else{
return graphheight;
}
})
// 背景を薄いグレーに
.attr("fill", "#fafafa");
// links配列を渡しリンクの作成
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke", "#999")
.style("stroke-opacity", 0.6)
.style("stroke-width", 2);
// nodes配列を渡しノードの作成
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", (NODEHEIGHT / 2))
.attr("cx", function(d) { return d.x;} )
.attr("cy", function(d) { return d.y; })
.style("fill", function(d) { return d.nodecolor; })
.style("stroke", '#fafafa')
.style("stroke-width", '1.5px')
// 末端ノードのみマウスアイコンをポインターに
.style("cursor", function(d){
if(d.path == "notend"){
return 'normal';
}else{
return 'pointer';
}
});
// nodes配列を渡しノードテキストの作成
var tnode = svg.selectAll("text.node")
.data(json.nodes)
.enter().append("svg:text")
.attr("class", "tnode")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text(function(d) { return d.name; })
.style("fill", '#000000')
.style("text-anchor", 'middle')
.style("pointer-events", "none");
// リンクテキストの作成
var tlink = svg.selectAll("text.link")
.data(json.links)
.enter().append("svg:text")
.attr("class", "tlink")
.attr("x", function(d) { return (json.nodes[d.source].x + json.nodes[d.target].x) / 2; })
.attr("y", function(d) { return (json.nodes[d.source].y + json.nodes[d.target].y) / 2; })
.style("fill", '#000000')
.style("text-anchor", 'middle');
// スコアテキストの作成
var tscore = svg.selectAll("text.score")
.data(json.nodes)
.enter().append("svg:text")
.attr("class", "tscore")
.attr("x", function(d) { return (d.x + scoreleftmargin); })
.attr("y", function(d) { return d.y + 4; })
.text(function(d) { return d.score; })
.style("fill", 'hsl(0, 50%, 75%)')
.style("text-anchor", 'middle')
.style("pointer-events", "none");
// ノードへのオンマウスでパス探索、パス中のリンク文字を表示
node.on("mouseover", function(d){
// 表示するパス保存用配列
var path = [];
// パス表示情報保存用配列
var pathname = [];
// まずオンマウスされたノードのidと名前をそれぞれ追加
path.push(d.nodeid);
pathname.push(d.name);
// パス探索
do{
// リンクの数だけ繰り返し
for(var i = 0; i < link.data().length; i++){
// 現在の最後尾に繋がるリンクがあれば
if(path[(path.length-1)] == link.data()[i].target){
// そのリンクのソース側ノードのidを追加
path.push(link.data()[i].source);
// そのリンクの名前とソース側ノードの名前を追加
pathname.push(link.data()[i].property);
pathname.push(node.data()[link.data()[i].source].name);
}
}
// ルートノードに辿り着くまで繰り返す
}while(path[(path.length-1)] != 0);
// ルートノードまたは途中ノードなら
if(d.nodeid == 0 || d.path == "notend"){
// パス表示領域をデフォルトに
$('.SBSelectedPath').html('Please select a leaf node and click to generate a SPARQL
');
// 末端ノードなら
}else{
// パス表示領域用文字列
var resultText = '';
// パスの名前配列分後ろから繰り返しながら
for (var i = pathname.length;i > 0; i--){
// 奇数番目(ノード)なら
if(i % 2 == 1){
// ルートか途中か末端かに応じてクラスを指定し追記
if(i == 1){
resultText = resultText + "" + pathname[i - 1] + "
";
}else if(i == pathname.length){
resultText = resultText + "" + pathname[i - 1] + "
";
}else{
resultText = resultText + "" + pathname[i - 1] + "
";
}
// 偶数番目(リンク)はリンク画像を前後につけ追記
}else{
resultText = resultText + "" + pathname[i - 1] + "
";
}
}
// パス表示領域の内容を書き換え
$('.SBSelectedPath').html(resultText);
// サーブレットに送り返すパスオブジェクトを保存
pathobj = d.path;
// パス表示領域の表示設定をvisivleに
$('.SBPath').css('overflow-y', 'visible');
// パス内容の高さがパス表示領域を超えていたら
if($('.SBPath').height() < $('.SBSelectedPath').innerHeight()){
// パス表示領域の表示設定をスクロールに
$('.SBPath').css('overflow-y', 'scroll');
}
}
// オンマウスされたノードの高さに親を合わせるために合わせる高さを保存
var movey = d.y;
// 各ノードに対し
node
// 輪郭線の色を設定
.style("stroke", function(d){
// まずは背景色(デフォルト)を指定
var strokecolor = "#fafafa";
// パスのノード数だけ繰り返しながら
for(var n = 0; n < path.length; n++){
// パス内に含まれるノードだったら
if(path[n] == d.nodeid){
// 輪郭線を赤に
strokecolor = "#ffaaaa";
}
}
// ここまでで得られた輪郭線の色を返す
return strokecolor;
})
// 高さの値
.attr("cy", function(d){
// 現在の高さを取得
var currenty = d.y
// パスのノード数だけ繰り返しながら
for(var n = 0; n < path.length; n++){
// パス内に含まれるノードだったら
if(path[n] == d.nodeid){
// 内部で持つ高さをオンマウスされたノードと同じに(再描画時に反映)
d.y = movey;
}
}
// 今は現時点の高さを返す
return currenty;
});
// 各リンクテキストに対し
tlink
// テキスト表示判定
.text(function(d) {
// デフォルトで空をセット
var linktext = "";
// パスのノード数だけ繰り返しながら
for(var t = 0; t < path.length; t++){
// 自身がそのノードへ接続しているリンクならば
if(path[t] == d.target){
// リンクテキストにプロパティの値をセット
linktext = d.property
}
}
// ここまででできたリンクテキストを返す
return linktext;
});
// 各リンクに対し
link
// 線の色判定
.style("stroke", function(d){
var strokecolor = "#999";
// パスのノード数だけ繰り返しながら
for(var t = 0; t < path.length; t++){
// 自身がそのノードへ接続しているリンクならば
if(path[t] == d.target){
// リンクの色に赤をセット
strokecolor = "#ffaaaa"
}
}
// 線の色を返す
return strokecolor;
});
// ここまでの設定を元に再描画
redraw();
// クリックされたとき
}).on("click", function(d){
// 末端ノードならスパークル発行
if(d.path != "notend"){
generateSPARQL();
}
});
// 再描画関数
var redraw = function (duration){
// かける時間が未指定ならば
if(duration == undefined){
// 0.5秒かけてアニメーション
duration = 500;
}
// 各リンクについて設定された位置に再描画
link
.transition()
.duration(duration)
.attr("x1", function(d) {return node.data()[d.source].x;})
.attr("y1", function(d) {return node.data()[d.source].y;})
.attr("x2", function(d) {return node.data()[d.target].x;})
.attr("y2", function(d) {return node.data()[d.target].y;});
// 各ノードについて設定された位置に再描画
node
.transition()
.duration(duration)
.attr("cx", function(d) {return d.x;})
.attr("cy", function(d) {return d.y;});
// 各ノードテキストについて設定された位置に再描画、テキスト描画位置を上下に振る
tnode
.transition()
.duration(duration)
.attr("x", function(d) {return d.x;})
.attr("y", function(d) {
// デフォルトで少し下げる
var updown = (NODEHEIGHT * 0.4);
// 奇数番目の深さなら少し上げる
if(d.group % 2 == 1){
updown = -(NODEHEIGHT * 0.2);
}
// その値を高さに返すことでテキスト描画位置が互い違いになる
return d.y + updown;
});
// 各リンクテキストについて設定された位置に再描画
tlink
.transition()
.duration(duration)
.attr("x", function(d) {return (node.data()[d.source].x + node.data()[d.target].x) / 2;})
.attr("y", function(d) {return ((node.data()[d.source].y + node.data()[d.target].y) / 2) + 4;});
};
// 初回のみdurationを0と指定し再描画(アニメーションなし)
redraw(0);
}else{
// SVGの削除
d3.select(".SBGraph svg").remove();
}
};
// データ作成メソッド
make_data = function(){
// 結果用オブジェクトを初期化
ret = new Object();
ret['nodes'] = new Array();
ret['links'] = new Array();
// 各種変数の初期化
PATHNUM = 0;
MAXDEPTH = 0;
TREESPACE = 0;
DRAWHEIGHT = NODEHEIGHT;
// 表示するパス数
var viewnum;
// jsontextを取得
var obj = jsontext;
// 結果パス数のスタイルをリセット
$('.SBResult').css('color', 'black').css('font-weight', 'normal').css('margin-top', '4px');
// 複数形のsをつける
$('.SBPlural').text('s');
// パスの数が0だったら
if(obj.length == 0){
// 結果パス数のスタイルを赤の太字にし領域内上下中央に
$('.SBResult').css('color', 'red').css('font-weight', 'bold').css('margin-top', '20px');
// 複数形のsを削除
$('.SBPlural').text('');
// パス数が1なら
}else if(obj.length == 1){
// 複数形のsを削除
$('.SBPlural').text('');
}
// パスの数が十以下なら
if(obj.length <= 10){
// 表示数をパス数に
viewnum = obj.length;
// 結果パス数のスタイルを領域内上下中央に
$('.SBResult').css('margin-top', '20px');
// 全表示ボタンを隠す
$('.SBViewAll').hide();
// リミットが10ならば
}else if(pathlimit == 10){
// 表示パス数を10に
viewnum = 10;
// 全表示ボタンを出す
$('.SBViewAll').show();
// リミットがなければ
}else{
// 表示パス数を全パス数に
viewnum = obj.length;
// 結果パス数のスタイルを領域内上下中央に
$('.SBResult').css('margin-top', '20px');
// 全表示ボタンを隠す
$('.SBViewAll').hide();
}
// 結果パス数の値を更新
$('.SBPathnum').text(obj.length);
// 結果パス数を表示
$('.SBResult').show();
// objトップ階層の数だけ繰り返しながら
for(var i = 0; i < viewnum; i++){
if(i == 0){
// 初回だけルートノードをプッシュ
ret['nodes'].push({'name': obj[0]['label'], 'uri': obj[0]['startClass'], 'group': 0, 'x':50, 'y':50, 'nodeid':ret['nodes'].length, 'path': 'notend', 'nodecolor': 'hsl(40, 50%, 75%)'});
}
// 先にsourceに0(ルート)を代入
var source = 0;
// 共通ルート判定をtrueに
var isCommon = true;
// このパスのスコアを取得
var score = obj[i]['score'];
// classLinksの数だけ繰り返しながら
for(var j = 0;j < obj[i]['classLinks'].length; j++){
// リンクの名前をURL末尾から取得
var propertytext = obj[i]['classLinks'][j]['predicate'];
var propertysplit1 = propertytext.split("/");
var propertysplit2 = propertysplit1[propertysplit1.length - 1];
var propertysplit3 = propertysplit2.split("#");
propertytext = propertysplit3[propertysplit3.length - 1];
// 深さが最大より大きければ更新
if(MAXDEPTH < j+1){
MAXDEPTH = j+1;
}
// ここまで共通ルートなら
if(isCommon){
// 今回も共通か確認するためのフラグ
var isCommonNow = false;
// nodes配列に同じlinkedClassが既にあるか確認
var targets = [];
for(var k = 0; k < ret['nodes'].length; k++){
// 同階層かつ同じ名前のものがあったらtargets配列に番号を追加
if(ret['nodes'][k]['group'] == (j+1) && obj[i]['classLinks'][j]['linkedClass'] == ret['nodes'][k]['uri']){
targets.push(k);
}
}
// 既にあった場合はlinks配列に同じlinkが存在するか確認
if(targets.length != 0){
// 先ほど見つけたtargetsの数だけ繰り返しながら
for(var l = 0; l