MediaWiki:LipoqualityChart.js

From Metabolomics.JP
(Difference between revisions)
Jump to: navigation, search
(Created page with "// 定数 const DEFAULT_BAR_COLOR = "#7cb5ec"; const MARGIN = 30; var barColor = DEFAULT_BAR_COLOR; // バーチャート(バンドル)のX軸ラベル変更用 var leg...")
 
 
Line 14: Line 14:
 
var defaultTickInterval = currentTickInterval = 5;
 
var defaultTickInterval = currentTickInterval = 5;
 
var gHeatmapData;
 
var gHeatmapData;
 +
var gChainData;
  
 
// 初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
Line 44: Line 45:
 
if(document.getElementById("pieContainer").style.display == "none")
 
if(document.getElementById("pieContainer").style.display == "none")
 
pieWidth = 0;
 
pieWidth = 0;
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - pieWidth - MARGIN;
+
var width = $(window).width() - $("#sortableList").width() - $("#p-logo").width() - pieWidth - MARGIN;
 
if(width < 300)
 
if(width < 300)
 
width = 300;
 
width = 300;
Line 55: Line 56:
 
// chain
 
// chain
 
var height = 500;
 
var height = 500;
var width = $(window).width() - $("#mw-panel").width() - MARGIN;
+
var width = $(window).width() - $("#sortableList").width()- $("#p-logo").width() - MARGIN;
 
$("#container0").highcharts().setSize(width, height);
 
$("#container0").highcharts().setSize(width, height);
  
Line 61: Line 62:
 
// heatmap or barchart(bundle)
 
// heatmap or barchart(bundle)
 
var height = 400;
 
var height = 400;
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - MARGIN;
+
var width = $(window).width() - $("#sortableList").width() - $("#p-logo").width() - MARGIN;
 
for(var i = 0; i < chart.length; i ++)
 
for(var i = 0; i < chart.length; i ++)
 
$("#container" + i).highcharts().setSize(width, height);
 
$("#container" + i).highcharts().setSize(width, height);
Line 118: Line 119:
 
cutoffText.id        = "cutoffValue";
 
cutoffText.id        = "cutoffValue";
 
cutoffText.type      = "text";
 
cutoffText.type      = "text";
cutoffText.value    = 0;
+
cutoffText.value    = 0; // デフォルトは1%カット -> 初期表示は0%にしておく
 
cutoffText.min      = 0;
 
cutoffText.min      = 0;
 
cutoffText.max      = 80;
 
cutoffText.max      = 80;
Line 143: Line 144:
 
showBarBundleChart(result);
 
showBarBundleChart(result);
  
// 表示ボタン、チャートdom等1を表示
+
// 表示ボタン、チャートdom等を表示
 
document.getElementById("showButton").disabled = false;
 
document.getElementById("showButton").disabled = false;
 
document.getElementById("bar")      .disabled = false;
 
document.getElementById("bar")      .disabled = false;
Line 150: Line 151:
 
}
 
}
 
// バーチャート(バンドル) /////////////////////////////////////////////////////////////////////////////////////////////////////
 
// バーチャート(バンドル) /////////////////////////////////////////////////////////////////////////////////////////////////////
 +
// JCBLの構造ページへ飛ぶ
 +
function jumpToStructureOnBundleBar(seq, x)
 +
{
 +
var chain    = attrEscape(chart[0].xAxis[0].categories[x]);
 +
jumpToMassBank(gBarData[seq]["type"], chain, chart[0].adduct[seq][x]);
 +
//console.log(gBarData[seq]["type"] + " " + chain + " " + chart[0].adduct[seq][x]);
 +
}
 
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function setBarBundleData()
 
function setBarBundleData()
Line 166: Line 174:
 
target[j] = not0;
 
target[j] = not0;
 
}
 
}
 +
var adduct  = [];
 
for(var j = 0; j < chart[0].series.length; j ++){
 
for(var j = 0; j < chart[0].series.length; j ++){
 
var i = 0;
 
var i = 0;
 
var data = [];
 
var data = [];
 
var xLabels = [];
 
var xLabels = [];
 +
adduct[j] = [];
 
for(var k = 0; k < chart[0].srcdata[j].length; k ++){
 
for(var k = 0; k < chart[0].srcdata[j].length; k ++){
 
if(target[k]){ // チェックボックスにチェックがついていれば表示対象
 
if(target[k]){ // チェックボックスにチェックがついていれば表示対象
Line 177: Line 187:
 
else
 
else
 
data[i]      = [chart[0].xLabels[k], chart[0].srcdata[j][k]];
 
data[i]      = [chart[0].xLabels[k], chart[0].srcdata[j][k]];
xLabels[i++] = chart[0].xLabels[k];
+
xLabels[i] = chart[0].xLabels[k];
 +
adduct[j][i] = gBarData[j][k];
 +
i ++;
 
}
 
}
 
}
 
}
 
if(document.getElementById("ratio").checked){ // 相対値でのY軸タイトル
 
if(document.getElementById("ratio").checked){ // 相対値でのY軸タイトル
chart[0].yAxis[0].setExtremes(0, 100);
+
// chart[0].yAxis[0].setExtremes(0, 100);
 +
chart[0].yAxis[0].update({max: 100});
 
chart[0].yAxis[0].axisTitle.attr({text: "Relative Intensity (%)"});
 
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>'})
 
chart[0].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'})
  
 
} else { // 絶対値でのY軸タイトル
 
} else { // 絶対値でのY軸タイトル
chart[0].yAxis[0].setExtremes(0, chart[0].max);
+
// chart[0].yAxis[0].setExtremes(0, chart[0].max);
 +
chart[0].yAxis[0].update({max: chart.max});
 
chart[0].yAxis[0].axisTitle.attr({text: "Intensity (" + chart[0].quantification + ")"});
 
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].tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '</b>'})
Line 193: Line 207:
 
chart[0].series[j].setData(data, true);
 
chart[0].series[j].setData(data, true);
 
}
 
}
 +
chart[0].adduct = adduct;
  
 
unzoomBarCharts();
 
unzoomBarCharts();
Line 276: Line 291:
 
data      = [];
 
data      = [];
 
srcdata    = [];
 
srcdata    = [];
var meta       = [];
+
var meta   = [];
 
var root        = document.getElementById('container');
 
var root        = document.getElementById('container');
 
var unifiedFlag = true;
 
var unifiedFlag = true;
Line 300: Line 315:
 
srcdata[i][j] = attrEscape(result[0].map[i].data[j][0]); // もともとの値を計算
 
srcdata[i][j] = attrEscape(result[0].map[i].data[j][0]); // もともとの値を計算
 
xLabels[j]    = attrEscape(result[0].x[j]); // X軸ラベル
 
xLabels[j]    = attrEscape(result[0].x[j]); // X軸ラベル
var type      = result[0].map[i].title.replace(/.*\//,"");
+
gBarData[i][j] = result[0].map[i].data[j].meta["Adduct"];
gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // LBG + lipid class + chain
+
 
}
 
}
 +
// for link
 +
var type    = result[0].map[i].title.replace(/.*\//,"").replace("[","_").replace("]", "");
 +
var ionmode = "";
 +
if(result[0].map[i].meta["Ion mode"] == "Positive")
 +
ionmode = "p";
 +
else if(result[0].map[i].meta["Ion mode"] == "Negative")
 +
ionmode = "n";
 +
gBarData[i]["type"]    = type;
 +
gBarData[i]["ionmode"] = ionmode;
 +
console.log(gBarData[i]);
 +
 
meta[i] = result[0].map[i].meta;
 
meta[i] = result[0].map[i].meta;
 
seriesData[i] = {
 
seriesData[i] = {
Line 310: Line 335:
 
  click: function(event) {
 
  click: function(event) {
 
//alert(event.point.name);
 
//alert(event.point.name);
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
+
var index = event.point.series.columnIndex;
jumpToStructureOnBar(index, event.point.x);
+
jumpToStructureOnBundleBar(index, event.point.x);
 
  }
 
  }
 
}  
 
}  
Line 338: Line 363:
 
style: {
 
style: {
 
fontSize: '11px',
 
fontSize: '11px',
 +
fontWeight: 'bold',
 
fontFamily: 'Verdana, sans-serif'
 
fontFamily: 'Verdana, sans-serif'
 
},
 
},
Line 369: Line 395:
 
chart[0].quantification      = unitType;
 
chart[0].quantification      = unitType;
 
chart[0].meta                = meta;
 
chart[0].meta                = meta;
 +
chart[0].adduct              = gBarData;
  
 
// 絶対量/相対量を切り替えるチェックボックス
 
// 絶対量/相対量を切り替えるチェックボックス
Line 388: Line 415:
 
if(unifiedFlag == false)
 
if(unifiedFlag == false)
 
alert("intensityの単位が統一されていません。");
 
alert("intensityの単位が統一されていません。");
 +
}
 +
// MassBankへ飛ぶ共通のメソッド
 +
function jumpToMassBank(lipidclass, chain, adduct)
 +
{
 +
var PRECURSOR_TYPE_NAMES = {
 +
    '[M]+':      'p',
 +
'[M+H]+':    'Hp',
 +
'[M+Na]+':    'Nap',
 +
'[M+NH4]+':  'NH4p',
 +
'[M-H]-':    'Hm',
 +
'[M+FA-H]-':  'FAm',
 +
'[M+Hac-H]-': 'Hacm'
 +
};
 +
var type = PRECURSOR_TYPE_NAMES[adduct];
 +
window.open("http://133.242.136.63/wiki/Volatile:" + lipidclass + "?my_1=" + chain + "&my_2=" + type);
 +
// window.open("http://133.242.136.63/wiki/?lc=" + lipidclass + "&c=" + chain + "&p" + adduct, "new");
 +
console.log(lipidclass +" " + chain +" " + adduct);
 
}
 
}
  
Line 394: Line 438:
 
function jumpToStructureOnBar(seq, x)
 
function jumpToStructureOnBar(seq, x)
 
{
 
{
window.open("http://jcbl.jp/wiki/LBG" + gBarData[seq][x], "new");
+
// window.open("http://jcbl.jp/wiki/LBG" + gBarData[seq][x], "new");
console.log(seq + "/" + x + " => " + gBarData[seq][x]);
+
// window.open("http://133.242.136.63/wiki/Category:CS:" + gBarData[seq][x], "new");
 +
// console.log(seq + "/" + x + " => " + gBarData[seq][x]);
 +
var chain    = attrEscape(chart[0].xAxis[0].categories[x]);
 +
jumpToMassBank(gBarData[seq]["type"], chain, chart[seq].adduct[x]);
 +
//console.log(gBarData[seq]["type"] + " " + chain + " " + chart[seq].adduct[x]);
 +
/* if(chain.indexOf("/") >= 0)
 +
chain = "(" + chain + ")";
 +
else
 +
chain = "_" + chain;
 +
var link = gBarData[seq]["type"] + chain + gBarData[seq]["ionmode"];
 +
window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
 +
console.log(seq + "/" + x + " => " + link);
 +
*/
 
}
 
}
 
// 全バーチャートのズーム解除 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 全バーチャートのズーム解除 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
Line 423: Line 479:
  
 
for(var j = 0; j < chart.length; j ++){
 
for(var j = 0; j < chart.length; j ++){
var i = 0;
+
var i       = 0;
var data = [];
+
var data   = [];
 
var xLabels = [];
 
var xLabels = [];
 +
var adduct  = [];
 
for(var k = 0,l = 0; k < chart[j].data.length; k ++){
 
for(var k = 0,l = 0; k < chart[j].data.length; k ++){
 
if(target[k]){
 
if(target[k]){
Line 433: Line 490:
 
else
 
else
 
data[i]      = [chart[j].xLabels[k], chart[j].srcdata[k]];
 
data[i]      = [chart[j].xLabels[k], chart[j].srcdata[k]];
 +
adduct[i] = gBarData[j].adduct[k];
 
xLabels[i++] = chart[j].xLabels[k];
 
xLabels[i++] = chart[j].xLabels[k];
 
}
 
}
Line 448: Line 506:
 
chart[j].xAxis[0].categories = xLabels;
 
chart[j].xAxis[0].categories = xLabels;
 
chart[j].series[0].setData(data, true);
 
chart[j].series[0].setData(data, true);
 +
chart[j].adduct            = adduct;
 
}
 
}
  
Line 563: Line 622:
 
var srcdata = [];
 
var srcdata = [];
 
var xLabels = [];
 
var xLabels = [];
 +
gBarData[i].adduct = [];
 
for(var j = 0; j < result[0].map[i].data.length; j ++){
 
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)];
Line 568: Line 628:
 
srcdata[j] = attrEscape(result[0].map[i].data[j][0]);
 
srcdata[j] = attrEscape(result[0].map[i].data[j][0]);
 
xLabels[j] = attrEscape(result[0].x[j]);
 
xLabels[j] = attrEscape(result[0].x[j]);
 +
gBarData[i].adduct[j] = result[0].map[i].data[j].meta["Adduct"];
 
// gBarData[i][j] = inchiEscape(result[0].map[i].data[j][2]); // InChIキー
 
// 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キー
+
/* var type = result[0].map[i].title.replace(/.*\//,"");
 +
gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー*/
 
}
 
}
 +
// for link
 +
var type    = result[0].map[i].title.replace(/.*\//,"").replace("[","_").replace("]", "");
 +
var ionmode = "";
 +
if(result[0].map[i].meta["Ion mode"] == "Positive")
 +
ionmode = "p";
 +
else if(result[0].map[i].meta["Ion mode"] == "Negative")
 +
ionmode = "n";
 +
gBarData[i]["type"]    = type;
 +
gBarData[i]["ionmode"] = ionmode;
  
 
// barchartの追加
 
// barchartの追加
Line 600: Line 671:
 
style: {
 
style: {
 
fontSize: '11px',
 
fontSize: '11px',
 +
fontWeight: 'bold',
 
fontFamily: 'Verdana, sans-serif'
 
fontFamily: 'Verdana, sans-serif'
 
},
 
},
Line 664: Line 736:
 
chart[i].xLabels            = xLabels;
 
chart[i].xLabels            = xLabels;
 
chart[i].quantification      = result[0].map[i].meta.Quantification;
 
chart[i].quantification      = result[0].map[i].meta.Quantification;
 +
chart[i].adduct              = gBarData[i].adduct;
  
 
// piechartの追加
 
// piechartの追加
Line 740: Line 813:
 
function jumpToStructureOnHeatmap(seq, x, y)
 
function jumpToStructureOnHeatmap(seq, x, y)
 
{
 
{
window.open("http://jcbl.jp/wiki/LBG" + gHeatmapData[seq].map[0].title.replace(/.*\//, "") + gHeatmapData[seq].x[x].replace("/","-"), "new");
+
// 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]);
+
// window.open("http://133.242.136.63/wiki/Category:CS:" + gBarData[seq][x], "new");
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x].replace("/","-"));
+
var type  = gHeatmapData[0].map[0].title.replace(/.*\//,"").replace("[","_").replace("]", "");
 +
var chain  = attrEscape(chart[0].xAxis[0].categories[x]);
 +
var adduct = gBarData[y].adduct[x];
 +
jumpToMassBank(type, chain, adduct);
 +
//console.log(type + " " + chain + " " + adduct);
 +
/* if(chain.indexOf("/") >= 0)
 +
chain = "(" + chain + ")";
 +
else
 +
chain = "_" + chain;
 +
var link = type + chain + gBarData[y];
 +
window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
 +
console.log(seq + "/" + y + "/" + x + " => " + link);
 +
*/
 +
// console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x]);
  
 
}
 
}
Line 770: Line 856:
 
xLabels[i++] = gHeatmapData[index].x[k];
 
xLabels[i++] = gHeatmapData[index].x[k];
 
}
 
}
 +
 +
// ジャンプ先の設定
 +
gBarData = [];
 +
for(var j = 0; j < seq.length; j ++){
 +
var ionmode = "";
 +
if(gHeatmapData[index].map[seq[j]].meta["Ion mode"] == "Positive")
 +
ionmode = "p";
 +
else if(gHeatmapData[index].map[seq[j]].meta["Ion mode"] == "Negative")
 +
ionmode = "n";
 +
gBarData[j] = ionmode; // LBG + lipid class + chain
 +
}
 +
gBarData.reverse();
  
 
var data          = [];
 
var data          = [];
Line 784: Line 882:
 
// データのセット
 
// データのセット
 
for(var j = 0; j < seq.length && j < length; j ++){
 
for(var j = 0; j < seq.length && j < length; j ++){
 +
gBarData[j]        = [];
 +
gBarData[j].adduct = [];
 
if(document.getElementById("eachInRate").checked)
 
if(document.getElementById("eachInRate").checked)
 
max = gHeatmapData[index].map[seq[j]].max;
 
max = gHeatmapData[index].map[seq[j]].max;
Line 792: Line 892:
 
for(var k = 0,l = 0; k < gHeatmapData[index].map[seq[j]].data.length; k ++){
 
for(var k = 0,l = 0; k < gHeatmapData[index].map[seq[j]].data.length; k ++){
 
if(target[k]){
 
if(target[k]){
data[i] = [l++, seq.length-j-1, attrEscape(gHeatmapData[index].map[seq[j]].data[k][0] * 100 / max)]; // 相対値の計算
+
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].meta["InChIKey"]); // インチ―キー
 
chart[index].inchi[j][k] = inchiEscape(gHeatmapData[index].map[seq[j]].data[k].meta["InChIKey"]); // インチ―キー
 +
gBarData[j].adduct[l++]  = gHeatmapData[index].map[seq[j]].data[k].meta["Adduct"];
 
i ++;
 
i ++;
 
}
 
}
Line 799: Line 900:
 
yLabels[j] = (parseInt(seq[j])+1) + "." + attrEscape(gHeatmapData[index].map[seq[j]].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
 
yLabels[j] = (parseInt(seq[j])+1) + "." + attrEscape(gHeatmapData[index].map[seq[j]].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
 
}
 
}
 +
gBarData.reverse();
 
yLabels.reverse();
 
yLabels.reverse();
 
chart[index].zoomOut();
 
chart[index].zoomOut();
chart[index].series[0].setData(data, true);
+
chart[index].series[0].setData(data, true, true, false);
 
chart[index].yAxis[0].setCategories(yLabels);
 
chart[index].yAxis[0].setCategories(yLabels);
 
chart[index].xAxis[0].setCategories(xLabels);
 
chart[index].xAxis[0].setCategories(xLabels);
Line 829: Line 931:
 
function showHeatmap(result)
 
function showHeatmap(result)
 
{
 
{
 +
gBarData    = [];
 
gHeatmapData = [];
 
gHeatmapData = [];
 
var root = document.getElementById('container');
 
var root = document.getElementById('container');
Line 853: Line 956:
 
inchi[j]    = [];
 
inchi[j]    = [];
 
ratioData[j] = [];
 
ratioData[j] = [];
 +
gBarData[j]        = {};
 +
gBarData[j].adduct = [];
 
for(var k = 0; k < result[i].map[j].data.length; k ++){
 
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].map[j].max)]; // 相対値の計算
 
// data[index] = [k, length-j-1, attrEscape(result[i].map[j].data[k][0] * 100 / result[i].maxOfAll)];
 
// 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].meta["InChIKey"]); // インチ-キーの格納
 
inchi[j][k] = inchiEscape(result[i].map[j].data[k].meta["InChIKey"]); // インチ-キーの格納
ratioData[j][index] = data[index][2]; // ???
+
ratioData[j][k] = data[index][2]; // cutoff用%値
 +
gBarData[j].adduct[k] = result[i].map[j].data[k].meta["Adduct"];
 
index ++;
 
index ++;
 
}
 
}
 +
/* var ionmode = "";
 +
if(result[i].map[j].meta["Ion mode"] == "Positive")
 +
ionmode = "p";
 +
else if(result[i].map[j].meta["Ion mode"] == "Negative")
 +
ionmode = "n";
 +
gBarData[j] = ionmode; // LBG + lipid class + chain
 +
*/
 
yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
 
yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
 
}
 
}
 +
console.log(gBarData);
 +
gBarData.reverse();
 +
console.log(gBarData);
 
yLabels.reverse(); // highchartsの性質上、Y軸ラベルを反転させる
 
yLabels.reverse(); // highchartsの性質上、Y軸ラベルを反転させる
 
for(var j = 0; j < result[i].x.length; j ++)
 
for(var j = 0; j < result[i].x.length; j ++)
Line 917: Line 1,033:
 
var label = document.createElement("label");
 
var label = document.createElement("label");
 
label.setAttribute("for", "eachInRate");
 
label.setAttribute("for", "eachInRate");
label.innerHTML = "Each in rate";
+
label.innerHTML = "ratio";
 
document.getElementById("rate").appendChild(rateCbox);
 
document.getElementById("rate").appendChild(rateCbox);
 
document.getElementById("rate").appendChild(label);
 
document.getElementById("rate").appendChild(label);
Line 950: Line 1,066:
 
style: {
 
style: {
 
fontSize: '11px',
 
fontSize: '11px',
 +
fontWeight: 'bold',
 
fontFamily: 'Verdana, sans-serif'
 
fontFamily: 'Verdana, sans-serif'
 
},
 
},
Line 1,015: Line 1,132:
 
}
 
}
 
// chainチャート ////////////////////////////////////////////////////////////////////
 
// chainチャート ////////////////////////////////////////////////////////////////////
 +
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
function setChainData()
 +
{ // inchiキー未処理 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
var target = [];
 +
// カットオフ値を考慮
 +
var cutoff = parseInt(document.getElementById("cutoffValue").value);
 +
for(var j = 0; j < chart.data.length; j ++){
 +
target[j] = chart.data[j]['y'] >= cutoff;
 +
}
 +
var i = 0;
 +
var data = [];
 +
var xLabels = [];
 +
adduct = [];
 +
// gBarData.ionmode = [];
 +
for(var k = 0; k < chart.srcdata.length; k ++){
 +
if(target[k]){ // チェックボックスにチェックがついていれば表示対象
 +
// data[i]      = [chart[j].xLabels[k], chart[j].data[k][1]];
 +
if(document.getElementById("ratio").checked) // 相対値か絶対値か
 +
data[i]      = {y:chart.srcdata[k] * 100 / chart.max, color:chart.colors[k%chart.colors.length]};
 +
else
 +
data[i]      = {y:chart.srcdata[k], color:chart.colors[k%chart.colors.length]};
 +
xLabels[i] = chart.xLabels[k];
 +
/*
 +
var ionmode = "";
 +
if(gChainData.ionmode[k] == "Positive")
 +
ionmode = "p";
 +
else if(gChainData.ionmode[k] == "Negative")
 +
ionmode = "n";
 +
gBarData.ionmode[i++] = ionmode;
 +
*/
 +
adduct[i++] = gBarData.adduct[k];
 +
}
 +
}
 +
if(document.getElementById("ratio").checked){ // 相対値でのY軸タイトル
 +
// chart.yAxis[0].setExtremes(0, 100);
 +
chart.yAxis[0].update({max: 100});
 +
chart.yAxis[0].axisTitle.attr({text: "Relative Intensity (%)"});
 +
chart.tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'})
 +
 +
} else { // 絶対値でのY軸タイトル
 +
// chart.yAxis[0].setExtremes(0, chart.max);
 +
chart.yAxis[0].update({max: chart.max});
 +
chart.yAxis[0].axisTitle.attr({text: "Intensity (" + chart.quantification + ")"});
 +
chart.tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '</b>'})
 +
}
 +
chart.xAxis[0].categories = xLabels;
 +
chart.series[0].setData(data, true);
 +
chart.adduct = adduct;
 +
 +
chart.xAxis[0].isDirty = true;
 +
chart.xAxis[0].setExtremes(null, null, animation=true);
 +
}
 
// param result 対象データ
 
// param result 対象データ
 
// return なし
 
// return なし
 
function showChainChart(result)
 
function showChainChart(result)
 
{
 
{
 +
var colors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];
 +
 +
gChainData = result;
 
gChartType = "chain";
 
gChartType = "chain";
 +
 +
// cutoffボックス。冗長的なので、整理したい
 +
var cutoff    = document.getElementById("cutoff");
 +
var cutoffText = document.createElement("input");
 +
cutoffText.id        = "cutoffValue";
 +
cutoffText.type      = "text";
 +
cutoffText.value    = 0; // デフォルトは1%カット
 +
cutoffText.min      = 0;
 +
cutoffText.max      = 80;
 +
cutoffText.maxLength = 2;
 +
cutoffText.style.width    = "4em";
 +
cutoffText.style.textAlign = "right";
 +
cutoffText.onchange = function(){
 +
setChainData();
 +
};
 +
cutoff.appendChild(cutoffText);
 +
 +
var cutoffButton = document.createElement("input");
 +
cutoffButton.value = "% < cutoff";
 +
cutoffButton.type  = "button";
 +
cutoff.appendChild(cutoffButton);
 +
 +
// create "sortable list"
 +
var sortableList = document.getElementById("sortableList");
 +
sortableList.style.display = "block";
 +
for(var i = 0; i < result.x.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;
 +
line.appendChild(cbox);
 +
var label = document.createElement("label");
 +
label.setAttribute("for", "item" + i);
 +
label.innerHTML = escape(result.x[i]);
 +
line.appendChild(label);
 +
sortableList.appendChild(line);
 +
}
  
 
// create barchart(s)
 
// create barchart(s)
 
// gBarData = [];
 
// gBarData = [];
// piechart = [];
 
 
var root    = document.getElementById('container');
 
var root    = document.getElementById('container');
  
 
// データの整理
 
// データの整理
 +
gBarData = [];
 +
gBarData.lipidclass = result.lipidclass;//.replace("[","_").replace("](","(").replace(/:/g,"_");
 +
gBarData.chain      = result.chain;
 +
gBarData.adduct = [];
 
var data = [];
 
var data = [];
// var srcdata = [];
+
var srcdata = [];
// var xLabels = [];
+
var xLabels = [];
 
for(var j = 0; j < result.intensity.length; j ++){
 
for(var j = 0; j < result.intensity.length; j ++){
data[j]    = [attrEscape(result.x[j]), attrEscape(result.intensity[j] * 100 / result.maxOfAll)]; // 相対値の計算
+
// data[j]    = [attrEscape(result.x[j]), attrEscape(result.intensity[j] * 100 / result.maxOfAll)]; // 相対値の計算
// srcdata[j] = attrEscape(result.intensity[j]);
+
data[j]    = {y:attrEscape(result.intensity[j] * 100 / result.maxOfAll), color:colors[j%colors.length]}; // 相対値の計算
// xLabels[j] = attrEscape(result.x[j]);
+
srcdata[j] = attrEscape(result.intensity[j]);
 +
xLabels[j] = attrEscape(result.x[j]);
 +
 
 +
gBarData.adduct[j] = result.adduct[j];
 +
/* var ionmode = "";
 +
if(result.ionmode[j] == "Positive")
 +
ionmode = "p";
 +
else if(result.ionmode[j] == "Negative")
 +
ionmode = "n";
 +
gBarData.ionmode[j] = ionmode;*/
 
// var type = result[0].map[i].title.replace(/.*\//,"");
 
// var type = result[0].map[i].title.replace(/.*\//,"");
 
// gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー
 
// gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー
Line 1,059: Line 1,283:
 
rotation: -90,
 
rotation: -90,
 
style: {
 
style: {
fontSize: '11px',
+
fontSize: '15px',
 +
fontWeight: 'bold',
 
fontFamily: 'Verdana, sans-serif'
 
fontFamily: 'Verdana, sans-serif'
 
},
 
},
Line 1,081: Line 1,306:
 
pointFormat: '<b>{point.y:.1f} %</b>',
 
pointFormat: '<b>{point.y:.1f} %</b>',
 
formatter: function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'}
 
formatter: function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'}
 +
},
 +
plotOptions: {
 +
column: {
 +
pointRange: 2
 +
}
 
},
 
},
 
series: [{
 
series: [{
Line 1,087: Line 1,317:
 
events: {
 
events: {
 
  click: function(event) {
 
  click: function(event) {
//alert(event.point.name);
+
jumpToStructureOnChain(event.point.x);
 
  }
 
  }
 
}  
 
}  
Line 1,094: Line 1,324:
  
 
// chart.xAxis[0].categories = result.x;
 
// chart.xAxis[0].categories = result.x;
// chart[i].data    = data;
+
chart.data    = data;
// chart[i].srcdata = srcdata;
+
chart.srcdata = srcdata;
// chart[i].max    = result[0].map[i].max;
+
chart.max    = result.maxOfAll;
// chart[i].xLabels = xLabels;
+
chart.xLabels = xLabels;
// chart[i].quantification = result[0].map[i].meta.Quantification;
+
chart.quantification = result.quantification;
 +
chart.colors  = colors;
 +
chart.adduct  = gBarData.adduct;
  
 
// 絶対量か相対量か
 
// 絶対量か相対量か
/*
 
 
var ratioCbox = document.createElement("input");
 
var ratioCbox = document.createElement("input");
 
ratioCbox.setAttribute("type", "checkbox");
 
ratioCbox.setAttribute("type", "checkbox");
Line 1,107: Line 1,338:
 
ratioCbox.id = "ratio";
 
ratioCbox.id = "ratio";
 
ratioCbox.onchange = function(e){
 
ratioCbox.onchange = function(e){
setBarchartData();
+
setChainData();
 
};
 
};
 
var label = document.createElement("label");
 
var label = document.createElement("label");
Line 1,114: Line 1,345:
 
document.getElementById("rate").appendChild(ratioCbox);
 
document.getElementById("rate").appendChild(ratioCbox);
 
document.getElementById("rate").appendChild(label);
 
document.getElementById("rate").appendChild(label);
*/
+
 
 
resizeChart();
 
resizeChart();
 +
 +
if(result.quantification == "?")
 +
alert("intensityの単位が統一されていません。");
 +
}
 +
function jumpToStructureOnChain(x)
 +
{/*
 +
var link = gBarData.title + gBarData.ionmode[x];
 +
window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
 +
console.log(x + " => " + link);
 +
*/
 +
jumpToMassBank(gBarData.lipidclass, gBarData.chain, chart.adduct[x]);
 +
//console.log(gBarData.lipidclass + " " + gBarData.chain + " " + chart.adduct[x]);
 
}
 
}
 
// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
Line 1,127: Line 1,370:
 
}
 
}
 
return null;
 
return null;
}
 
function jumpToJcbl(inchi)
 
{
 
window.open("http://jcbl.jp/","new");
 
console.log(inchi);
 
 
}
 
}

Latest revision as of 09:05, 25 October 2018

// 定数 
const DEFAULT_BAR_COLOR = "#7cb5ec";
const MARGIN = 30;

var barColor = DEFAULT_BAR_COLOR;

// バーチャート(バンドル)のX軸ラベル変更用
var legendOptions = ["Sample name","Sample source","Sample type","Tissue","Treatment","Extraction","LC type","MS type","Ion mode","Quantification"];

// グローバル変数
var gBarData;
var chart;
var piechart;
var defaultTickInterval = currentTickInterval = 5;
var gHeatmapData;
var gChainData;

// 初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function lipoqulityChartInit()
{
	// insert "Reset zoom" button
	var resetZoomButton = document.createElement("input");
	resetZoomButton.setAttribute("type", "button");
	resetZoomButton.value            = "Reset zoom";
	resetZoomButton.id               = "resetZoomButton";
	resetZoomButton.style.visibility = "hidden";
	resetZoomButton.onclick          = unzoomBarCharts;
	document.getElementById("resetZoom").appendChild(resetZoomButton);

	// ウィンドウサイズが変更されたら、チャートもリサイズする
	$(window).resize(function() {
		resizeChart();
	});
}
// ウィンドウサイズが変更されたとき、チャートの幅も修正する ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function resizeChart()
{
	if(chart == undefined || chart.length == 0)
		return;

	if(gChartType == "bar"){
		// barchart & piechart
		var height   = 300;
		var pieWidth = 400;
		if(document.getElementById("pieContainer").style.display == "none")
			pieWidth = 0;
		var width = $(window).width() - $("#sortableList").width() - $("#p-logo").width() - pieWidth - MARGIN;
		if(width < 300)
			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 if(gChartType == "chain"){
		// chain
		var height = 500;
		var width = $(window).width() - $("#sortableList").width()- $("#p-logo").width() - MARGIN;
		$("#container0").highcharts().setSize(width, height);

	} else {
		// heatmap or barchart(bundle)
		var height = 400;
		var width = $(window).width() - $("#sortableList").width() - $("#p-logo").width() - MARGIN;
		for(var i = 0; i < chart.length; i ++)
			$("#container" + i).highcharts().setSize(width, height);
	}
}
// 指定されたIDを持つDOMの全子ノードを削除する
// param id - 対象ID
function removeAllChild(id)
{
	var dom = document.getElementById(id);
	for(var i = dom.childNodes.length-1; i >= 0; i --)
		dom.removeChild(dom.childNodes[i]);
}
// チャート表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// すべてのチャートの起点となる 
function showChart(targets)
{
	if(targets.length == 0)
		return;

	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";

	// 以前の結果(ソートリスト、カットオフ、パイチャート等)を削除
	removeAllChild("sortableList");
	removeAllChild("rate");
	removeAllChild("optionHeader");	
	removeAllChild("cutoff");
	removeAllChild("pieContainer");
	removeAllChild("container");

	// 「取得中」を表示
	document.getElementById('retrieving').style.display = "block";

	if(document.getElementById('bar').checked)
		chartType = 'bar';
	else if(document.getElementById('heatmap').checked)
		chartType = 'heatmap';
	else
		chartType = "bar_bundle";

	gChartType = chartType
	var result = retrieveChartData(targets, chartType);

	document.getElementById('retrieving').style.display = "none";

	var root = document.getElementById('container');
	root.textContent = '';

	var cutoff     = document.getElementById("cutoff");
	var cutoffText = document.createElement("input");
	cutoffText.id        = "cutoffValue";
	cutoffText.type      = "text";
	cutoffText.value     = 0; // デフォルトは1%カット -> 初期表示は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 = JSON.parse(escape(jsonp));
	if(gChartType == 'bar')
		showBarChart(result);
	else if(gChartType == 'heatmap'){
		showHeatmap(result);
	}else
		showBarBundleChart(result);

	// 表示ボタン、チャートdom等を表示
	document.getElementById("showButton").disabled = false;
	document.getElementById("bar")       .disabled = false;
	document.getElementById("heatmap")   .disabled = false;
	document.getElementById("sortableList").style.display = "block";
}
// バーチャート(バンドル) /////////////////////////////////////////////////////////////////////////////////////////////////////
// JCBLの構造ページへ飛ぶ
function jumpToStructureOnBundleBar(seq, x)
{
	var chain     = attrEscape(chart[0].xAxis[0].categories[x]);
	jumpToMassBank(gBarData[seq]["type"], chain, chart[0].adduct[seq][x]);
//console.log(gBarData[seq]["type"] + " " + chain + " " + chart[0].adduct[seq][x]);
}
// データの切り替え(表示/非表示、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;
	}
	var adduct  = [];
	for(var j = 0; j < chart[0].series.length; j ++){
		var i = 0;
		var data = [];
		var xLabels = [];
		adduct[j] = [];
		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];
				adduct[j][i] = gBarData[j][k];
				i ++;
			}
		}
		if(document.getElementById("ratio").checked){ // 相対値でのY軸タイトル
//			chart[0].yAxis[0].setExtremes(0, 100);
			chart[0].yAxis[0].update({max: 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 { // 絶対値でのY軸タイトル
//			chart[0].yAxis[0].setExtremes(0, chart[0].max);
			chart[0].yAxis[0].update({max: chart.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);
	}
	chart[0].adduct = adduct;

	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]); // X軸ラベル
			gBarData[i][j] = result[0].map[i].data[j].meta["Adduct"];
		}
		// for link
		var type    = result[0].map[i].title.replace(/.*\//,"").replace("[","_").replace("]", "");
		var ionmode = "";
		if(result[0].map[i].meta["Ion mode"] == "Positive")
			ionmode = "p";
		else if(result[0].map[i].meta["Ion mode"] == "Negative")
			ionmode = "n";
		gBarData[i]["type"]    = type;
		gBarData[i]["ionmode"] = ionmode;
console.log(gBarData[i]);

		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.point.series.columnIndex;
				jumpToStructureOnBundleBar(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',
					fontWeight: 'bold',
					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;
	chart[0].adduct              = gBarData;

	// 絶対量/相対量を切り替えるチェックボックス
	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の単位が統一されていません。");
}
// MassBankへ飛ぶ共通のメソッド
function jumpToMassBank(lipidclass, chain, adduct)
{
var PRECURSOR_TYPE_NAMES = {
    '[M]+':       'p',
	'[M+H]+':     'Hp',
	'[M+Na]+':    'Nap',
	'[M+NH4]+':   'NH4p',
	'[M-H]-':     'Hm',
	'[M+FA-H]-':  'FAm',
	'[M+Hac-H]-': 'Hacm'
};
var type = PRECURSOR_TYPE_NAMES[adduct];
window.open("http://133.242.136.63/wiki/Volatile:" + lipidclass + "?my_1=" + chain + "&my_2=" + type);
//	window.open("http://133.242.136.63/wiki/?lc=" + lipidclass + "&c=" + chain + "&p" + adduct, "new");
console.log(lipidclass +" " + chain +" " + adduct);
}

// バーチャート ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// JCBLの構造ページへ飛ぶ
function jumpToStructureOnBar(seq, x)
{
//	window.open("http://jcbl.jp/wiki/LBG" + gBarData[seq][x], "new");
//	window.open("http://133.242.136.63/wiki/Category:CS:" + gBarData[seq][x], "new");
//	console.log(seq + "/" + x + " => " + gBarData[seq][x]);
	var chain     = attrEscape(chart[0].xAxis[0].categories[x]);
	jumpToMassBank(gBarData[seq]["type"], chain, chart[seq].adduct[x]);
//console.log(gBarData[seq]["type"] + " " + chain + " " + chart[seq].adduct[x]);
/*	if(chain.indexOf("/") >= 0)
		chain = "(" + chain + ")";
	else
		chain = "_" + chain;
	var link = gBarData[seq]["type"] + chain + gBarData[seq]["ionmode"];
	window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
	console.log(seq + "/" + x + " => " + link);
*/
}
// 全バーチャートのズーム解除 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
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 = [];
		var adduct  = [];
		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]];
				adduct[i] = gBarData[j].adduct[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);
		chart[j].adduct             = adduct;
	}

	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);
//console.log(result);
		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 = [];
		gBarData[i].adduct = [];
		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].adduct[j] = result[0].map[i].data[j].meta["Adduct"];
//			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キー*/
		}
		// for link
		var type    = result[0].map[i].title.replace(/.*\//,"").replace("[","_").replace("]", "");
		var ionmode = "";
		if(result[0].map[i].meta["Ion mode"] == "Positive")
			ionmode = "p";
		else if(result[0].map[i].meta["Ion mode"] == "Negative")
			ionmode = "n";
		gBarData[i]["type"]    = type;
		gBarData[i]["ionmode"] = ionmode;

		// 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',
						fontWeight: 'bold',
						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","");
					jumpToStructureOnBar(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;
		chart[i].adduct              = gBarData[i].adduct;

		// 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) {
						// パイチャートをクリックしたら、別lipidlcassへ切り替える
						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.push(w[0] + "/" + w[1] + "/" + nextType);
						}
						showChart(targets);
					}
				}
			}]
		});
	}
	// 絶対量/相対量を切り替えるチェックボックス
	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();
}
// ヒートマップ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// JCBLの構造ページへ飛ぶ
function jumpToStructureOnHeatmap(seq, x, y)
{
//	window.open("http://jcbl.jp/wiki/LBG" + gHeatmapData[seq].map[0].title.replace(/.*\//, "") + gHeatmapData[seq].x[x].replace("/","-"), "new");
//	window.open("http://133.242.136.63/wiki/Category:CS:" + gBarData[seq][x], "new");
	var type   = gHeatmapData[0].map[0].title.replace(/.*\//,"").replace("[","_").replace("]", "");
	var chain  = attrEscape(chart[0].xAxis[0].categories[x]);
	var adduct = gBarData[y].adduct[x];
jumpToMassBank(type, chain, adduct);
//console.log(type + " " + chain + " " + adduct);
/*	if(chain.indexOf("/") >= 0)
		chain = "(" + chain + ")";
	else
		chain = "_" + chain;
	var link = type + chain + gBarData[y];
	window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
	console.log(seq + "/" + y + "/" + x + " => " + link);
*/
//	console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x]);

}
// ヒートマップデータの切り替え(表示/非表示、0-intensityで呼ばれる) ////////////////////////////////////////////////////////////////////////////////////////////////////////
// param index - 何番目のデータか(おそらく0のみ)
// param seq - 順番を格納した配列
// return なし
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];
	}

	// ジャンプ先の設定
	gBarData = [];
	for(var j = 0; j < seq.length; j ++){
		var ionmode = "";
		if(gHeatmapData[index].map[seq[j]].meta["Ion mode"] == "Positive")
			ionmode = "p";
		else if(gHeatmapData[index].map[seq[j]].meta["Ion mode"] == "Negative")
			ionmode = "n";
		gBarData[j] = ionmode; // LBG + lipid class + chain
	}
	gBarData.reverse();

	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 ++){
		gBarData[j]        = [];
		gBarData[j].adduct = [];
		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].meta["InChIKey"]); // インチ―キー
				gBarData[j].adduct[l++]  = gHeatmapData[index].map[seq[j]].data[k].meta["Adduct"];
				i ++;
			}
		}
		yLabels[j] = (parseInt(seq[j])+1) + "." + attrEscape(gHeatmapData[index].map[seq[j]].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
	}
	gBarData.reverse();
	yLabels.reverse();
	chart[index].zoomOut();
	chart[index].series[0].setData(data, true, true, false);
	chart[index].yAxis[0].setCategories(yLabels);
	chart[index].xAxis[0].setCategories(xLabels);

	// バグ対策用 - なぜか、データを再セットすると拡大されるため
	chart[index].xAxis[0].isDirty = true;
	chart[index].xAxis[0].setExtremes(null, null,animation=true);
	chart[index].yAxis[0].isDirty = true;
	chart[index].yAxis[0].setExtremes(null, null,animation=true);
}
// ヒートマップのデータを再設定する ////////////////////////////////////////////////////////////////////////
// param index - ソートリストのインデックス(おそらく0のみ)
// return なし
function resetHeatmapData(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);
}
// ヒートマップ作成 /////////////////////////////////////////////////////////////////////////////////////////
// param result チャートデータ
// return なし
function showHeatmap(result)
{
	gBarData     = [];
	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] = [];
			gBarData[j]        = {};
			gBarData[j].adduct = [];
			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].meta["InChIKey"]); // インチ-キーの格納
				ratioData[j][k] = data[index][2]; // cutoff用%値
				gBarData[j].adduct[k] = result[i].map[j].data[k].meta["Adduct"];
				index ++;
			}
/*			var ionmode = "";
			if(result[i].map[j].meta["Ion mode"] == "Positive")
				ionmode = "p";
			else if(result[i].map[j].meta["Ion mode"] == "Negative")
				ionmode = "n";
			gBarData[j] = ionmode; // LBG + lipid class + chain
*/
			yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title.replace(/\/[^\/]+$/, "")); // Y軸ラベル
		}
console.log(gBarData);
		gBarData.reverse();
console.log(gBarData);
		yLabels.reverse(); // highchartsの性質上、Y軸ラベルを反転させる
		for(var j = 0; j < result[i].x.length; j ++)
			result[i].x[j] = attrEscape(result[i].x[j]); // X軸ラベル

		// create "ignore 0-intensity button"
		document.getElementById("cutoffValue").onchange = function(){
			// 表示/非表示の切り替え // 下と同じなので、後でまとめる
			for(var index = 0; index < chart.length; index ++){
				resetHeatmapData(index);
			}
		};

		// 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", "");
				resetHeatmapData(index);
			};
			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", "");
				resetHeatmapData(index);
			}
		});
		$('#sortableList').sortable(false);

		// それぞれのレート/全体でのレート
		var rateCbox = document.createElement("input");
		rateCbox.setAttribute("type", "checkbox");
		rateCbox.setAttribute("checked", "yes");
		rateCbox.id = "eachInRate";
		rateCbox.onchange = function(e){
			// rateの切り替え
			resetHeatmapData(0); // 一つであると仮定するので、複数ある場合は修正が必要なことに注意
		};
		var label = document.createElement("label");
		label.setAttribute("for", "eachInRate");
		label.innerHTML = "ratio";
		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: 0,
				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',
						fontWeight: 'bold',
						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: {
						click: function(event){
//							var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
							jumpToStructureOnHeatmap(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();
}
// chainチャート ////////////////////////////////////////////////////////////////////
// データの切り替え(表示/非表示、0-intensity) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function setChainData()
{ // inchiキー未処理 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	var target = [];
	// カットオフ値を考慮
	var cutoff = parseInt(document.getElementById("cutoffValue").value);
	for(var j = 0; j < chart.data.length; j ++){
		target[j] = chart.data[j]['y'] >= cutoff;
	}
	var i = 0;
	var data = [];
	var xLabels = [];
	adduct = [];
//	gBarData.ionmode = [];
	for(var k = 0; k < chart.srcdata.length; k ++){
		if(target[k]){ // チェックボックスにチェックがついていれば表示対象
//			data[i]      = [chart[j].xLabels[k], chart[j].data[k][1]];
			if(document.getElementById("ratio").checked) // 相対値か絶対値か
				data[i]      = {y:chart.srcdata[k] * 100 / chart.max, color:chart.colors[k%chart.colors.length]};
			else
				data[i]      = {y:chart.srcdata[k], color:chart.colors[k%chart.colors.length]};
			xLabels[i] = chart.xLabels[k];
/*
			var ionmode = "";
			if(gChainData.ionmode[k] == "Positive")
				ionmode = "p";
			else if(gChainData.ionmode[k] == "Negative")
				ionmode = "n";
			gBarData.ionmode[i++] = ionmode;
*/
			adduct[i++] = gBarData.adduct[k];
		}
	}
	if(document.getElementById("ratio").checked){ // 相対値でのY軸タイトル
//		chart.yAxis[0].setExtremes(0, 100);
		chart.yAxis[0].update({max: 100});
		chart.yAxis[0].axisTitle.attr({text: "Relative Intensity (%)"});
		chart.tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '%</b>'})

	} else { // 絶対値でのY軸タイトル
//		chart.yAxis[0].setExtremes(0, chart.max);
		chart.yAxis[0].update({max: chart.max});
		chart.yAxis[0].axisTitle.attr({text: "Intensity (" + chart.quantification + ")"});
		chart.tooltip.options.formatter = (function(){return this.x + '<br/ ><b>' + this.y.toFixed(1) + '</b>'})
	}
	chart.xAxis[0].categories = xLabels;
	chart.series[0].setData(data, true);
	chart.adduct = adduct;

	chart.xAxis[0].isDirty = true;
	chart.xAxis[0].setExtremes(null, null, animation=true);
}
// param result 対象データ
// return なし
function showChainChart(result)
{
	var colors = ['#ff7f7f','#7f7fff','#7fff7f','#ff7fbf','#bfff7f','#ff7fff','#7fffff','#000000','#bf7fff','#7fffbf','#ffbf7f','#808080'];

	gChainData = result;
	gChartType = "chain";

	// cutoffボックス。冗長的なので、整理したい
	var cutoff     = document.getElementById("cutoff");
	var cutoffText = document.createElement("input");
	cutoffText.id        = "cutoffValue";
	cutoffText.type      = "text";
	cutoffText.value     = 0; // デフォルトは1%カット
	cutoffText.min       = 0;
	cutoffText.max       = 80;
	cutoffText.maxLength = 2;
	cutoffText.style.width     = "4em";
	cutoffText.style.textAlign = "right";
	cutoffText.onchange = function(){
		setChainData();
	};
	cutoff.appendChild(cutoffText);

	var cutoffButton = document.createElement("input");
	cutoffButton.value = "% < cutoff";
	cutoffButton.type  = "button";
	cutoff.appendChild(cutoffButton);

	// create "sortable list"
	var sortableList = document.getElementById("sortableList");
	sortableList.style.display = "block";
	for(var i = 0; i < result.x.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;
		line.appendChild(cbox);
		var label = document.createElement("label");
		label.setAttribute("for", "item" + i);
		label.innerHTML = escape(result.x[i]);
		line.appendChild(label);
		sortableList.appendChild(line);
	}

	// create barchart(s)
//	gBarData = [];
	var root    = document.getElementById('container');

	// データの整理
	gBarData = [];
	gBarData.lipidclass = result.lipidclass;//.replace("[","_").replace("](","(").replace(/:/g,"_");
	gBarData.chain      = result.chain;
	gBarData.adduct = [];
	var data = [];
	var srcdata = [];
	var xLabels = [];
	for(var j = 0; j < result.intensity.length; j ++){
//		data[j]    = [attrEscape(result.x[j]), attrEscape(result.intensity[j] * 100 / result.maxOfAll)]; // 相対値の計算
		data[j]    = {y:attrEscape(result.intensity[j] * 100 / result.maxOfAll), color:colors[j%colors.length]}; // 相対値の計算
		srcdata[j] = attrEscape(result.intensity[j]);
		xLabels[j] = attrEscape(result.x[j]);

		gBarData.adduct[j] = result.adduct[j];
/*		var ionmode = "";
		if(result.ionmode[j] == "Positive")
			ionmode = "p";
		else if(result.ionmode[j] == "Negative")
			ionmode = "n";
		gBarData.ionmode[j] = ionmode;*/
//		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 = 'container0';
	root.appendChild(parent);
	chart = new Highcharts.Chart({
		chart: {
			type: 'column',
			zoomType: 'x',
			renderTo: parent,
			height: 500
		},
		title: {
			text: attrEscape(result.title)
		},
		xAxis: {
			min: 0,
			type: 'category',
			categories:result.x,
			labels: {
				rotation: -90,
				style: {
					fontSize: '15px',
					fontWeight: 'bold',
					fontFamily: 'Verdana, sans-serif'
				},
				step: 1
			}
		},
		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>'}
		},
		plotOptions: {
			column: {
				pointRange: 2
			}
		},
		series: [{
			name: 'Population',
			data: data,
			events: {
			  click: function(event) {
				jumpToStructureOnChain(event.point.x);
			  }
			} 
		}]
	});

//	chart.xAxis[0].categories = result.x;
	chart.data    = data;
	chart.srcdata = srcdata;
	chart.max     = result.maxOfAll;
	chart.xLabels = xLabels;
	chart.quantification = result.quantification;
	chart.colors  = colors;
	chart.adduct  = gBarData.adduct;

	// 絶対量か相対量か
	var ratioCbox = document.createElement("input");
	ratioCbox.setAttribute("type", "checkbox");
	ratioCbox.setAttribute("checked", "no");
	ratioCbox.id = "ratio";
	ratioCbox.onchange = function(e){
		setChainData();
	};
	var label = document.createElement("label");
	label.setAttribute("for", "ratio");
	label.innerHTML = "ratio";
	document.getElementById("rate").appendChild(ratioCbox);
	document.getElementById("rate").appendChild(label);

	resizeChart();

	if(result.quantification == "?")
		alert("intensityの単位が統一されていません。");
}
function jumpToStructureOnChain(x)
{/*
	var link = gBarData.title + gBarData.ionmode[x];
	window.open("http://133.242.136.63/wiki/Category:CS:" + link, "new");
	console.log(x + " => " + link);
*/
	jumpToMassBank(gBarData.lipidclass, gBarData.chain, chart.adduct[x]);
//console.log(gBarData.lipidclass + " " + gBarData.chain + " " + chart.adduct[x]);
}
// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
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;
}
Personal tools
Namespaces

Variants
Actions
Navigation
metabolites
Toolbox