Difference between revisions of "MediaWiki:Lipoquality.js"

From Jcbl.jp
Jump to: navigation, search
Line 4: Line 4:
  
 
// external script //////////////////////////////////////////////////////////////////////////////////////////////
 
// external script //////////////////////////////////////////////////////////////////////////////////////////////
mw.loader.load('https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js', "text/javascript");
+
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");
  
Line 10: Line 10:
 
addOnloadHook(init);  
 
addOnloadHook(init);  
  
 +
// 初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function init()
 
function init()
 
{
 
{
Line 29: Line 30:
 
showButton.onclick = function(){showChart()};
 
showButton.onclick = function(){showChart()};
 
document.getElementById("show").appendChild(showButton);
 
document.getElementById("show").appendChild(showButton);
 +
 +
// 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);
  
 
setCombobox('Classification');
 
setCombobox('Classification');
 
setCombobox('Sample');
 
setCombobox('Sample');
 
setCombobox('Type');
 
setCombobox('Type');
 +
 +
$(window).resize(function() {
 +
resizeHeatmap();
 +
});
 
}
 
}
 +
// ウィンドウサイズが変更されたとき、ヒートマップの幅も修正する ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
function resizeHeatmap()
 +
{
 +
var height = 400;
 +
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width();
 +
if(chart == undefined || chart.length == 0 || chart[0].options.chart.type != "heatmap")
 +
return;
 +
 +
for(var i = 0; i < chart.length; i ++)
 +
$("#container" + i).highcharts().setSize(width, height);
 +
}
 +
 +
// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function setCombobox(name)
 
function setCombobox(name)
 
{
 
{
Line 70: Line 97:
 
xmlHttpRequest.send(null);
 
xmlHttpRequest.send(null);
 
}
 
}
 +
// XSS対策用 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function escape(text)
 
function escape(text)
 
{
 
{
Line 88: Line 116:
 
return text.replace(/[^A-Z0-9-]/g, "");
 
return text.replace(/[^A-Z0-9-]/g, "");
 
}
 
}
 +
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function search()
 
function search()
 
{
 
{
Line 97: Line 126:
 
var type    = document.getElementById("type").value;
 
var type    = document.getElementById("type").value;
  
var url = 'https://script.google.com/macros/s/AKfycbx3YyRXv0nkMVsJqasLJBp0n1j744dkI8AOXDibLJVx0_D4MKo/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
+
var url = 'https://script.google.com/macros/s/AKfycbwnSskrJWOPYksPyPqL5zHhGQxqeRpHhxt6ZzfaH-OCoMbG_w51/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
 
// var url = '/lipo/json.txt'
 
// var url = '/lipo/json.txt'
  
Line 119: Line 148:
 
//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;
 
for(var i = 0; i < result.length; i ++){
 
for(var i = 0; i < result.length; i ++){
 +
if(result[i].title.length > lenmax)
 +
lenmax = result[i].title.length;
 +
}
 +
lenmax /= 2;
 +
for(var i = 0; i < result.length; i ++){
 +
var span = document.createElement('span');
 +
span.style = "display: inline-block; width: " + lenmax + "em";
 +
 
var check = document.createElement('input');
 
var check = document.createElement('input');
 
check.type = 'checkbox';
 
check.type = 'checkbox';
check.id = attrEscape(result[i]);
+
check.id = attrEscape(result[i].title);
check.value = attrEscape(result[i]);
+
check.value = attrEscape(result[i].title);
 
check.name  = 'target';
 
check.name  = 'target';
root.appendChild(check);
+
span.appendChild(check);
 
var title = document.createElement('label');
 
var title = document.createElement('label');
title.setAttribute('for', attrEscape(result[i]));
+
title.setAttribute('for', attrEscape(result[i].title));
title.innerHTML = escape(result[i]);
+
title.innerHTML = escape(result[i].title);
root.appendChild(title);
+
span.appendChild(title);
root.appendChild(document.createElement('br'));
+
 
 +
root.appendChild(span);
 
}
 
}
 
document.getElementById("searchButton").disabled = false;
 
document.getElementById("searchButton").disabled = false;
 
}
 
}
 
+
// チャート表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showChart()
 
function showChart()
 
{
 
{
Line 148: Line 188:
 
}
 
}
 
targets = targets.substring(1);
 
targets = targets.substring(1);
 +
document.getElementById("resetZoomButton").style = "visibility: hidden";
  
 
document.getElementById("showButton").disabled = true;
 
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 chartType;
 
var chartType;
 
if(document.getElementById('bar').checked)
 
if(document.getElementById('bar').checked)
Line 155: Line 204:
 
else
 
else
 
chartType = 'heatmap';
 
chartType = 'heatmap';
var url = 'https://script.google.com/macros/s/AKfycbx3YyRXv0nkMVsJqasLJBp0n1j744dkI8AOXDibLJVx0_D4MKo/exec?id=' + targets + '&type=' + chartType + '&q=data&callback=hasRetrieved';
+
 
 +
retrieveChartData(targets, chartType);
 +
}
 +
// データ取得  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
function retrieveChartData(targets, chartType)
 +
{
 +
var url = 'https://script.google.com/macros/s/AKfycbwnSskrJWOPYksPyPqL5zHhGQxqeRpHhxt6ZzfaH-OCoMbG_w51/exec?id=' + targets + '&type=' + chartType + '&q=data&callback=hasRetrieved';
 
//var url = '/lipo/data.php?id=' +  targets + '&type=' + chartType + '&q=data';
 
//var url = '/lipo/data.php?id=' +  targets + '&type=' + chartType + '&q=data';
  
 
// jsonpを使った取得
 
// jsonpを使った取得
 +
var ignore0 = document.getElementById("ignore0");
 +
for(var i = ignore0.childNodes.length-1; i >= 0; i --)
 +
ignore0.removeChild(ignore0.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');
 
var root = document.getElementById('container');
 +
for(var i = root.childNodes.length-1; i >= 0; i --)
 +
root.removeChild(root.childNodes[i]);
 
root.textContent = 'Retrieving...';
 
root.textContent = 'Retrieving...';
 
var jsonp = document.createElement('script');
 
var jsonp = document.createElement('script');
Line 166: Line 229:
 
}
 
}
  
 +
// コールバック関数(jsonp)  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function hasRetrieved(jsonp)
 
function hasRetrieved(jsonp)
 
{
 
{
Line 171: Line 235:
 
// remove old elements
 
// remove old elements
 
root.textContent = '';
 
root.textContent = '';
for(var i = root.childNodes.length-1; i >= 0; i --)
+
// for(var i = root.childNodes.length-1; i >= 0; i --)
root.removeChild(root.childNodes[i]);
+
// root.removeChild(root.childNodes[i]);
  
 
var chartType;
 
var chartType;
Line 179: Line 243:
 
else
 
else
 
chartType = 'heatmap';
 
chartType = 'heatmap';
 +
 +
var ignore0 = document.getElementById("ignore0");
 +
var cbox0ignore = document.createElement("input");
 +
cbox0ignore.id = "ignore0box";
 +
cbox0ignore.setAttribute("type","checkbox");
 +
ignore0.appendChild(cbox0ignore);
 +
var ignoreLabel = document.createElement("label");
 +
ignoreLabel.innerHTML = "ignore 0-intensity column(s)";
 +
ignoreLabel.setAttribute("for", "ignore0box");
 +
ignore0.appendChild(ignoreLabel);
  
 
var result = jsonp;
 
var result = jsonp;
Line 187: Line 261:
 
showHeatmap(result);
 
showHeatmap(result);
 
document.getElementById("showButton").disabled = false;
 
document.getElementById("showButton").disabled = false;
 +
document.getElementById("bar")      .disabled = false;
 +
document.getElementById("heatmap")  .disabled = false;
 +
document.getElementById("sortableList").style.display = "block";
 
}
 
}
  
 +
// バーチャート ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
var gBarData;
 
var gBarData;
 
function getInchiOnBar(seq, x)
 
function getInchiOnBar(seq, x)
Line 195: Line 273:
 
console.log(seq + "/" + x + " => " + gBarData[seq][x]);
 
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 ignore0 = !document.getElementById("ignore0box").checked;
 +
var xLabels = [];
 +
for(var j = 0; j < chart[0].data.length; j ++){
 +
var not0 = false;
 +
for(var i = 0; i < chart.length; i ++){
 +
if(ignore0 || chart[i].data[j] != 0){
 +
not0 = true;
 +
break;
 +
}
 +
}
 +
target[j] = not0;
 +
}
 +
 +
for(var j = 0; j < chart.length; j ++){
 +
var i = 0;
 +
var data = [];
 +
for(var k = 0,l = 0; k < chart[j].data.length; k ++){
 +
if(target[k]){
 +
data[i++] = chart[j].data[k];
 +
}
 +
}
 +
chart[j].series[0].setData(data, true);
 +
}
 +
 +
unzoomBarCharts();
 +
}
 +
// 表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showBarChart(result)
 
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("ignore0box").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;
 +
})
 +
);
 +
}
 +
});
 +
 +
// create barchart(s)
 
gBarData = [];
 
gBarData = [];
var root = document.getElementById('container');
+
chart    = [];
for(var i = 0; i < result.length; i ++){
+
piechart = [];
 +
var root   = document.getElementById('container');
 +
var pieRoot = document.getElementById('pieContainer');
 +
for(var i = 0; i < result[0].map.length; i ++){
 
gBarData[i] = [];
 
gBarData[i] = [];
 
// データの整理
 
// データの整理
 
var data = [];
 
var data = [];
for(var j = 0; j < result[i].data.length; j ++){
+
for(var j = 0; j < result[0].map[i].data.length; j ++){
data[j] = [attrEscape(result[i].data[j][2]), attrEscape(result[i].data[j][3])];
+
data[j] = [attrEscape(result[0].x[j]), attrEscape(result[0].map[i].data[j][0])];
gBarData[i][j] = inchiEscape(result[i].data[j][5]); // InChIキー
+
gBarData[i][j] = inchiEscape(result[0].map[i].data[j][2]); // InChIキー
 
}
 
}
  
Line 211: Line 413:
 
var parent = document.createElement('div');
 
var parent = document.createElement('div');
 
parent.id = 'container' + i;
 
parent.id = 'container' + i;
 +
parent.setAttribute("order", i);
 
root.appendChild(parent);
 
root.appendChild(parent);
var chart = new Highcharts.Chart({
+
chart[i] = new Highcharts.Chart({
 
chart: {
 
chart: {
 
type: 'column',
 
type: 'column',
 +
zoomType: 'x',
 
renderTo: parent,
 
renderTo: parent,
 
height: 250,
 
height: 250,
 +
resetZoomButton: {
 +
theme: {
 +
display: 'none'
 +
}
 +
}
 
},
 
},
 
title: {
 
title: {
text: (i+1) + '.' + attrEscape(result[i].title)
+
text: (i+1) + '.' + attrEscape(result[0].map[i].title)
 
},
 
},
 
xAxis: {
 
xAxis: {
 +
min: 0,
 
type: 'category',
 
type: 'category',
 
labels: {
 
labels: {
Line 233: Line 443:
 
text: '分子種'
 
text: '分子種'
 
},
 
},
 +
events : {
 +
afterSetExtremes: function(){
 +
if(!this.chart.options.chart.isZoomed){
 +
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;
 +
}
 +
}
 +
document.getElementById("resetZoomButton").style = "visibility: visible";
 +
}
 +
},
 +
}
 
},
 
},
 
scrollbar: {
 
scrollbar: {
Line 241: Line 471:
 
max: 100,
 
max: 100,
 
title: {
 
title: {
text: 'Height'
+
text: 'Relative Intensity(%)'
 
}
 
}
 
},
 
},
Line 248: Line 478:
 
},
 
},
 
tooltip: {
 
tooltip: {
pointFormat: '<b>{point.y:.1f}</b>'
+
pointFormat: '<b>{point.y:.1f} %</b>'
 
},
 
},
 
series: [{
 
series: [{
Line 260: Line 490:
 
  }
 
  }
 
}  
 
}  
 +
}]
 +
});
 +
chart[i].data = data;
 +
 +
// 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) + '.amount'
 +
},
 +
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: 'Brands',
 +
colorByPoint: true,
 +
data: result[0].map[i].pie,
 +
events: {
 +
click: function(event) {
 +
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 chart;
 
var gHeatmapData;
 
var gHeatmapData;
function getInchiOnHeatmap(seq, x, y)
+
function getInchiOnHeatmap(seq, x, y) // 未使用
 
{
 
{
 
window.open("http://jcbl.jp/","new");
 
window.open("http://jcbl.jp/","new");
 
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]);
 
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]);
 
}
 
}
 +
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 ignore0 = !document.getElementById("ignore0box").checked;
 +
var xLabels = [];
 +
for(var k = 0; k < gHeatmapData[index].map[0].data.length; k ++){
 +
var not0 = false;
 +
for(var j = 0; j < length; j ++){
 +
if(ignore0 || gHeatmapData[index].map[j].data[k][0] != 0){
 +
not0 = true;
 +
break;
 +
}
 +
}
 +
target[k] = not0;
 +
if(not0)
 +
xLabels[i++] = gHeatmapData[index].x[k];
 +
}
 +
 +
var data = [];
 +
var yLabels = [];
 +
chart[index].inchi = [];
 +
i = 0;
 +
for(var j = 0; j < seq.length && j < length; j ++){
 +
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])];
 +
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);
 +
}
 +
yLabels.reverse();
 +
chart[index].series[0].setData(data, true);
 +
chart[index].yAxis[0].setCategories(yLabels);
 +
chart[index].xAxis[0].setCategories(xLabels);
 +
}
 +
// 表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function showHeatmap(result)
 
function showHeatmap(result)
 
{
 
{
 
gHeatmapData = [];
 
gHeatmapData = [];
 
var root = document.getElementById('container');
 
var root = document.getElementById('container');
 +
 +
var sortableList = document.getElementById("sortableList");
 +
chart = [];
 +
gHeatmapData = result;
 
for(var i = 0; i < result.length; i ++){
 
for(var i = 0; i < result.length; i ++){
 
// タイトル
 
// タイトル
Line 286: Line 633:
 
var data = [];
 
var data = [];
 
var yLabels = [];
 
var yLabels = [];
gHeatmapData[i] = [];
+
var length = result[i].map.length
for(var j = 0; j < result[i].map.length; j ++){
+
var inchi = [];
gHeatmapData[i][j] = [];
+
for(var j = 0; j < length; j ++){
 +
inchi[j] = [];
 
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, j, attrEscape(result[i].map[j].data[k][0])];
+
data[index] = [k, length-j-1, attrEscape(result[i].map[j].data[k][0])];
gHeatmapData[i][j][k] = inchiEscape(result[i].map[j].data[k][2]);
+
inchi[j][k] = inchiEscape(result[i].map[j].data[k][2]);
 
index ++;
 
index ++;
 
}
 
}
yLabels[j] = attrEscape(result[i].map[j].title);
+
yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title);
 
}
 
}
 +
yLabels.reverse();
 
for(var j = 0; j < result[i].x.length; j ++)
 
for(var j = 0; j < result[i].x.length; j ++)
 
result[i].x[j] = attrEscape(result[i].x[j]);
 
result[i].x[j] = attrEscape(result[i].x[j]);
var xMax = result[i].x.length-1;
+
 
if(xMax > 10)
+
// create ignore 0-intensity button
xMax = 10;
+
document.getElementById("ignore0box").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 chart = new Highcharts.Chart({
+
chart[i] = new Highcharts.Chart({
 
 
 
chart: {
 
chart: {
 
type: 'heatmap',
 
type: 'heatmap',
 +
zoomType: 'xy',
 +
animation: 1,
 
marginBottom: 0,
 
marginBottom: 0,
 
plotBorderWidth: 1,
 
plotBorderWidth: 1,
 
renderTo: parent,
 
renderTo: parent,
 +
animation: true,
 
},
 
},
 
 
Line 316: Line 724:
 
 
 
title: {
 
title: {
text: title
+
text: title,
 +
align: 'left'
 
},
 
},
 
 
Line 329: Line 738:
 
}
 
}
 
},
 
},
max: xMax
 
 
},
 
},
 
 
Line 340: Line 748:
 
min: 0,
 
min: 0,
 
max: 100,
 
max: 100,
minColor: '#FFFFFF',
+
minColor: '#ffffff',
 
maxColor: Highcharts.getOptions().colors[8]
 
maxColor: Highcharts.getOptions().colors[8]
 
},
 
},
Line 357: Line 765:
 
return this.series.yAxis.categories[this.point.y] + '<br />' +
 
return this.series.yAxis.categories[this.point.y] + '<br />' +
 
this.series.xAxis.categories[this.point.x] + '<br />' +
 
this.series.xAxis.categories[this.point.x] + '<br />' +
(Math.round(this.point.value*10)/10);
+
(Math.round(this.point.value*10)/10) + ' %';
 
}
 
}
 
},
 
},
Line 394: Line 802:
 
},*/
 
},*/
 
click: function(event){
 
click: function(event){
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
+
// var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
getInchiOnHeatmap(index, event.point.x, event.point.y);
+
// getInchiOnHeatmap(index, event.point.x, event.point.y);
 +
jumpToJcbl(event.point.series.chart.inchi[event.point.y][event.point.x]);
 
}
 
}
 
}
 
}
Line 402: Line 811:
 
 
 
});
 
});
 +
chart[i].inchi = inchi;
 
//chart.setSize(600,300,false);
 
//chart.setSize(600,300,false);
 
}
 
}
 +
resizeHeatmap();
 
}
 
}
 +
 +
// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
function getTarget(children, target)
 
function getTarget(children, target)
 
{
 
{

Revision as of 15:51, 19 April 2016

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

// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
addOnloadHook(init); 

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

	var searchButton = document.createElement("input");
	searchButton.value = "search";
	searchButton.id    = "searchButton";
	searchButton.type  = "button";
	searchButton.onclick = function(){search()};
	document.getElementById("search").appendChild(searchButton);
	var showButton = document.createElement("input");
	showButton.value = "show";
	showButton.id    = "showButton";
	showButton.type  = "button";
	showButton.onclick = function(){showChart()};
	document.getElementById("show").appendChild(showButton);

	// 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);

	setCombobox('Classification');
	setCombobox('Sample');
	setCombobox('Type');

	$(window).resize(function() {
		resizeHeatmap();
	});
}
// ウィンドウサイズが変更されたとき、ヒートマップの幅も修正する ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function resizeHeatmap()
{
	var height = 400;
	var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width();
	if(chart == undefined || chart.length == 0 || chart[0].options.chart.type != "heatmap")
		return;

	for(var i = 0; i < chart.length; i ++)
		$("#container" + i).highcharts().setSize(width, height);
}

// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
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 != 'Type')
					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);
			}
		}
	}

	// search
	xmlHttpRequest.open('GET', url, true);
	xmlHttpRequest.responseType = 'text';
	xmlHttpRequest.send(null);
}
// XSS対策用 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function escape(text)
{
	if(isFinite(text))
		return text;
	return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
function attrEscape(text)
{
	if(isFinite(text))
		return text;
	return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&rsquo;");
}
function inchiEscape(text)
{
	if(isFinite(text))
		return text;
	return text.replace(/[^A-Z0-9-]/g, "");
}
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function search()
{
	document.getElementById("searchButton").disabled = true;
	document.getElementById('hit').innerHTML = '';

	var classification = document.getElementById("classification").value;
	var sample   = document.getElementById("sample").value;
	var type     = document.getElementById("type").value;

	var url = 'https://script.google.com/macros/s/AKfycbwnSskrJWOPYksPyPqL5zHhGQxqeRpHhxt6ZzfaH-OCoMbG_w51/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
//	var url = '/lipo/json.txt'

	// jsonpを使って検索
	var root = document.getElementById('result');
	root.textContent = 'Searching...';
	var jsonp = document.createElement('script');
	jsonp.src = url;
	document.head.appendChild(jsonp);
}

function hasSearched(jsonp)
{
	var root = document.getElementById('result');
	// remove old elements
	root.textContent = '';
	for(var i = root.childNodes.length-1; i >= 0; i --)
		root.removeChild(root.childNodes[i]);

	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 /= 2;
	for(var i = 0; i < result.length; i ++){
		var span = document.createElement('span');
		span.style = "display: inline-block; 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';
		span.appendChild(check);
		var title = document.createElement('label');
		title.setAttribute('for', attrEscape(result[i].title));
		title.innerHTML = escape(result[i].title);
		span.appendChild(title);

		root.appendChild(span);
	}
	document.getElementById("searchButton").disabled = false;
}
// チャート表示 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
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 chartType;
	if(document.getElementById('bar').checked)
		chartType = 'bar';
	else
		chartType = 'heatmap';

	retrieveChartData(targets, chartType);
}
// データ取得  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function retrieveChartData(targets, chartType)
{
	var url = 'https://script.google.com/macros/s/AKfycbwnSskrJWOPYksPyPqL5zHhGQxqeRpHhxt6ZzfaH-OCoMbG_w51/exec?id=' + targets + '&type=' + chartType + '&q=data&callback=hasRetrieved';
	//var url = '/lipo/data.php?id=' +  targets + '&type=' + chartType + '&q=data';

	// jsonpを使った取得
	var ignore0 = document.getElementById("ignore0");
	for(var i = ignore0.childNodes.length-1; i >= 0; i --)
		ignore0.removeChild(ignore0.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]);
	root.textContent = 'Retrieving...';
	var jsonp = document.createElement('script');
	jsonp.src = url;
	document.head.appendChild(jsonp);
}

// コールバック関数(jsonp)  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
function hasRetrieved(jsonp)
{
	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
		chartType = 'heatmap';

	var ignore0 = document.getElementById("ignore0");
	var cbox0ignore = document.createElement("input");
	cbox0ignore.id = "ignore0box";
	cbox0ignore.setAttribute("type","checkbox");
	ignore0.appendChild(cbox0ignore);
	var ignoreLabel = document.createElement("label");
	ignoreLabel.innerHTML = "ignore 0-intensity column(s)";
	ignoreLabel.setAttribute("for", "ignore0box");
	ignore0.appendChild(ignoreLabel);

	var result = jsonp;
	//var result = JSON.parse(escape(jsonp));
	if(chartType == 'bar')
		showBarChart(result);
	else
		showHeatmap(result);
	document.getElementById("showButton").disabled = false;
	document.getElementById("bar")       .disabled = false;
	document.getElementById("heatmap")   .disabled = false;
	document.getElementById("sortableList").style.display = "block";
}

// バーチャート ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
var gBarData;
function getInchiOnBar(seq, x)
{
	window.open("http://jcbl.jp/","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 ignore0 = !document.getElementById("ignore0box").checked;
	var xLabels = [];
	for(var j = 0; j < chart[0].data.length; j ++){
		var not0 = false;
		for(var i = 0; i < chart.length; i ++){
			if(ignore0 || chart[i].data[j] != 0){
				not0 = true;
				break;
			}
		}
		target[j] = not0;
	}

	for(var j = 0; j < chart.length; j ++){
		var i = 0;
		var data = [];
		for(var k = 0,l = 0; k < chart[j].data.length; k ++){
			if(target[k]){
				data[i++] = chart[j].data[k];
			}
		}
		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("ignore0box").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;
				})
			);
		}
	});

	// 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 = [];
		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])];
			gBarData[i][j] = inchiEscape(result[0].map[i].data[j][2]); // 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'
					}
				},
				title: {
					text: '分子種'
				},
				events : {
					afterSetExtremes: function(){
						if(!this.chart.options.chart.isZoomed){
							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;
								}
							}
							document.getElementById("resetZoomButton").style = "visibility: visible";
						}
					},
				}
			},
			scrollbar: {
				enabled: true
			},
			yAxis: {
				min: 0,
				max: 100,
				title: {
					text: 'Relative Intensity(%)'
				}
			},
			legend: {
				enabled: false
			},
			tooltip: {
				pointFormat: '<b>{point.y:.1f} %</b>'
			},
			series: [{
				name: 'Population',
				data: data,
				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].data = data;

		// 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) + '.amount'
			},
			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: 'Brands',
				colorByPoint: true,
				data: result[0].map[i].pie,
				events: {
					click: function(event) {
						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 chart;
var gHeatmapData;
function getInchiOnHeatmap(seq, x, y) // 未使用
{
	window.open("http://jcbl.jp/","new");
	console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]);
}
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 ignore0 = !document.getElementById("ignore0box").checked;
	var xLabels = [];
	for(var k = 0; k < gHeatmapData[index].map[0].data.length; k ++){
		var not0 = false;
		for(var j = 0; j < length; j ++){
			if(ignore0 || gHeatmapData[index].map[j].data[k][0] != 0){
				not0 = true;
				break;
			}
		}
		target[k] = not0;
		if(not0)
			xLabels[i++] = gHeatmapData[index].x[k];
	}

	var data = [];
	var yLabels = [];
	chart[index].inchi = [];
	i = 0;
	for(var j = 0; j < seq.length && j < length; j ++){
		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])];
				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);
	}
	yLabels.reverse();
	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 = [];
		for(var j = 0; j < length; j ++){
			inchi[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])];
				inchi[j][k] = inchiEscape(result[i].map[j].data[k][2]);
				index ++;
			}
			yLabels[j] = (j+1) + "." + attrEscape(result[i].map[j].title);
		}
		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("ignore0box").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);

		// ヒートマップ
		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'
					}
				},
			},
	
			yAxis: {
				categories: yLabels,
				title: null
			},
	
			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(index, event.point.x, event.point.y);
							jumpToJcbl(event.point.series.chart.inchi[event.point.y][event.point.x]);
						}
					}
				}
			}]
	
		});
		chart[i].inchi = inchi;
		//chart.setSize(600,300,false);
	}
	resizeHeatmap();
}

// ※未使用※ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
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