Difference between revisions of "MediaWiki:Lipoquality.js"

From Jcbl.jp
Jump to: navigation, search
m
 
(26 intermediate revisions by one user not shown)
Line 1: Line 1:
 +
// Last-Update: 2020/03/23
 
// html /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// html /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// <span id="search"></span><span id="show"></span>
 
// <span id="search"></span><span id="show"></span>
 +
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
//
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  
 
// 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");
 +
importScript( 'MediaWiki:LipoqualityCommon.js' );
 +
importScript( 'MediaWiki:LipoqualityGet.js'    );
 +
importScript( 'MediaWiki:LipoqualitySearch.js' );
 +
importScript( 'MediaWiki:LipoqualityChart.js'  );
  
 
// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
 
// initialize //////////////////////////////////////////////////////////////////////////////////////////////////
addOnloadHook(init);  
+
addOnloadHook(lipoqulityInit);
 +
 
 +
var gChartType;
 +
var gDataType;
  
function init()
+
// 初期化 //////////////////////////////////////////////////////////////////////////////////////////////////////
 +
function lipoqulityInit()
 
{
 
{
 
// highstock.jsに依存するため、別で読み込む
 
// highstock.jsに依存するため、別で読み込む
Line 16: Line 27:
 
heatmapJS.src = "https://code.highcharts.com/modules/heatmap.js";
 
heatmapJS.src = "https://code.highcharts.com/modules/heatmap.js";
 
document.getElementsByTagName("head")[0].appendChild(heatmapJS);
 
document.getElementsByTagName("head")[0].appendChild(heatmapJS);
 +
var exportingJS = document.createElement("script");
 +
exportingJS.src = "https://code.highcharts.com/modules/exporting.js";
 +
document.getElementsByTagName("head")[0].appendChild(exportingJS);
  
 +
// 検索、表示、チェックボタンを作成
 +
// 検索ボタン
 
var searchButton = document.createElement("input");
 
var searchButton = document.createElement("input");
searchButton.value = "search";
+
searchButton.value   = "search";
searchButton.id   = "searchButton";
+
searchButton.id       = "searchButton";
searchButton.type = "button";
+
searchButton.type     = "button";
searchButton.onclick = function(){search()};
+
searchButton.disabled = true;
 +
searchButton.style.width = "100%";
 +
searchButton.onclick = function(){
 +
var sampleSource = document.getElementById("samplesource").value;
 +
var sampleType  = document.getElementById("sampletype").value;
 +
var lipidClass  = document.getElementById("lipidclass").value;
 +
gDataType        = document.getElementById("datatype").value;
 +
search(sampleSource, sampleType, lipidClass, gDataType);
 +
};
 
document.getElementById("search").appendChild(searchButton);
 
document.getElementById("search").appendChild(searchButton);
 +
// グラフ表示ボタン
 
var showButton = document.createElement("input");
 
var showButton = document.createElement("input");
showButton.value = "show";
+
showButton.value = "show graph";
 
showButton.id    = "showButton";
 
showButton.id    = "showButton";
 
showButton.type  = "button";
 
showButton.type  = "button";
showButton.onclick = function(){showChart()};
+
showButton.disabled = true;
 +
showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; document.getElementById('drawing').style.display = "block"; window.setTimeout( function(){showChart(getSelectedIDs(), gDataType); document.getElementById('drawing').style.display = "none"; }, 10 );};
 
document.getElementById("show").appendChild(showButton);
 
document.getElementById("show").appendChild(showButton);
 +
// チェックボタン
 +
var checkButton = document.createElement("input");
 +
checkButton.value = "all check/uncheck";
 +
checkButton.id    = "allswitch";
 +
checkButton.type  = "button";
 +
checkButton.onclick = function(){checkAllResult()};
 +
document.getElementById("check").appendChild(checkButton);
 +
// ダウンロードボタン
 +
var downloadFileName = "lipodata.txt";
 +
var downloadLink = document.createElement("a");
 +
downloadLink.href = "#";
 +
downloadLink.download = downloadFileName;
 +
downloadLink.id = "downloadLink";
 +
downloadLink.onclick = function(){
 +
    var blob = new Blob([ getDownloadData(getSelectedIDs()) ], { "type" : "text/plain" });
  
setCombobox('Classification');
+
    if (window.navigator.msSaveBlob) {
setCombobox('Sample');
+
        window.navigator.msSaveBlob(blob, downloadFileName);
setCombobox('Type');
+
        window.navigator.msSaveOrOpenBlob(blob, downloadFileName);
 +
    } else {
 +
        document.getElementById("downloadLink").href = window.URL.createObjectURL(blob);
 +
    }
 +
};
 +
document.getElementById("check").appendChild(downloadLink);
 +
var downloadButton = document.createElement("input");
 +
downloadButton.value = "download checked";
 +
downloadButton.type  = "button";
 +
downloadButton.style = "margin-left: 1em";
 +
downloadButton.disabled = true;
 +
downloadButton.id    = "downloadButton";
 +
downloadLink.appendChild(downloadButton);
 +
 
 +
 
 +
document.getElementById("graphform").style.display = "none";
 +
 
 +
// コンポーネント初期化
 +
lipoqulityChartInit();
 +
 
 +
// コンボボックスの初期化
 +
// setCombobox('SampleSource');
 +
// setCombobox('SampleType');
 +
// setCombobox('LipidClass');
 +
retrieveSelectionList(setCombobox);
 +
 
 +
// 全データの取得
 +
retrieveAllDataFromText(hasRetrievedAllData);
 +
}
 +
// 全データの取得が完了した後の処理 /////////////////////////////////////
 +
// return なし
 +
function hasRetrievedAllData()
 +
{
 +
// GETメソッドによる検索を行う場合の処理 /////////////////////////////
 +
var query  = window.location.search.substring(1);
 +
var params = query.split('&');
 +
var sampleSource = "All";
 +
var sampleType  = "All";
 +
var lipidClass  = "";
 +
var chain        = "";
 +
var chart        = "";
 +
var species      = "";
 +
var sampleName  = "";
 +
// パラメータの取得
 +
// ss = SampleSource - デフォルトはAll
 +
// st = SampleType - デフォルトはAll
 +
// lc = LipidClass - デフォルトは空文字。この文字列が入っていないと、検索は行わない
 +
// chain = Lipid chain - chainグラフの表示には必須項目。16:0/16:0/16:0のようにスラッシュ区切り
 +
for(var i = 0; i < params.length; i++){
 +
var w = params[i].split('=');
 +
var name  = decodeURIComponent(w[0]);
 +
var value = decodeURIComponent(w[1]);
 +
if(name == "ss"){ // sample source
 +
sampleSource = value;
 +
 
 +
} else if(name == "st"){ // sample type
 +
sampleType = value;
 +
 
 +
} else if(name == "lc"){ // lipid class
 +
lipidClass = value;
 +
 
 +
} else if(name == "ct"){ // chart type
 +
chart = value;
 +
 
 +
} else if(name == "sp"){ // species
 +
species = value;
 +
 
 +
} else if(name == "sn"){ // sample name
 +
sampleName = value;
 +
 
 +
} else if(name == "dt"){
 +
gDataType = value;
 +
}
 +
}
 +
// speciesが指定された場合、対象データ以外を削除する ///////////
 +
if(species.length > 0){
 +
var spReg = new RegExp(translateForReg(species), "i");
 +
for(key in gAllData){
 +
if(!spReg.test(key)){ // speciesが合致するか
 +
delete gAllData[key];
 +
}
 +
}
 +
}
 +
////////////////////////////////////////////////////////////////
 +
var index = lipidClass.indexOf(" ");
 +
if(index > 0){
 +
chain = lipidClass.substring(index+1);
 +
lipidClass = lipidClass.substring(0, index);
 +
} else {
 +
index = lipidClass.indexOf("(");
 +
if(index >= 0){
 +
chain = lipidClass.substring(index+1, lipidClass.length-1);
 +
lipidClass = lipidClass.substring(0, index);
 +
}
 +
}
 +
chain = chain.replace(/^\(/g,"");
 +
chain = chain.replace(/[_]/g,"/");
 +
if(lipidClass.indexOf("Cer-") < 0){
 +
// chain = chain.replace(/\)$/g,"");
 +
chain = chain.replace(/[)(]/g,"/");
 +
}
 +
chain = chain.replace(/\/\//g,"/");
 +
if(chart == "c" && chain.length > 0){
 +
// lipidclass基準の棒グラフを表示
 +
selectCombobox([sampleSource, sampleType, lipidClass, gDataType]);
 +
var result = retrieveChainData(sampleName, sampleSource, sampleType, lipidClass, chain, gDataType); // speciesからsamplenameに変更
 +
if(result.x.length > 0){
 +
showChainChart(result);
 +
}
 +
 
 +
} else if(chart == "b" && lipidClass.length > 0){
 +
// bar(棒グラフ)を表示
 +
selectCombobox([sampleSource, sampleType, lipidClass, gDataType]);
 +
search(sampleSource, sampleType, lipidClass, gDataType);
 +
if(document.getElementsByClassName("results").length > 0){
 +
document.getElementById('allswitch').click();
 +
document.getElementById('bar').checked = true;
 +
showChart(getSelectedIDs(), gDataType);
 +
}
 +
}
 +
 
 +
document.getElementById('loading').style.display = "none";
 +
// 検索ボタンは有効化しておく
 +
document.getElementById("searchButton").disabled = false;
 +
}
 +
function getSelectedIDs()
 +
{
 +
var targets = [];
 +
var boxes = document.getElementsByName('target');
 +
for(var i = 0; i < boxes.length; i ++){
 +
if(boxes[i].checked)
 +
targets.push(boxes[i].value);
 +
}
 +
if(targets.length == 0){
 +
alert("選択してください");
 +
return [];
 +
}
 +
return targets;
 
}
 
}
 +
// 検索ボックスの初期化 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 +
// param name カテゴリ名
 +
// return なし
 
function setCombobox(name)
 
function setCombobox(name)
 
{
 
{
Line 46: Line 227:
 
if(this.status == HTTP_STATUS_OK) {
 
if(this.status == HTTP_STATUS_OK) {
 
// success
 
// success
console.log(this.response);
 
 
var parser = new DOMParser();
 
var parser = new DOMParser();
var dom = parser.parseFromString(this.response, "text/xml");
+
var dom = parser.parseFromString(this.response.trim(), "text/xml");
 
var text = dom.getElementsByTagName("rev");
 
var text = dom.getElementsByTagName("rev");
 
var lines = text[0].textContent.split("\n");
 
var lines = text[0].textContent.split("\n");
 
var select = document.getElementById(name.toLowerCase());
 
var select = document.getElementById(name.toLowerCase());
if(name != 'Type')
+
if(name != 'LipidClass')
 
lines.unshift('All');
 
lines.unshift('All');
 
for(var i = 0; i < lines.length; i ++){
 
for(var i = 0; i < lines.length; i ++){
Line 66: Line 246:
 
}
 
}
  
// search
+
// AJAXを使って、コンボボックスの選択項目を取得する
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.send(null);
 
xmlHttpRequest.send(null);
 
}
 
}
function escape(text)
+
var globalList = null;
 +
function setCombobox()
 
{
 
{
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+
document.getElementById("samplesource").onchange  = function(){ setNames() };
 +
document.getElementById("sampletype").onchange    = function(){ setLipidcategories() };
 +
document.getElementById("lipidcategory").onchange = function(){ setLipidclassess() };
 +
 
 +
var keys = Object.keys(gListData);
 +
appendOption("samplesource", "All");
 +
for(var i = 0; i < keys.length; i ++){
 +
appendOption("samplesource", keys[i]);
 +
}
 +
 
 +
setNames();
 
}
 
}
function attrEscape(text)
+
 
 +
function appendOption(id, value)
 
{
 
{
if(isFinite(text))
+
var parent = document.getElementById(id);
return text;
+
var op = document.createElement("option");
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&rsquo;");
+
op.valuie = value;
 +
op.textContent = value;
 +
parent.appendChild(op);
 
}
 
}
function search()
+
function removeAll(id)
 
{
 
{
document.getElementById("searchButton").disabled = true;
+
parent = document.getElementById(id);
document.getElementById('hit').innerHTML = '';
+
while(parent.lastChild){
 
+
parent.removeChild(parent.lastChild);
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/AKfycbzx6dDKYI8fDsEpKJtHCtsjIGYS3sgfEFIuLbN9zJb6ba_yxAAs/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search';
+
// var url = '/lipo/json.txt'
+
 
+
var xmlHttpRequest = new XMLHttpRequest();
+
xmlHttpRequest.onreadystatechange = function()
+
{
+
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 READYSTATE_COMPLETED = 4;
+
if(this.readyState == READYSTATE_COMPLETED){
+
var HTTP_STATUS_OK = 200;
+
if(this.status == HTTP_STATUS_OK ) {
+
// success
+
var result = JSON.parse(escape(this.response));
+
document.getElementById('hit').innerHTML = 'result. ' + result.length + ' hit(s).';
+
for(var i = 0; i < result.length; i ++){
+
var check = document.createElement('input');
+
check.type = 'checkbox';
+
check.id = result[i].replace(/"/g, "&quot");
+
check.value = result[i].replace(/"/g, "&quot");
+
check.name  = 'target';
+
root.appendChild(check);
+
var title = document.createElement('label');
+
title.setAttribute('for', result[i]);
+
title.innerHTML = result[i];
+
root.appendChild(title);
+
root.appendChild(document.createElement('br'));
+
}
+
} else {
+
// error
+
root.textContent = 'search failed. ' + this.status + ':' + this.statusText;
+
}
+
document.getElementById("searchButton").disabled = false;
+
}
+
 
}
 
}
 
// search
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.send(null);
 
var root = document.getElementById('result');
 
root.textContent = 'Searching...';
 
 
}
 
}
function showChart()
+
function getRegExp(id)
 
{
 
{
var targets = '';
+
var item = document.getElementById(id).value;
var boxes = document.getElementsByName('target');
+
var regexp;
for(var i = 0; i < boxes.length; i ++){
+
if(item == "All"){
if(boxes[i].checked)
+
regexp = new RegExp('.*');
targets += ',' + boxes[i].value;
+
} else {
 +
regexp = new RegExp("^" + item.replace("(","\\(").replace(")","\\)") + "$");
 
}
 
}
if(targets.length == 0){
+
return regexp;
alert("選択してください");
+
}
return;
+
function setNames()
 +
{
 +
removeAll("sampletype");
 +
globalList = [];
 +
getSelectionList([getRegExp("samplesource"), null, null], gListData, 0, 0);
 +
globalList.sort();
 +
appendOption("sampletype", "All");
 +
for(var i = 0; i < globalList.length; i ++){
 +
appendOption("sampletype", globalList[i]);
 
}
 
}
targets = targets.substring(1);
 
  
document.getElementById("showButton").disabled = true;
+
setLipidcategories();
var chartType;
+
}
if(document.getElementById('bar').checked)
+
function setLipidcategories()
chartType = 'bar';
+
{
else
+
removeAll("lipidcategory");
chartType = 'heatmap';
+
globalList = [];
var url = 'https://script.google.com/macros/s/AKfycbzx6dDKYI8fDsEpKJtHCtsjIGYS3sgfEFIuLbN9zJb6ba_yxAAs/exec?id=' + targets + '&type=' + chartType + '&q=data';
+
getSelectionList([getRegExp("samplesource"), getRegExp("sampletype"), null], gListData, 1, 0);
//var url = '/lipo/data.php?id=' +  targets + '&type=' + chartType + '&q=data';
+
globalList.sort();
 
+
appendOption("lipidcategory", "All");
var xmlHttpRequest = new XMLHttpRequest();
+
for(var i = 0; i < globalList.length; i ++){
xmlHttpRequest.onreadystatechange = function()
+
appendOption("lipidcategory", globalList[i]);
{
+
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 READYSTATE_COMPLETED = 4;
+
var HTTP_STATUS_OK = 200;
+
if(this.readyState == READYSTATE_COMPLETED){
+
if(this.status == HTTP_STATUS_OK) {
+
    // success
+
  var result = JSON.parse(escape(this.response));
+
if(chartType == 'bar')
+
showBarChart(result);
+
else
+
showHeatmap(result);
+
} else {
+
// error
+
root.textContent = 'retrieving failed. ' + this.status + ':' + this.statusText;
+
}
+
document.getElementById("showButton").disabled = false;
+
}
+
 
}
 
}
// retrieving
 
xmlHttpRequest.open('GET', url, true);
 
xmlHttpRequest.responseType = 'text';
 
xmlHttpRequest.send(null);
 
var root = document.getElementById('container');
 
root.textContent = 'Retrieving...';
 
  
 +
setLipidclassess();
 
}
 
}
var gBarData;
+
function setLipidclassess()
function getInchiOnBar(seq, x)
+
 
{
 
{
window.open("http://jcbl.jp/","new");
+
removeAll("lipidclass");
console.log(seq + "/" + x + " => " + gBarData[seq][x]);
+
globalList = [];
 +
getSelectionList([getRegExp("samplesource"), getRegExp("sampletype"), getRegExp("lipidcategory")], gListData, 2, 0);
 +
globalList.sort();
 +
for(var i = 0; i < globalList.length; i ++){
 +
appendOption("lipidclass", globalList[i]);
 +
}
 
}
 
}
function showBarChart(result)
+
function getSelectionList(patterns, obj, depth, level)
 
{
 
{
gBarData = [];
+
if(level == 2){
var root = document.getElementById('container');
+
// last
for(var i = 0; i < result.length; i ++){
+
var targets = Object.keys(obj);
gBarData[i] = [];
+
for(var i = 0; i < targets.length; i ++){
// データの整理
+
if(patterns[level].test(targets[i])){
var data = [];
+
for(var j = 0; j < obj[targets[i]].length; j ++){
for(var j = 0; j < result[i].data.length; j ++){
+
if(globalList.indexOf(obj[targets[i]][j]) == -1)
data[j] = [attrEscape(result[i].data[j][2]), attrEscape(result[i].data[j][3])];
+
globalList.push(obj[targets[i]][j]);
gBarData[i][j] = result[i].data[j][5]; // InChIキー
+
}
 +
}
 
}
 
}
 
+
} else {
// barchartの追加
+
// sub
var parent = document.createElement('div');
+
var keys = Object.keys(obj);
parent.id = 'container' + i;
+
for(var i = 0; i < keys.length; i ++){
root.appendChild(parent);
+
if(patterns[level].test(keys[i])){
var chart = new Highcharts.Chart({
+
if(level == depth){
chart: {
+
var targets = Object.keys(obj[keys[i]][0]);
type: 'column',
+
for(var j = 0; j < targets.length; j ++){
renderTo: parent,
+
if(globalList.indexOf(targets[j]) == -1)
height: 250,
+
globalList.push(targets[j]);
},
+
title: {
+
text: (i+1) + '.' + attrEscape(result[i].title)
+
},
+
xAxis: {
+
type: 'category',
+
labels: {
+
rotation: -90,
+
style: {
+
fontSize: '11px',
+
fontFamily: 'Verdana, sans-serif'
+
 
}
 
}
},
+
} else {
title: {
+
getSelectionList(patterns, obj[keys[i]][0], depth, level+1);
text: '分子種'
+
},
+
},
+
scrollbar: {
+
enabled: true
+
},
+
yAxis: {
+
min: 0,
+
max: 100,
+
title: {
+
text: 'Height'
+
 
}
 
}
},
+
}
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);
+
  }
+
}
+
}]
+
});
+
 
}
 
}
 
}
 
}
var gHeatmapData;
+
 
function getInchiOnHeatmap(seq, x, y)
+
// 指定されたコンボボックスの値をセットする /////////////////////////////////////
 +
// param targets - 選択するSampleSource, SampleType, LipidClassの項目値
 +
// return なし
 +
function selectCombobox(targets)
 
{
 
{
window.open("http://jcbl.jp/","new");
+
var ids = ["samplesource", "sampletype", "lipidclass", "datatype"];
console.log(seq + "/" + y + "/" + x + " => " + gHeatmapData[seq][y][x]);
+
}
+
function showHeatmap(result)
+
{
+
gHeatmapData = [];
+
var root = document.getElementById('container');
+
for(var i = 0; i < result.length; i ++){
+
// タイトル
+
var title = attrEscape(result[i].title);
+
  
// 親要素
+
// 一つでもコンボボックスの初期化が終わっていなければ、処理を後回しにする
var parent = document.createElement('div');
+
var counter = 1;
parent.id = 'container' + i;
+
for(var i = 0; i < ids.length; i ++)
root.appendChild(parent);
+
counter *= document.getElementById(ids[i]).options.length;
 +
if(counter == 0){
 +
window.setTimeout( function() { selectCombobox(targets) }, 50 );
 +
return;
 +
}
  
var index = 0;
+
// コンボボックスの値をセットする
var data = [];
+
for(var i = 0; i < ids.length; i ++){
var yLabels = [];
+
var cb = document.getElementById(ids[i]);
gHeatmapData[i] = [];
+
for(var j = 0; j < cb.options.length; j ++){
for(var j = 0; j < result[i].map.length; j ++){
+
if(cb.options[j].value == targets[i]){
gHeatmapData[i][j] = [];
+
cb.selectedIndex = j;
for(var k = 0; k < result[i].map[j].data.length; k ++){
+
break;
data[index] = [k, j, attrEscape(result[i].map[j].data[k][0])];
+
gHeatmapData[i][j][k] = result[i].map[j].data[k][2];
+
index ++;
+
 
}
 
}
yLabels[j] = attrEscape(result[i].map[j].title);
 
 
}
 
}
for(var j = 0; j < result[i].x.length; j ++)
+
}
result[i].x[j] = attrEscape(result[i].x[j]);
+
}
var xMax = result[i].x.length-1;
+
// 検索 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(xMax > 10)
+
// param sampleSource - 検索対象のSampleSource
xMax = 10;
+
// param sampleType  - 検索対象のSampleType
// ヒートマップ
+
// param lipidClass  - 検索対象のLipidClass
var chart = new Highcharts.Chart({
+
// return なし
+
function search(sampleSource, sampleType, lipidClass, dataType)
chart: {
+
{
type: 'heatmap',
+
// 検索ボタン等を無効化しておく
marginBottom: 0,
+
document.getElementById("searchButton").disabled      = true;
plotBorderWidth: 1,
+
document.getElementById("downloadButton").disabled    = true;
renderTo: parent,
+
document.getElementById("showButton") .disabled      = true;
},
+
document.getElementById('hit')         .innerHTML    = "";
+
document.getElementById("graphform")   .style.display = "none";
scrollbar: {
+
enabled: true
+
},
+
+
title: {
+
text: title
+
},
+
+
xAxis: {
+
categories: result[i].x,
+
opposite: true,
+
labels: {
+
rotation: -90,
+
style: {
+
fontSize: '11px',
+
fontFamily: 'Verdana, sans-serif'
+
}
+
},
+
max: xMax
+
},
+
+
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');
+
document.getElementById('searching').style.display = "block";
},
+
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', '');
+
var result = lipoqualitySearch(sampleSource, sampleType, lipidClass, dataType);
},*/
+
// var url = 'https://script.google.com/macros/s/AKfycbxW5WpkJH0PUmmLrMtrluvkaKmz0OTTfeBucudy5-LxalQ7vus/exec?classification=' + classification + '&sample=' + sample + '&type=' + type + '&q=search&callback=hasSearched';
click: function(event){
+
// var url = '/lipo/json.txt'
var index = event.target.farthestViewportElement.parentNode.parentElement.id.replace("container","");
+
 
getInchiOnHeatmap(index, event.point.x, event.point.y);
+
// 過去の検索結果を削除する
}
+
var root = document.getElementById('result');
}
+
root.textContent = '';
}
+
for(var i = root.childNodes.length-1; i >= 0; i --)
}]
+
root.removeChild(root.childNodes[i]);
+
 
});
+
// 「検索中」を非表示
//chart.setSize(600,300,false);
+
document.getElementById('searching').style.display = "none";
 +
var root = document.getElementById('result');
 +
 
 +
// var result = jsonp;
 +
//var result = JSON.parse(escape(jsonp));
 +
document.getElementById('hit').innerHTML = 'result. ' + escape(result.length) + ' hit(s).';
 +
// チェックボックスを並べるため、最長文字数を調べる
 +
var lenmax = 0;
 +
for(var i = 0; i < result.length; i ++){
 +
if(result[i].title.length > lenmax)
 +
lenmax = result[i].title.length;
 
}
 
}
 +
lenmax += 6; // "(meta)"分
 +
lenmax /= 1.5;
 +
// チェックボックスの作成
 +
for(var i = 0; i < result.length; i ++){
 +
var span = document.createElement('span');
 +
span.style.display = "inline-block";
 +
span.style.width  = lenmax + "em";
 +
 +
var check = document.createElement('input');
 +
check.type = 'checkbox';
 +
check.id = attrEscape(result[i].title);
 +
check.value = attrEscape(result[i].title);
 +
check.name  = 'target';
 +
check.className = "results";
 +
check.onchange = function(e){
 +
checkSelection();
 +
};
 +
span.appendChild(check);
 +
var title = document.createElement('label');
 +
title.setAttribute('for', attrEscape(result[i].title));
 +
title.innerHTML = escape(result[i].title) + ' <a href="' + result[i]["Method link"] + '" target="_blank">(meta)</a>';
 +
span.appendChild(title);
 +
 +
root.appendChild(span);
 +
}
 +
// 検索ボタンを有効化
 +
document.getElementById("searchButton").disabled = false;
 +
 +
document.getElementById("graphform").style.display = "block";
 
}
 
}
function getTarget(children, target)
+
// チェックボックスの状態に応じて、グラフ表示ボタンを有効/無効化する /////////////////
 +
// return なし
 +
function checkSelection()
 
{
 
{
for(var i = 0; i < children.length; i ++){
+
var c = document.getElementsByClassName("results");
if(target == children[i].childNodes[0].textContent){
+
var disabled = true;
return $(children[i]);
+
for(var i = 0; i < c.length; i ++){
 +
if(c[i].checked){
 +
disabled = false;
 +
break;
 
}
 
}
// console.log(children[i].childNodes[0].textContent);
 
 
}
 
}
return null;
+
document.getElementById("showButton").disabled    = disabled;
 +
document.getElementById("downloadButton").disabled = disabled;
 +
}
 +
// すべてのチェックボックスをチェックする/アンチェックする //////////////////////
 +
// return なし
 +
function checkAllResult()
 +
{
 +
var c = document.getElementsByClassName("results");
 +
 
 +
// チェックするか、アンチェックするかを調べる
 +
var checked = 0;
 +
for(var i = 0; i < c.length; i ++){
 +
if(c[i].checked)
 +
checked ++;
 +
}
 +
var state = true;
 +
if(checked == c.length)
 +
state = false;
 +
 
 +
// チェック状態を変更する
 +
for(var i = 0; i < c.length; i ++)
 +
c[i].checked = state;
 +
 
 +
checkSelection();
 
}
 
}

Latest revision as of 11:57, 23 March 2020

// Last-Update: 2020/03/23
// html /////////////////////////////////////////////////////////////////////////////////////////////////////////
// <span id="search"></span><span id="show"></span>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

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

var gChartType;
var gDataType;

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

	// 検索、表示、チェックボタンを作成
		// 検索ボタン
	var searchButton = document.createElement("input");
	searchButton.value    = "search";
	searchButton.id       = "searchButton";
	searchButton.type     = "button";
	searchButton.disabled = true;
	searchButton.style.width = "100%";
	searchButton.onclick = function(){
		var sampleSource = document.getElementById("samplesource").value;
		var sampleType   = document.getElementById("sampletype").value;
		var lipidClass   = document.getElementById("lipidclass").value;
		gDataType        = document.getElementById("datatype").value;
		search(sampleSource, sampleType, lipidClass, gDataType);
	};
	document.getElementById("search").appendChild(searchButton);
		// グラフ表示ボタン
	var showButton = document.createElement("input");
	showButton.value = "show graph";
	showButton.id    = "showButton";
	showButton.type  = "button";
	showButton.disabled = true;
	showButton.onclick = function(){barColor = DEFAULT_BAR_COLOR; document.getElementById('drawing').style.display = "block"; window.setTimeout( function(){showChart(getSelectedIDs(), gDataType); document.getElementById('drawing').style.display = "none"; }, 10 );};
	document.getElementById("show").appendChild(showButton);
		// チェックボタン
	var checkButton = document.createElement("input");
	checkButton.value = "all check/uncheck";
	checkButton.id    = "allswitch";
	checkButton.type  = "button";
	checkButton.onclick = function(){checkAllResult()};
	document.getElementById("check").appendChild(checkButton);
		// ダウンロードボタン
	var downloadFileName = "lipodata.txt";
	var downloadLink = document.createElement("a");
	downloadLink.href = "#";
	downloadLink.download = downloadFileName;
	downloadLink.id = "downloadLink";
	downloadLink.onclick = function(){
	    var blob = new Blob([ getDownloadData(getSelectedIDs()) ], { "type" : "text/plain" });

	    if (window.navigator.msSaveBlob) { 
	        window.navigator.msSaveBlob(blob, downloadFileName); 
	        window.navigator.msSaveOrOpenBlob(blob, downloadFileName); 
	    } else {
	        document.getElementById("downloadLink").href = window.URL.createObjectURL(blob);
	    }
	};
	document.getElementById("check").appendChild(downloadLink);
	var downloadButton = document.createElement("input");
	downloadButton.value = "download checked";
	downloadButton.type  = "button";
	downloadButton.style = "margin-left: 1em";
	downloadButton.disabled = true;
	downloadButton.id    = "downloadButton";
	downloadLink.appendChild(downloadButton);


	document.getElementById("graphform").style.display = "none";

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

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

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

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

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

		} else if(name == "ct"){ // chart type
			chart = value;

		} else if(name == "sp"){ // species
			species = value;

		} else if(name == "sn"){ // sample name
			sampleName = value;

		} else if(name == "dt"){
			gDataType = value;
		}
	}
// speciesが指定された場合、対象データ以外を削除する ///////////
	if(species.length > 0){
		var spReg = new RegExp(translateForReg(species), "i");
		for(key in gAllData){
			if(!spReg.test(key)){ // speciesが合致するか
				delete gAllData[key];
			}
		}
	}
////////////////////////////////////////////////////////////////
	var index = lipidClass.indexOf(" ");
	if(index > 0){
		chain = lipidClass.substring(index+1);
		lipidClass = lipidClass.substring(0, index);
	} else {
		index = lipidClass.indexOf("(");
		if(index >= 0){
			chain = lipidClass.substring(index+1, lipidClass.length-1);
			lipidClass = lipidClass.substring(0, index);
		}
	}
	chain = chain.replace(/^\(/g,"");
	chain = chain.replace(/[_]/g,"/");
	if(lipidClass.indexOf("Cer-") < 0){
//		chain = chain.replace(/\)$/g,"");
		chain = chain.replace(/[)(]/g,"/");
	}
	chain = chain.replace(/\/\//g,"/");
	if(chart == "c" && chain.length > 0){
		// lipidclass基準の棒グラフを表示
		selectCombobox([sampleSource, sampleType, lipidClass, gDataType]);
		var result = retrieveChainData(sampleName, sampleSource, sampleType, lipidClass, chain, gDataType); // speciesからsamplenameに変更
		if(result.x.length > 0){
			showChainChart(result);
		}

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

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

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

	// AJAXを使って、コンボボックスの選択項目を取得する
	xmlHttpRequest.open('GET', url, true);
	xmlHttpRequest.responseType = 'text';
	xmlHttpRequest.send(null);
}
var globalList = null;
function setCombobox()
{
	document.getElementById("samplesource").onchange  = function(){ setNames() };
	document.getElementById("sampletype").onchange    = function(){ setLipidcategories() };
	document.getElementById("lipidcategory").onchange = function(){ setLipidclassess() };

	var keys = Object.keys(gListData);
	appendOption("samplesource", "All");
	for(var i = 0; i < keys.length; i ++){
		appendOption("samplesource", keys[i]);
	}

	setNames();
}

function appendOption(id, value)
{
	var parent = document.getElementById(id);
	var op = document.createElement("option");
	op.valuie = value;
	op.textContent = value;
	parent.appendChild(op);
}
function removeAll(id)
{
	parent = document.getElementById(id);
	while(parent.lastChild){
		parent.removeChild(parent.lastChild);
	}
}
function getRegExp(id)
{
	var item = document.getElementById(id).value;
	var regexp;
	if(item == "All"){
		regexp = new RegExp('.*');
	} else {
		regexp = new RegExp("^" + item.replace("(","\\(").replace(")","\\)") + "$");
	}
	return regexp;
}
function setNames()
{
	removeAll("sampletype");
	globalList = [];
	getSelectionList([getRegExp("samplesource"), null, null], gListData, 0, 0);
	globalList.sort();
	appendOption("sampletype", "All");
	for(var i = 0; i < globalList.length; i ++){
		appendOption("sampletype", globalList[i]);
	}

	setLipidcategories();
}
function setLipidcategories()
{
	removeAll("lipidcategory");
	globalList = [];
	getSelectionList([getRegExp("samplesource"), getRegExp("sampletype"), null], gListData, 1, 0);
	globalList.sort();
	appendOption("lipidcategory", "All");
	for(var i = 0; i < globalList.length; i ++){
		appendOption("lipidcategory", globalList[i]);
	}

	setLipidclassess();
}
function setLipidclassess()
{
	removeAll("lipidclass");
	globalList = [];
	getSelectionList([getRegExp("samplesource"), getRegExp("sampletype"), getRegExp("lipidcategory")], gListData, 2, 0);
	globalList.sort();
	for(var i = 0; i < globalList.length; i ++){
		appendOption("lipidclass", globalList[i]);
	}
}
function getSelectionList(patterns, obj, depth, level)
{
	if(level == 2){
		// last
		var targets = Object.keys(obj);
		for(var i = 0; i < targets.length; i ++){
			if(patterns[level].test(targets[i])){
				for(var j = 0; j < obj[targets[i]].length; j ++){
					if(globalList.indexOf(obj[targets[i]][j]) == -1)
						globalList.push(obj[targets[i]][j]);
				}
			}
		}
	} else {
		// sub
		var keys = Object.keys(obj);
		for(var i = 0; i < keys.length; i ++){
			if(patterns[level].test(keys[i])){
				if(level == depth){
					var targets = Object.keys(obj[keys[i]][0]);
					for(var j = 0; j < targets.length; j ++){
						if(globalList.indexOf(targets[j]) == -1)
							globalList.push(targets[j]);
					}
				} else {
					getSelectionList(patterns, obj[keys[i]][0], depth, level+1);
				}
			}
		}
	}
}

// 指定されたコンボボックスの値をセットする /////////////////////////////////////
// param targets - 選択するSampleSource, SampleType, LipidClassの項目値
// return なし
function selectCombobox(targets)
{
	var ids = ["samplesource", "sampletype", "lipidclass", "datatype"];

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

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

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

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

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

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

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

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

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

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

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

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

	checkSelection();
}
Personal tools