sequenceserver 1.1.0.beta6 → 1.1.0.beta7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sequenceserver/version.rb +1 -1
- data/public/js/circos.js +4 -4
- data/public/js/{errormodal.js → error_modal.js} +0 -0
- data/public/js/{alignmentsoverview.js → hits_overview.js} +2 -2
- data/public/js/kablammo.js +2 -2
- data/public/js/{lengthdistribution.js → length_distribution.js} +1 -1
- data/public/js/report.js +212 -200
- data/public/sequenceserver-report.min.js +17 -16
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 596bc25ee4cb80b8fad1de7a63b7677f291a0743
|
4
|
+
data.tar.gz: bb5bda8278682fb5a79526542023d3addfce8933
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e71d8f58e66599466f5149043f20e1ab5e1490857a557a71005889fdbd70ac46ac3649b18ff5b04037154f9b49ca98a3f37bbccfcef614786c3fc963222424b5
|
7
|
+
data.tar.gz: faaa045609c7009b1dae99175da8da6adbf8bb7a01439a2f2dbbd21d6a64f353ac76a5fe5c276051d96c7dbf9f9041c2ae2f90355ea002d1c37b112bfa8a772e
|
data/public/js/circos.js
CHANGED
@@ -316,10 +316,10 @@ class Graph {
|
|
316
316
|
.attr('transform','translate('+this.svgContainer.width() / 2+','+this.svgContainer.height()/2+')')
|
317
317
|
.append('text')
|
318
318
|
.attr('text-anchor','start')
|
319
|
-
.attr('dy','0.
|
320
|
-
.attr('x', -
|
321
|
-
.
|
322
|
-
.text('
|
319
|
+
.attr('dy','-0.25em')
|
320
|
+
.attr('x', -175)
|
321
|
+
.style("font-size", "14px")
|
322
|
+
.text('Circos looks great with less than 16 queries')
|
323
323
|
}
|
324
324
|
|
325
325
|
layoutReset() {
|
File without changes
|
data/public/js/kablammo.js
CHANGED
@@ -19,11 +19,11 @@ import * as Helpers from './visualisation_helpers';
|
|
19
19
|
|
20
20
|
class Graph {
|
21
21
|
static name() {
|
22
|
-
return '
|
22
|
+
return 'Matching region(s)';
|
23
23
|
}
|
24
24
|
|
25
25
|
static className() {
|
26
|
-
return 'kablammo
|
26
|
+
return 'kablammo';
|
27
27
|
}
|
28
28
|
|
29
29
|
static collapseId(props) {
|
data/public/js/report.js
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
import
|
2
|
-
import showErrorModal from './errormodal';
|
3
|
-
|
4
|
-
import _ from 'underscore';
|
1
|
+
import './sequenceserver' // for custom $.tooltip function
|
5
2
|
import React from 'react';
|
6
|
-
import
|
3
|
+
import _ from 'underscore';
|
7
4
|
|
8
|
-
import * as Helpers from './visualisation_helpers';
|
9
|
-
import GraphicalOverview from './alignmentsoverview';
|
10
|
-
//import Kablammo from './kablammo';
|
11
|
-
import './sequence';
|
12
|
-
import AlignmentExporter from './alignment_exporter';
|
13
|
-
import LengthDistribution from './lengthdistribution';
|
14
5
|
import Circos from './circos';
|
6
|
+
import HitsOverview from './hits_overview';
|
7
|
+
import LengthDistribution from './length_distribution'; // length distribution of hits
|
8
|
+
import HSPOverview from './kablammo';
|
9
|
+
import AlignmentExporter from './alignment_exporter'; // to download textual alignment
|
10
|
+
import './sequence';
|
15
11
|
|
12
|
+
import * as Helpers from './visualisation_helpers'; // for toLetters
|
13
|
+
import showErrorModal from './error_modal';
|
16
14
|
|
17
15
|
/**
|
18
16
|
* Dynamically create form and submit.
|
@@ -514,9 +512,9 @@ var Hit = React.createClass({
|
|
514
512
|
}, this))
|
515
513
|
}
|
516
514
|
</div>
|
517
|
-
{
|
518
|
-
|
519
|
-
|
515
|
+
<HSPOverview key={"kablammo"+this.props.query.id}
|
516
|
+
query={this.props.query} hit={this.props.hit}
|
517
|
+
algorithm={this.props.algorithm}/>
|
520
518
|
<table
|
521
519
|
className="table hsps">
|
522
520
|
<tbody>
|
@@ -678,7 +676,7 @@ var Query = React.createClass({
|
|
678
676
|
{this.numhits() &&
|
679
677
|
(
|
680
678
|
<div className="section-content">
|
681
|
-
<
|
679
|
+
<HitsOverview key={"GO_"+this.props.query.number} query={this.props.query} program={this.props.data.program} collapsed={this.props.data.veryBig}/>
|
682
680
|
<LengthDistribution key={"LD_"+this.props.query.id} query={this.props.query} algorithm={this.props.data.program} collapsed="true"/>
|
683
681
|
<HitsTable key={"HT_"+this.props.query.number} query={this.props.query}/>
|
684
682
|
<div
|
@@ -921,65 +919,12 @@ var SideBar = React.createClass({
|
|
921
919
|
*/
|
922
920
|
var Report = React.createClass({
|
923
921
|
|
924
|
-
//
|
925
|
-
|
926
|
-
/**
|
927
|
-
* Event-handler when hit is selected
|
928
|
-
* Adds glow to hit component.
|
929
|
-
* Updates number of Fasta that can be downloaded
|
930
|
-
*/
|
931
|
-
selectHit: function (id) {
|
932
|
-
|
933
|
-
var checkbox = $("#" + id);
|
934
|
-
var num_checked = $('.hit-links :checkbox:checked').length;
|
935
|
-
|
936
|
-
if (!checkbox || !checkbox.val()) {
|
937
|
-
return;
|
938
|
-
}
|
939
|
-
|
940
|
-
var $hit = $(checkbox.data('target'));
|
941
|
-
|
942
|
-
// Highlight selected hit and sync checkboxes if sequence viewer is open.
|
943
|
-
if (checkbox.is(":checked")) {
|
944
|
-
$hit
|
945
|
-
.addClass('glow')
|
946
|
-
.find(":checkbox").not(checkbox).check();
|
947
|
-
var $a = $('.download-fasta-of-selected');
|
948
|
-
var $b = $('.download-alignment-of-selected');
|
949
|
-
$b.enable()
|
950
|
-
var $n = $a.find('span');
|
951
|
-
$a
|
952
|
-
.enable()
|
953
|
-
}
|
954
|
-
|
955
|
-
else {
|
956
|
-
$hit
|
957
|
-
.removeClass('glow')
|
958
|
-
.find(":checkbox").not(checkbox).uncheck();
|
959
|
-
}
|
960
|
-
|
961
|
-
if (num_checked >= 1)
|
962
|
-
{
|
963
|
-
var $a = $('.download-fasta-of-selected');
|
964
|
-
var $b = $('.download-alignment-of-selected');
|
965
|
-
$a.find('.text-bold').html(num_checked);
|
966
|
-
$b.find('.text-bold').html(num_checked);
|
967
|
-
}
|
968
|
-
|
969
|
-
if (num_checked == 0) {
|
970
|
-
var $a = $('.download-fasta-of-selected');
|
971
|
-
var $b = $('.download-alignment-of-selected');
|
972
|
-
$a.addClass('disabled').find('.text-bold').html('');
|
973
|
-
$b.addClass('disabled').find('.text-bold').html('');
|
974
|
-
}
|
975
|
-
},
|
976
|
-
|
977
|
-
|
978
|
-
// Internal helpers. //
|
979
|
-
|
980
|
-
// Life-cycle methods. //
|
922
|
+
// Model //
|
981
923
|
|
982
924
|
getInitialState: function () {
|
925
|
+
this.fetchResults();
|
926
|
+
this.updateCycle = 0;
|
927
|
+
|
983
928
|
return {
|
984
929
|
search_id: '',
|
985
930
|
program: '',
|
@@ -991,17 +936,77 @@ var Report = React.createClass({
|
|
991
936
|
};
|
992
937
|
},
|
993
938
|
|
994
|
-
|
995
|
-
|
939
|
+
/**
|
940
|
+
* Fetch results.
|
941
|
+
*/
|
942
|
+
fetchResults: function () {
|
943
|
+
var intervals = [200, 400, 800, 1200, 2000, 3000, 5000];
|
944
|
+
|
945
|
+
(function poll (comp) {
|
946
|
+
$.getJSON(location.pathname + '.json')
|
947
|
+
.complete(function (jqXHR) {
|
948
|
+
switch (jqXHR.status) {
|
949
|
+
case 202:
|
950
|
+
var interval;
|
951
|
+
if (intervals.length === 1) {
|
952
|
+
interval = intervals[0];
|
953
|
+
}
|
954
|
+
else {
|
955
|
+
interval = intervals.shift;
|
956
|
+
}
|
957
|
+
setTimeout(poll, interval);
|
958
|
+
break;
|
959
|
+
case 200:
|
960
|
+
comp.updateState(jqXHR.responseJSON);
|
961
|
+
break;
|
962
|
+
case 404:
|
963
|
+
case 400:
|
964
|
+
case 500:
|
965
|
+
showErrorModal(jqXHR.responseJSON);
|
966
|
+
break;
|
967
|
+
}
|
968
|
+
});
|
969
|
+
}(this));
|
996
970
|
},
|
997
971
|
|
998
972
|
/**
|
999
|
-
*
|
1000
|
-
*
|
1001
|
-
* A holding message is shown till results are fetched.
|
973
|
+
* Incrementally update state so that the rendering process is
|
974
|
+
* not overwhelemed when there are too many queries.
|
1002
975
|
*/
|
1003
|
-
|
1004
|
-
|
976
|
+
updateState: function(responseJSON) {
|
977
|
+
var queries = responseJSON.queries;
|
978
|
+
|
979
|
+
// Render results for first 50 queries and set flag if total queries is
|
980
|
+
// more than 250.
|
981
|
+
var numHits = 0;
|
982
|
+
responseJSON.veryBig = queries.length > 250;
|
983
|
+
//responseJSON.veryBig = !_.every(queries, (query) => {
|
984
|
+
//numHits += query.hits.length;
|
985
|
+
//return (numHits <= 500);
|
986
|
+
//});
|
987
|
+
responseJSON.queries = queries.splice(0, 50);
|
988
|
+
this.setState(responseJSON);
|
989
|
+
|
990
|
+
// Render results for remaining queries.
|
991
|
+
var update = function () {
|
992
|
+
if (queries.length > 0) {
|
993
|
+
this.setState({
|
994
|
+
queries: this.state.queries.concat(queries.splice(0, 50))
|
995
|
+
});
|
996
|
+
setTimeout(update.bind(this), 500);
|
997
|
+
}
|
998
|
+
else {
|
999
|
+
this.componentFinishedUpdating();
|
1000
|
+
}
|
1001
|
+
};
|
1002
|
+
setTimeout(update.bind(this), 500);
|
1003
|
+
},
|
1004
|
+
|
1005
|
+
|
1006
|
+
// View //
|
1007
|
+
render: function () {
|
1008
|
+
return this.isResultAvailable() ?
|
1009
|
+
this.resultsJSX() : this.loadingJSX();
|
1005
1010
|
},
|
1006
1011
|
|
1007
1012
|
/**
|
@@ -1049,9 +1054,11 @@ var Report = React.createClass({
|
|
1049
1054
|
}
|
1050
1055
|
<div className={this.shouldShowSidebar() ?
|
1051
1056
|
'col-md-9' : 'col-md-12'}>
|
1052
|
-
{ this.
|
1053
|
-
|
1054
|
-
|
1057
|
+
{ this.overviewJSX() }
|
1058
|
+
{ this.isHitsAvailable()
|
1059
|
+
? <Circos queries={this.state.queries}
|
1060
|
+
program={this.state.program} collapsed="true"/>
|
1061
|
+
: <span></span> }
|
1055
1062
|
{
|
1056
1063
|
_.map(this.state.queries, _.bind(function (query) {
|
1057
1064
|
return (
|
@@ -1065,31 +1072,10 @@ var Report = React.createClass({
|
|
1065
1072
|
);
|
1066
1073
|
},
|
1067
1074
|
|
1068
|
-
/**
|
1069
|
-
* Returns true if sidebar should be shown.
|
1070
|
-
*
|
1071
|
-
* Sidebar is not shown if there is only one query and there are no hits
|
1072
|
-
* corresponding to the query.
|
1073
|
-
*/
|
1074
|
-
shouldShowSidebar: function () {
|
1075
|
-
return !(this.state.queries.length == 1 &&
|
1076
|
-
this.state.queries[0].hits.length == 0);
|
1077
|
-
},
|
1078
|
-
|
1079
|
-
/**
|
1080
|
-
* Returns true if index should be shown in the sidebar.
|
1081
|
-
*
|
1082
|
-
* Index is not shown in the sidebar if there are more than eight queries
|
1083
|
-
* in total.
|
1084
|
-
*/
|
1085
|
-
shouldShowIndex: function () {
|
1086
|
-
return this.state.queries.length <= 8;
|
1087
|
-
},
|
1088
|
-
|
1089
1075
|
/**
|
1090
1076
|
* Renders report overview.
|
1091
1077
|
*/
|
1092
|
-
|
1078
|
+
overviewJSX: function () {
|
1093
1079
|
return (
|
1094
1080
|
<div
|
1095
1081
|
className="overview">
|
@@ -1104,8 +1090,8 @@ var Report = React.createClass({
|
|
1104
1090
|
}).join(", ")
|
1105
1091
|
}
|
1106
1092
|
<br/>
|
1107
|
-
Total: {this.state.stats.nsequences} sequences,
|
1108
|
-
|
1093
|
+
Total: {this.state.stats.nsequences} sequences,
|
1094
|
+
{this.state.stats.ncharacters} characters
|
1109
1095
|
<br/>
|
1110
1096
|
<br/>
|
1111
1097
|
{
|
@@ -1118,106 +1104,86 @@ var Report = React.createClass({
|
|
1118
1104
|
);
|
1119
1105
|
},
|
1120
1106
|
|
1121
|
-
|
1122
|
-
|
1123
|
-
},
|
1107
|
+
|
1108
|
+
// Controller //
|
1124
1109
|
|
1125
1110
|
/**
|
1126
|
-
*
|
1111
|
+
* Returns true if results have been fetched.
|
1112
|
+
*
|
1113
|
+
* A holding message is shown till results are fetched.
|
1127
1114
|
*/
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
$.getJSON(location.pathname + '.json')
|
1132
|
-
.complete(_.bind(function (jqXHR) {
|
1133
|
-
switch (jqXHR.status) {
|
1134
|
-
case 202:
|
1135
|
-
var interval;
|
1136
|
-
if (intervals.length === 1) {
|
1137
|
-
interval = intervals[0];
|
1138
|
-
}
|
1139
|
-
else {
|
1140
|
-
interval = intervals.shift;
|
1141
|
-
}
|
1142
|
-
setTimeout(this.fetchResults, interval);
|
1143
|
-
break;
|
1144
|
-
case 200:
|
1145
|
-
this.updatePage(jqXHR.responseJSON);
|
1146
|
-
break;
|
1147
|
-
case 404:
|
1148
|
-
case 400:
|
1149
|
-
case 500:
|
1150
|
-
showErrorModal(jqXHR.responseJSON);
|
1151
|
-
break;
|
1152
|
-
}
|
1153
|
-
}, this));
|
1115
|
+
isResultAvailable: function () {
|
1116
|
+
return this.state.queries.length >= 1;
|
1154
1117
|
},
|
1155
1118
|
|
1156
|
-
|
1157
|
-
var
|
1119
|
+
isHitsAvailable: function () {
|
1120
|
+
var cnt = 0;
|
1121
|
+
_.each(this.state.queries, function (query) {
|
1122
|
+
if(query.hits.length == 0) cnt++;
|
1123
|
+
});
|
1124
|
+
return !(cnt == this.state.queries.length);
|
1125
|
+
},
|
1158
1126
|
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1127
|
+
/**
|
1128
|
+
* Returns true if sidebar should be shown.
|
1129
|
+
*
|
1130
|
+
* Sidebar is not shown if there is only one query and there are no hits
|
1131
|
+
* corresponding to the query.
|
1132
|
+
*/
|
1133
|
+
shouldShowSidebar: function () {
|
1134
|
+
return !(this.state.queries.length == 1 &&
|
1135
|
+
this.state.queries[0].hits.length == 0);
|
1136
|
+
},
|
1169
1137
|
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
else {
|
1179
|
-
this.componentFinishedUpdating();
|
1180
|
-
}
|
1181
|
-
};
|
1182
|
-
setTimeout(update.bind(this), 500);
|
1138
|
+
/**
|
1139
|
+
* Returns true if index should be shown in the sidebar.
|
1140
|
+
*
|
1141
|
+
* Index is not shown in the sidebar if there are more than eight queries
|
1142
|
+
* in total.
|
1143
|
+
*/
|
1144
|
+
shouldShowIndex: function () {
|
1145
|
+
return this.state.queries.length <= 8;
|
1183
1146
|
},
|
1184
1147
|
|
1185
1148
|
/**
|
1186
|
-
*
|
1187
|
-
*
|
1149
|
+
* Called after first call to render. The results may not be available at
|
1150
|
+
* this stage and thus results DOM cannot be scripted here, unless using
|
1151
|
+
* delegated events bound to the window, document, or body.
|
1188
1152
|
*/
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
this.
|
1193
|
-
this.setupDownloadLinks();
|
1153
|
+
componentDidMount: function () {
|
1154
|
+
// This sets up an event handler which enables users to select text
|
1155
|
+
// from hit header without collapsing the hit.
|
1156
|
+
this.preventCollapseOnSelection();
|
1194
1157
|
},
|
1195
1158
|
|
1196
1159
|
/**
|
1197
|
-
*
|
1198
|
-
*
|
1199
|
-
* TODO: can't this be done with CSS?
|
1160
|
+
* Called after each state change. Only a part of results DOM may be
|
1161
|
+
* available after a state change.
|
1200
1162
|
*/
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1163
|
+
componentDidUpdate: function () {
|
1164
|
+
// We track the number of updates to the component.
|
1165
|
+
this.updateCycle += 1;
|
1166
|
+
|
1167
|
+
// Lock sidebar in its position on first update of
|
1168
|
+
// results DOM.
|
1169
|
+
if (this.updateCycle === 1 ) this.affixSidebar();
|
1208
1170
|
},
|
1209
1171
|
|
1210
1172
|
/**
|
1211
|
-
*
|
1173
|
+
* Prevents folding of hits during text-selection, etc.
|
1212
1174
|
*/
|
1213
|
-
|
1214
|
-
|
1175
|
+
|
1176
|
+
/**
|
1177
|
+
* Called after all results have been rendered.
|
1178
|
+
*/
|
1179
|
+
componentFinishedUpdating: function () {
|
1180
|
+
this.shouldShowIndex() && this.setupScrollSpy();
|
1215
1181
|
},
|
1216
1182
|
|
1217
1183
|
/**
|
1218
1184
|
* Prevents folding of hits during text-selection.
|
1219
1185
|
*/
|
1220
|
-
|
1186
|
+
preventCollapseOnSelection: function () {
|
1221
1187
|
$('body').on('mousedown', ".hit > .section-header > h4", function (event) {
|
1222
1188
|
var $this = $(this);
|
1223
1189
|
$this.on('mouseup mousemove', function handler(event) {
|
@@ -1234,28 +1200,74 @@ var Report = React.createClass({
|
|
1234
1200
|
});
|
1235
1201
|
},
|
1236
1202
|
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
$(
|
1242
|
-
|
1243
|
-
|
1203
|
+
/**
|
1204
|
+
* Affixes the sidebar.
|
1205
|
+
*/
|
1206
|
+
affixSidebar: function () {
|
1207
|
+
var $sidebar = $('.sidebar');
|
1208
|
+
$sidebar.affix({
|
1209
|
+
offset: {
|
1210
|
+
top: $sidebar.offset().top
|
1211
|
+
}
|
1212
|
+
});
|
1213
|
+
},
|
1244
1214
|
|
1245
|
-
|
1215
|
+
/**
|
1216
|
+
* For the query in viewport, highlights corresponding entry in the index.
|
1217
|
+
*/
|
1218
|
+
setupScrollSpy: function () {
|
1219
|
+
$('body').scrollspy({target: '.sidebar'});
|
1220
|
+
},
|
1246
1221
|
|
1247
|
-
|
1222
|
+
/**
|
1223
|
+
* Event-handler when hit is selected
|
1224
|
+
* Adds glow to hit component.
|
1225
|
+
* Updates number of Fasta that can be downloaded
|
1226
|
+
*/
|
1227
|
+
selectHit: function (id) {
|
1248
1228
|
|
1249
|
-
|
1229
|
+
var checkbox = $("#" + id);
|
1230
|
+
var num_checked = $('.hit-links :checkbox:checked').length;
|
1250
1231
|
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1232
|
+
if (!checkbox || !checkbox.val()) {
|
1233
|
+
return;
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
var $hit = $(checkbox.data('target'));
|
1237
|
+
|
1238
|
+
// Highlight selected hit and sync checkboxes if sequence viewer is open.
|
1239
|
+
if (checkbox.is(":checked")) {
|
1240
|
+
$hit
|
1241
|
+
.addClass('glow')
|
1242
|
+
.find(":checkbox").not(checkbox).check();
|
1243
|
+
var $a = $('.download-fasta-of-selected');
|
1244
|
+
var $b = $('.download-alignment-of-selected');
|
1245
|
+
$b.enable()
|
1246
|
+
var $n = $a.find('span');
|
1247
|
+
$a
|
1248
|
+
.enable()
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
else {
|
1252
|
+
$hit
|
1253
|
+
.removeClass('glow')
|
1254
|
+
.find(":checkbox").not(checkbox).uncheck();
|
1255
|
+
}
|
1256
|
+
|
1257
|
+
if (num_checked >= 1)
|
1258
|
+
{
|
1259
|
+
var $a = $('.download-fasta-of-selected');
|
1260
|
+
var $b = $('.download-alignment-of-selected');
|
1261
|
+
$a.find('.text-bold').html(num_checked);
|
1262
|
+
$b.find('.text-bold').html(num_checked);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
if (num_checked == 0) {
|
1266
|
+
var $a = $('.download-fasta-of-selected');
|
1267
|
+
var $b = $('.download-alignment-of-selected');
|
1268
|
+
$a.addClass('disabled').find('.text-bold').html('');
|
1269
|
+
$b.addClass('disabled').find('.text-bold').html('');
|
1270
|
+
}
|
1259
1271
|
},
|
1260
1272
|
});
|
1261
1273
|
|