MediaWiki:Lipoquality.js: Difference between revisions
Jcblmaster (talk | contribs) (Replaced content with "http://192.168.56.101/wiki/MediaWiki:Lipoquality.js") |
Jcblmaster (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
http:// | // 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); | |||
// 初期化 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
const DEFAULT_BAR_COLOR = "#7cb5ec"; | |||
var barColor = DEFAULT_BAR_COLOR; | |||
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.style.width = "100%"; | |||
searchButton.onclick = function(){search()}; | |||
document.getElementById("search").appendChild(searchButton); | |||
var showButton = document.createElement("input"); | |||
showButton.value = "show graph"; | |||
showButton.id = "showButton"; | |||
showButton.type = "button"; | |||
showButton.disabled = "yes"; | |||
showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; showChart()}; | |||
document.getElementById("show").appendChild(showButton); | |||
var checkButton = document.createElement("input"); | |||
checkButton.value = "all check/uncheck"; | |||
checkButton.type = "button"; | |||
checkButton.onclick = function(){checkAllResult()}; | |||
document.getElementById("check").appendChild(checkButton); | |||
document.getElementById("graphform").style.display = "none"; | |||
// 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('SampleSource'); | |||
setCombobox('SampleType'); | |||
setCombobox('LipidClass'); | |||
$(window).resize(function() { | |||
resizeChart(); | |||
}); | |||
} | |||
// ウィンドウサイズが変更されたとき、チャートの幅も修正する /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function resizeChart() | |||
{ | |||
if(chart == undefined || chart.length == 0) | |||
return; | |||
if(chart[0].options.chart.type != "heatmap"){ | |||
// barchart & piechart | |||
var height = 300; | |||
var pieWidth = 400; | |||
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - pieWidth; | |||
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 { | |||
var height = 400; | |||
var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width(); | |||
// heatmap | |||
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 != 'LipidClass') | |||
lines.unshift('All'); | |||
for(var i = 0; i < lines.length; i ++){ | |||
var opt = document.createElement('option'); | |||
opt.value = opt.textContent = lines[i].replace(/^\*/, '').replace(/^ */, '').replace(/ *$/, '').replace(/"/g, """).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, "&").replace(/</g, "<").replace(/>/g, ">"); | |||
} | |||
function attrEscape(text) | |||
{ | |||
if(isFinite(text)) | |||
return text; | |||
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "’"); | |||
} | |||
function inchiEscape(text) | |||
{ | |||
if(isFinite(text)) | |||
return text; | |||
return text.replace(/^InChIKey=/, "").replace(/[^A-Z0-9-]/g, ""); | |||
} | |||
// 検索 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function search() | |||
{ | |||
document.getElementById("searchButton").disabled = true; | |||
document.getElementById('hit').innerHTML = ''; | |||
document.getElementById("showButton").disabled = "yes"; | |||
document.getElementById("graphform").style.display = "none"; | |||
var classification = document.getElementById("samplesource").value; | |||
var sample = document.getElementById("sampletype").value; | |||
var type = document.getElementById("lipidclass").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' | |||
document.getElementById('searching').style.display = "block"; | |||
// remove old elements | |||
var root = document.getElementById('result'); | |||
root.textContent = ''; | |||
for(var i = root.childNodes.length-1; i >= 0; i --) | |||
root.removeChild(root.childNodes[i]); | |||
// jsonpを使って検索 | |||
var jsonp = document.createElement('script'); | |||
jsonp.src = url; | |||
document.head.appendChild(jsonp); | |||
} | |||
function hasSearched(jsonp) | |||
{ | |||
document.getElementById('searching').style.display = "none"; | |||
var root = document.getElementById('result'); | |||
var result = jsonp; | |||
//var result = JSON.parse(escape(jsonp)); | |||
document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).'; | |||
// 最長文字数を調べる | |||
var lenmax = 0; | |||
for(var i = 0; i < result.length; i ++){ | |||
if(result[i].title.length > lenmax) | |||
lenmax = result[i].title.length; | |||
} | |||
lenmax /= 1.5; | |||
for(var i = 0; i < result.length; i ++){ | |||
var span = document.createElement('span'); | |||
span.style.display = "inline-block"; | |||
span.style.width = lenmax + "em"; | |||
var check = document.createElement('input'); | |||
check.type = 'checkbox'; | |||
check.id = attrEscape(result[i].title); | |||
check.value = attrEscape(result[i].title); | |||
check.name = 'target'; | |||
check.className = "results"; | |||
check.onchange = function(e){ | |||
checkSelection(); | |||
}; | |||
span.appendChild(check); | |||
var title = document.createElement('label'); | |||
title.setAttribute('for', attrEscape(result[i].title)); | |||
title.innerHTML = escape(result[i].title); | |||
span.appendChild(title); | |||
root.appendChild(span); | |||
} | |||
document.getElementById("searchButton").disabled = false; | |||
document.getElementById("graphform").style.display = "block"; | |||
} | |||
function checkSelection() | |||
{ | |||
var c = document.getElementsByClassName("results"); | |||
var disabled = true; | |||
for(var i = 0; i < c.length; i ++){ | |||
if(c[i].checked){ | |||
disabled = false; | |||
break; | |||
} | |||
} | |||
document.getElementById("showButton").disabled = disabled; | |||
} | |||
function checkAllResult() | |||
{ | |||
var c = document.getElementsByClassName("results"); | |||
var checked = 0; | |||
for(var i = 0; i < c.length; i ++){ | |||
if(c[i].checked) | |||
checked ++; | |||
} | |||
var state = true; | |||
if(checked == c.length) | |||
state = false; | |||
for(var i = 0; i < c.length; i ++) | |||
c[i].checked = state; | |||
checkSelection(); | |||
} | |||
// チャート表示 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
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 cutoff = document.getElementById("cutoff"); | |||
for(var i = cutoff.childNodes.length-1; i >= 0; i --) | |||
cutoff.removeChild(cutoff.childNodes[i]); | |||
var pieRoot = document.getElementById('pieContainer'); | |||
for(var i = pieRoot.childNodes.length-1; i >= 0; i --) | |||
pieRoot.removeChild(pieRoot.childNodes[i]); | |||
var root = document.getElementById('container'); | |||
for(var i = root.childNodes.length-1; i >= 0; i --) | |||
root.removeChild(root.childNodes[i]); | |||
document.getElementById('retrieving').style.display = "block"; | |||
var jsonp = document.createElement('script'); | |||
jsonp.src = url; | |||
document.head.appendChild(jsonp); | |||
} | |||
// コールバック関数(jsonp) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function hasRetrieved(jsonp) | |||
{ | |||
document.getElementById('retrieving').style.display = "none"; | |||
var root = document.getElementById('container'); | |||
// remove old elements | |||
root.textContent = ''; | |||
// for(var i = root.childNodes.length-1; i >= 0; i --) | |||
// root.removeChild(root.childNodes[i]); | |||
var chartType; | |||
if(document.getElementById('bar').checked) | |||
chartType = 'bar'; | |||
else | |||
chartType = 'heatmap'; | |||
var cutoff = document.getElementById("cutoff"); | |||
var cutoffText = document.createElement("input"); | |||
cutoffText.id = "cutoffValue"; | |||
cutoffText.type = "number"; | |||
cutoffText.value = 0; | |||
cutoffText.min = 0; | |||
cutoffText.max = 80; | |||
cutoffText.style.width = "4em"; | |||
cutoffText.style.textAlign = "right"; | |||
cutoff.appendChild(cutoffText); | |||
var cutoffButton = document.createElement("input"); | |||
cutoffButton.value = "< cutoff"; | |||
cutoffButton.type = "button"; | |||
cutoff.appendChild(cutoffButton); | |||
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/wiki/LBG" + gBarData[seq][x], "new"); | |||
console.log(seq + "/" + x + " => " + gBarData[seq][x]); | |||
} | |||
var chart; | |||
var piechart; | |||
var defaultTickInterval = currentTickInterval = 5; | |||
// バーチャートのズーム解除 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function unzoomBarCharts() { | |||
for(var i = 0; i < chart.length; i ++){ | |||
//chart[i].xAxis[0].options.tickInterval = defaultTickInterval; | |||
chart[i].xAxis[0].isDirty = true; | |||
chart[i].xAxis[0].setExtremes(null, null, animation=true); | |||
} | |||
document.getElementById("resetZoomButton").style.visibility = "hidden"; | |||
} | |||
// データの切り替え(表示/非表示、0-intensity) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function setBarchartData() | |||
{ // inchiキー未処理 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
var target = []; | |||
var cutoff = parseInt(document.getElementById("cutoffValue").value); | |||
var xLabels = []; | |||
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 = []; | |||
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("cutoffValue").onchange = function(){ | |||
setBarchartData(); | |||
}; | |||
// create sortable list | |||
var sortableList = document.getElementById("sortableList"); | |||
for(var i = 0; i < result[0].map.length; i ++){ | |||
var line = document.createElement("div"); | |||
var cbox = document.createElement("input"); | |||
cbox.setAttribute("type", "checkbox"); | |||
cbox.setAttribute("checked", "yes"); | |||
cbox.setAttribute("seq", i); | |||
cbox.id = "item" + i; | |||
cbox.onchange = function(e){ | |||
// 表示/非表示の切り替え | |||
var seq = this.getAttribute("seq"); | |||
var option; | |||
if(this.checked){ | |||
option = "block"; | |||
} else { | |||
option = "none"; | |||
} | |||
document.getElementById("container" + seq).style.display = option; | |||
document.getElementById("pieContainer" + seq).style.display = option; | |||
}; | |||
line.appendChild(cbox); | |||
var label = document.createElement("label"); | |||
label.setAttribute("for", "item" + i); | |||
label.innerHTML = (i+1) + "." + escape(result[0].map[i].title); | |||
line.appendChild(label); | |||
sortableList.appendChild(line); | |||
} | |||
$('#sortableList').sortable({ | |||
cursor: 'move', | |||
update: function(event, ui){ | |||
var sortableList = document.getElementById("sortableList"); | |||
for(var i = 0; i < sortableList.childNodes.length; i ++){ | |||
var seq = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); | |||
document.getElementById("container" + seq).setAttribute("order", i); | |||
document.getElementById("pieContainer" + seq).setAttribute("order", i); | |||
} | |||
$("#container").html( | |||
$("#container > div").sort(function(o1,o2) | |||
{ | |||
var n1 = parseInt($(o1).attr("order"), 10); | |||
var n2 = parseInt($(o2).attr("order"), 10); | |||
if(n1 < n2) return -1; | |||
if(n1 > n2) return 1; | |||
return 0; | |||
}) | |||
); | |||
$("#pieContainer").html( | |||
$("#pieContainer > div").sort(function(o1,o2) | |||
{ | |||
var n1 = parseInt($(o1).attr("order"), 10); | |||
var n2 = parseInt($(o2).attr("order"), 10); | |||
if(n1 < n2) return -1; | |||
if(n1 > n2) return 1; | |||
return 0; | |||
}) | |||
); | |||
} | |||
}); | |||
// 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キー | |||
var type = result[0].map[i].title.replace(/.*\//,""); | |||
gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー | |||
} | |||
// barchartの追加 | |||
var parent = document.createElement('div'); | |||
parent.id = 'container' + i; | |||
parent.setAttribute("order", i); | |||
root.appendChild(parent); | |||
chart[i] = new Highcharts.Chart({ | |||
chart: { | |||
type: 'column', | |||
zoomType: 'x', | |||
renderTo: parent, | |||
height: 250, | |||
resetZoomButton: { | |||
theme: { | |||
display: 'none' | |||
} | |||
} | |||
}, | |||
title: { | |||
text: (i+1) + '.' + attrEscape(result[0].map[i].title) | |||
}, | |||
xAxis: { | |||
min: 0, | |||
type: 'category', | |||
labels: { | |||
rotation: -90, | |||
style: { | |||
fontSize: '11px', | |||
fontFamily: 'Verdana, sans-serif' | |||
}, | |||
step: 1 | |||
}, | |||
events : { | |||
afterSetExtremes: function(){ | |||
if(!this.chart.options.chart.isZoomed){ | |||
if(this.chart.options.chart.isZoomed !== undefined) | |||
document.getElementById("resetZoomButton").style.visibility = "visible"; | |||
var xMin = this.chart.xAxis[0].min; | |||
var xMax = this.chart.xAxis[0].max; | |||
var zmRange = computeTickInterval(xMin, xMax); | |||
for(var i = 0; i < chart.length; i ++){ | |||
chart[i].xAxis[0].options.tickInterval = zmRange; | |||
chart[i].xAxis[0].isDirty = true; | |||
if(chart[i] !== this){ | |||
chart[i].options.chart.isZoomed = true; | |||
chart[i].xAxis[0].setExtremes(xMin, xMax, true); | |||
chart[i].options.chart.isZoomed = false; | |||
} | |||
} | |||
} | |||
}, | |||
} | |||
}, | |||
scrollbar: { | |||
enabled: true | |||
}, | |||
yAxis: { | |||
min: 0, | |||
max: 100, | |||
title: { | |||
text: 'Relative Intensity(%)' | |||
} | |||
}, | |||
legend: { | |||
enabled: false | |||
}, | |||
tooltip: { | |||
pointFormat: '<b>{point.y:.1f} %</b>' | |||
}, | |||
series: [{ | |||
name: 'Population', | |||
data: data, | |||
color: barColor, | |||
events: { | |||
click: function(event) { | |||
//alert(event.point.name); | |||
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container",""); | |||
getInchiOnBar(index, event.point.x); | |||
} | |||
} | |||
}] | |||
}); | |||
chart[i].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) + '.ratio' | |||
}, | |||
tooltip: { | |||
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>' | |||
}, | |||
plotOptions: { | |||
pie: { | |||
allowPointSelect: true, | |||
cursor: 'pointer', | |||
dataLabels: { | |||
enabled: true, | |||
format: '<b>{point.name}</b>: {point.percentage:.1f} %', | |||
style: { | |||
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black' | |||
} | |||
} | |||
} | |||
}, | |||
series: [{ | |||
name: 'Rate', | |||
colorByPoint: true, | |||
data: result[0].map[i].pie, | |||
events: { | |||
click: function(event) { | |||
barColor = event.point.color; | |||
var nextType = event.point.name; | |||
var targets = ''; | |||
var sortableList = document.getElementById("sortableList"); | |||
for(var i = 0; i < sortableList.childNodes.length; i ++){ | |||
var w = sortableList.childNodes[i].childNodes[1].innerHTML.replace(/^[0-9]+./,"").split("/"); | |||
targets += "," + w[0] + "/" + w[1] + "/" + nextType; | |||
} | |||
targets = targets.substring(1); | |||
document.getElementById("showButton").disabled = true; | |||
document.getElementById("bar") .disabled = true; | |||
document.getElementById("heatmap") .disabled = true; | |||
document.getElementById("sortableList").style.display = "none"; | |||
var sortableList = document.getElementById("sortableList"); | |||
for(var i = sortableList.childNodes.length-1; i >= 0; i --) | |||
sortableList.removeChild(sortableList.childNodes[i]); | |||
retrieveChartData(targets, 'bar'); | |||
} | |||
} | |||
}] | |||
}); | |||
} | |||
resizeChart(); | |||
} | |||
// ヒートマップ /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
var chart; | |||
var gHeatmapData; | |||
function getInchiOnHeatmap(seq, x, y) // 未使用 | |||
{ | |||
window.open("http://jcbl.jp/wiki/LBG" + gHeatmapData[seq].map[0].title.replace(/.*\//, "") + gHeatmapData[seq].x[x].replace("/","-"), "new"); | |||
// console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]); | |||
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x].replace("/","-")); | |||
} | |||
function jumpToJcbl(inchi) | |||
{ | |||
window.open("http://jcbl.jp/","new"); | |||
console.log(inchi); | |||
} | |||
// データの切り替え(表示/非表示、0-intensity) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function setHeatmapData(index, seq) | |||
{ | |||
var i = 0; | |||
var length = gHeatmapData[index].map.length; | |||
var target = []; | |||
var cutoff = parseInt(document.getElementById("cutoffValue").value); | |||
var xLabels = []; | |||
for(var k = 0; k < gHeatmapData[index].map[0].data.length; k ++){ | |||
var not0 = false; | |||
for(var j = 0; j < length; j ++){ | |||
if(gHeatmapData[index].map[j].data[k][0] >= cutoff){ | |||
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.replace(/\/[^\/]+$/, "")); | |||
} | |||
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.replace(/\/[^\/]+$/, "")); | |||
} | |||
yLabels.reverse(); | |||
for(var j = 0; j < result[i].x.length; j ++) | |||
result[i].x[j] = attrEscape(result[i].x[j]); | |||
// create ignore 0-intensity button | |||
document.getElementById("cutoffValue").onchange = function(){ | |||
// 表示/非表示の切り替え // 下と同じなので、後でまとめる | |||
for(var index = 0; index < chart.length; index ++){ | |||
var sortableList = document.getElementById("sortableList" + index); | |||
var sequence = []; | |||
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ | |||
if(sortableList.childNodes[i].childNodes[0].checked) | |||
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); | |||
} | |||
setHeatmapData(index, sequence); | |||
} | |||
}; | |||
// create sortable list | |||
var listDiv = document.createElement("div"); | |||
listDiv.id = "sortableList" + i; | |||
for(var j = 0; j < result[i].map.length; j ++){ | |||
var line = document.createElement("div"); | |||
var cbox = document.createElement("input"); | |||
cbox.setAttribute("type", "checkbox"); | |||
cbox.setAttribute("checked", "yes"); | |||
cbox.setAttribute("seq", j); | |||
cbox.id = "item" + j; | |||
cbox.onchange = function(e){ | |||
// 表示/非表示の切り替え | |||
var index = this.parentElement.parentElement.id.replace("sortableList", ""); | |||
var sortableList = document.getElementById("sortableList" + index); | |||
var sequence = []; | |||
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ | |||
if(sortableList.childNodes[i].childNodes[0].checked) | |||
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); | |||
} | |||
setHeatmapData(index, sequence); | |||
}; | |||
line.appendChild(cbox); | |||
var label = document.createElement("label"); | |||
label.setAttribute("for", "item" + j); | |||
label.innerHTML = (j+1) + "." + escape(result[i].map[j].title); | |||
line.appendChild(label); | |||
listDiv.appendChild(line); | |||
} | |||
sortableList.appendChild(listDiv); | |||
$('#sortableList' + i).sortable({ | |||
cursor: 'move', | |||
update: function(event, ui){ | |||
var index = ui.item[0].parentElement.id.replace("sortableList", ""); | |||
var sortableList = document.getElementById("sortableList" + index); | |||
var sequence = []; | |||
for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ | |||
if(sortableList.childNodes[i].childNodes[0].checked) | |||
sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); | |||
} | |||
setHeatmapData(index, sequence); | |||
} | |||
}); | |||
$('#sortableList').sortable(false); | |||
// ヒートマップ | |||
chart[i] = new Highcharts.Chart({ | |||
chart: { | |||
type: 'heatmap', | |||
zoomType: 'xy', | |||
animation: 1, | |||
marginBottom: 0, | |||
plotBorderWidth: 1, | |||
renderTo: parent, | |||
animation: true, | |||
}, | |||
scrollbar: { | |||
enabled: true | |||
}, | |||
title: { | |||
text: title, | |||
align: 'left' | |||
}, | |||
xAxis: { | |||
categories: result[i].x, | |||
opposite: true, | |||
labels: { | |||
rotation: -90, | |||
style: { | |||
fontSize: '11px', | |||
fontFamily: 'Verdana, sans-serif' | |||
}, | |||
step: 1 | |||
}, | |||
}, | |||
yAxis: { | |||
categories: yLabels, | |||
title: null, | |||
labels: { | |||
step: 1 | |||
} | |||
}, | |||
colorAxis: { | |||
min: 0, | |||
max: 100, | |||
minColor: '#ffffff', | |||
maxColor: Highcharts.getOptions().colors[8] | |||
}, | |||
legend: { | |||
align: 'right', | |||
layout: 'vertical', | |||
margin: 0, | |||
verticalAlign: 'top', | |||
y: 100, | |||
symbolHeight: 145 | |||
}, | |||
tooltip: { | |||
formatter: function () { | |||
return this.series.yAxis.categories[this.point.y] + '<br />' + | |||
this.series.xAxis.categories[this.point.x] + '<br />' + | |||
(Math.round(this.point.value*10)/10) + ' %'; | |||
} | |||
}, | |||
series: [{ | |||
name: 'HEK', | |||
borderWidth: 1, | |||
data: data, | |||
dataLabels: { | |||
enabled: false, | |||
color: '#000000' | |||
}, | |||
point: { | |||
events: { | |||
/*mouseOver: function() { | |||
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", ""); | |||
var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]); | |||
if(target != null){ | |||
target.css('fill', 'red'); | |||
target.css('fontWeight', 'bold'); | |||
} | |||
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', 'red'); | |||
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', 'bold'); | |||
}, | |||
mouseOut: function() { | |||
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", ""); | |||
var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]); | |||
if(target != null){ | |||
target.css('fill', '#666666'); | |||
target.css('fontWeight', ''); | |||
} | |||
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', '#666666'); | |||
$(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', ''); | |||
},*/ | |||
click: function(event){ | |||
// var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container",""); | |||
getInchiOnHeatmap(0, event.point.x, event.point.y); | |||
// jumpToJcbl(event.point.series.chart.inchi[event.point.y][event.point.x]); | |||
} | |||
} | |||
} | |||
}] | |||
}); | |||
chart[i].inchi = inchi; | |||
//chart.setSize(600,300,false); | |||
} | |||
resizeChart(); | |||
} | |||
// ※未使用※ /////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function getTarget(children, target) | |||
{ | |||
for(var i = 0; i < children.length; i ++){ | |||
if(target == children[i].childNodes[0].textContent){ | |||
return $(children[i]); | |||
} | |||
// console.log(children[i].childNodes[0].textContent); | |||
} | |||
return null; | |||
} |
Revision as of 06:09, 20 July 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); // 初期化 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// const DEFAULT_BAR_COLOR = "#7cb5ec"; var barColor = DEFAULT_BAR_COLOR; 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.style.width = "100%"; searchButton.onclick = function(){search()}; document.getElementById("search").appendChild(searchButton); var showButton = document.createElement("input"); showButton.value = "show graph"; showButton.id = "showButton"; showButton.type = "button"; showButton.disabled = "yes"; showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; showChart()}; document.getElementById("show").appendChild(showButton); var checkButton = document.createElement("input"); checkButton.value = "all check/uncheck"; checkButton.type = "button"; checkButton.onclick = function(){checkAllResult()}; document.getElementById("check").appendChild(checkButton); document.getElementById("graphform").style.display = "none"; // 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('SampleSource'); setCombobox('SampleType'); setCombobox('LipidClass'); $(window).resize(function() { resizeChart(); }); } // ウィンドウサイズが変更されたとき、チャートの幅も修正する /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function resizeChart() { if(chart == undefined || chart.length == 0) return; if(chart[0].options.chart.type != "heatmap"){ // barchart & piechart var height = 300; var pieWidth = 400; var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width() - pieWidth; 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 { var height = 400; var width = $(window).width() - $("#sortableList").width() - $("#mw-panel").width(); // heatmap 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 != 'LipidClass') lines.unshift('All'); for(var i = 0; i < lines.length; i ++){ var opt = document.createElement('option'); opt.value = opt.textContent = lines[i].replace(/^\*/, '').replace(/^ */, '').replace(/ *$/, '').replace(/"/g, """).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, "&").replace(/</g, "<").replace(/>/g, ">"); } function attrEscape(text) { if(isFinite(text)) return text; return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "’"); } function inchiEscape(text) { if(isFinite(text)) return text; return text.replace(/^InChIKey=/, "").replace(/[^A-Z0-9-]/g, ""); } // 検索 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function search() { document.getElementById("searchButton").disabled = true; document.getElementById('hit').innerHTML = ''; document.getElementById("showButton").disabled = "yes"; document.getElementById("graphform").style.display = "none"; var classification = document.getElementById("samplesource").value; var sample = document.getElementById("sampletype").value; var type = document.getElementById("lipidclass").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' document.getElementById('searching').style.display = "block"; // remove old elements var root = document.getElementById('result'); root.textContent = ''; for(var i = root.childNodes.length-1; i >= 0; i --) root.removeChild(root.childNodes[i]); // jsonpを使って検索 var jsonp = document.createElement('script'); jsonp.src = url; document.head.appendChild(jsonp); } function hasSearched(jsonp) { document.getElementById('searching').style.display = "none"; var root = document.getElementById('result'); var result = jsonp; //var result = JSON.parse(escape(jsonp)); document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).'; // 最長文字数を調べる var lenmax = 0; for(var i = 0; i < result.length; i ++){ if(result[i].title.length > lenmax) lenmax = result[i].title.length; } lenmax /= 1.5; for(var i = 0; i < result.length; i ++){ var span = document.createElement('span'); span.style.display = "inline-block"; span.style.width = lenmax + "em"; var check = document.createElement('input'); check.type = 'checkbox'; check.id = attrEscape(result[i].title); check.value = attrEscape(result[i].title); check.name = 'target'; check.className = "results"; check.onchange = function(e){ checkSelection(); }; span.appendChild(check); var title = document.createElement('label'); title.setAttribute('for', attrEscape(result[i].title)); title.innerHTML = escape(result[i].title); span.appendChild(title); root.appendChild(span); } document.getElementById("searchButton").disabled = false; document.getElementById("graphform").style.display = "block"; } function checkSelection() { var c = document.getElementsByClassName("results"); var disabled = true; for(var i = 0; i < c.length; i ++){ if(c[i].checked){ disabled = false; break; } } document.getElementById("showButton").disabled = disabled; } function checkAllResult() { var c = document.getElementsByClassName("results"); var checked = 0; for(var i = 0; i < c.length; i ++){ if(c[i].checked) checked ++; } var state = true; if(checked == c.length) state = false; for(var i = 0; i < c.length; i ++) c[i].checked = state; checkSelection(); } // チャート表示 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 cutoff = document.getElementById("cutoff"); for(var i = cutoff.childNodes.length-1; i >= 0; i --) cutoff.removeChild(cutoff.childNodes[i]); var pieRoot = document.getElementById('pieContainer'); for(var i = pieRoot.childNodes.length-1; i >= 0; i --) pieRoot.removeChild(pieRoot.childNodes[i]); var root = document.getElementById('container'); for(var i = root.childNodes.length-1; i >= 0; i --) root.removeChild(root.childNodes[i]); document.getElementById('retrieving').style.display = "block"; var jsonp = document.createElement('script'); jsonp.src = url; document.head.appendChild(jsonp); } // コールバック関数(jsonp) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function hasRetrieved(jsonp) { document.getElementById('retrieving').style.display = "none"; var root = document.getElementById('container'); // remove old elements root.textContent = ''; // for(var i = root.childNodes.length-1; i >= 0; i --) // root.removeChild(root.childNodes[i]); var chartType; if(document.getElementById('bar').checked) chartType = 'bar'; else chartType = 'heatmap'; var cutoff = document.getElementById("cutoff"); var cutoffText = document.createElement("input"); cutoffText.id = "cutoffValue"; cutoffText.type = "number"; cutoffText.value = 0; cutoffText.min = 0; cutoffText.max = 80; cutoffText.style.width = "4em"; cutoffText.style.textAlign = "right"; cutoff.appendChild(cutoffText); var cutoffButton = document.createElement("input"); cutoffButton.value = "< cutoff"; cutoffButton.type = "button"; cutoff.appendChild(cutoffButton); 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/wiki/LBG" + gBarData[seq][x], "new"); console.log(seq + "/" + x + " => " + gBarData[seq][x]); } var chart; var piechart; var defaultTickInterval = currentTickInterval = 5; // バーチャートのズーム解除 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function unzoomBarCharts() { for(var i = 0; i < chart.length; i ++){ //chart[i].xAxis[0].options.tickInterval = defaultTickInterval; chart[i].xAxis[0].isDirty = true; chart[i].xAxis[0].setExtremes(null, null, animation=true); } document.getElementById("resetZoomButton").style.visibility = "hidden"; } // データの切り替え(表示/非表示、0-intensity) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function setBarchartData() { // inchiキー未処理 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var target = []; var cutoff = parseInt(document.getElementById("cutoffValue").value); var xLabels = []; 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 = []; 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("cutoffValue").onchange = function(){ setBarchartData(); }; // create sortable list var sortableList = document.getElementById("sortableList"); for(var i = 0; i < result[0].map.length; i ++){ var line = document.createElement("div"); var cbox = document.createElement("input"); cbox.setAttribute("type", "checkbox"); cbox.setAttribute("checked", "yes"); cbox.setAttribute("seq", i); cbox.id = "item" + i; cbox.onchange = function(e){ // 表示/非表示の切り替え var seq = this.getAttribute("seq"); var option; if(this.checked){ option = "block"; } else { option = "none"; } document.getElementById("container" + seq).style.display = option; document.getElementById("pieContainer" + seq).style.display = option; }; line.appendChild(cbox); var label = document.createElement("label"); label.setAttribute("for", "item" + i); label.innerHTML = (i+1) + "." + escape(result[0].map[i].title); line.appendChild(label); sortableList.appendChild(line); } $('#sortableList').sortable({ cursor: 'move', update: function(event, ui){ var sortableList = document.getElementById("sortableList"); for(var i = 0; i < sortableList.childNodes.length; i ++){ var seq = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); document.getElementById("container" + seq).setAttribute("order", i); document.getElementById("pieContainer" + seq).setAttribute("order", i); } $("#container").html( $("#container > div").sort(function(o1,o2) { var n1 = parseInt($(o1).attr("order"), 10); var n2 = parseInt($(o2).attr("order"), 10); if(n1 < n2) return -1; if(n1 > n2) return 1; return 0; }) ); $("#pieContainer").html( $("#pieContainer > div").sort(function(o1,o2) { var n1 = parseInt($(o1).attr("order"), 10); var n2 = parseInt($(o2).attr("order"), 10); if(n1 < n2) return -1; if(n1 > n2) return 1; return 0; }) ); } }); // 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キー var type = result[0].map[i].title.replace(/.*\//,""); gBarData[i][j] = type + attrEscape(result[0].x[j]).replace("/","-"); // InChIキー } // barchartの追加 var parent = document.createElement('div'); parent.id = 'container' + i; parent.setAttribute("order", i); root.appendChild(parent); chart[i] = new Highcharts.Chart({ chart: { type: 'column', zoomType: 'x', renderTo: parent, height: 250, resetZoomButton: { theme: { display: 'none' } } }, title: { text: (i+1) + '.' + attrEscape(result[0].map[i].title) }, xAxis: { min: 0, type: 'category', labels: { rotation: -90, style: { fontSize: '11px', fontFamily: 'Verdana, sans-serif' }, step: 1 }, events : { afterSetExtremes: function(){ if(!this.chart.options.chart.isZoomed){ if(this.chart.options.chart.isZoomed !== undefined) document.getElementById("resetZoomButton").style.visibility = "visible"; var xMin = this.chart.xAxis[0].min; var xMax = this.chart.xAxis[0].max; var zmRange = computeTickInterval(xMin, xMax); for(var i = 0; i < chart.length; i ++){ chart[i].xAxis[0].options.tickInterval = zmRange; chart[i].xAxis[0].isDirty = true; if(chart[i] !== this){ chart[i].options.chart.isZoomed = true; chart[i].xAxis[0].setExtremes(xMin, xMax, true); chart[i].options.chart.isZoomed = false; } } } }, } }, scrollbar: { enabled: true }, yAxis: { min: 0, max: 100, title: { text: 'Relative Intensity(%)' } }, legend: { enabled: false }, tooltip: { pointFormat: '<b>{point.y:.1f} %</b>' }, series: [{ name: 'Population', data: data, color: barColor, events: { click: function(event) { //alert(event.point.name); var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container",""); getInchiOnBar(index, event.point.x); } } }] }); chart[i].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) + '.ratio' }, tooltip: { pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>' }, plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', dataLabels: { enabled: true, format: '<b>{point.name}</b>: {point.percentage:.1f} %', style: { color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black' } } } }, series: [{ name: 'Rate', colorByPoint: true, data: result[0].map[i].pie, events: { click: function(event) { barColor = event.point.color; var nextType = event.point.name; var targets = ''; var sortableList = document.getElementById("sortableList"); for(var i = 0; i < sortableList.childNodes.length; i ++){ var w = sortableList.childNodes[i].childNodes[1].innerHTML.replace(/^[0-9]+./,"").split("/"); targets += "," + w[0] + "/" + w[1] + "/" + nextType; } targets = targets.substring(1); document.getElementById("showButton").disabled = true; document.getElementById("bar") .disabled = true; document.getElementById("heatmap") .disabled = true; document.getElementById("sortableList").style.display = "none"; var sortableList = document.getElementById("sortableList"); for(var i = sortableList.childNodes.length-1; i >= 0; i --) sortableList.removeChild(sortableList.childNodes[i]); retrieveChartData(targets, 'bar'); } } }] }); } resizeChart(); } // ヒートマップ /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var chart; var gHeatmapData; function getInchiOnHeatmap(seq, x, y) // 未使用 { window.open("http://jcbl.jp/wiki/LBG" + gHeatmapData[seq].map[0].title.replace(/.*\//, "") + gHeatmapData[seq].x[x].replace("/","-"), "new"); // console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]); console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq].x[x].replace("/","-")); } function jumpToJcbl(inchi) { window.open("http://jcbl.jp/","new"); console.log(inchi); } // データの切り替え(表示/非表示、0-intensity) /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function setHeatmapData(index, seq) { var i = 0; var length = gHeatmapData[index].map.length; var target = []; var cutoff = parseInt(document.getElementById("cutoffValue").value); var xLabels = []; for(var k = 0; k < gHeatmapData[index].map[0].data.length; k ++){ var not0 = false; for(var j = 0; j < length; j ++){ if(gHeatmapData[index].map[j].data[k][0] >= cutoff){ 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.replace(/\/[^\/]+$/, "")); } 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.replace(/\/[^\/]+$/, "")); } yLabels.reverse(); for(var j = 0; j < result[i].x.length; j ++) result[i].x[j] = attrEscape(result[i].x[j]); // create ignore 0-intensity button document.getElementById("cutoffValue").onchange = function(){ // 表示/非表示の切り替え // 下と同じなので、後でまとめる for(var index = 0; index < chart.length; index ++){ var sortableList = document.getElementById("sortableList" + index); var sequence = []; for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ if(sortableList.childNodes[i].childNodes[0].checked) sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); } setHeatmapData(index, sequence); } }; // create sortable list var listDiv = document.createElement("div"); listDiv.id = "sortableList" + i; for(var j = 0; j < result[i].map.length; j ++){ var line = document.createElement("div"); var cbox = document.createElement("input"); cbox.setAttribute("type", "checkbox"); cbox.setAttribute("checked", "yes"); cbox.setAttribute("seq", j); cbox.id = "item" + j; cbox.onchange = function(e){ // 表示/非表示の切り替え var index = this.parentElement.parentElement.id.replace("sortableList", ""); var sortableList = document.getElementById("sortableList" + index); var sequence = []; for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ if(sortableList.childNodes[i].childNodes[0].checked) sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); } setHeatmapData(index, sequence); }; line.appendChild(cbox); var label = document.createElement("label"); label.setAttribute("for", "item" + j); label.innerHTML = (j+1) + "." + escape(result[i].map[j].title); line.appendChild(label); listDiv.appendChild(line); } sortableList.appendChild(listDiv); $('#sortableList' + i).sortable({ cursor: 'move', update: function(event, ui){ var index = ui.item[0].parentElement.id.replace("sortableList", ""); var sortableList = document.getElementById("sortableList" + index); var sequence = []; for(var i = 0, j = 0; i < sortableList.childNodes.length; i ++){ if(sortableList.childNodes[i].childNodes[0].checked) sequence[j++] = sortableList.childNodes[i].childNodes[0].getAttribute("seq"); } setHeatmapData(index, sequence); } }); $('#sortableList').sortable(false); // ヒートマップ chart[i] = new Highcharts.Chart({ chart: { type: 'heatmap', zoomType: 'xy', animation: 1, marginBottom: 0, plotBorderWidth: 1, renderTo: parent, animation: true, }, scrollbar: { enabled: true }, title: { text: title, align: 'left' }, xAxis: { categories: result[i].x, opposite: true, labels: { rotation: -90, style: { fontSize: '11px', fontFamily: 'Verdana, sans-serif' }, step: 1 }, }, yAxis: { categories: yLabels, title: null, labels: { step: 1 } }, colorAxis: { min: 0, max: 100, minColor: '#ffffff', maxColor: Highcharts.getOptions().colors[8] }, legend: { align: 'right', layout: 'vertical', margin: 0, verticalAlign: 'top', y: 100, symbolHeight: 145 }, tooltip: { formatter: function () { return this.series.yAxis.categories[this.point.y] + '<br />' + this.series.xAxis.categories[this.point.x] + '<br />' + (Math.round(this.point.value*10)/10) + ' %'; } }, series: [{ name: 'HEK', borderWidth: 1, data: data, dataLabels: { enabled: false, color: '#000000' }, point: { events: { /*mouseOver: function() { var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", ""); var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]); if(target != null){ target.css('fill', 'red'); target.css('fontWeight', 'bold'); } $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', 'red'); $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', 'bold'); }, mouseOut: function() { var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container", ""); var target = getTarget(this.series.chart.xAxis[0].labelGroup.element.childNodes, result[index].x[this.x]); if(target != null){ target.css('fill', '#666666'); target.css('fontWeight', ''); } $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fill', '#666666'); $(this.series.chart.yAxis[0].labelGroup.element.childNodes[this.y]).css('fontWeight', ''); },*/ click: function(event){ // var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container",""); getInchiOnHeatmap(0, event.point.x, event.point.y); // jumpToJcbl(event.point.series.chart.inchi[event.point.y][event.point.x]); } } } }] }); chart[i].inchi = inchi; //chart.setSize(600,300,false); } resizeChart(); } // ※未使用※ /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function getTarget(children, target) { for(var i = 0; i < children.length; i ++){ if(target == children[i].childNodes[0].textContent){ return $(children[i]); } // console.log(children[i].childNodes[0].textContent); } return null; }