Skip to content

Instantly share code, notes, and snippets.

@coronin
Last active August 29, 2015 14:06
Show Gist options
  • Save coronin/3fbdec65f0dfdae59b56 to your computer and use it in GitHub Desktop.
Save coronin/3fbdec65f0dfdae59b56 to your computer and use it in GitHub Desktop.
run nicely with ots_server and Web Blat
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>crispr scanner, made by Liang Cai</title>
<style type="text/css" media="screen"><!--
body{margin:25px;padding:0;font-family:Arial,Helvetica,sans-serif;font-size:100%;line-height:1.5}
article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}
h1,h2,h3,h4{margin:1em 0 .5em;line-height:1.25;font-weight:700}
h1{font-size:2em}
h2{font-size:1.5em}
h3{font-size:1.2em}
h4{font-size:1em}
ol,ul{margin:1em 0;padding:1em;background:#eee;list-style-type:none;font-family:"Courier New",Courier,monospace}
p{margin:1em 0}
blockquote{margin:1em 40px}
figure{margin:1em 0}
a{text-decoration:underline}
a:link{color:#00E}
a:visited{color:#551A8B}
a:active{color:#E00}
a:active,a:hover{outline:0}
a img{border:none}
cite,q{font-style:italic}
q:after,q:before{content:""}
sub,sup{line-height:0}
fieldset{margin:0;padding:0;border:none}
button,input,select{vertical-align:middle}
table{border-collapse:collapse}
td,th{padding:1px;vertical-align:top;text-align:left}
td:first-child,th:first-child{empty-cells:hide}
.blat{font-size:0.8em}
.line{position:fixed;bottom:0;width:12px;height:20px;font-size:8px}
--></style>
</head>
<body>
<h1>crispr scanner, made by Liang Cai</h1>
<p>Cas9 species = S. pyogenes (PAM = NGG)</p>
<p>Use <a href="https://github.com/htgt/CRISPR-Analyser">ots_server</a> as data source
<span id="server_status"><br/></span></p>
<hr/>
<p>
<em>species</em><br/>
<input type="radio" name="species" value="dog" id="species_dog" checked /><label for="species_dog">dog</label><br/>
<input type="radio" name="species" value="human" id="species_human" /><label for="species_human">human</label><br/>
<input type="radio" name="species" value="mouse" id="species_mouse" /><label for="species_mouse">mouse</label>
</p>
<hr/>
<p>
option 1, <em>check a gRNA sequence</em><br/>
<input type="text" name="gRNA" size="20" id="gRNA_seq" />
</p>
<p>
option 2, <em>search gRNAs in a genomic sequence</em> &nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" id="rigorous" /><span id="rigorous_label">only four</span><br/>
<!-- human EMX1 locus : ggaggaagggcctgagtccgagcagaagaagaagggctcccatcacatcaaccggtggcgcattgccacgaagcaggccaatggggaggacatcgatgtcacctccaatgactagggtgggc -->
<textarea cols="60" rows="12" id="target_seq"></textarea>
</p>
<hr/>
<p>
<input type="submit" value="submit" id="submit" />
<span id="progress" style="background:yellow;font-size:75%;margin-left:25px"></span>
</p>
<div><ul id="ots_result"></ul></div>
<div id="graph_show"></div>
<script src="jquery-2.1.1.min.js"></script>
<script>
var ots_addr = 'http://localhost:8080',
blat_addr = 'http://localhost/cgi-bin/webBlat',
rigorous = false,
pix_size = 1;
function quick_e(g, idx, pam, antiparallel) {
var e = '';
if (idx && antiparallel) {
e = '<span style="color:#f00;background:white">-</span> <i>'+pam+'</i> <b>'+g+'</b> : #'+(idx+3)+', ';
} else if (idx) {
e = '<span style="color:#0f0;background:white">+</span> <b>'+g+'</b> <i>'+pam+'</i> : #'+(idx-21)+', ';
} else {
e = '5-<b>'+g+'</b>-3 : ';
}
return e;
}
function blat_23nt(idx, s) {
var seq = $('#q'+idx).text().split(' : ')[0].replace(/[^ATgC]/g, '');
$.ajax({
type: 'POST',
url: blat_addr,
dataType: 'html',
data: {'wb_db':s,'wb_seq':seq,'wb_qType':'DNA','wb_sort':'query,score','wb_output':'psl no header'},
success: function (d) {
var psl = $(d).find('TT').text(), pslsub;
if (psl.substr(0,2) !== '23') {
console.log(seq);
console.log( 'blat output : '+psl.replace(/\t/g, ' ') );
$('#q'+idx).remove(); // not a genomic seq, most likely on different exons
$('.line'+idx).remove();
} else {
pslsub = psl.split("query\t")[1].split("\t");
$('#blat'+idx).text('['+pslsub[3]+' '+pslsub[5]+'-'+pslsub[6]+']');
}
return true;
},
error: function () {
$('#blat'+idx).text('[please verify 23nt by Blat or Blast]');
return false;
}
});
}
function search_an_id(s, a, g, idx, pam, antiparallel) {
$.getJSON(ots_addr+'/api/off_targets?callback=?',
{'species':s, 'ids':a},
function (d) {
var b = d[''+a].off_target_summary,
c = eval('(' + b + ')'), e;
if (c[0] === 0) {
if (idx) {
$('#q'+idx).remove();
} else {
$('#ots_result').append('<li>5-<b>'+g+'</b>-3 : ignore. zero hit in '+s+'</li>');
}
} else if (c[0] > 1) {
if (idx) {
$('#q'+idx).remove();
} else {
$('#ots_result').append('<li>5-<b>'+g+'</b>-3 : alert! do not use, '+c[0]+' exact hits</li>');
}
} else if (c[1] || c[2]) {
if (idx) {
$('#q'+idx).remove();
} else {
$('#ots_result').append('<li>5-<b>'+g+'</b>-3 : warning! one '+c[1]+', two '+c[2]+'</li>');
}
} else if (c[3]) {
e = quick_e(g, idx, pam, antiparallel) + 'fine. three '+c[3]+', four '+c[4];
if (idx && rigorous) {
$('#q'+idx).remove();
} else if (idx) {
$('#q'+idx).html(e+' <span class="blat" id="blat'+idx+'"></span>');
if (antiparallel) {
$('#graph_show').append('<div class="line line'+idx+'" style="background-color:rgba(255,100,100,0.6);text-align:left;border-left:1px solid #999;left:'+(25+idx*pix_size)+'px">'+(idx+3)+'</div>');
} else {
$('#graph_show').append('<div class="line line'+idx+'" style="background-color:rgba(100,255,100,0.6);text-align:right;border-right:1px solid #999;left:'+(25+idx*pix_size)+'px">'+(idx-21)+'</div>');
}
blat_23nt(idx, s);
} else {
$('#ots_result').append('<li>'+e+'</li>');
}
} else {
e = quick_e(g, idx, pam, antiparallel) + 'good. four '+c[4];
if (idx) {
$('#q'+idx).html(e+' <span class="blat" id="blat'+idx+'"></span>');
if (antiparallel) {
$('#graph_show').append('<div class="line line'+idx+'" style="background-color:rgba(255,0,0,0.6);text-align:left;border-left:1px solid #333;left:'+(25+idx*pix_size)+'px">'+(idx+3)+'</div>');
} else {
$('#graph_show').append('<div class="line line'+idx+'" style="background-color:rgba(0,255,0,0.6);text-align:right;border-right:1px solid #333;left:'+(25+idx*pix_size)+'px">'+(idx-21)+'</div>');
}
blat_23nt(idx, s);
} else {
$('#ots_result').append('<li>'+e+'</li>');
}
}
}).done(function () {
$('#progress').append(' .');
});
}
function search_seq(s, g, idx, pam, antiparallel) {
return $.getJSON(ots_addr+'/api/search?callback=?',
{'species':s, 'seq':g},
function (d) {
if (d.length > 1) {
if (!idx) { $('#ots_result').append('<li>5-<b>'+s+'</b>-3 : '+d.length+' hits</li>'); }
} else if (d.length === 1) {
if (idx && antiparallel) {
$('#ots_result').append('<li id="q'+idx+'">...</li>');
} else if (idx) {
$('#ots_result').append('<li id="q'+idx+'">...</li>');
}
search_an_id(s, d[0], g, idx, pam, antiparallel);
} else {
if (!idx) { $('#ots_result').append('<li>5-<b>'+g+'</b>-3 : ignore. zero hit in '+s+'</li>'); }
}
});
}
function plus_strand_search(s, t) {
var pam_seq = 'gg', // NGG
t1 = t.indexOf(pam_seq), tsub, tsub1,
t2 = t.lastIndexOf(pam_seq);
while (t1 < 21) {
t1 += 1;
tsub = t.substr(t1);
tsub1 = tsub.indexOf(pam_seq);
if (tsub1 > -1) {
t1 += tsub1;
} else { break; }
}
if (t1 > t2) {
$('#progress').append(', none in the + strand');
} else {
$('#progress').append('; will process the + strand between '+t1+' ~ '+t2);
var seqs = [], idxs = [], ti, tt, pams = [];
for (ti = t1; ti <= t2; ti += 1) {
if (t.substr(ti, 2) === pam_seq) {
tt = t.substr(ti-21, 20);
if (seqs.indexOf(tt) === -1) {
seqs.push(tt);
idxs.push(ti);
pams.push( t.substr(ti-1, 3) );
}
}
}
defrs_search(s, seqs, idxs, pams, false);
}
}
function minus_strand_search(s, t) {
var pam_seq = 'CC', // CCN
t1 = t.indexOf(pam_seq), tsub, tsub2,
t2 = t.lastIndexOf(pam_seq);
while ((t.length-t2) < 21) {
tsub = t.substring(0, t2-1);
tsub2 = tsub.lastIndexOf(pam_seq);
t2 = -1
if (tsub2 > -1) {
t2 = tsub2;
} else { break; }
}
if (t2 === -1) {
$('#progress').append(', none in the - strand');
} else {
$('#progress').append('; will process the - strand between '+t1+' ~ '+t2);
var seqs = [], idxs = [], ti, tt, pams = [];
for (ti = t1; ti <= t2; ti += 1) {
if (t.substr(ti, 2) === pam_seq) {
tt = t.substr(ti+3, 20);
if (seqs.indexOf(tt) === -1) {
seqs.push(tt);
idxs.push(ti);
pams.push( t.substr(ti, 3) );
}
}
}
defrs_search(s, seqs, idxs, pams, true);
}
}
function defrs_search(s, seqs, idxs, pams, antiparallel) {
var defrs = [];
$.each(seqs, function (iV, ele) {
defrs.push( search_seq(s, ele, idxs[iV], pams[iV], antiparallel) );
});
$('#progress').append(', looped');
$.when(defrs).done(function () {
$('#progress').append(', queued');
});
}
function anti_parallel(t) {
var apt_list = [],
t_list = t.split('');
$.each(t_list, function (iV, ele) {
if (ele === 'A') {
apt_list.unshift( 'T' );
} else if (ele === 'T') {
apt_list.unshift( 'A' );
} else if (ele === 'g') {
apt_list.unshift( 'C' );
} else if (ele === 'C') {
apt_list.unshift( 'g' );
}
});
return apt_list.join('');
}
function check_server() {
$.getJSON(ots_addr+'/api/search?callback=?',
{'seq':'TTAATTGTTTAGCAGTGTCA', 'species':'mouse'},
function (d) {
if (d.length === 1) {
$('#server_status').append('the server is running');
$('#server_status').css({'background':'#eee','color':'green'});
} else {
$('#server_status').append('SERVER ERROR');
$('#server_status').css({'background':'yellow','color':'red'});
$('#submit').hide();
}
});
}
$(document).ready(function () {
check_server();
$('#submit').on('click', function (event) {
$('#ots_result').html('');
$('#graph_show').html('');
$('#progress').text('ing...');
var s = $('input:checked').val(),
g = $('#gRNA_seq').val(),
t = $('#target_seq').val();
if (g) {
$('#target_seq').val('');
rigorous = false;
$('#rigorous').attr('checked', false);
$('#rigorous_label').show();
g = g.replace(/[^atgc]/gi, '').toUpperCase().replace(/G/g, 'g');
if (g && g.length === 20) {
search_seq(s, g);
$('#progress').text('done job1!');
} else {
$('#progress').text('!! please input a 20-nt seq :-p');
$('#gRNA_seq').focus();
}
} else if (t) {
$('#gRNA_seq').val('');
if( $('#rigorous').is(':checked') ) {
rigorous = true;
$('#rigorous_label').show();
} else {
rigorous = false;
$('#rigorous_label').hide();
}
t = t.replace(/[^atgc]/gi, '').toUpperCase().replace(/G/g, 'g');
if ( $('#graph_show').width() > t.length ) {
pix_size = $('#graph_show').width() / t.length;
}
$('#progress').text('job2 starts (if nothing shown means no hit)');
plus_strand_search(s, t);
$('#progress').append('; now the anti-parallel');
minus_strand_search(s, t);
} else {
$('#progress').text('!! please input something correct :-p');
$('#gRNA_seq').focus();
}
event.preventDefault();
});
});
</script>
</body>
</html>
@coronin
Copy link
Author

coronin commented Sep 7, 2014

now, it is public

@coronin
Copy link
Author

coronin commented Sep 8, 2014

now, with local Web Blat support

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment