MediaWiki:Lipoquality.js

From Metabolomics.JP
(Difference between revisions)
Jump to: navigation, search
Line 2: Line 2:
 
// <span id="search"></span><span id="show"></span>
 
// <span id="search"></span><span id="show"></span>
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 2017/03/31 ・meta情報に「Tissue」を追加
+
//
// 2017/03/30 ・4行目の項目名を「Mutant type」から「Treatment」に変更
+
// 2017/03/15 ・パイチャートのタイトルを「ratio」から「Intensity ratio」へ変更
+
//            ・パイチャートのサイズ統一をキャンセル
+
//      ・パイチャートの表示/非表示の切り替えを実装
+
//      ・バンドルチャートにおいて、凡例をリアルタイムで変更可能に
+
// 2017/03/13 ・ヒートマップにおいて、カットオフ値が相対値ではなく絶対値で計算していた不具合を修正
+
// 2017/03/06 ・カットオフに「%」を追加
+
//            ・パイチャートのサイズを統一
+
//            ・カットオフ値をnumberからtextにして、2桁までしか入力できないよう修正(つまり、-9~99までに制限)
+
// 2017/01/31 ・ひとまとめにした棒グラフをサポート
+
// 2017/01/26 ・棒グラフで絶対量の時に、単位を表示するように変更
+
// 2017/01/06 ・新フォーマットに対応
+
//            ・barchartにおいて、ratioと絶対量で切り替え可能とした
+
//            ※ cutoffをどうするか検討中
+
// 2016/10/26 ・ヒートマップを拡大した状態でsetDataするとおかしな挙動になるため
+
//             必ずzoomOutするよう修正
+
//            ・画像出力できるよう修正
+
//            ・画像出力時、X軸がおかしくなるバグを修正
+
// 2016/10/18 ・highchartsの仕様が変わったようで、setDataやズームをするとX軸がおかしくなるので、
+
//             setCategoriesを使用して対処
+
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
Line 28: Line 8:
 
mw.loader.load( ['jquery.ui.sortable'] );
 
mw.loader.load( ['jquery.ui.sortable'] );
 
mw.loader.load('https://code.highcharts.com/stock/highstock.js', "text/javascript");
 
mw.loader.load('https://code.highcharts.com/stock/highstock.js', "text/javascript");
 +
importScript( 'MediaWiki:LipoqualityCommon.js' );
 +
importScript( 'MediaWiki:LipoqualityGet.js'    );
 +
importScript( 'MediaWiki:LipoqualitySearch.js' );
 +
importScript( 'MediaWiki:LipoqualityChart.js'  );
  
 
// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
 
// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
addOnloadHook(init);  
+
addOnloadHook(lipoqulityInit);  
  
// 初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
var gChartType;
const DEFAULT_BAR_COLOR = "#7cb5ec";
+
const MARGIN = 30;
+
var barColor = DEFAULT_BAR_COLOR;
+
var legendOptions = ["Sample name","Sample source","Sample type","Tissue","Treatment","Extraction","LC type","MS type","Ion mode","Quantification"];
+
  
function init()
+
// 初期化 //////////////////////////////////////////////////////////////////////////////////////////////////////
 +
function lipoqulityInit()
 
{
 
{
 
// highstock.jsに依存するため、別で読み込む
 
// highstock.jsに依存するため、別で読み込む
Line 48: Line 29:
 
document.getElementsByTagName("head")[0].appendChild(exportingJS);
 
document.getElementsByTagName("head")[0].appendChild(exportingJS);
  
 +
// 検索、表示、チェックボタンを作成
 +
// 検索ボタン
 
var searchButton = document.createElement("input");
 
var searchButton = document.createElement("input");
searchButton.value = "search";
+
searchButton.value   = "search";
searchButton.id   = "searchButton";
+
searchButton.id       = "searchButton";
searchButton.type = "button";
+
searchButton.type     = "button";
 +
searchButton.disabled = true;
 
searchButton.style.width = "100%";
 
searchButton.style.width = "100%";
searchButton.onclick = function(){search()};
+
searchButton.onclick = function(){
 +
var sampleSource = document.getElementById("samplesource").value;
 +
var sampleType  = document.getElementById("sampletype").value;
 +
var lipidClass  = document.getElementById("lipidclass").value;
 +
search(sampleSource, sampleType, lipidClass);
 +
};
 
document.getElementById("search").appendChild(searchButton);
 
document.getElementById("search").appendChild(searchButton);
 +
// グラフ表示ボタン
 
var showButton = document.createElement("input");
 
var showButton = document.createElement("input");
 
showButton.value = "show graph";
 
showButton.value = "show graph";
 
showButton.id    = "showButton";
 
showButton.id    = "showButton";
 
showButton.type  = "button";
 
showButton.type  = "button";
showButton.disabled = "yes";
+
showButton.disabled = true;
showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; showChart()};
+
showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; showChart(getSelectedIDs())};
 
document.getElementById("show").appendChild(showButton);
 
document.getElementById("show").appendChild(showButton);
 +
// チェックボタン
 
var checkButton = document.createElement("input");
 
var checkButton = document.createElement("input");
 
checkButton.value = "all check/uncheck";
 
checkButton.value = "all check/uncheck";
 +
checkButton.id    = "allswitch";
 
checkButton.type  = "button";
 
checkButton.type  = "button";
 
checkButton.onclick = function(){checkAllResult()};
 
checkButton.onclick = function(){checkAllResult()};
Line 69: Line 61:
 
document.getElementById("graphform").style.display = "none";
 
document.getElementById("graphform").style.display = "none";
  
// insert "Reset zoom" button
+
// コンポーネント初期化
var resetZoomButton    = document.createElement("input");
+
lipoqulityChartInit();
resetZoomButton.setAttribute("type", "button");
+
resetZoomButton.value            = "Reset zoom";
+
resetZoomButton.id              = "resetZoomButton";
+
resetZoomButton.style.visibility = "hidden";
+
resetZoomButton.onclick          = unzoomBarCharts;
+
document.getElementById("resetZoom").appendChild(resetZoomButton);
+
  
 +
// コンボボックスの初期化
 
setCombobox('SampleSource');
 
setCombobox('SampleSource');
 
setCombobox('SampleType');
 
setCombobox('SampleType');
 
setCombobox('LipidClass');
 
setCombobox('LipidClass');
  
$(window).resize(function() {
+
// 全データの取得
resizeChart();
+
retrieveAllDataFromText(hasRetrievedAllData);
});
+
 
}
 
}
// ウィンドウサイズが変更されたとき、チャートの幅も修正する ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
// 全データの取得が完了した後の処理 /////////////////////////////////////
function resizeChart()
+
// return なし
 +
function hasRetrievedAllData()
 
{
 
{
if(chart == undefined || chart.length == 0)
+
// GETメソッドによる検索を行う場合の処理 /////////////////////////////
return;
+
var query  = window.location.search.substring(1);
 +
var params = query.split('&');
 +
var sampleSource = "All";
 +
var sampleType  = "All";
 +
var lipidClass  = "";
 +
var chain        = "";
 +
// パラメータの取得
 +
// ss = SampleSource - デフォルトはAll
 +
// st = SampleType - デフォルトはAll
 +
// lc = LipidClass - デフォルトは空文字。この文字列が入っていないと、検索は行わない
 +
// chain = Lipid chain - chainグラフの表示には必須項目。16:0/16:0/16:0のようにスラッシュ区切り
 +
for(var i = 0; i < params.length; i++){
 +
var w = params[i].split('=');
 +
var name  = decodeURIComponent(w[0]);
 +
var value = decodeURIComponent(w[1]);
 +
if(name == "ss"){ // sample source
 +
sampleSource = value;
  
if(gChartType == "bar"){
+
} else if(name == "st"){ // sample type
// barchart & piechart
+
sampleType = value;
var height  = 300;
+
 
var pieWidth = 400;
+
} else if(name == "lc"){ // lipid class
if(document.getElementById("pieContainer").style.display == "none")
+
lipidClass = value;
pieWidth = 0;
+
 
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - pieWidth - MARGIN;
+
} else if(name == "chain"){ // lipid chain
if(width < 300)
+
chain = value;
width = 300;
+
}
for(var i = 0; i < chart.length; i ++)
+
$("#container" + i).highcharts().setSize(width, height);
+
for(var i = 0; i < piechart.length; i ++)
+
$("#pieContainer" + i).highcharts().setSize(pieWidth, height);
+
} else {
+
var height = 400;
+
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - MARGIN;
+
// heatmap or barchart(bundle)
+
for(var i = 0; i < chart.length; i ++)
+
$("#container" + i).highcharts().setSize(width, height);
+
 
}
 
}
 +
if(chain.length > 0){
 +
// lipidclass基準の棒グラフを表示
 +
selectCombobox([sampleSource, sampleType, lipidClass]);
 +
var result = retrieveChainData(sampleSource, sampleType, lipidClass, chain);
 +
if(result.x.length > 0){
 +
showChainChart(result);
 +
}
 +
 +
} else if(lipidClass.length > 0){
 +
// bar(棒グラフ)を表示
 +
selectCombobox([sampleSource, sampleType, lipidClass]);
 +
search(sampleSource, sampleType, lipidClass);
 +
if(document.getElementsByClassName("results").length > 0){
 +
document.getElementById('allswitch').click();
 +
document.getElementById('bar').checked = true;
 +
showChart(getSelectedIDs());
 +
}
 +
}
 +
 +
document.getElementById('loading').style.display = "none";
 +
// 検索ボタンは有効化しておく
 +
document.getElementById("searchButton").disabled = false;
 +
}
 +
function getSelectedIDs()
 +
{
 +
var targets = [];
 +
var boxes = document.getElementsByName('target');
 +
for(var i = 0; i < boxes.length; i ++){
 +
if(boxes[i].checked)
 +
targets.push(boxes[i].value);
 +
}
 +
if(targets.length == 0){
 +
alert("選択してください");
 +
return [];
 +
}
 +
return targets;
 
}
 
}
 
 
// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
// param name カテゴリ名
 +
// return なし
 
function setCombobox(name)
 
function setCombobox(name)
 
{
 
{
Line 146: Line 176:
 
}
 
}
  
// search
+
// AJAXを使って、コンボボックスの選択項目を取得する
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.send(null);
 
xmlHttpRequest.send(null);
 
}
 
}
// XSS対策用 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
// 指定されたコンボボックスの値をセットする /////////////////////////////////////
function escape(text)
+
// param targets - 選択するSampleSource, SampleType, LipidClassの項目値
 +
// return なし
 +
function selectCombobox(targets)
 
{
 
{
if(isFinite(text))
+
var ids = ["samplesource", "sampletype", "lipidclass"];
return text;
+
 
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+
// 一つでもコンボボックスの初期化が終わっていなければ、処理を後回しにする
}
+
var counter = 1;
function attrEscape(text)
+
for(var i = 0; i < ids.length; i ++)
{
+
counter *= document.getElementById(ids[i]).options.length;
if(isFinite(text))
+
if(counter == 0){
return text;
+
window.setTimeout( function() { selectCombobox(targets) }, 50 );
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&rsquo;");
+
return;
}
+
}
function inchiEscape(text)
+
 
{
+
// コンボボックスの値をセットする
if(isFinite(text))
+
for(var i = 0; i < ids.length; i ++){
return text;
+
var cb = document.getElementById(ids[i]);
return text.replace(/^InChIKey=/, "").replace(/[^A-Z0-9-]/g, "");
+
for(var j = 0; j < cb.options.length; j ++){
 +
if(cb.options[j].value == targets[i]){
 +
cb.selectedIndex = j;
 +
break;
 +
}
 +
}
 +
}
 
}
 
}
 
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function search()
+
// param sampleSource - 検索対象のSampleSource
 +
// param sampleType  - 検索対象のSampleType
 +
// param lipidClass  - 検索対象のLipidClass
 +
// return なし
 +
function search(sampleSource, sampleType, lipidClass)
 
{
 
{
document.getElementById("searchButton").disabled = true;
+
// 検索ボタン等を無効化しておく
document.getElementById('hit').innerHTML = '';
+
document.getElementById("searchButton").disabled     = true;
document.getElementById("showButton").disabled = "yes";
+
document.getElementById("showButton") .disabled      = true;
document.getElementById("graphform").style.display = "none";
+
document.getElementById('hit')         .innerHTML    = "";
 +
document.getElementById("graphform")   .style.display = "none";
  
var classification = document.getElementById("samplesource").value;
+
// 「検索中」を表示
var sample  = document.getElementById("sampletype").value;
+
document.getElementById('searching').style.display = "block";
var type    = document.getElementById("lipidclass").value;
+
  
var url = 'https://script.google.com/macros/s/AKfycbxW5WpkJH0PUmmLrMtrluvkaKmz0OTTfeBucudy5-LxalQ7vus/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
+
// 検索を行う
 +
var result = lipoqualitySearch(sampleSource, sampleType, lipidClass);
 +
// var url = 'https://script.google.com/macros/s/AKfycbxW5WpkJH0PUmmLrMtrluvkaKmz0OTTfeBucudy5-LxalQ7vus/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
 
// var url = '/lipo/json.txt'
 
// var url = '/lipo/json.txt'
  
document.getElementById('searching').style.display = "block";
+
// 過去の検索結果を削除する
 
+
// remove old elements
+
 
var root = document.getElementById('result');
 
var root = document.getElementById('result');
 
root.textContent = '';
 
root.textContent = '';
Line 193: Line 235:
 
root.removeChild(root.childNodes[i]);
 
root.removeChild(root.childNodes[i]);
  
// jsonpを使って検索
+
// 「検索中」を非表示
var jsonp = document.createElement('script');
+
jsonp.src = url;
+
document.head.appendChild(jsonp);
+
}
+
 
+
function hasSearched(jsonp)
+
{
+
 
document.getElementById('searching').style.display = "none";
 
document.getElementById('searching').style.display = "none";
 
var root = document.getElementById('result');
 
var root = document.getElementById('result');
  
var result = jsonp;
+
// var result = jsonp;
 
//var result = JSON.parse(escape(jsonp));
 
//var result = JSON.parse(escape(jsonp));
 
document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).';
 
document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).';
// 最長文字数を調べる
+
// チェックボックスを並べるため、最長文字数を調べる
 
var lenmax = 0;
 
var lenmax = 0;
 
for(var i = 0; i < result.length; i ++){
 
for(var i = 0; i < result.length; i ++){
Line 215: Line 250:
 
lenmax += 6; // "(meta)"分
 
lenmax += 6; // "(meta)"分
 
lenmax /= 1.5;
 
lenmax /= 1.5;
 +
// チェックボックスの作成
 
for(var i = 0; i < result.length; i ++){
 
for(var i = 0; i < result.length; i ++){
 
var span = document.createElement('span');
 
var span = document.createElement('span');
Line 232: Line 268:
 
var title = document.createElement('label');
 
var title = document.createElement('label');
 
title.setAttribute('for', attrEscape(result[i].title));
 
title.setAttribute('for', attrEscape(result[i].title));
title.innerHTML = escape(result[i].title) + ' <a href="' + result[i].meta["Method link"] + '" target="_blank">(meta)</a>';
+
title.innerHTML = escape(result[i].title) + ' <a href="' + result[i]["Method link"] + '" target="_blank">(meta)</a>';
 
span.appendChild(title);
 
span.appendChild(title);
  
 
root.appendChild(span);
 
root.appendChild(span);
 
}
 
}
 +
// 検索ボタンを有効化
 
document.getElementById("searchButton").disabled = false;
 
document.getElementById("searchButton").disabled = false;
  
 
document.getElementById("graphform").style.display = "block";
 
document.getElementById("graphform").style.display = "block";
 
}
 
}
 +
// チェックボックスの状態に応じて、グラフ表示ボタンを有効/無効化する /////////////////
 +
// return なし
 
function checkSelection()
 
function checkSelection()
 
{
 
{
Line 253: Line 292:
 
document.getElementById("showButton").disabled = disabled;
 
document.getElementById("showButton").disabled = disabled;
 
}
 
}
 +
// すべてのチェックボックスをチェックする/アンチェックする //////////////////////
 +
// return なし
 
function checkAllResult()
 
function checkAllResult()
 
{
 
{
 
var c = document.getElementsByClassName("results");
 
var c = document.getElementsByClassName("results");
 +
 +
// チェックするか、アンチェックするかを調べる
 
var checked = 0;
 
var checked = 0;
 
for(var i = 0; i < c.length; i ++){
 
for(var i = 0; i < c.length; i ++){
Line 264: Line 307:
 
if(checked == c.length)
 
if(checked == c.length)
 
state = false;
 
state = false;
 +
 +
// チェック状態を変更する
 
for(var i = 0; i < c.length; i ++)
 
for(var i = 0; i < c.length; i ++)
 
c[i].checked = state;
 
c[i].checked = state;
  
 
checkSelection();
 
checkSelection();
}
 
var gChartType;
 
// チャート表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showChart()
 
{
 
var targets = '';
 
var boxes = document.getElementsByName('target');
 
for(var i = 0; i < boxes.length; i ++){
 
if(boxes[i].checked)
 
targets += ',' + boxes[i].value;
 
}
 
if(targets.length == 0){
 
alert("選択してください");
 
return;
 
}
 
targets = targets.substring(1);
 
document.getElementById("resetZoomButton").style.visibility = "hidden";
 
 
document.getElementById("showButton").disabled = true;
 
document.getElementById("bar")      .disabled = true;
 
document.getElementById("heatmap")  .disabled = true;
 
document.getElementById("sortableList").style.display = "none";
 
 
var sortableList = document.getElementById("sortableList");
 
for(var i = sortableList.childNodes.length-1; i >= 0; i --)
 
sortableList.removeChild(sortableList.childNodes[i]);
 
var rateDiv = document.getElementById("rate");
 
for(var i = rateDiv.childNodes.length-1; i >= 0; i --)
 
rateDiv.removeChild(rateDiv.childNodes[i]);
 
var optionDiv = document.getElementById("optionHeader");
 
for(var i = optionDiv.childNodes.length-1; i >= 0; i --)
 
optionDiv.removeChild(optionDiv.childNodes[i]);
 
 
if(document.getElementById('bar').checked)
 
chartType = 'bar';
 
else if(document.getElementById('heatmap').checked)
 
chartType = 'heatmap';
 
else
 
chartType = "bar_bundle";
 
 
gChartType = chartType
 
retrieveChartData(targets, chartType);
 
}
 
// データ取得  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function retrieveChartData(targets, chartType)
 
{
 
var url = 'https://script.google.com/macros/s/AKfycbxW5WpkJH0PUmmLrMtrluvkaKmz0OTTfeBucudy5-LxalQ7vus/exec?id=' + targets + '&type=' + chartType + '&q=data&callback=hasRetrieved';
 
//var url = '/lipo/data.php?id=' +  targets + '&type=' + chartType + '&q=data';
 
 
// jsonpを使った取得
 
var cutoff = document.getElementById("cutoff");
 
for(var i = cutoff.childNodes.length-1; i >= 0; i --)
 
cutoff.removeChild(cutoff.childNodes[i]);
 
var pieRoot = document.getElementById('pieContainer');
 
for(var i = pieRoot.childNodes.length-1; i >= 0; i --)
 
pieRoot.removeChild(pieRoot.childNodes[i]);
 
var root = document.getElementById('container');
 
for(var i = root.childNodes.length-1; i >= 0; i --)
 
root.removeChild(root.childNodes[i]);
 
document.getElementById('retrieving').style.display = "block";
 
var jsonp = document.createElement('script');
 
jsonp.src = url;
 
document.head.appendChild(jsonp);
 
}
 
 
// コールバック関数(jsonp)  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function hasRetrieved(jsonp)
 
{
 
document.getElementById('retrieving').style.display = "none";
 
 
var root = document.getElementById('container');
 
// remove old elements
 
root.textContent = '';
 
// for(var i = root.childNodes.length-1; i >= 0; i --)
 
// root.removeChild(root.childNodes[i]);
 
 
/* var chartType;
 
if(document.getElementById('bar').checked)
 
chartType = 'bar';
 
else if(document.getElementById('heatmap').checked)
 
chartType = 'heatmap';
 
else
 
chartType = 'bar_bundle';*/
 
 
var cutoff    = document.getElementById("cutoff");
 
var cutoffText = document.createElement("input");
 
cutoffText.id    = "cutoffValue";
 
cutoffText.type  = "text";
 
cutoffText.value = 0;
 
cutoffText.min  = 0;
 
cutoffText.max  = 80;
 
cutoffText.maxLength = 2;
 
cutoffText.style.width = "4em";
 
cutoffText.style.textAlign = "right";
 
cutoff.appendChild(cutoffText);
 
/*
 
var unitLabel    = document.createElement("span");
 
unitLabel.innerHTML = "%";
 
cutoff.appendChild(unitLabel);
 
*/
 
var cutoffButton = document.createElement("input");
 
cutoffButton.value = "% < cutoff";
 
cutoffButton.type  = "button";
 
cutoff.appendChild(cutoffButton);
 
 
var result = jsonp;
 
//var result = JSON.parse(escape(jsonp));
 
if(gChartType == 'bar')
 
showBarChart(result);
 
else if(gChartType == 'heatmap'){
 
showHeatmap(result);
 
}else
 
showBarBundleChart(result);
 
document.getElementById("showButton").disabled = false;
 
document.getElementById("bar")      .disabled = false;
 
document.getElementById("heatmap")  .disabled = false;
 
document.getElementById("sortableList").style.display = "block";
 
}
 
 
// バーチャート(バンドル) /////////////////////////////////////////////////////////////////////////////////////////////////////
 
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function setBarBundleData()
 
{ // inchiキー未処理 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
var target = [];
 
var cutoff = parseInt(document.getElementById("cutoffValue").value);
 
for(var j = 0; j < chart[0].data[0].length; j ++){
 
var not0 = false;
 
for(var i = 0; i < chart[0].series.length; i ++){
 
if(chart[0].data[i][j][1] >= cutoff){
 
not0 = true;
 
break;
 
}
 
}
 
target[j] = not0;
 
}
 
for(var j = 0; j < chart[0].series.length; j ++){
 
var i = 0;
 
var data = [];
 
var xLabels = [];
 
for(var k = 0; k < chart[0].srcdata[j].length; k ++){
 
if(target[k]){
 
// data[i]      = [chart[j].xLabels[k], chart[j].data[k][1]];
 
if(document.getElementById("ratio").checked)
 
data[i]      = [chart[0].xLabels[k], chart[0].srcdata[j][k] * 100 / chart[0].max];
 
else
 
data[i]      = [chart[0].xLabels[k], chart[0].srcdata[j][k]];
 
xLabels[i++] = chart[0].xLabels[k];
 
}
 
}
 
if(document.getElementById("ratio").checked){
 
chart[0].yAxis[0].setExtremes(0, 100);
 
chart[0].yAxis[0].axisTitle.attr({text: "Relative Intensity (%)"});
 
chart[0].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'})
 
 
} else {
 
chart[0].yAxis[0].setExtremes(0, chart[0].max);
 
chart[0].yAxis[0].axisTitle.attr({text: "Intensity (" + chart[0].quantification + ")"});
 
chart[0].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '</b>'})
 
}
 
chart[0].xAxis[0].categories = xLabels;
 
chart[0].series[j].setData(data, true);
 
}
 
 
unzoomBarCharts();
 
}
 
// 表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showBarBundleChart(result)
 
{
 
// create ignore 0-intensity button
 
document.getElementById("cutoffValue").onchange = function(){
 
setBarBundleData();
 
};
 
 
// create sortable list
 
var sortableList = document.getElementById("sortableList");
 
for(var i = 0; i < result[0].map.length; i ++){
 
var line = document.createElement("div");
 
var cbox = document.createElement("input");
 
cbox.setAttribute("type", "checkbox");
 
cbox.setAttribute("checked", "yes");
 
cbox.setAttribute("seq", i);
 
cbox.setAttribute("disabled", "yes");
 
cbox.id = "item" + i;
 
cbox.onchange = function(e){
 
// 表示/非表示の切り替え
 
/* var index = this.parentElement.parentElement.id.replace("sortableList", "");
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}*/
 
setBarBundleData();
 
};
 
line.appendChild(cbox);
 
var label = document.createElement("label");
 
label.setAttribute("for", "item" + i);
 
label.innerHTML = escape(result[0].map[i].title);
 
line.appendChild(label);
 
sortableList.appendChild(line);
 
}/*
 
$('#sortableList').sortable({
 
cursor: 'move',
 
update: function(event, ui){
 
/* var index = ui.item[0].parentElement.id.replace("sortableList", "");
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}*//*
 
setBarBundleData();
 
}
 
});*/
 
// 凡例の切り替え
 
var changeLegend = document.getElementById("optionHeader");
 
var legendLabel = document.createElement("span");
 
legendLabel.innerHTML = "Legend";
 
changeLegend.appendChild(legendLabel);
 
var selectLegend = document.createElement("select");
 
selectLegend.id  = "selectLegend";
 
for(var i = 0; i < legendOptions.length; i ++){
 
var option = document.createElement('option');
 
option.setAttribute("value", legendOptions[i]);
 
if(legendOptions[i] == "Treatment")
 
option.setAttribute("selected", "true");
 
option.innerHTML = legendOptions[i];
 
selectLegend.appendChild(option);
 
}
 
selectLegend.onchange = function(e){
 
var index = document.getElementById("selectLegend").selectedIndex;
 
for(var i = 0; i < chart[0].series.length; i ++){
 
chart[0].series[i].update({name:chart[0].meta[i][legendOptions[index]]}, false);
 
}
 
chart[0].redraw(false);
 
}
 
changeLegend.appendChild(selectLegend);
 
 
// create barchart(s)
 
gBarData = [];
 
chart    = [];
 
piechart = [];
 
seriesData = [];
 
data      = [];
 
srcdata    = [];
 
var meta  = [];
 
var root    = document.getElementById('container');
 
var unifiedFlag = true;
 
var unitType = '';
 
for(var i = 0; i < result[0].map.length; i ++){
 
// 単位の統一がなされているかチェック
 
if(i == 0)
 
unitType = result[0].map[i].meta.Quantification;
 
else if(unitType != result[0].map[i].meta.Quantification){
 
unitType = '???';
 
unifiedFlag = false;
 
}
 
gBarData[i] = [];
 
// データの整理
 
data[i] = [];
 
srcdata[i] = [];
 
var xLabels = [];
 
 
for(var j = 0; j < result[0].map[i].data.length; j ++){
 
// data[j] = [attrEscape(result[0].x[j]), attrEscape(result[0].map[i].data[j][0] * 100 / result[0].map[i].max)];
 
data[i][j]    = [attrEscape(result[0].x[j]), attrEscape(result[0].map[i].data[j][0] * 100 / result[0].maxOfAll)];
 
srcdata[i][j] = attrEscape(result[0].map[i].data[j][0]);
 
xLabels[j]    = attrEscape(result[0].x[j]);
 
// gBarData[i][j] = inchiEscape(result[0].map[i].data[j][2]); // InChIキー
 
var type = result[0].map[i].title.replace(/.*\//,"");
 
gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー
 
}
 
meta[i] = result[0].map[i].meta;
 
seriesData[i] = {
 
name: attrEscape(result[0].map[i].meta["Treatment"]),
 
data: data[i],
 
events: {
 
  click: function(event) {
 
//alert(event.point.name);
 
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
 
getInchiOnBar(index, event.point.x);
 
  }
 
}
 
}
 
}
 
 
// barchartの追加
 
var parent = document.createElement('div');
 
parent.id = 'container' + 0;
 
parent.setAttribute("order", 0);
 
root.appendChild(parent);
 
chart[0] = new Highcharts.Chart({
 
chart: {
 
type: 'column',
 
zoomType: 'x',
 
renderTo: parent
 
},
 
title: {
 
text: attrEscape(result[0].title)
 
},
 
xAxis: {
 
min: 0,
 
type: 'category',
 
labels: {
 
rotation: -90,
 
style: {
 
fontSize: '11px',
 
fontFamily: 'Verdana, sans-serif'
 
},
 
step: 1
 
}
 
},
 
scrollbar: {
 
enabled: true
 
},
 
yAxis: {
 
min: 0,
 
max: 100,
 
title: {
 
text: 'Relative Intensity (%)'
 
}
 
},
 
legend: {
 
enabled: true
 
},
 
tooltip: {
 
pointFormat: '<b>{point.y:.1f} %</b>',
 
formatter: function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'}
 
},
 
series: seriesData
 
});
 
chart[0].xAxis[0].categories = xLabels;
 
chart[0].data    = data;
 
chart[0].srcdata = srcdata;
 
chart[0].max    = result[0].maxOfAll;
 
chart[0].xLabels = xLabels;
 
chart[0].quantification = unitType;
 
chart[0].meta    = meta;
 
console.log(meta);
 
 
// 絶対量か相対量か
 
var ratioCbox = document.createElement("input");
 
ratioCbox.setAttribute("type", "checkbox");
 
ratioCbox.setAttribute("checked", "no");
 
ratioCbox.id = "ratio";
 
ratioCbox.onchange = function(e){
 
setBarBundleData();
 
};
 
var label = document.createElement("label");
 
label.setAttribute("for", "ratio");
 
label.innerHTML = "ratio";
 
document.getElementById("rate").appendChild(ratioCbox);
 
document.getElementById("rate").appendChild(label);
 
 
resizeChart();
 
 
if(unifiedFlag == false)
 
alert("intensityの単位が統一されていません。");
 
}
 
 
// バーチャート ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
var gBarData;
 
function getInchiOnBar(seq, x)
 
{
 
window.open("http://jcbl.jp/wiki/LBG" + gBarData[seq][x], "new");
 
console.log(seq + "/" + x + " => " + gBarData[seq][x]);
 
}
 
var chart;
 
var piechart;
 
var defaultTickInterval = currentTickInterval = 5;
 
// バーチャートのズーム解除 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function unzoomBarCharts() {
 
for(var i = 0; i < chart.length; i ++){
 
//chart[i].xAxis[0].options.tickInterval = defaultTickInterval;
 
chart[i].xAxis[0].isDirty = true;
 
chart[i].xAxis[0].setExtremes(null, null, animation=true);
 
}
 
document.getElementById("resetZoomButton").style.visibility = "hidden";
 
}
 
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function setBarchartData()
 
{ // inchiキー未処理 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
var target = [];
 
var cutoff = parseInt(document.getElementById("cutoffValue").value);
 
for(var j = 0; j < chart[0].data.length; j ++){
 
var not0 = false;
 
for(var i = 0; i < chart.length; i ++){
 
if(chart[i].data[j][1] >= cutoff){
 
not0 = true;
 
break;
 
}
 
}
 
target[j] = not0;
 
}
 
 
for(var j = 0; j < chart.length; j ++){
 
var i = 0;
 
var data = [];
 
var xLabels = [];
 
for(var k = 0,l = 0; k < chart[j].data.length; k ++){
 
if(target[k]){
 
// data[i]      = [chart[j].xLabels[k], chart[j].data[k][1]];
 
if(document.getElementById("ratio").checked)
 
data[i]      = [chart[j].xLabels[k], chart[j].srcdata[k] * 100 / chart[j].max];
 
else
 
data[i]      = [chart[j].xLabels[k], chart[j].srcdata[k]];
 
xLabels[i++] = chart[j].xLabels[k];
 
}
 
}
 
if(document.getElementById("ratio").checked){
 
chart[j].yAxis[0].setExtremes(0, 100);
 
chart[j].yAxis[0].axisTitle.attr({text: "Relative Intensity (%)"});
 
chart[j].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'})
 
 
} else {
 
chart[j].yAxis[0].setExtremes(0, chart[j].max);
 
chart[j].yAxis[0].axisTitle.attr({text: "Intensity (" + chart[j].quantification + ")"});
 
chart[j].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '</b>'})
 
}
 
chart[j].xAxis[0].categories = xLabels;
 
chart[j].series[0].setData(data, true);
 
}
 
 
unzoomBarCharts();
 
}
 
// 表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showBarChart(result)
 
{
 
function computeTickInterval(xMin, xMax)
 
{
 
var zoomRange = xMax - xMin;
 
 
if(zoomRange <= 2)
 
currentTickInterval = 0.5;
 
if(zoomRange < 20)
 
currentTickInterval = 1;
 
else if(zoomRange < 100)
 
currentTickInterval = 5;
 
}
 
 
// create ignore 0-intensity button
 
document.getElementById("cutoffValue").onchange = function(){
 
setBarchartData();
 
};
 
 
// create sortable list
 
var sortableList = document.getElementById("sortableList");
 
for(var i = 0; i < result[0].map.length; i ++){
 
var line = document.createElement("div");
 
var cbox = document.createElement("input");
 
cbox.setAttribute("type", "checkbox");
 
cbox.setAttribute("checked", "yes");
 
cbox.setAttribute("seq", i);
 
cbox.id = "item" + i;
 
cbox.onchange = function(e){
 
// 表示/非表示の切り替え
 
var seq = this.getAttribute("seq");
 
var option;
 
if(this.checked){
 
option = "block";
 
} else {
 
option = "none";
 
}
 
document.getElementById("container" + seq).style.display = option;
 
document.getElementById("pieContainer" + seq).style.display = option;
 
};
 
line.appendChild(cbox);
 
var label = document.createElement("label");
 
label.setAttribute("for", "item" + i);
 
label.innerHTML = (i+1) + "." + escape(result[0].map[i].title);
 
line.appendChild(label);
 
sortableList.appendChild(line);
 
}
 
$('#sortableList').sortable({
 
cursor: 'move',
 
update: function(event, ui){
 
var sortableList = document.getElementById("sortableList");
 
for(var i = 0; i < sortableList.childNodes.length; i ++){
 
var seq = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
document.getElementById("container" + seq).setAttribute("order", i);
 
document.getElementById("pieContainer" + seq).setAttribute("order", i);
 
}
 
$("#container").html(
 
$("#container > div").sort(function(o1,o2)
 
{
 
var n1 = parseInt($(o1).attr("order"), 10);
 
var n2 = parseInt($(o2).attr("order"), 10);
 
if(n1 < n2) return -1;
 
if(n1 > n2) return 1;
 
return 0;
 
})
 
);
 
$("#pieContainer").html(
 
$("#pieContainer > div").sort(function(o1,o2)
 
{
 
var n1 = parseInt($(o1).attr("order"), 10);
 
var n2 = parseInt($(o2).attr("order"), 10);
 
if(n1 < n2) return -1;
 
if(n1 > n2) return 1;
 
return 0;
 
})
 
);
 
}
 
});
 
// パイチャートの表示/非表示の切り替え
 
var switchPieHidden = document.getElementById("optionHeader");
 
var hiddenButton = document.createElement("input");
 
hiddenButton.setAttribute("type", "button");
 
hiddenButton.setAttribute("value", "hide piechart(s)");
 
hiddenButton.id = "switchPieHidden";
 
hiddenButton.onclick = function(e){
 
var pieContainer = document.getElementById("pieContainer");
 
if(pieContainer.style.display == "none"){
 
pieContainer.style.display = "block";
 
document.getElementById("switchPieHidden").setAttribute("value", "hide piechart(s)");
 
} else {
 
pieContainer.style.display = "none";
 
document.getElementById("switchPieHidden").setAttribute("value", "show piechart(s)");;
 
}
 
resizeChart();
 
}
 
switchPieHidden.appendChild(hiddenButton);
 
 
// create barchart(s)
 
gBarData = [];
 
chart    = [];
 
piechart = [];
 
var root    = document.getElementById('container');
 
var pieRoot = document.getElementById('pieContainer');
 
for(var i = 0; i < result[0].map.length; i ++){
 
gBarData[i] = [];
 
// データの整理
 
var data = [];
 
var srcdata = [];
 
var xLabels = [];
 
for(var j = 0; j < result[0].map[i].data.length; j ++){
 
// data[j] = [attrEscape(result[0].x[j]), attrEscape(result[0].map[i].data[j][0] * 100 / result[0].map[i].max)];
 
data[j]    = [attrEscape(result[0].x[j]), attrEscape(result[0].map[i].data[j][0] * 100 / result[0].map[i].max)];
 
srcdata[j] = attrEscape(result[0].map[i].data[j][0]);
 
xLabels[j] = attrEscape(result[0].x[j]);
 
// gBarData[i][j] = inchiEscape(result[0].map[i].data[j][2]); // InChIキー
 
var type = result[0].map[i].title.replace(/.*\//,"");
 
gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー
 
}
 
 
// barchartの追加
 
var parent = document.createElement('div');
 
parent.id = 'container' + i;
 
parent.setAttribute("order", i);
 
root.appendChild(parent);
 
chart[i] = new Highcharts.Chart({
 
chart: {
 
type: 'column',
 
zoomType: 'x',
 
renderTo: parent,
 
height: 250,
 
resetZoomButton: {
 
theme: {
 
display: 'none'
 
}
 
}
 
},
 
title: {
 
text: (i+1) + '.' + attrEscape(result[0].map[i].title)
 
},
 
xAxis: {
 
min: 0,
 
type: 'category',
 
labels: {
 
rotation: -90,
 
style: {
 
fontSize: '11px',
 
fontFamily: 'Verdana, sans-serif'
 
},
 
step: 1
 
},
 
events : {
 
afterSetExtremes: function(){
 
if(!this.chart.options.chart.isZoomed){
 
if(this.chart.options.chart.isZoomed !== undefined)
 
document.getElementById("resetZoomButton").style.visibility = "visible";
 
 
var xMin = this.chart.xAxis[0].min;
 
var xMax = this.chart.xAxis[0].max;
 
 
var zmRange = computeTickInterval(xMin, xMax);
 
for(var i = 0; i < chart.length; i ++){
 
chart[i].xAxis[0].options.tickInterval = zmRange;
 
chart[i].xAxis[0].isDirty = true;
 
if(chart[i] !== this){
 
chart[i].options.chart.isZoomed = true;
 
chart[i].xAxis[0].setExtremes(xMin, xMax, true);
 
chart[i].options.chart.isZoomed = false;
 
}
 
}
 
}
 
},
 
}
 
},
 
scrollbar: {
 
enabled: true
 
},
 
yAxis: {
 
min: 0,
 
max: 100,
 
title: {
 
text: 'Relative Intensity (%)'
 
}
 
},
 
legend: {
 
enabled: false
 
},
 
tooltip: {
 
pointFormat: '<b>{point.y:.1f} %</b>',
 
formatter: function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'}
 
},
 
series: [{
 
name: 'Population',
 
data: data,
 
color: barColor,
 
events: {
 
  click: function(event) {
 
//alert(event.point.name);
 
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
 
getInchiOnBar(index, event.point.x);
 
  }
 
}
 
}]
 
});
 
chart[i].xAxis[0].categories = xLabels;
 
chart[i].data    = data;
 
chart[i].srcdata = srcdata;
 
chart[i].max    = result[0].map[i].max;
 
chart[i].xLabels = xLabels;
 
chart[i].quantification = result[0].map[i].meta.Quantification;
 
 
// piechartの追加
 
var pieParent = document.createElement('div');
 
pieParent.id = 'pieContainer' + i;
 
pieParent.setAttribute("order", i);
 
pieRoot.appendChild(pieParent);
 
piechart[i] = new Highcharts.Chart({
 
chart: {
 
plotBackgroundColor: null,
 
plotBorderWidth: null,
 
plotShadow: false,
 
type: 'pie',
 
renderTo: pieParent,
 
height: 250
 
},
 
title: {
 
text: (i+1) + '.Intensity ratio'
 
},
 
tooltip: {
 
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
 
},
 
plotOptions: {
 
pie: {
 
allowPointSelect: true,
 
cursor: 'pointer',
 
dataLabels: {
 
enabled: true,
 
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
 
style: {
 
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
 
}
 
}
 
}
 
},
 
series: [{
 
name: 'Rate',
 
colorByPoint: true,
 
data: result[0].map[i].pie,
 
events: {
 
click: function(event) {
 
barColor = event.point.color;
 
 
var nextType = event.point.name;
 
var targets = '';
 
var sortableList = document.getElementById("sortableList");
 
for(var i = 0; i < sortableList.childNodes.length; i ++){
 
var w = sortableList.childNodes[i].childNodes[1].innerHTML.replace(/^[0-9]+./,"").split("/");
 
targets += "," + w[0] + "/" + w[1] + "/" + nextType;
 
}
 
targets = targets.substring(1);
 
document.getElementById("showButton").disabled = true;
 
document.getElementById("bar")      .disabled = true;
 
document.getElementById("heatmap")  .disabled = true;
 
document.getElementById("sortableList").style.display = "none";
 
 
var sortableList = document.getElementById("sortableList");
 
for(var i = sortableList.childNodes.length-1; i >= 0; i --)
 
sortableList.removeChild(sortableList.childNodes[i]);
 
 
retrieveChartData(targets, 'bar');
 
}
 
}
 
}]
 
});
 
}
 
// 絶対量か相対量か
 
var ratioCbox = document.createElement("input");
 
ratioCbox.setAttribute("type", "checkbox");
 
ratioCbox.setAttribute("checked", "no");
 
ratioCbox.id = "ratio";
 
ratioCbox.onchange = function(e){
 
setBarchartData();
 
};
 
var label = document.createElement("label");
 
label.setAttribute("for", "ratio");
 
label.innerHTML = "ratio";
 
document.getElementById("rate").appendChild(ratioCbox);
 
document.getElementById("rate").appendChild(label);
 
 
resizeChart();
 
}
 
// ヒートマップ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
var chart;
 
var gHeatmapData;
 
function getInchiOnHeatmap(seq, x, y) // 未使用
 
{
 
window.open("http://jcbl.jp/wiki/LBG" + gHeatmapData[seq].map[0].title.replace(/.*\//, "") + gHeatmapData[seq].x[x].replace("/","-"), "new");
 
// console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]);
 
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x].replace("/","-"));
 
 
}
 
function jumpToJcbl(inchi)
 
{
 
window.open("http://jcbl.jp/","new");
 
console.log(inchi);
 
}
 
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function setHeatmapData(index, seq)
 
{
 
var i = 0;
 
var length = gHeatmapData[index].map.length;
 
 
var target = [];
 
var cutoff = parseInt(document.getElementById("cutoffValue").value);
 
var xLabels = [];
 
for(var k = 0; k < chart[index].data[0].length; k ++){
 
var not0 = false;
 
for(var j = 0; j < length; j ++){
 
if(chart[index].data[j][k] >= cutoff){
 
not0 = true;
 
break;
 
}
 
}
 
target[k] = not0;
 
if(not0)
 
xLabels[i++] = gHeatmapData[index].x[k];
 
}
 
 
var data = [];
 
var yLabels = [];
 
chart[index].inchi = [];
 
i = 0;
 
// 表示されている中での最大値を取得する
 
var maxOfDisplayedAll = 0;
 
for(var j = 0; j < seq.length && j < length; j ++){
 
if(maxOfDisplayedAll < gHeatmapData[index].map[seq[j]].max)
 
maxOfDisplayedAll = gHeatmapData[index].map[seq[j]].max;
 
}
 
var max = 0;
 
for(var j = 0; j < seq.length && j < length; j ++){
 
if(document.getElementById("eachInRate").checked)
 
max = gHeatmapData[index].map[seq[j]].max;
 
else
 
max = maxOfDisplayedAll;
 
// max = gHeatmapData[index].maxOfAll; // 常に全ての最大値を基準にする場合はこちらを使う
 
chart[index].inchi[j] = [];
 
for(var k = 0,l = 0; k < gHeatmapData[index].map[seq[j]].data.length; k ++){
 
if(target[k]){
 
data[i] = [l++, seq.length-j-1, attrEscape(gHeatmapData[index].map[seq[j]].data[k][0] * 100 / max)];
 
chart[index].inchi[j][k] = inchiEscape(gHeatmapData[index].map[seq[j]].data[k][2]);
 
i ++;
 
}
 
}
 
yLabels[j] = (parseInt(seq[j])+1) + "." + attrEscape(gHeatmapData[index].map[seq[j]].title.replace(/\/[^\/]+$/, ""));
 
}
 
yLabels.reverse();
 
chart[index].zoomOut();
 
chart[index].series[0].setData(data, true);
 
chart[index].yAxis[0].setCategories(yLabels);
 
chart[index].xAxis[0].setCategories(xLabels);
 
}
 
// 表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showHeatmap(result)
 
{
 
gHeatmapData = [];
 
var root = document.getElementById('container');
 
 
var sortableList = document.getElementById("sortableList");
 
chart = [];
 
gHeatmapData = result;
 
for(var i = 0; i < result.length; i ++){
 
// タイトル
 
var title = attrEscape(result[i].title);
 
 
// 親要素
 
var parent = document.createElement('div');
 
parent.id = 'container' + i;
 
root.appendChild(parent);
 
 
var index = 0;
 
var data = [];
 
var yLabels = [];
 
var length = result[i].map.length
 
var inchi = [];
 
var ratioData = [];
 
for(var j = 0; j < length; j ++){
 
inchi[j] = [];
 
ratioData[j] = [];
 
for(var k = 0; k < result[i].map[j].data.length; k ++){
 
data[index] = [k, length-j-1, attrEscape(result[i].map[j].data[k][0] * 100 / result[i].map[j].max)];
 
// data[index] = [k, length-j-1, attrEscape(result[i].map[j].data[k][0] * 100 / result[i].maxOfAll)];
 
inchi[j][k] = inchiEscape(result[i].map[j].data[k][2]);
 
ratioData[j][index] = data[index][2];
 
index ++;
 
}
 
yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title.replace(/\/[^\/]+$/, ""));
 
}
 
yLabels.reverse();
 
for(var j = 0; j < result[i].x.length; j ++)
 
result[i].x[j] = attrEscape(result[i].x[j]);
 
 
// create ignore 0-intensity button
 
document.getElementById("cutoffValue").onchange = function(){
 
// 表示/非表示の切り替え // 下と同じなので、後でまとめる
 
for(var index = 0; index < chart.length; index ++){
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}
 
setHeatmapData(index, sequence);
 
}
 
};
 
 
// create sortable list
 
var listDiv = document.createElement("div");
 
listDiv.id = "sortableList" + i;
 
for(var j = 0; j < result[i].map.length; j ++){
 
var line = document.createElement("div");
 
var cbox = document.createElement("input");
 
cbox.setAttribute("type", "checkbox");
 
cbox.setAttribute("checked", "yes");
 
cbox.setAttribute("seq", j);
 
cbox.id = "item" + j;
 
cbox.onchange = function(e){
 
// 表示/非表示の切り替え
 
var index = this.parentElement.parentElement.id.replace("sortableList", "");
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}
 
setHeatmapData(index, sequence);
 
};
 
line.appendChild(cbox);
 
var label = document.createElement("label");
 
label.setAttribute("for", "item" + j);
 
label.innerHTML = (j+1) + "." + escape(result[i].map[j].title);
 
line.appendChild(label);
 
listDiv.appendChild(line);
 
}
 
sortableList.appendChild(listDiv);
 
$('#sortableList' + i).sortable({
 
cursor: 'move',
 
update: function(event, ui){
 
var index = ui.item[0].parentElement.id.replace("sortableList", "");
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}
 
setHeatmapData(index, sequence);
 
}
 
});
 
$('#sortableList').sortable(false);
 
 
// それぞれのレート/全体でのレート
 
var rateCbox = document.createElement("input");
 
rateCbox.setAttribute("type", "checkbox");
 
rateCbox.setAttribute("checked", "yes");
 
rateCbox.id = "eachInRate";
 
rateCbox.onchange = function(e){
 
// rateの切り替え
 
var index = 0; // つであると仮定するので、複数ある場合は修正が必要なことに注意
 
var sortableList = document.getElementById("sortableList" + index);
 
var sequence = [];
 
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){
 
if(sortableList.childNodes[i].childNodes[0].checked)
 
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq");
 
}
 
setHeatmapData(index, sequence);
 
};
 
var label = document.createElement("label");
 
label.setAttribute("for", "eachInRate");
 
label.innerHTML = "Each in rate";
 
document.getElementById("rate").appendChild(rateCbox);
 
document.getElementById("rate").appendChild(label);
 
 
// ヒートマップ
 
chart[i] = new Highcharts.Chart({
 
 
chart: {
 
type: 'heatmap',
 
zoomType: 'xy',
 
animation: 1,
 
marginBottom: 0,
 
plotBorderWidth: 1,
 
renderTo: parent,
 
animation: true,
 
},
 
 
scrollbar: {
 
enabled: true
 
},
 
 
title: {
 
text: title,
 
align: 'left'
 
},
 
 
xAxis: {
 
categories: result[i].x,
 
opposite: true,
 
labels: {
 
rotation: -90,
 
style: {
 
fontSize: '11px',
 
fontFamily: 'Verdana, sans-serif'
 
},
 
step: 1
 
},
 
},
 
 
yAxis: {
 
categories: yLabels,
 
title: null,
 
labels: {
 
step: 1
 
}
 
},
 
 
colorAxis: {
 
min: 0,
 
max: 100,
 
minColor: '#ffffff',
 
maxColor: Highcharts.getOptions().colors[8]
 
},
 
 
legend: {
 
align: 'right',
 
layout: 'vertical',
 
margin: 0,
 
verticalAlign: 'top',
 
y: 100,
 
symbolHeight: 145
 
},
 
 
tooltip: {
 
formatter: function () {
 
return this.series.yAxis.categories[this.point.y] + '<br />' +
 
this.series.xAxis.categories[this.point.x] + '<br />' +
 
(Math.round(this.point.value*10)/10) + ' %';
 
}
 
},
 
 
series: [{
 
name: 'HEK',
 
borderWidth: 1,
 
data: data,
 
dataLabels: {
 
enabled: false,
 
color: '#000000'
 
},
 
point: {
 
events: {
 
/*mouseOver: function() {
 
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", "");
 
var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]);
 
if(target != null){
 
target.css('fill', 'red');
 
target.css('fontWeight', 'bold');
 
}
 
 
  $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', 'red');
 
  $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', 'bold');
 
},
 
mouseOut: function() {
 
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", "");
 
var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]);
 
if(target != null){
 
target.css('fill', '#666666');
 
target.css('fontWeight', '');
 
}
 
 
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', '#666666');
 
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', '');
 
},*/
 
click: function(event){
 
// var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
 
getInchiOnHeatmap(0, event.point.x, event.point.y);
 
// jumpToJcbl(event.point.series.chart.inchi[event.point.y][event.point.x]);
 
}
 
}
 
}
 
}]
 
 
});
 
chart[i].inchi = inchi;
 
chart[i].data  = ratioData;
 
//chart.setSize(600,300,false);
 
}
 
resizeChart();
 
}
 
 
// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function getTarget(children, target)
 
{
 
for(var i = 0; i < children.length; i ++){
 
if(target == children[i].childNodes[0].textContent){
 
return $(children[i]);
 
}
 
// console.log(children[i].childNodes[0].textContent);
 
}
 
return null;
 
 
}
 
}

Revision as of 13:56, 14 November 2017

// html /////////////////////////////////////////////////////////////////////////////////////////////////////////
// <span id="search"></span><span id="show"></span>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// external script //////////////////////////////////////////////////////////////////////////////////////////////
mw.loader.load( ['jquery.ui.sortable'] );
mw.loader.load('https://code.highcharts.com/stock/highstock.js', "text/javascript");
importScript( 'MediaWiki:LipoqualityCommon.js' );
importScript( 'MediaWiki:LipoqualityGet.js'    );
importScript( 'MediaWiki:LipoqualitySearch.js' );
importScript( 'MediaWiki:LipoqualityChart.js'  );

// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
addOnloadHook(lipoqulityInit); 

var gChartType;

// 初期化 //////////////////////////////////////////////////////////////////////////////////////////////////////
function lipoqulityInit()
{
	// highstock.jsに依存するため、別で読み込む
	var heatmapJS = document.createElement("script");
	heatmapJS.src = "https://code.highcharts.com/modules/heatmap.js";
	document.getElementsByTagName("head")[0].appendChild(heatmapJS);
	var exportingJS = document.createElement("script");
	exportingJS.src = "https://code.highcharts.com/modules/exporting.js";
	document.getElementsByTagName("head")[0].appendChild(exportingJS);

	// 検索、表示、チェックボタンを作成
		// 検索ボタン
	var searchButton = document.createElement("input");
	searchButton.value    = "search";
	searchButton.id       = "searchButton";
	searchButton.type     = "button";
	searchButton.disabled = true;
	searchButton.style.width = "100%";
	searchButton.onclick = function(){
		var sampleSource = document.getElementById("samplesource").value;
		var sampleType   = document.getElementById("sampletype").value;
		var lipidClass   = document.getElementById("lipidclass").value;
		search(sampleSource, sampleType, lipidClass);
	};
	document.getElementById("search").appendChild(searchButton);
		// グラフ表示ボタン
	var showButton = document.createElement("input");
	showButton.value = "show graph";
	showButton.id    = "showButton";
	showButton.type  = "button";
	showButton.disabled = true;
	showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; showChart(getSelectedIDs())};
	document.getElementById("show").appendChild(showButton);
		// チェックボタン
	var checkButton = document.createElement("input");
	checkButton.value = "all check/uncheck";
	checkButton.id    = "allswitch";
	checkButton.type  = "button";
	checkButton.onclick = function(){checkAllResult()};
	document.getElementById("check").appendChild(checkButton);
	document.getElementById("graphform").style.display = "none";

	// コンポーネント初期化
	lipoqulityChartInit();

	// コンボボックスの初期化
	setCombobox('SampleSource');
	setCombobox('SampleType');
	setCombobox('LipidClass');

	// 全データの取得
	retrieveAllDataFromText(hasRetrievedAllData);
}
// 全データの取得が完了した後の処理 /////////////////////////////////////
// return なし
function hasRetrievedAllData()
{
	// GETメソッドによる検索を行う場合の処理 /////////////////////////////
	var query  = window.location.search.substring(1);
	var params = query.split('&');
	var sampleSource = "All";
	var sampleType   = "All";
	var lipidClass   = "";
	var chain        = "";
	// パラメータの取得
	// ss = SampleSource - デフォルトはAll
	// st = SampleType - デフォルトはAll
	// lc = LipidClass - デフォルトは空文字。この文字列が入っていないと、検索は行わない
	// chain = Lipid chain - chainグラフの表示には必須項目。16:0/16:0/16:0のようにスラッシュ区切り
	for(var i = 0; i < params.length; i++){
		var w = params[i].split('=');
		var name  = decodeURIComponent(w[0]);
		var value = decodeURIComponent(w[1]);
		if(name == "ss"){ // sample source
			sampleSource = value;

		} else if(name == "st"){ // sample type
			sampleType = value;

		} else if(name == "lc"){ // lipid class
			lipidClass = value;

		} else if(name == "chain"){ // lipid chain
			chain = value;
		}
	}
	if(chain.length > 0){
		// lipidclass基準の棒グラフを表示
		selectCombobox([sampleSource, sampleType, lipidClass]);
		var result = retrieveChainData(sampleSource, sampleType, lipidClass, chain);
		if(result.x.length > 0){
			showChainChart(result);
		}

	} else if(lipidClass.length > 0){
		// bar(棒グラフ)を表示
		selectCombobox([sampleSource, sampleType, lipidClass]);
		search(sampleSource, sampleType, lipidClass);
		if(document.getElementsByClassName("results").length > 0){
			document.getElementById('allswitch').click();
			document.getElementById('bar').checked = true;
			showChart(getSelectedIDs());
		}
	}

	document.getElementById('loading').style.display = "none";
	// 検索ボタンは有効化しておく
	document.getElementById("searchButton").disabled = false;
}
function getSelectedIDs()
{
	var targets = [];
	var boxes = document.getElementsByName('target');
	for(var i = 0; i < boxes.length; i ++){
		if(boxes[i].checked)
			targets.push(boxes[i].value);
	}
	if(targets.length == 0){
		alert("選択してください");
		return [];
	}
	return targets;
}
// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// param name カテゴリ名
// return なし
function setCombobox(name)
{
	var url = '/mediawiki/api.php?action=query&prop=revisions&redirects=1&titles=Lipoquality:' + name + '&rvprop=content&format=xml'

	var xmlHttpRequest = new XMLHttpRequest();
	xmlHttpRequest.onreadystatechange = function()
	{
		var READYSTATE_COMPLETED = 4;
		if(this.readyState == READYSTATE_COMPLETED){
			var HTTP_STATUS_OK = 200;
			if(this.status == HTTP_STATUS_OK) {
				// success
				var parser = new DOMParser();
				var dom = parser.parseFromString(this.response.trim(), "text/xml");
				var text = dom.getElementsByTagName("rev");
				var lines = text[0].textContent.split("\n");
				var select = document.getElementById(name.toLowerCase());
				if(name != 'LipidClass')
					lines.unshift('All');
				for(var i = 0; i < lines.length; i ++){
					var opt = document.createElement('option');
					opt.value = opt.textContent = lines[i].replace(/^\*/, '').replace(/^ */, '').replace(/ *$/, '').replace(/"/g, "&quot;").replace(/'/g, "&rsquo");;
					select.appendChild(opt);
				}
			} else {
				// error
				console.log('search failed. ' + this.status + ':' + this.statusText + "/" + this.readyState);
			}
		}
	}

	// AJAXを使って、コンボボックスの選択項目を取得する
	xmlHttpRequest.open('GET', url, true);
	xmlHttpRequest.responseType = 'text';
	xmlHttpRequest.send(null);
}
// 指定されたコンボボックスの値をセットする /////////////////////////////////////
// param targets - 選択するSampleSource, SampleType, LipidClassの項目値
// return なし
function selectCombobox(targets)
{
	var ids = ["samplesource", "sampletype", "lipidclass"];

	// 一つでもコンボボックスの初期化が終わっていなければ、処理を後回しにする
	var counter = 1;
	for(var i = 0; i < ids.length; i ++)
		counter *= document.getElementById(ids[i]).options.length;
	if(counter == 0){
		window.setTimeout( function() { selectCombobox(targets) }, 50 );
		return;
	}

	// コンボボックスの値をセットする
	for(var i = 0; i < ids.length; i ++){
		var cb = document.getElementById(ids[i]);
		for(var j = 0; j < cb.options.length; j ++){
			if(cb.options[j].value == targets[i]){
				cb.selectedIndex = j;
				break;
			}
		}
	}
}
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// param sampleSource - 検索対象のSampleSource
// param sampleType   - 検索対象のSampleType
// param lipidClass   - 検索対象のLipidClass
// return なし
function search(sampleSource, sampleType, lipidClass)
{
	// 検索ボタン等を無効化しておく
	document.getElementById("searchButton").disabled      = true;
	document.getElementById("showButton")  .disabled      = true;
	document.getElementById('hit')         .innerHTML     = "";
	document.getElementById("graphform")   .style.display = "none";

	// 「検索中」を表示
	document.getElementById('searching').style.display = "block";

	// 検索を行う
	var result = lipoqualitySearch(sampleSource, sampleType, lipidClass);
//	var url = 'https://script.google.com/macros/s/AKfycbxW5WpkJH0PUmmLrMtrluvkaKmz0OTTfeBucudy5-LxalQ7vus/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
//	var url = '/lipo/json.txt'

	// 過去の検索結果を削除する
	var root = document.getElementById('result');
	root.textContent = '';
	for(var i = root.childNodes.length-1; i >= 0; i --)
		root.removeChild(root.childNodes[i]);

	// 「検索中」を非表示
	document.getElementById('searching').style.display = "none";
	var root = document.getElementById('result');

//	var result = jsonp;
	//var result = JSON.parse(escape(jsonp));
	document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).';
	// チェックボックスを並べるため、最長文字数を調べる
	var lenmax = 0;
	for(var i = 0; i < result.length; i ++){
		if(result[i].title.length > lenmax)
			lenmax = result[i].title.length;
	}
	lenmax += 6; // "(meta)"分
	lenmax /= 1.5;
	// チェックボックスの作成
	for(var i = 0; i < result.length; i ++){
		var span = document.createElement('span');
		span.style.display = "inline-block";
		span.style.width   = lenmax + "em";

		var check = document.createElement('input');
		check.type = 'checkbox';
		check.id	= attrEscape(result[i].title);
		check.value = attrEscape(result[i].title);
		check.name  = 'target';
		check.className = "results";
		check.onchange = function(e){
			checkSelection();
		};
		span.appendChild(check);
		var title = document.createElement('label');
		title.setAttribute('for', attrEscape(result[i].title));
		title.innerHTML = escape(result[i].title) + ' <a href="' + result[i]["Method link"] + '" target="_blank">(meta)</a>';
		span.appendChild(title);

		root.appendChild(span);
	}
	// 検索ボタンを有効化
	document.getElementById("searchButton").disabled = false;

	document.getElementById("graphform").style.display = "block";
}
// チェックボックスの状態に応じて、グラフ表示ボタンを有効/無効化する /////////////////
// return なし
function checkSelection()
{
	var c = document.getElementsByClassName("results");
	var disabled = true;
	for(var i = 0; i < c.length; i ++){
		if(c[i].checked){
			disabled = false;
			break;
		}
	}
	document.getElementById("showButton").disabled = disabled;
}
// すべてのチェックボックスをチェックする/アンチェックする //////////////////////
// return なし
function checkAllResult()
{
	var c = document.getElementsByClassName("results");

	// チェックするか、アンチェックするかを調べる
	var checked = 0;
	for(var i = 0; i < c.length; i ++){
		if(c[i].checked)
			checked ++;
	}
	var state = true;
	if(checked == c.length)
		state = false;

	// チェック状態を変更する
	for(var i = 0; i < c.length; i ++)
		c[i].checked = state;

	checkSelection();
}
Personal tools
Namespaces

Variants
Actions
Navigation
metabolites
Toolbox