source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_pools.jsp @ 1975

Last change on this file since 1975 was 1975, checked in by Nicklas Nordborg, 9 years ago

References #485 and #479. Only use 1 decimal in lab protocols for pooling. Use the rounded values when calculating molarity and other values for the pool.

File size: 16.0 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.User"
5  import="net.sf.basedb.core.DbControl"
6  import="net.sf.basedb.core.SessionControl"
7  import="net.sf.basedb.core.Application"
8  import="net.sf.basedb.util.formatter.WellCoordinateFormatter"
9  import="net.sf.basedb.clients.web.Base" 
10  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
11%>
12<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
13<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
14<%
15final SessionControl sc = Base.getExistingSessionControl(request, true);
16final String ID = sc.getId();
17final float scale = Base.getScale(sc);
18final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
19DbControl dc = null;
20try
21{
22  dc = sc.newDbControl();
23  final User user = User.getById(dc, sc.getLoggedInUserId());
24%>
25<base:page type="default" >
26<base:head scripts="ajax.js" styles="path.css">
27  <link rel="stylesheet" type="text/css" href="../css/reggie.css">
28  <link rel="stylesheet" type="text/css" href="../css/plate.css">
29  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
30  <script language="JavaScript" src="pools.js" type="text/javascript" charset="UTF-8"></script>
31  <script language="JavaScript" src="plate.js" type="text/javascript" charset="UTF-8"></script>
32
33<script language="JavaScript">
34var debug = false;
35var currentStep = 1;
36
37// Loaded from servlet when getting Library information
38var TARGET_MOLARITY_IN_POOL;
39var TARGET_VOLUME_IN_POOL_PER_LIB;
40
41function init()
42{
43  var frm = document.forms['reggie'];
44  var bioplates = getLibraryBioPlates();
45 
46  var plates = frm.bioplate;
47  if (bioplates != null && bioplates.length > 0)
48  {
49    for (var i=0; i < bioplates.length; i++)
50    {
51      var bioplate = bioplates[i];
52      var option = new Option(bioplate.name, bioplate.id);
53      option.bioplate = bioplate;
54      plates.options[plates.length] = option;
55    }
56    bioplateIsValid = true;
57    setInputStatus('bioplate', '', 'valid');
58  }
59  else
60  {
61    var msg = 'No Library bioplates available for processing.';
62    setFatalError(msg);
63    return;
64  }
65}
66
67
68function getLibraryBioPlates()
69{
70  var frm = document.forms['reggie']; 
71 
72  var request = Ajax.getXmlHttpRequest();
73  try
74  {
75    showLoadingAnimation('Loading Library bioplates...');
76    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForPooling';
77    request.open("GET", url, false); 
78    request.send(null);
79  }
80  finally
81  {
82    hideLoadingAnimation();
83  }
84 
85  if (debug) Main.debug(request.responseText);
86  var response = JSON.parse(request.responseText); 
87  if (response.status != 'ok')
88  {
89    setFatalError(response.message);
90    return false;
91  }
92  return response.bioplates;
93}
94
95function goNext(manual)
96{
97  setInnerHTML('gonext.message', '');
98  if (currentStep == 1)
99  {   
100    gotoStep2();
101  }
102  setCurrentStep(currentStep);
103}
104
105function gotoStep2()
106{
107  var frm = document.forms['reggie'];
108  frm.bioplate.disabled = true;
109  Main.addClass(document.getElementById('step.1.section'), 'disabled');
110 
111  loadPoolNames();
112  loadLibraryInformation();
113
114  currentStep = 2;
115  Main.hide('step.1.section');
116  Main.show('step.2.section');
117  Main.hide('gonext');
118  Main.show('gocancel');
119  Main.show('gocreate');
120}
121
122function goCreate()
123{
124
125  var submitInfo = {};
126  submitInfo.pools = [];
127 
128  var numPools = Plate.getPools();
129  for (var poolNo = 0; poolNo < numPools; poolNo++)
130  {
131    var wells = Plate.getPool(poolNo);
132   
133    var poolInfo = {};
134    poolInfo.name = POOL_NAMES[poolNo];
135    poolInfo.libs = [];
136   
137    for (var wellNo = 0; wellNo < wells.length; wellNo++)
138    {
139      var lib = wells[wellNo].extract;
140      if (lib)
141      {
142        // We send library id, name and mixin volumes
143        var tmp = {};
144        tmp.id = lib.id;
145        tmp.name = lib.name;
146        tmp.volume = lib.volume;
147        tmp.eb = lib.eb;
148        tmp.mixFactor = lib.mixFactor;
149        poolInfo.libs[poolInfo.libs.length] = tmp;
150      }
151    }
152   
153    submitInfo.pools[submitInfo.pools.length] = poolInfo;
154  }
155 
156  Main.addClass(document.getElementById('step.2.section'), 'disabled');
157  Main.hide('gocancel');
158  Main.hide('gocreate');
159
160  if (debug) Main.debug(JSON.stringify(submitInfo));
161
162  var request = Ajax.getXmlHttpRequest();
163  try
164  {
165    showLoadingAnimation('Creating pools...');
166    var url = '../Pool.servlet?ID=<%=ID%>';
167    url += '&cmd=CreatePools';
168    request.open("POST", url, false);
169    request.setRequestHeader("Content-Type", "application/json");
170    request.send(JSON.stringify(submitInfo));
171  }
172  finally
173  {
174    hideLoadingAnimation();
175  }
176
177  if (debug) Main.debug(request.responseText);
178
179  var response = JSON.parse(request.responseText);
180  if (response.status != 'ok')
181  {
182    setFatalError(response.message);
183    return false;
184  }
185
186  var msg = '<ul>';
187  for (var i = 0; i < response.messages.length; i++)
188  {
189    msg += '<li>' + response.messages[i];
190  }
191  msg += '</ul>';
192  setInnerHTML('done', msg);
193  Main.show('done');
194  Main.show('gorestart');
195  scrollToBottom(document.getElementById('content'));
196
197}
198
199function loadLibraryInformation()
200{
201  var frm = document.forms['reggie'];
202  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
203
204  var schema = PoolSchema.getById(libPlate.poolSchema);
205  var barcodeVariant = PoolSchema.getBarcodeVariantByName(schema, libPlate.barcodeVariant);
206  Plate.setPoolSchema(schema);
207  WellPainter.barcodeVariant = barcodeVariant;
208
209  setInnerHTML('pool_schema', schema.name);
210  setInnerHTML('barcode_variant', barcodeVariant.name);
211 
212  // Load Libraries and related info from the selected bioplate
213  var request = Ajax.getXmlHttpRequest();
214  try
215  {
216    showLoadingAnimation('Loading information about libraries...');
217    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPlate&bioplate='+libPlate.id;   
218    request.open("GET", url, false);
219    request.send(null);
220  }
221  finally
222  {
223    hideLoadingAnimation();
224  }
225 
226  if (debug) Main.debug(request.responseText);
227  var response = JSON.parse(request.responseText);
228  if (response.status != 'ok')
229  {
230    setFatalError(response.message);
231    return false;
232  }
233 
234  var poolInfo = response.poolInfo;
235  TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
236  TARGET_VOLUME_IN_POOL_PER_LIB = poolInfo.targetVolumePerLib;
237 
238  setInnerHTML('target_molarity', Numbers.formatNumber(TARGET_MOLARITY_IN_POOL, 1) + ' nM');
239  setInnerHTML('target_volume', Numbers.formatNumber(TARGET_VOLUME_IN_POOL_PER_LIB, 1) + ' µl');
240 
241  // Pre-process the Library items
242  var list = response.libraries;
243  for (var i = 0; i < list.length; i++)
244  {
245    checkAndPreProcessLibrary(list[i], schema, barcodeVariant);
246  }
247 
248  viewAsPlate(list, schema, barcodeVariant)
249}
250
251function loadPoolNames()
252{
253  var frm = document.forms['reggie'];
254  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
255
256  var schema = PoolSchema.getById(libPlate.poolSchema);
257
258  // Load Libraries and related info from the selected bioplate
259  var request = Ajax.getXmlHttpRequest();
260  try
261  {
262    showLoadingAnimation('Loading Library bioplate information...');
263    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetNextAutoGeneratedPoolNames&numNames='+schema.numPools;   
264    request.open("GET", url, false);
265    request.send(null);
266  }
267  finally
268  {
269    hideLoadingAnimation();
270  }
271 
272  if (debug) Main.debug(request.responseText);
273  var response = JSON.parse(request.responseText);
274  if (response.status != 'ok')
275  {
276    setFatalError(response.message);
277    return false;
278  }
279 
280  var list = response.names;
281  for (var i = 0; i < list.length; i++)
282  {
283    POOL_NAMES[i] = list[i];
284  }
285
286}
287
288
289function checkAndPreProcessLibrary(lib, schema, barcodeVariant)
290{
291  var well = lib.bioWell;
292  var remarks = [];
293
294  // Check if default barcode has been modified
295  var indexSet = barcodeVariant.indexSets[well.column];
296  if (indexSet)
297  {
298    var defaultBarcode = indexSet.barcodes[well.row];
299    if (defaultBarcode && lib.barcode.name != defaultBarcode)
300    {
301      remarks[remarks.length] = 'Modified barcode';
302      lib.barcode.modified = true;
303    }
304  }
305 
306  if (lib.volume)
307  {
308    if (lib.speedVacConc != null)
309    {
310      remarks[remarks.length] = 'SpeedVac';
311    }
312    if (lib.volume > TARGET_VOLUME_IN_POOL_PER_LIB + 0.001)  // +0.001 to allow for rounding errors
313    {
314      remarks[remarks.length] = 'Use '+TARGET_VOLUME_IN_POOL_PER_LIB+' µl';
315    }
316
317    if (lib.mixFactor > 1.001)
318    {
319      // Larger mix than default
320      var mixedVolume = (lib.volume+lib.eb)*(lib.mixFactor);
321      remarks[remarks.length] = 'Mix ' + Numbers.formatNumber(mixedVolume, 0) + 'µl';
322    }
323
324  }
325 
326  lib.remarks = remarks;
327}
328
329function viewAsPlate(list, schema, barcodeVariant)
330{
331  Plate.init(8, 12, schema, WellPainter);
332 
333  for (var i = 0; i < list.length; i++)
334  {
335    var lib = list[i];
336    var well = lib.bioWell;
337    Plate.getWell(well.row, well.column).setExtract(lib);
338  }
339
340  WellPainter.barcodeVariant = barcodeVariant;
341  Plate.paint(Plate.getWells());
342  PoolSchema.buildPoolTableRow(schema, 12);
343 
344  for (var poolNo = 0; poolNo < Plate.getPools(); poolNo++)
345  {
346    var wells = Plate.getPool(poolNo);
347    var poolMolarity = 0;
348    var poolVolume = 0;
349    var numLibs = 0;
350    for (var wellNo = 0; wellNo < wells.length; wellNo++)
351    {
352      var lib = wells[wellNo].extract;
353      if (lib)
354      {
355        poolMolarity += Math.min(lib.molarity, lib.mixMolarity);
356        poolVolume += TARGET_VOLUME_IN_POOL_PER_LIB;
357        numLibs++;
358      }
359    }
360   
361    var poolData = '<div class="pool-data">';
362    poolData += Numbers.formatNumber(poolMolarity/numLibs, 2)+'nM; ';
363    poolData += Numbers.formatNumber(poolVolume, 0) + 'µl';
364    poolData += '</div>';
365    document.getElementById('pool.'+poolNo).innerHTML = POOL_NAMES[poolNo] + poolData;
366  }
367 
368}
369
370var WellPainter = function()
371{
372  var painter = {};
373 
374  painter.getClassNameForWell = function(well, schema)
375  {
376    var cls = '';
377    var indexSet = painter.barcodeVariant.indexSets[well.column];
378    if (indexSet)
379    {
380      var lib = well.extract;
381      cls += lib && lib.barcode.modified ? 'bg-modified' : indexSet.color;
382    }
383    return cls;
384  }
385 
386  painter.getWellText = function(well, schema)
387  {
388    var text = '';
389    var lib = well.extract;
390    if (lib && lib.remainingQuantity && lib.molarity)
391    {
392      var name = lib.name;
393      var i = name.indexOf('.m');
394      var mixFactor = lib.mixFactor;
395      var displayName = name.substring(0, i)+'.<br>&nbsp;'+name.substring(i);
396      text += '<div class="lib">'+displayName+'</div>';
397      text += '<span class="barcode">'+lib.barcode.name+'</span>';
398      text += '<span class="molarity">'+Numbers.formatNumber(lib.molarity, 2)+'nM</span>';
399      text += '<span class="volume">'+Numbers.formatNumber(lib.volume*mixFactor, 1) + 'µl</span>';
400      text += '<span class="eb">'+Numbers.formatNumber(lib.eb*mixFactor, 1)+'µl</span>';
401      text += '<div class="remarks">'+ lib.remarks.join('; ') + '</div>';
402    }
403    return text;
404  }
405
406  return painter;
407}();
408
409</script>
410<style>
411.lib
412{
413  font-weight: bold;
414  margin-bottom: 0.25em;
415  overflow: hidden;
416  text-overflow: ellipsis;
417}
418.barcode
419{}
420.molarity
421{
422  float: right;
423}
424
425.volume
426{
427  color: #C80000;
428}
429.eb
430{
431  color: #0000C8;
432  float: right;
433}
434.remarks
435{
436  color: #C80000;
437  font-style: italic;
438}
439.pool-data
440{
441  font-weight: normal;
442}
443</style>
444</base:head>
445<base:body onload="init()">
446
447  <p:path><p:pathelement 
448    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
449    /><p:pathelement title="Create pooled libraries" 
450    /></p:path>
451
452  <div class="content" id="content">
453  <%
454  if (sc.getActiveProjectId() == 0)
455  {
456    %>
457    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
458      No project has been selected. You may proceed with the registration but
459      created items will not be shared.
460    </div>
461    <%
462  }
463  %>
464
465  <div class="allsteps">
466    <div class="step current" id="step.1">1</div>
467    ›
468    <div class="step future" id="step.2">2</div>
469  </div>
470
471  <form name="reggie" onsubmit="return false;">
472 
473  <div id="step.1.section">
474  <table class="stepform">
475  <tr>
476    <td rowspan="3" class="stepno">1</td>
477    <td class="steptitle">Select source for pool</td>
478  </tr>
479  <tr>
480    <td class="stepfields">
481      <table>
482      <tr valign="top">
483        <td class="prompt">Library bioplate</td>
484        <td class="input"><select style="width:90%" 
485            name="bioplate" id="bioplate" onchange="bioPlateOnChange()"></select>
486        </td>
487        <td class="status" id="bioplate.status"></td>
488        <td class="help"><span id="bioplate.message" class="message" style="display: none;"></span>
489          Select an existing Library bioplate. The list contain all Library bioplates that
490          contain libraries with no child items.
491        </td>
492      </tr>
493      <tr valign="top">
494        <td class="prompt"></td>
495        <td class="input"> - or -</td>
496        <td class="status" id="bioplate.status"></td>
497        <td class="help"></td>
498      </tr>
499      <tr valign="top">
500        <td class="prompt">Manual select</td>
501        <td class="input"> // TODO</td>
502        <td class="status"></td>
503        <td class="help"></td>
504      </tr>
505      </table>
506    </td>
507  </tr>
508  </table>
509  </div>
510 
511  <div id="step.2.section" style="display: none;">
512  <table class="stepform" style="width: auto;">
513  <tr>
514    <td rowspan="2" class="stepno">2</td>
515    <td class="steptitle">Confirm pool layout</td>
516  </tr>
517  <tr>
518    <td class="stepfields">
519
520      <table class="bottomborder" style="width: 100%;">
521      <tr valign="top">
522        <td class="prompt">Pool layout</td>
523        <td class="input">
524          <span id="pool_schema"></span>
525        </td>
526        <td class="help"></td>
527      </tr>
528      <tr valign="top">
529        <td class="prompt">Barcode variant</td>
530        <td class="input">
531          <span id="barcode_variant"></span>
532        </td>
533        <td class="help"></td>
534      </tr>
535      <tr valign="top">
536        <td class="prompt">Target molarity</td>
537        <td class="input">
538          <span id="target_molarity"></span>
539        </td>
540        <td class="help"></td>
541      </tr>
542      <tr valign="top">
543        <td class="prompt">Target volume / lib</td>
544        <td class="input">
545          <span id="target_volume"></span>
546        </td>
547        <td class="help"></td>
548      </tr>
549      </table>
550     
551      <table class="plate" style="margin: 1em 1em 1em 1em;" id="plate">
552      <%
553      int columns = 12;
554      int rows = 8;
555      WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
556      WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
557      %>
558      <tr class="header">
559        <th></th>
560        <%
561        for (int c = 0; c < columns; ++c)
562        {
563          %>
564          <th id="col.<%=c%>"><%=colF.format(c)%></th>
565          <%
566        }
567        %>
568      </tr>
569      <tbody>
570      <%
571      for (int r = 0; r < rows; ++r)
572      {
573        String row = rowF.format(r);
574        %>
575        <tr class="row-<%=r%>">
576          <th id="row.<%=r%>" class="rowheader"><%=row%></th>
577          <%
578          for (int c = 0; c < columns; ++c)
579          {
580            %>
581            <td class="well col-<%=c%>" id="well.<%=r%>.<%=c%>"
582              title=""
583              ></td>
584            <%
585          }
586          %>
587        </tr>
588        <%
589      }
590      %>
591      </tbody>
592      <tr id="pool-row">
593        <th colspan="13">&nbsp;</th>
594      </tr>
595      </table>
596    </td>
597  </tr>
598  </table>
599  </div>
600 
601  <div class="loading" id="loading" style="display: none;"><table><tr><td><img src="../images/loading.gif"></td><td id="loading.msg">Please wait...</td></tr></table></div>
602 
603  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
604 
605  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
606 
607  <table style="margin-left: 20px; margin-top: 10px; margin-bottom: 3em;" class="navigation">
608    <tr>
609      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
610      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)"/></td>
611      <td><base:button id="gocreate" title="Create" image="<%=home+"/images/gonext.png"%>" onclick="goCreate()" style="display: none;"/></td>
612      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
613      <td id="gonext.message" class="message"></td>
614    </tr>
615  </table>
616 
617 
618  </form>
619  </div>
620 
621</base:body>
622</base:page>
623<%
624}
625finally
626{
627  if (dc != null) dc.close();
628}
629%>
Note: See TracBrowser for help on using the repository browser.