root/SPARQLBuilderWWW/web/newsparqlbuilder.js @ 241

リビジョン 241, 31.0 KB (コミッタ: lenz, 10 年 前)

細かな調整

  • 属性 svn:mime-type の設定値 text/plain
行番号 
1
2var PATHNUM = 0;
3var MAXDEPTH = 0;
4var TREESPACE = 0;
5var NODEHEIGHT = 50;
6var DRAWHEIGHT = 0;
7
8var endpoint = "";
9var startclass= "";
10var endclass = "";
11
12var defendpoint = "";
13var defstartclass= "";
14var defendclass = "";
15
16var jsontext = "";
17var pathobj = "";
18
19var pathlimit = 10;
20
21
22// 繝壹�繧ク隱ュ縺ソ霎シ縺ソ縺悟ョ御コ�ャ。隨ャ螳溯。�
23$(function(){
24
25        // 繝壹�繧ク縺ョ繝代�繝�Κ蛻�r霑ス蜉
26        initparts();
27
28        getParameter();
29
30        if(defendpoint != "" && defstartclass != "" && defendclass != ""){
31                openSPARQLBuilder();
32        }
33
34});
35
36function initparts(){
37        var sbdiv = $('div#SPARQLBUILDER');
38        if(sbdiv.find('div').length == 0){
39                var sbtop = '<div class="SBTopItems"><input type="button" class="SBTopButton" value="Open SPARQLBuilder" onclick="openSPARQLBuilder()"><input type="button" class="SBTopButton" value="Try with Sample" onclick="openSample(\'http://www.ebi.ac.uk/rdf/services/reactome/sparql\', \'http://www.biopax.org/release/biopax-level3.owl#Protein\', \'http://www.biopax.org/release/biopax-level3.owl#Pathway\')"><br><textarea class="SBSparqlArea" rows="10"></textarea><br><input type="button" class="SBTopButton" value="Send SPARQL" onclick="sendSPARQL()"><input type="button" class="SBTopButton" value="Download Result" onclick="downloadResult()"></div><div class="SBTutorialLink">Tutorial for SPARQL Builder GUI is <a href="http://www.sparqlbuilder.org/doc/how-to-use-sparql-builder-gui/" target="_blank">here</a>.</div>';
40                var sbmodal = '<div class="SBModalView"><div class="SBModalContents"><div class="SBForms"><div class="SBSelects"><select class="SBEndPointSelect"></select><select class="SBStartClassSelect"></select><select class="SBEndClassSelect"></select></div><div class="SBPermaLink"><input type="button" class="SBPermaLinkButton" value="Permalink" onclick="openPermalink()" disabled="disabled"></div></div><div class="SBMessage"><div class="SBResult"><span class="SBPathnum"></span> Path<span class="SBPlural"></span> found.</div><input type="button" class="SBViewAll" value="View All Path" onclick="viewAll()"></div><div class="SBGraph"><div class="SBAjaxLoad" style="display: none;"><div class="SBLoadIcon"><img src="images/ajax-loader.gif"></div></div></div><div class="SBPath"><div class="SBSelectedPath"></div></div><div class="SBModalButtons"><input type="button" class="SBModalButton" value="Close" onclick="closeSPARQLBuilder()"></div></div></div>';
41
42                sbdiv.html(sbtop);
43                $('body').append(sbmodal);
44        }
45
46        $('.SBModalView').click(function(){
47                $(this).fadeOut(700);
48        });
49
50        $('.SBModalContents').click(function(){
51                event.stopPropagation();
52        });
53
54        loadEndPointList();
55
56        $(".SBEndPointSelect").change(function() {
57                changeEndPoint();
58        });
59
60        $(".SBStartClassSelect").change(function() {
61                startClass = $(".SBStartClassSelect").val();
62                loadPathList();
63        });
64        $(".SBEndClassSelect").change(function() {
65                endClass = $(".SBEndClassSelect").val();
66                loadPathList();
67        });
68
69        d3.select('.SBModalView').on("mousewheel", function(){
70                event.preventDefault();
71        });
72
73}
74
75
76function getParameter()
77{
78    if( 1 < window.location.search.length )
79    {
80        var query = window.location.search.substring( 1 );
81        var parameters = query.split( '&' );
82
83        for( var i = 0; i < parameters.length; i++ )
84        {
85            var element = parameters[ i ].split( '=' );
86            if(decodeURIComponent( element[ 0 ] ) == "ep"){
87                defendpoint = decodeURIComponent( element[ 1 ] )
88            }else if(decodeURIComponent( element[ 0 ] ) == "st"){
89                defstartclass = decodeURIComponent( element[ 1 ] )
90            }else if(decodeURIComponent( element[ 0 ] ) == "en"){
91                defendclass = decodeURIComponent( element[ 1 ] )
92            }
93        }
94    }
95}
96
97
98function openSPARQLBuilder(){
99
100        $('.SBModalView').css('top', $(window).scrollTop()).css('height', window.innerHeight).fadeIn();
101
102        resizeModalView();
103
104        $(".SBEndPointSelect").select2();
105        $(".SBStartClassSelect").select2();
106        $(".SBEndClassSelect").select2();
107
108        if(defendpoint != "" && defstartclass != "" && defendclass != ""){
109
110                $('.SBStartClassSelect').on('lccomplete', function(){
111                        $('.SBStartClassSelect').val(defstartclass);
112                        defstartclass = "";
113                        $('.SBEndClassSelect').val(defendclass);
114                        defendclass = "";
115
116                        $(".SBEndPointSelect").select2();
117                        $(".SBStartClassSelect").select2();
118                        $(".SBEndClassSelect").select2();
119
120                        $('.SBStartClassSelect').unbind('lccomplete');
121                });
122
123                loadPathList();
124
125                var eplist = $('.SBEndPointSelect option');
126
127                if(eplist.length == 0){
128                        $('.SBEndPointSelect').on('epcomplete', function(){
129                                $('.SBEndPointSelect').val(defendpoint);
130                                defendpoint = "";
131                                loadClassList();
132                                $('.SBEndPointSelect').unbind('epcomplete');
133                        });
134                }else{
135                        $('.SBEndPointSelect').val(defendpoint);
136                        defendpoint = "";
137                        loadClassList();
138                }
139        }
140}
141
142function resizeModalView(){
143
144        if($('.SBModalView').css('display') == 'block'){
145                var mvw = $('.SBModalContents').width();
146                var mvh = $('.SBModalContents').height();
147                $('.SBModalContents .SBForms').css('width', (mvw - 201) + 'px').css('height', 56 + 'px');
148                $('.SBModalContents .SBMessage').css('width', 200 + 'px').css('height', 56 + 'px');
149                $('.SBModalContents .SBGraph').css('width', (mvw - 201) + 'px').css('height', (mvh - 57) + 'px');
150                $('.SBModalContents .SBPath').css('width', 180 + 'px').css('height', (mvh - 77 - 26) + 'px');
151                $('.SBModalContents .SBModalButtons').css('width', 200 + 'px').css('height', '26px');
152
153                var selw = Math.floor($('.SBModalContents .SBSelects').width());
154
155                if(selw % 2 == 1){
156                        selw--;
157                }
158                $('.SBModalContents .SBSelects').css('width', selw);
159        }
160}
161
162function openSample(ep, st, en){
163        defendpoint = ep;
164        defstartclass = st;
165        defendclass = en;
166
167        openSPARQLBuilder();
168}
169
170function openPermalink(){
171        var baseurl = location.href;
172        var spliturl = baseurl.split('?');
173        var url = spliturl[0] + "?ep=" + encodeURIComponent(endpoint) + "&st=" + encodeURIComponent(startclass) + "&en=" + encodeURIComponent(endclass);
174
175        window.open(url);
176}
177
178function closeSPARQLBuilder(){
179        $('.SBModalView').fadeOut();
180}
181
182function switchLoadIcon(mode) {
183        if(mode == "view"){
184                $('.SBAjaxLoad').show();
185        }else{
186                $('.SBAjaxLoad').hide();
187        }
188};
189
190function loadEndPointList(){
191        $('.SBSaveESE').attr('disabled', true);
192        var url = 'http://www.sparqlbuilder.org/api/eplist';
193        $.ajax({
194                url: url,
195                success: function(data) {
196                        var list = eval(data);
197                        $(".SBEndPointSelect").empty();
198                        $(".SBEndPointSelect").append('<option value="SBDefault">SELECT Endpoint</option>');
199                        for (var i = 0; i < list.length; ++i) {
200                                $(".SBEndPointSelect").append('<option value="' + list[i] + '">' + list[i] + '</option>');
201                                switchLoadIcon("hide");
202                                if($('.SBModalView').attr('display') == 'block'){
203                                        $(".SBEndPointSelect").select2();
204                                        $(".SBStartClassSelect").select2();
205                                        $(".SBEndClassSelect").select2();
206                                }
207                        }
208                        $(".SBEndPointSelect").trigger(new $.Event('epcomplete'));
209                },
210        });
211}
212
213changeEndPoint = function() {
214        endpoint = $(".SBEndPointSelect").val();
215        if(endpoint != "SBDefault"){
216                loadClassList();
217        }
218};
219
220loadClassList = function() {
221        $('.SBSaveESE').attr('disabled', true);
222        var url = "http://www.sparqlbuilder.org/api/clist?ep=" + encodeURIComponent(endpoint);
223        $.ajax({
224                type : "GET",
225                url : url,
226                async : false,
227                success : function(data) {
228                        var list = eval(data);
229                        $(".SBStartClassSelect").empty();
230                        $(".SBEndClassSelect").empty();
231                        $(".SBStartClassSelect").append('<option value="SBDefault">SELECT StartClass</option>');
232                        $(".SBEndClassSelect").append('<option value="SBDefault">SELECT EndClass</option>');
233                        for (var i = 0; i < list.length; ++i) {
234                                $(".SBStartClassSelect").append('<option value="' + list[i]['uri'] + '">' + list[i]['label'] + ' (' + list[i]['number'] + ')' + '</option>');
235                                $(".SBEndClassSelect").append('<option value="' + list[i]['uri'] + '">' + list[i]['label'] + ' (' + list[i]['number'] + ')' + '</option>');
236                        }
237                        $(".SBStartClassSelect").select2();
238                        $(".SBEndClassSelect").select2();
239                        $(".SBStartClassSelect").trigger(new $.Event('lccomplete'));
240                }
241        });
242};
243
244loadPathList = function() {
245        startclass = $(".SBStartClassSelect").val();
246        endclass = $(".SBEndClassSelect").val();
247
248        if(defendpoint != "" && defstartclass != "" && defendclass != ""){
249                endpoint = defendpoint;
250                startclass = defstartclass;
251                endclass = defendclass;
252        }
253
254        $('.SBSaveESE').attr('disabled', true);
255        if (startclass == null || endclass == null || startclass == "SBDefault" || endclass == "SBDefault"){
256                return;
257        }
258
259        pathlimit = 10;
260
261        $('.SBResult').hide();
262        $('.SBViewAll').hide();
263        $('.SBSelectedPath').html('<h1>Please <span style="color: hsl(150, 50%, 75%);">select a leaf node</span> and click to generate a SPARQL</h1><img src=\"images/pathline.png\" style="display:none;">');
264
265        var url = "http://www.sparqlbuilder.org/api/plist?ep=" + encodeURIComponent(endpoint)
266                                                                                                                        + "&startclass=" + encodeURIComponent(startclass)
267                                                                                                                        + "&endclass="   + encodeURIComponent(endclass);
268
269        switchLoadIcon("view");
270        setTimeout(function(){
271                $.ajax({
272                        type : "GET",
273                        url : url,
274                        //async : false,
275                        timeout : 1000000,
276                        success : function(data) {
277                                jsontext = data;
278                                view_map();
279                                switchLoadIcon("hide");
280                                $('.SBSaveESE').attr('disabled', false);
281                        },
282                        error: function(data){
283                                switchLoadIcon("hide");
284                                alert("error: ", data);
285                        }
286                });
287        }, 100);
288};
289
290function viewAll(){
291        pathlimit = 0;
292        view_map();
293}
294
295generateSPARQL = function() {
296    var path = JSON.stringify(pathobj);
297    var url = 'http://www.sparqlbuilder.org/api/sparql?path=' + encodeURIComponent(path);
298    $.ajax({
299        type: "GET",
300        url : url,
301        dataType: 'text',
302        async: false,
303        success : function(data) {
304            $(".SBSparqlArea").val(data);
305            closeSPARQLBuilder();
306        }
307    });
308};
309
310function sendSPARQL(){
311        var sendep = $(".SBEndPointSelect").val();
312
313        var query = $(".SBSparqlArea").val();
314
315        if(sendep == "SBDefault" || query == ""){
316                return;
317        }
318
319        query = encodeURIComponent(query);
320
321        openpage = sendep + "?format=text%2Fhtml&query=" + query;
322
323        window.open(openpage);
324}
325
326function downloadResult(){
327
328        var sendep = $(".SBEndPointSelect").val();
329
330        var query = $(".SBSparqlArea").val();
331
332        if(sendep == "SBDefault" || query == ""){
333                return;
334        }
335
336        qr = sendQuery(sendep,query);
337
338        qr.fail(
339                function (xhr, textStatus, thrownError) {
340                        alert("Error: A '" + textStatus+ "' occurred.");
341                }
342        );
343        qr.done(
344                function (d) {
345                        downloadCSV(d.results.bindings);
346                }
347        );
348}
349
350function downloadCSV(data){
351
352        if (data instanceof Array) {
353                var result_txt ="";
354
355                var i=0;
356                for ( var key in data[0]) {
357                        if(i>0){result_txt +=",";}
358                        result_txt += key;
359                        i++;
360                }
361
362                result_txt += "\n";
363
364                for (var d = 0; d < data.length; d++) {
365                        var i = 0;
366                        for ( var key in data[d]) {
367                                if(i>0){result_txt +=",";}
368                                result_txt += data[d][key].value;
369                                i++;
370                        }
371                        result_txt += '\n';
372                }
373
374                var blob = new Blob( [result_txt], {type: 'text/plain'} )
375
376                var link = document.createElement('a')
377                link.href = URL.createObjectURL(blob)
378                link.download = 'result' + '.csv'
379
380                document.body.appendChild(link) // for Firefox
381                link.click()
382                document.body.removeChild(link) // for Firefox
383        }
384};
385
386
387// 繧ー繝ゥ繝墓緒逕サ驛ィ蛻�
388view_map = function(){
389
390        // make_data繝。繧ス繝�ラ縺ョ邨先棡繧貞叙蠕�
391        var json = make_data();
392
393        // 繝代せ謨ー縺�縺ァ縺ェ縺代l縺ー
394        if(json['nodes'].length != 0){
395
396                // 蜃コ譚・荳翫′縺」縺溽オ先棡繧呈ク。縺励※繝槭ャ繝嶺ク翫�蠎ァ讓吶r繧サ繝�ヨ
397                set_map_location(0, json['nodes'], json['links']);
398
399                // SVG縺ョ蟷�→鬮倥&逕ィ縺ォ謠冗判鬆伜沺縺ョ繧オ繧、繧コ繧貞叙蠕�
400                var width = $('.SBGraph').width();
401                var height = $('.SBGraph').height();
402                // SVG蜀��繧ー繝ゥ繝暮Κ蛻�ォ倥&�医ヱ繧ケ謨ー縺ォ蠢懊§繧具シ峨r繧サ繝�ヨ
403                var graphheight = ((NODEHEIGHT * 1.5) * PATHNUM) + (NODEHEIGHT / 2);
404
405                // 繧ケ繧ウ繧「陦ィ遉コ縺ョ繝槭�繧ク繝ウ
406                var scoreleftmargin = NODEHEIGHT * 1.5;
407
408                // SVG縺ョ蜑企勁
409                d3.select(".SBGraph svg").remove();
410                // 逕サ髱「繧オ繧、繧コ縺ォ蜷医o縺婀VG縺ョ霑ス蜉
411                var svg = d3.select(".SBGraph").append("svg")
412                        .attr("width", width)
413                        .attr("height", height)
414                        // 繝薙Η繝シ繝懊ャ繧ッ繧ケ縺ョ繧サ繝�ヨ
415                        .attr("viewBox", "0 0 " + width + " " + height)
416                        // 繧ケ繧ッ繝ュ繝シ繝ォ縺輔l縺溘i
417                        .on("mousewheel", function(){
418                                // 迴セ蝨ィ縺ョ繝薙Η繝シ繝懊ャ繧ッ繧ケ縺ョ迥カ諷九r蜿門セ�
419                                var vb = svg.attr("viewBox");
420                                // 繧ケ繝壹�繧ケ縺ァ蛹コ蛻�j蜷�€、縺ォ蛻�ァ」
421                                var spvb = vb.split(" ");
422
423                                // 繝薙Η繝シ繝懊ャ繧ッ繧ケ縺ョy縺ョ蛟、縺九i莉雁屓縺ョ繝帙う繝シ繝ォ繧、繝吶Φ繝医�蟾ョ蛻�r蠑輔¥
424                                var vby = (parseInt(spvb[1]) - event.wheelDelta);
425
426                                // 0繧貞牡縺」縺ヲ縺�◆繧�縺ォ
427                                if(vby < 0){
428                                        vby = 0;
429                                // 繧ケ繧ッ繝ュ繝シ繝ォ荳企剞�医げ繝ゥ繝輔し繧、繧コ蠑輔¥陦ィ遉コ鬆伜沺繧オ繧、繧コ�峨r雜�∴縺ヲ縺�◆繧芽」懈ュ」
430                                }else if(vby > (graphheight - height)){
431                                        vby = (graphheight - height);
432                                        // 陬懈ュ」縺励◆邨先棡0繧貞牡縺」縺ヲ縺�◆繧�縺ォ
433                                        if(vby < 0){
434                                                vby = 0;
435                                        }
436                                }
437
438                                // 縺薙%縺セ縺ァ縺ァ縺ァ縺阪◆y繧偵そ繝�ヨ縺励ン繝・繝シ繝懊ャ繧ッ繧ケ繧呈峩譁ー
439                                svg.attr("viewBox", "0 " + vby + " " + width + " " + height);
440                    });
441
442                // 閭梧勹縺ョ霑ス蜉�磯ォ倥&莉・螟悶�謠冗判鬆伜沺縺昴�縺セ縺セ��
443                var bg = svg
444                        .append("rect")
445                        .attr("x", 0)
446                        .attr("y", 0)
447                        .attr("width", width)
448                        .attr("height", function(){
449                                // 繧ー繝ゥ繝暮Κ蛻��鬮倥&縺梧緒逕サ鬆伜沺縺ョ鬮倥&繧貞牡縺」縺ヲ縺�◆繧会シ医ヱ繧ケ縺悟ー代↑縺代l縺ー�画緒逕サ鬆伜沺縺ョ鬮倥&繧定ソ斐☆
450                                        if(graphheight < height){
451                                                return height;
452                                        }else{
453                                                return graphheight;
454                                        }
455                                })
456                        // 閭梧勹繧定埋縺�げ繝ャ繝シ縺ォ
457                        .attr("fill", "#fafafa");
458
459                // links驟榊�繧呈ク。縺励Μ繝ウ繧ッ縺ョ菴懈�
460                var link = svg.selectAll(".link")
461                        .data(json.links)
462                        .enter().append("line")
463                        .attr("class", "link")
464                        .style("stroke", "#999")
465                        .style("stroke-opacity", 0.6)
466                        .style("stroke-width", 2);
467
468                // nodes驟榊�繧呈ク。縺励ヮ繝シ繝峨�菴懈�
469                var node = svg.selectAll(".node")
470                        .data(json.nodes)
471                        .enter().append("circle")
472                        .attr("class", "node")
473                        .attr("r", (NODEHEIGHT / 2))
474                        .attr("cx", function(d) { return d.x;} )
475                        .attr("cy",  function(d) { return d.y; })
476                        .style("fill", function(d) { return d.nodecolor; })
477                        .style("stroke", '#fafafa')
478                        .style("stroke-width", '1.5px')
479                        // 譛ォ遶ッ繝弱�繝峨�縺ソ繝槭え繧ケ繧「繧、繧ウ繝ウ繧偵�繧、繝ウ繧ソ繝シ縺ォ
480                        .style("cursor", function(d){
481                                if(d.path == "notend"){
482                                        return 'normal';
483                                }else{
484                                        return 'pointer';
485                                }
486                        });
487
488                // nodes驟榊�繧呈ク。縺励ヮ繝シ繝峨ユ繧ュ繧ケ繝医�菴懈�
489                var tnode = svg.selectAll("text.node")
490                        .data(json.nodes)
491                        .enter().append("svg:text")
492                        .attr("class", "tnode")
493                        .attr("x", function(d) { return d.x; })
494                        .attr("y", function(d) { return d.y; })
495                        .text(function(d) { return d.name; })
496                        .style("fill", '#000000')
497                        .style("text-anchor", 'middle')
498                        .style("pointer-events", "none");
499
500                // 繝ェ繝ウ繧ッ繝�く繧ケ繝医�菴懈�
501                var tlink = svg.selectAll("text.link")
502                        .data(json.links)
503                        .enter().append("svg:text")
504                        .attr("class", "tlink")
505                        .attr("x", function(d) { return (json.nodes[d.source].x + json.nodes[d.target].x) / 2; })
506                        .attr("y", function(d) { return (json.nodes[d.source].y + json.nodes[d.target].y) / 2; })
507                        .style("fill", '#000000')
508                        .style("text-anchor", 'middle');
509
510                // 繧ケ繧ウ繧「繝�く繧ケ繝医�菴懈�
511                var tscore = svg.selectAll("text.score")
512                        .data(json.nodes)
513                        .enter().append("svg:text")
514                        .attr("class", "tscore")
515                        .attr("x", function(d) { return (d.x + scoreleftmargin); })
516                        .attr("y", function(d) { return d.y + 4; })
517                        .text(function(d) { return d.score; })
518                        .style("fill", '#ff0000')
519                        .style("text-anchor", 'middle')
520                        .style("pointer-events", "none");
521
522                // 繝弱�繝峨∈縺ョ繧ェ繝ウ繝槭え繧ケ縺ァ繝代せ謗「邏「縲√ヱ繧ケ荳ュ縺ョ繝ェ繝ウ繧ッ譁�ュ励r陦ィ遉コ
523                node.on("mouseover", function(d){
524
525                        // 陦ィ遉コ縺吶k繝代せ菫晏ュ倡畑驟榊�
526                        var path = [];
527                        // 繝代せ陦ィ遉コ諠�ア菫晏ュ倡畑驟榊�
528                        var pathname = [];
529
530                        // 縺セ縺壹が繝ウ繝槭え繧ケ縺輔l縺溘ヮ繝シ繝峨�id縺ィ蜷榊燕繧偵◎繧後◇繧瑚ソス蜉
531                        path.push(d.nodeid);
532                        pathname.push(d.name);
533
534                        // 繝代せ謗「邏「
535                        do{
536                                // 繝ェ繝ウ繧ッ縺ョ謨ー縺縺醍ケー繧願ソ斐@
537                                for(var i = 0; i < link.data().length; i++){
538                                        // 迴セ蝨ィ縺ョ譛€蠕悟ーセ縺ォ郢九′繧九Μ繝ウ繧ッ縺後≠繧後�
539                                        if(path[(path.length-1)] == link.data()[i].target){
540                                                // 縺昴�繝ェ繝ウ繧ッ縺ョ繧ス繝シ繧ケ蛛エ繝弱�繝峨�id繧定ソス蜉
541                                                path.push(link.data()[i].source);
542                                                // 縺昴�繝ェ繝ウ繧ッ縺ョ蜷榊燕縺ィ繧ス繝シ繧ケ蛛エ繝弱�繝峨�蜷榊燕繧定ソス蜉
543                                                pathname.push(link.data()[i].property);
544                                                pathname.push(node.data()[link.data()[i].source].name);
545                                        }
546                                }
547                        // 繝ォ繝シ繝医ヮ繝シ繝峨↓霎ソ繧顔捩縺上∪縺ァ郢ー繧願ソ斐☆
548                        }while(path[(path.length-1)] != 0);
549
550                        // 繝ォ繝シ繝医ヮ繝シ繝峨∪縺溘�騾比クュ繝弱�繝峨↑繧�
551                        if(d.nodeid == 0 || d.path == "notend"){
552                                // 繝代せ陦ィ遉コ鬆伜沺繧偵ョ繝輔か繝ォ繝医↓
553                                $('.SBSelectedPath').html('<h1>Please <span style="color: hsl(150, 50%, 75%);">select a leaf node</span> and click to generate a SPARQL</h1>');
554                        // 譛ォ遶ッ繝弱�繝峨↑繧�
555                        }else{
556
557                                // 繝代せ陦ィ遉コ鬆伜沺逕ィ譁�ュ怜�
558                                var resultText = '';
559                                // 繝代せ縺ョ蜷榊燕驟榊�蛻�セ後m縺九i郢ー繧願ソ斐@縺ェ縺後i
560                                for (var i = pathname.length;i > 0; i--){
561                                        // 螂�焚逡ェ逶ョ�医ヮ繝シ繝会シ峨↑繧�
562                                        if(i % 2 == 1){
563                                                // 繝ォ繝シ繝医°騾比クュ縺区忰遶ッ縺九↓蠢懊§縺ヲ繧ッ繝ゥ繧ケ繧呈欠螳壹@霑ス險�
564                                                if(i == 1){
565                                                        resultText = resultText + "<div class=\"SBLeafNode\">" + pathname[i - 1] + "</div>";
566                                                }else if(i == pathname.length){
567                                                        resultText = resultText + "<div class=\"SBRootNode\">" + pathname[i - 1] + "</div>";
568                                                }else{
569                                                        resultText = resultText + "<div class=\"SBPathNode\">" + pathname[i - 1] + "</div>";
570                                                }
571                                        // 蛛カ謨ー逡ェ逶ョ�医Μ繝ウ繧ッ�峨�繝ェ繝ウ繧ッ逕サ蜒上r蜑榊セ後↓縺、縺題ソス險�
572                                        }else{
573                                                resultText = resultText + "<img src=\"images/pathline.png\"><div class=\"SBPathProperty\">" + pathname[i - 1] + "</div><img src=\"images/pathline.png\">";
574                                        }
575                                }
576
577                                // 繝代せ陦ィ遉コ鬆伜沺縺ョ蜀�ョケ繧呈嶌縺肴鋤縺�
578                                $('.SBSelectedPath').html(resultText);
579
580                                // 繧オ繝シ繝悶Ξ繝�ヨ縺ォ騾√j霑斐☆繝代せ繧ェ繝悶ず繧ァ繧ッ繝医r菫晏ュ�
581                                pathobj = d.path;
582
583                                // 繝代せ陦ィ遉コ鬆伜沺縺ョ陦ィ遉コ險ュ螳壹rvisivle縺ォ
584                                $('.SBPath').css('overflow-y', 'visible');
585
586                                // 繝代せ蜀�ョケ縺ョ鬮倥&縺後ヱ繧ケ陦ィ遉コ鬆伜沺繧定カ�∴縺ヲ縺�◆繧�
587                                if($('.SBPath').height() < $('.SBSelectedPath').innerHeight()){
588                                        // 繝代せ陦ィ遉コ鬆伜沺縺ョ陦ィ遉コ險ュ螳壹r繧ケ繧ッ繝ュ繝シ繝ォ縺ォ
589                                        $('.SBPath').css('overflow-y', 'scroll');
590                                }
591                        }
592
593                        // 繧ェ繝ウ繝槭え繧ケ縺輔l縺溘ヮ繝シ繝峨�鬮倥&縺ォ隕ェ繧貞粋繧上○繧九◆繧√↓蜷医o縺帙k鬮倥&繧剃ソ晏ュ�
594                        var movey = d.y;
595
596                        // 蜷�ヮ繝シ繝峨↓蟇セ縺�
597                        node
598                                // 霈ェ驛ュ邱壹�濶イ繧定ィュ螳�
599                                .style("stroke", function(d){
600                                        // 縺セ縺壹�閭梧勹濶イ�医ョ繝輔か繝ォ繝茨シ峨r謖�ョ�
601                                        var strokecolor = "#fafafa";
602
603                                        // 繝代せ縺ョ繝弱�繝画焚縺縺醍ケー繧願ソ斐@縺ェ縺後i
604                                        for(var n = 0; n < path.length; n++){
605                                                // 繝代せ蜀�↓蜷ォ縺セ繧後k繝弱�繝峨□縺」縺溘i
606                                                if(path[n] == d.nodeid){
607                                                        // 霈ェ驛ュ邱壹r襍、縺ォ
608                                                        strokecolor = "#ffaaaa";
609                                                }
610                                        }
611
612                                        // 縺薙%縺セ縺ァ縺ァ蠕励i繧後◆霈ェ驛ュ邱壹�濶イ繧定ソ斐☆
613                                        return strokecolor;
614                                })
615                                // 鬮倥&縺ョ蛟、
616                                .attr("cy", function(d){
617
618                                        // 迴セ蝨ィ縺ョ鬮倥&繧貞叙蠕�
619                                        var currenty = d.y
620
621                                        // 繝代せ縺ョ繝弱�繝画焚縺縺醍ケー繧願ソ斐@縺ェ縺後i
622                                        for(var n = 0; n < path.length; n++){
623                                                // 繝代せ蜀�↓蜷ォ縺セ繧後k繝弱�繝峨□縺」縺溘i
624                                                if(path[n] == d.nodeid){
625                                                        // 蜀�Κ縺ァ謖√▽鬮倥&繧偵が繝ウ繝槭え繧ケ縺輔l縺溘ヮ繝シ繝峨→蜷後§縺ォ�亥�謠冗判譎ゅ↓蜿肴丐��
626                                                        d.y = movey;
627                                                }
628                                        }
629
630                                        // 莉翫�迴セ譎らせ縺ョ鬮倥&繧定ソ斐☆
631                                        return currenty;
632                                });
633
634                        // 蜷�Μ繝ウ繧ッ繝�く繧ケ繝医↓蟇セ縺�
635                        tlink
636                                // 繝�く繧ケ繝郁。ィ遉コ蛻、螳�
637                                .text(function(d) {
638                                        // 繝�ヵ繧ゥ繝ォ繝医〒遨コ繧偵そ繝�ヨ
639                                        var linktext = "";
640
641                                        // 繝代せ縺ョ繝弱�繝画焚縺縺醍ケー繧願ソ斐@縺ェ縺後i
642                                        for(var t = 0; t < path.length; t++){
643                                                // 閾ェ霄ォ縺後◎縺ョ繝弱�繝峨∈謗・邯壹@縺ヲ縺�k繝ェ繝ウ繧ッ縺ェ繧峨�
644                                                if(path[t] == d.target){
645                                                        // 繝ェ繝ウ繧ッ繝�く繧ケ繝医↓繝励Ο繝代ユ繧」縺ョ蛟、繧偵そ繝�ヨ
646                                                        linktext = d.property
647                                                }
648                                        }
649
650                                        // 縺薙%縺セ縺ァ縺ァ縺ァ縺阪◆繝ェ繝ウ繧ッ繝�く繧ケ繝医r霑斐☆
651                                        return linktext;
652                                });
653
654                        // 蜷�Μ繝ウ繧ッ縺ォ蟇セ縺�
655                        link
656                                // 邱壹�濶イ蛻、螳�
657                                .style("stroke", function(d){
658
659                                        var strokecolor = "#999";
660
661                                        // 繝代せ縺ョ繝弱�繝画焚縺縺醍ケー繧願ソ斐@縺ェ縺後i
662                                        for(var t = 0; t < path.length; t++){
663                                                // 閾ェ霄ォ縺後◎縺ョ繝弱�繝峨∈謗・邯壹@縺ヲ縺�k繝ェ繝ウ繧ッ縺ェ繧峨�
664                                                if(path[t] == d.target){
665                                                        // 繝ェ繝ウ繧ッ縺ョ濶イ縺ォ襍、繧偵そ繝�ヨ
666                                                        strokecolor = "#ffaaaa"
667                                                }
668                                        }
669
670                                        // 邱壹�濶イ繧定ソ斐☆
671                                        return strokecolor;
672                                });
673
674                        // 縺薙%縺セ縺ァ縺ョ險ュ螳壹r蜈�↓蜀肴緒逕サ
675                        redraw();
676
677                // 繧ッ繝ェ繝�け縺輔l縺溘→縺�
678                }).on("click", function(d){
679                        // 譛ォ遶ッ繝弱�繝峨↑繧峨せ繝代�繧ッ繝ォ逋コ陦�
680                        if(d.path != "notend"){
681                                generateSPARQL();
682                        }
683                });
684
685                // 蜀肴緒逕サ髢「謨ー
686                var redraw = function (duration){
687
688                        // 縺九¢繧区凾髢薙′譛ェ謖�ョ壹↑繧峨�
689                        if(duration == undefined){
690                                // 0.5遘偵°縺代※繧「繝九Γ繝シ繧キ繝ァ繝ウ
691                                duration = 500;
692                        }
693
694                        // 蜷�Μ繝ウ繧ッ縺ォ縺、縺�※險ュ螳壹&繧後◆菴咲スョ縺ォ蜀肴緒逕サ
695                        link
696                                .transition()
697                                .duration(duration)
698                                .attr("x1", function(d) {return node.data()[d.source].x;})
699                                .attr("y1", function(d) {return node.data()[d.source].y;})
700                                .attr("x2", function(d) {return node.data()[d.target].x;})
701                                .attr("y2", function(d) {return node.data()[d.target].y;});
702
703                        // 蜷�ヮ繝シ繝峨↓縺、縺�※險ュ螳壹&繧後◆菴咲スョ縺ォ蜀肴緒逕サ
704                        node
705                                .transition()
706                                .duration(duration)
707                                .attr("cx", function(d) {return d.x;})
708                                .attr("cy", function(d) {return d.y;});
709
710                        // 蜷�ヮ繝シ繝峨ユ繧ュ繧ケ繝医↓縺、縺�※險ュ螳壹&繧後◆菴咲スョ縺ォ蜀肴緒逕サ縲√ユ繧ュ繧ケ繝域緒逕サ菴咲スョ繧剃ク贋ク九↓謖ッ繧�
711                        tnode
712                                .transition()
713                                .duration(duration)
714                                .attr("x", function(d) {return d.x;})
715                                .attr("y", function(d) {
716                                        // 繝�ヵ繧ゥ繝ォ繝医〒蟆代@荳九£繧�
717                                        var updown = (NODEHEIGHT * 0.4);
718                                        // 螂�焚逡ェ逶ョ縺ョ豺ア縺輔↑繧牙ー代@荳翫£繧�
719                                        if(d.group % 2 == 1){
720                                                updown = -(NODEHEIGHT * 0.2);
721                                        }
722                                        // 縺昴�蛟、繧帝ォ倥&縺ォ霑斐☆縺薙→縺ァ繝�く繧ケ繝域緒逕サ菴咲スョ縺御コ偵>驕輔>縺ォ縺ェ繧�
723                                        return d.y + updown;
724                                });
725
726                        // 蜷�Μ繝ウ繧ッ繝�く繧ケ繝医↓縺、縺�※險ュ螳壹&繧後◆菴咲スョ縺ォ蜀肴緒逕サ
727                        tlink
728                                .transition()
729                                .duration(duration)
730                                .attr("x", function(d) {return (node.data()[d.source].x + node.data()[d.target].x) / 2;})
731                                .attr("y", function(d) {return ((node.data()[d.source].y + node.data()[d.target].y) / 2) + 4;});
732
733                };
734
735                // 蛻晏屓縺ョ縺ソduration繧�縺ィ謖�ョ壹@蜀肴緒逕サ�医い繝九Γ繝シ繧キ繝ァ繝ウ縺ェ縺暦シ�
736                redraw(0);
737
738        }else{
739                // SVG縺ョ蜑企勁
740                d3.select(".SBGraph svg").remove();
741        }
742};
743
744
745// 繝��繧ソ菴懈�繝。繧ス繝�ラ
746make_data = function(){
747
748        // 邨先棡逕ィ繧ェ繝悶ず繧ァ繧ッ繝医r蛻晄悄蛹�
749        ret = new Object();
750        ret['nodes'] = new Array();
751        ret['links'] = new Array();
752
753        // 蜷�ィョ螟画焚縺ョ蛻晄悄蛹�
754        PATHNUM = 0;
755        MAXDEPTH = 0;
756        TREESPACE = 0;
757        DRAWHEIGHT = NODEHEIGHT;
758
759        // 陦ィ遉コ縺吶k繝代せ謨ー
760        var viewnum;
761
762        // jsontext繧貞叙蠕�
763        var obj = jsontext;
764
765        // 邨先棡繝代せ謨ー縺ョ繧ケ繧ソ繧、繝ォ繧偵Μ繧サ繝�ヨ
766        $('.SBResult').css('color', 'black').css('font-weight', 'normal').css('margin-top', '4px');
767
768        // 隍�焚蠖「縺ョs繧偵▽縺代k
769        $('.SBPlural').text('s');
770
771        // 繝代せ縺ョ謨ー縺�縺縺」縺溘i
772        if(obj.length == 0){
773                // 邨先棡繝代せ謨ー縺ョ繧ケ繧ソ繧、繝ォ繧定オ、縺ョ螟ェ蟄励↓縺鈴伜沺蜀�ク贋ク倶クュ螟ョ縺ォ
774                $('.SBResult').css('color', 'red').css('font-weight', 'bold').css('margin-top', '20px');
775                // 隍�焚蠖「縺ョs繧貞炎髯、
776                $('.SBPlural').text('');
777        // 繝代せ謨ー縺�縺ェ繧�
778        }else if(obj.length == 1){
779                // 隍�焚蠖「縺ョs繧貞炎髯、
780                $('.SBPlural').text('');
781        }
782
783        // 繝代せ縺ョ謨ー縺悟香莉・荳九↑繧�
784        if(obj.length <= 10){
785                // 陦ィ遉コ謨ー繧偵ヱ繧ケ謨ー縺ォ
786                viewnum = obj.length;
787                // 邨先棡繝代せ謨ー縺ョ繧ケ繧ソ繧、繝ォ繧帝伜沺蜀�ク贋ク倶クュ螟ョ縺ォ
788                $('.SBResult').css('margin-top', '20px');
789                // 蜈ィ陦ィ遉コ繝懊ち繝ウ繧帝國縺�
790                $('.SBViewall').hide();
791        // 繝ェ繝溘ャ繝医′10縺ェ繧峨�
792        }else if(pathlimit == 10){
793                // 陦ィ遉コ繝代せ謨ー繧�0縺ォ
794                viewnum = 10;
795                // 蜈ィ陦ィ遉コ繝懊ち繝ウ繧貞�縺�
796                $('.SBViewall').show();
797        // 繝ェ繝溘ャ繝医′縺ェ縺代l縺ー
798        }else{
799                // 陦ィ遉コ繝代せ謨ー繧貞�繝代せ謨ー縺ォ
800                viewnum = obj.length;
801                // 邨先棡繝代せ謨ー縺ョ繧ケ繧ソ繧、繝ォ繧帝伜沺蜀�ク贋ク倶クュ螟ョ縺ォ
802                $('.SBResult').css('margin-top', '20px');
803                // 蜈ィ陦ィ遉コ繝懊ち繝ウ繧帝國縺�
804                $('.SBViewall').hide();
805        }
806
807        // 邨先棡繝代せ謨ー縺ョ蛟、繧呈峩譁ー
808        $('.SBPathnum').text(obj.length);
809        // 邨先棡繝代せ謨ー繧定。ィ遉コ
810        $('.SBResult').show();
811
812        // obj繝医ャ繝鈴嚴螻、縺ョ謨ー縺縺醍ケー繧願ソ斐@縺ェ縺後i
813        for(var i = 0; i < viewnum; i++){
814                if(i == 0){
815                        // 蛻晏屓縺縺代Ν繝シ繝医ヮ繝シ繝峨r繝励ャ繧キ繝・
816                        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%)'});
817                }
818                // 蜈医↓source縺ォ0�医Ν繝シ繝茨シ峨r莉」蜈・
819                var source = 0;
820                // 蜈ア騾壹Ν繝シ繝亥愛螳壹rtrue縺ォ
821                var isCommon = true;
822
823                // 縺薙�繝代せ縺ョ繧ケ繧ウ繧「繧貞叙蠕�
824                var score = obj[i]['score'];
825
826                // classLinks縺ョ謨ー縺縺醍ケー繧願ソ斐@縺ェ縺後i
827                for(var j = 0;j < obj[i]['classLinks'].length; j++){
828
829                        // 繝ェ繝ウ繧ッ縺ョ蜷榊燕繧旦RL譛ォ蟆セ縺九i蜿門セ�
830                        var propertytext = obj[i]['classLinks'][j]['predicate'];
831                        var propertysplit1 = propertytext.split("/");
832                        var propertysplit2 = propertysplit1[propertysplit1.length - 1];
833                        var propertysplit3 = propertysplit2.split("#");
834                        propertytext = propertysplit3[propertysplit3.length - 1];
835
836                        // 豺ア縺輔′譛€螟ァ繧医j螟ァ縺阪¢繧後�譖エ譁ー
837                        if(MAXDEPTH < j+1){
838                                MAXDEPTH = j+1;
839                        }
840                        // 縺薙%縺セ縺ァ蜈ア騾壹Ν繝シ繝医↑繧�
841                        if(isCommon){
842                                // 莉雁屓繧ょ�騾壹°遒コ隱阪☆繧九◆繧√�繝輔Λ繧ー
843                                var isCommonNow = false;
844                                // nodes驟榊�縺ォ蜷後§linkedClass縺梧里縺ォ縺ゅk縺狗「コ隱�
845                                var targets = [];
846                                for(var k = 0; k < ret['nodes'].length; k++){
847                                        // 蜷碁嚴螻、縺九▽蜷後§蜷榊燕縺ョ繧ゅ�縺後≠縺」縺溘itargets驟榊�縺ォ逡ェ蜿キ繧定ソス蜉
848                                        if(ret['nodes'][k]['group'] == (j+1) && obj[i]['classLinks'][j]['linkedClass'] == ret['nodes'][k]['uri']){
849                                                targets.push(k);
850                                        }
851                                }
852
853                                // 譌「縺ォ縺ゅ▲縺溷エ蜷医�links驟榊�縺ォ蜷後§link縺悟ュ伜惠縺吶k縺狗「コ隱�
854                                if(targets.length != 0){
855                                        // 蜈医⊇縺ゥ隕九▽縺代◆targets縺ョ謨ー縺縺醍ケー繧願ソ斐@縺ェ縺後i
856                                        for(var l = 0; l <targets.length; l++){
857                                                // links驟榊�縺ォ蜈ィ縺丞酔縺俶擅莉カ縺ョ繧ゅ�縺後≠繧九°遒コ隱�
858                                                for(var m = 0; m < ret['links'].length; m++){
859                                                        // 縺ゅ▲縺溷エ蜷井サ雁屓縺ョ繧ゅ�縺ッ霑ス蜉縺帙★source繧呈峩譁ー縺励※谺。縺ク
860                                                        if(ret['links'][m]['source'] == source && ret['links'][m]['target'] == targets[l] && ret['links'][m]['uri'] == obj[i]['classLinks'][j]['predicate'] && !isCommonNow){
861                                                                // 蜈ア騾壹Ν繝シ繝医ヵ繝ゥ繧ー繧偵が繝ウ
862                                                                isCommonNow = true;
863                                                                source = targets[l];
864                                                        }
865                                                }
866                                        }
867
868                                        // 蜷дarget繧堤「コ隱阪@縺ヲ蜈ア騾壹Ν繝シ繝医〒縺ッ縺ェ縺九▲縺溷エ蜷域眠隕剰ソス蜉
869                                        if(!isCommonNow){
870                                                isCommon = false;
871                                                ret['nodes'].push({'name': obj[i]['classLinks'][j]['label'], 'uri': obj[i]['classLinks'][j]['linkedClass'], 'group': (j+1), 'x':0, 'y':0, 'nodeid':ret['nodes'].length, 'path': 'notend', 'nodecolor': '#cccccc'});
872                                                ret['links'].push({'source':source, 'target':ret['nodes'].length - 1, 'property': propertytext, 'uri': obj[i]['classLinks'][j]['predicate']});
873                                                source = ret['nodes'].length - 1;
874                                        }
875
876                                // 縺ェ縺九▲縺溷エ蜷医�蛻・譚。莉カ縺ェ縺ョ縺ァ譁ー隕剰ソス蜉縺励※谺。縺ク
877                                }else{
878
879                                        isCommon = false;
880                                        ret['nodes'].push({'name': obj[i]['classLinks'][j]['label'], 'uri': obj[i]['classLinks'][j]['linkedClass'], 'group': (j+1), 'x':0, 'y':0, 'nodeid':ret['nodes'].length, 'path': 'notend', 'nodecolor': '#cccccc'});
881                                        ret['links'].push({'source':source, 'target':ret['nodes'].length - 1, 'property': propertytext, 'uri': obj[i]['classLinks'][j]['predicate']});
882                                        source = ret['nodes'].length - 1;
883                                }
884                        // 譌「縺ォ蜈ア騾壹Ν繝シ繝医〒縺ェ縺�↑繧画眠隕剰ソス蜉縺励※谺。縺ク
885                        }else{
886                                ret['nodes'].push({'name': obj[i]['classLinks'][j]['label'], 'uri': obj[i]['classLinks'][j]['linkedClass'], 'group': (j+1), 'x':0, 'y':0, 'nodeid':ret['nodes'].length, 'path': 'notend', 'nodecolor': '#cccccc'});
887                                ret['links'].push({'source':source, 'target':ret['nodes'].length - 1, 'property': propertytext, 'uri': obj[i]['classLinks'][j]['predicate']});
888                                source = ret['nodes'].length - 1;
889                        }
890
891                }
892                // 譛€蠕鯉シ域忰遶ッ繝弱�繝会シ峨↓蜷�ィョ蛟、繧定ソス蜉
893                ret['nodes'][ret['nodes'].length - 1]['path'] = obj[i];
894                ret['nodes'][ret['nodes'].length - 1]['score'] = score;
895                ret['nodes'][ret['nodes'].length - 1]['nodecolor'] = 'hsl(150, 50%, 75%)';
896                // 繝代せ謨ー繧定ソス蜉
897                PATHNUM++;
898        }
899        // 繝弱�繝蛾俣縺ョ繧ケ繝壹�繧ケ繧定ィ育ョ�
900        TREESPACE = $('.SBGraph').width() / (MAXDEPTH + 1);
901
902        // 縺ァ縺阪◆邨先棡繧定ソ斐☆
903        return ret;
904};
905
906set_map_location = function(myNodeIndex, nodes, links, depth, fromAngle, toAngle){
907
908    // depth縺梧悴螳夂セゥ縺ェ繧峨�0繧偵そ繝�ヨ
909    if (depth == undefined){
910        depth = 0;
911    }
912
913    // 蜷�ィョ蛻晄悄蛹�
914    var children = undefined;
915    var parent = undefined;
916    var parentsChildren = undefined;
917
918    // links驟榊�縺ョ謨ー縺縺醍ケー繧願ソ斐@縺ェ縺後i
919    for (var i=0; i<links.length; i++){
920        // 縺昴�links縺ョtarget縺稽yNodeIndex縺ェ繧英arent繧偵そ繝�ヨ
921        if (links[i].target == myNodeIndex){
922            parent = links[i].source;
923        }
924    }
925
926    // parent縺瑚ヲ九▽縺九▲縺ヲ縺�◆縺ェ繧峨�
927    if (parent != undefined){
928        // parent縺ィlinks繧呈ク。縺揚et_children繝。繧ス繝�ラ繧貞ョ溯。�
929        parentsChildren = get_children(parent, links);
930    }
931
932    if(myNodeIndex != 0){
933        DRAWHEIGHT += (NODEHEIGHT * 1.5);
934        var x = (depth * TREESPACE) + (TREESPACE / 3);
935        var y = DRAWHEIGHT;
936        nodes[myNodeIndex].x = x;
937        nodes[myNodeIndex].y = y;
938    }else{
939        var x = TREESPACE / 3;
940        var y = (NODEHEIGHT * 1.5) * ((PATHNUM - 1) / 2) + NODEHEIGHT;
941        nodes[myNodeIndex].x = x;
942        nodes[myNodeIndex].y = y;
943    }
944
945    children = get_children(myNodeIndex, links);
946
947    for (var i=0; i<children.length; i++){
948        if(i == 0){
949            DRAWHEIGHT -= (NODEHEIGHT * 1.5);
950        }
951        var child = children[i];
952        set_map_location(child, nodes, links, depth+1, fromAngle + ((toAngle - fromAngle) / children.length) * i, fromAngle + ((toAngle - fromAngle) / children.length) * (i+1));
953    }
954
955};
956
957// 謖�ョ壹&繧後◆隕ェ縺梧戟縺、蟄舌r霑斐☆
958get_children = function(index, links){
959    var children = new Array();
960    // links縺ョ謨ー縺縺醍「コ隱阪@縺ェ縺後i
961    for (var i=0; i<links.length; i++){
962        // 隕ェ縺梧ク。縺輔l縺溯ヲェ縺ィ荳€閾エ縺吶k譎ゅ�蟄舌r霑ス蜉
963        if (links[i].source == index){
964            children.push(links[i].target);
965        }
966    }
967    return children;
968};
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。