www/include/scripts/plate.js

Code
Comments
Other
Rev Date Author Line
7604 25 Feb 19 nicklas 1 /* $Id $
7604 25 Feb 19 nicklas 2   ------------------------------------------------------------------
7604 25 Feb 19 nicklas 3   Copyright (C) 2010 Nicklas Nordborg
7604 25 Feb 19 nicklas 4
7604 25 Feb 19 nicklas 5   This file is part of BASE - BioArray Software Environment.
7604 25 Feb 19 nicklas 6   Available at http://base.thep.lu.se/
7604 25 Feb 19 nicklas 7
7604 25 Feb 19 nicklas 8   BASE is free software; you can redistribute it and/or
7604 25 Feb 19 nicklas 9   modify it under the terms of the GNU General Public License
7604 25 Feb 19 nicklas 10   as published by the Free Software Foundation; either version 3
7604 25 Feb 19 nicklas 11   of the License, or (at your option) any later version.
7604 25 Feb 19 nicklas 12
7604 25 Feb 19 nicklas 13   BASE is distributed in the hope that it will be useful,
7604 25 Feb 19 nicklas 14   but WITHOUT ANY WARRANTY; without even the implied warranty of
7604 25 Feb 19 nicklas 15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7604 25 Feb 19 nicklas 16   GNU General Public License for more details.
7604 25 Feb 19 nicklas 17
7604 25 Feb 19 nicklas 18   You should have received a copy of the GNU General Public License
7604 25 Feb 19 nicklas 19   along with BASE. If not, see <http://www.gnu.org/licenses/>.
7604 25 Feb 19 nicklas 20   ------------------------------------------------------------------
7604 25 Feb 19 nicklas 21
7604 25 Feb 19 nicklas 22   JavaScript functions for the bioplates and well mapping
7604 25 Feb 19 nicklas 23
7604 25 Feb 19 nicklas 24   @author Nicklas
7604 25 Feb 19 nicklas 25   @version 2.16
7604 25 Feb 19 nicklas 26 */
7604 25 Feb 19 nicklas 27 'use strict';
7604 25 Feb 19 nicklas 28
7604 25 Feb 19 nicklas 29 /**
7604 25 Feb 19 nicklas 30   A list of biomaterial items. The prefix is used 
7604 25 Feb 19 nicklas 31   to find DOM elements for the items in the list. Each
7604 25 Feb 19 nicklas 32   item should have a prefix.item-id element and may
7604 25 Feb 19 nicklas 33   also have a prefix.item-id.info and prefix.item-id.label 
7604 25 Feb 19 nicklas 34   elements.
7604 25 Feb 19 nicklas 35   
7604 25 Feb 19 nicklas 36   Use addItem(id, name) to add items to the list.
7604 25 Feb 19 nicklas 37
7604 25 Feb 19 nicklas 38 */
7604 25 Feb 19 nicklas 39 function ItemList(prefix)
7604 25 Feb 19 nicklas 40 {
7604 25 Feb 19 nicklas 41   this.prefix = prefix;
7604 25 Feb 19 nicklas 42   this.items = new Array();
7604 25 Feb 19 nicklas 43   this.selectedItemClass = 'selected';
7604 25 Feb 19 nicklas 44   this.linkedItemClass = 'linked';
7604 25 Feb 19 nicklas 45   this.mappedItemClass = 'mapped';
7604 25 Feb 19 nicklas 46   
7604 25 Feb 19 nicklas 47   /**
7604 25 Feb 19 nicklas 48     Get the main DOM tag for the item list. It's ID should be
7604 25 Feb 19 nicklas 49     the same as the list prefix.
7604 25 Feb 19 nicklas 50   */
7604 25 Feb 19 nicklas 51   ItemList.prototype.getTag = function()
7604 25 Feb 19 nicklas 52   {
7604 25 Feb 19 nicklas 53     if (!this.tag)
7604 25 Feb 19 nicklas 54     {
7604 25 Feb 19 nicklas 55       this.tag = Doc.element(this.prefix);
7604 25 Feb 19 nicklas 56     }
7604 25 Feb 19 nicklas 57     return this.tag;
7604 25 Feb 19 nicklas 58   }
7604 25 Feb 19 nicklas 59
7604 25 Feb 19 nicklas 60   
7604 25 Feb 19 nicklas 61   /**
7604 25 Feb 19 nicklas 62     Add an item to the list. The DOM should contain an element
7604 25 Feb 19 nicklas 63     with id=prefix.item-id
7604 25 Feb 19 nicklas 64   */
7604 25 Feb 19 nicklas 65   ItemList.prototype.addItem = function(id, name)
7604 25 Feb 19 nicklas 66   {
7604 25 Feb 19 nicklas 67     var item = new Item(this, id, name);
7604 25 Feb 19 nicklas 68     this.items[this.items.length] = item;
7604 25 Feb 19 nicklas 69     this.items['item.' + id] = item;
7604 25 Feb 19 nicklas 70     return item;
7604 25 Feb 19 nicklas 71   }
7604 25 Feb 19 nicklas 72
7604 25 Feb 19 nicklas 73   /**
7604 25 Feb 19 nicklas 74     Get the item with the given id.
7604 25 Feb 19 nicklas 75   */
7604 25 Feb 19 nicklas 76   ItemList.prototype.getItem = function(id)
7604 25 Feb 19 nicklas 77   {
7604 25 Feb 19 nicklas 78     return this.items['item.' + id];
7604 25 Feb 19 nicklas 79   }
7604 25 Feb 19 nicklas 80   
7604 25 Feb 19 nicklas 81   /**
7604 25 Feb 19 nicklas 82     Get the next unmapped item after the given item in the list.
7604 25 Feb 19 nicklas 83   */
7604 25 Feb 19 nicklas 84   ItemList.prototype.nextUnmappedItem = function(item)
7604 25 Feb 19 nicklas 85   {
7604 25 Feb 19 nicklas 86     var i = 0;
7604 25 Feb 19 nicklas 87     // Find the given item
7604 25 Feb 19 nicklas 88     while (i < this.items.length && this.items[i] != item)
7604 25 Feb 19 nicklas 89     {
7604 25 Feb 19 nicklas 90       i++;
7604 25 Feb 19 nicklas 91     }
7604 25 Feb 19 nicklas 92     // Move to the next until an unmapped item is found
7604 25 Feb 19 nicklas 93     i++;
7604 25 Feb 19 nicklas 94     while (i < this.items.length)
7604 25 Feb 19 nicklas 95     {
7604 25 Feb 19 nicklas 96       if (!this.items[i].mappedWell) return this.items[i];
7604 25 Feb 19 nicklas 97       i++;
7604 25 Feb 19 nicklas 98     }
7604 25 Feb 19 nicklas 99     return null;
7604 25 Feb 19 nicklas 100   }
7604 25 Feb 19 nicklas 101   
7604 25 Feb 19 nicklas 102   ItemList.prototype.unmapAll = function(graphics)
7604 25 Feb 19 nicklas 103   {
7604 25 Feb 19 nicklas 104     for (var i = 0; i < this.items.length; i++)
7604 25 Feb 19 nicklas 105     {
7604 25 Feb 19 nicklas 106       var item = this.items[i];
7604 25 Feb 19 nicklas 107       item.hideLink(graphics);
7604 25 Feb 19 nicklas 108       item.unmapWell();
7604 25 Feb 19 nicklas 109     }
7604 25 Feb 19 nicklas 110   }
7604 25 Feb 19 nicklas 111   
7604 25 Feb 19 nicklas 112 }
7604 25 Feb 19 nicklas 113
7604 25 Feb 19 nicklas 114 /**
7604 25 Feb 19 nicklas 115   A single item in a list of biomaterial. Use ItemList.addItem() to 
7604 25 Feb 19 nicklas 116   add items to the list.
7604 25 Feb 19 nicklas 117   @param list The list object
7604 25 Feb 19 nicklas 118   @param id The id of the item
7604 25 Feb 19 nicklas 119   @param name The name (label) of the item
7604 25 Feb 19 nicklas 120 */
7604 25 Feb 19 nicklas 121 function Item(list, id, name)
7604 25 Feb 19 nicklas 122 {
7604 25 Feb 19 nicklas 123   this.list = list;
7604 25 Feb 19 nicklas 124   this.id = id;
7604 25 Feb 19 nicklas 125   this.name = name;
7604 25 Feb 19 nicklas 126   this.selected = false;
7604 25 Feb 19 nicklas 127   this.linked = false;
7604 25 Feb 19 nicklas 128   this.mappedWell = null;
7604 25 Feb 19 nicklas 129   
7604 25 Feb 19 nicklas 130   /**
7604 25 Feb 19 nicklas 131     Get the main DOM tag for the item. It should have and ID combined
7604 25 Feb 19 nicklas 132     of 'list-prefix.item-id'
7604 25 Feb 19 nicklas 133   */
7604 25 Feb 19 nicklas 134   Item.prototype.getTag = function()
7604 25 Feb 19 nicklas 135   {
7604 25 Feb 19 nicklas 136     if (!this.tag)
7604 25 Feb 19 nicklas 137     {
7604 25 Feb 19 nicklas 138       this.tag = Doc.element(this.list.prefix+'.'+this.id);
7604 25 Feb 19 nicklas 139     }
7604 25 Feb 19 nicklas 140     return this.tag;
7604 25 Feb 19 nicklas 141   }
7604 25 Feb 19 nicklas 142   
7604 25 Feb 19 nicklas 143   /**
7604 25 Feb 19 nicklas 144     Add a CSS class to the item's DOM tag.
7604 25 Feb 19 nicklas 145   */
7604 25 Feb 19 nicklas 146   Item.prototype.addClass = function(cls)
7604 25 Feb 19 nicklas 147   {
7604 25 Feb 19 nicklas 148     Doc.addClass(this.getTag(), cls);
7604 25 Feb 19 nicklas 149   }
7604 25 Feb 19 nicklas 150
7604 25 Feb 19 nicklas 151   /**
7604 25 Feb 19 nicklas 152     Remove a CSS class from the item's DOM tag.
7604 25 Feb 19 nicklas 153   */
7604 25 Feb 19 nicklas 154   Item.prototype.removeClass = function(cls)
7604 25 Feb 19 nicklas 155   {
7604 25 Feb 19 nicklas 156     Doc.removeClass(this.getTag(), cls);
7604 25 Feb 19 nicklas 157   }
7604 25 Feb 19 nicklas 158   
7604 25 Feb 19 nicklas 159   /**
7604 25 Feb 19 nicklas 160     Set the contents of the info element. The tag should have an ID combined
7604 25 Feb 19 nicklas 161     of 'list-prefix.item-id.info'.
7604 25 Feb 19 nicklas 162   */
7604 25 Feb 19 nicklas 163   Item.prototype.setInfo = function(info)
7604 25 Feb 19 nicklas 164   {
7604 25 Feb 19 nicklas 165     var infoTag = Doc.element(this.list.prefix+'.'+this.id + '.info');
7604 25 Feb 19 nicklas 166     if (!infoTag) return;
7604 25 Feb 19 nicklas 167     infoTag.innerHTML = info;
7604 25 Feb 19 nicklas 168   }
7604 25 Feb 19 nicklas 169   
7604 25 Feb 19 nicklas 170   /**
7604 25 Feb 19 nicklas 171     Mark the item as selected/deselected.
7604 25 Feb 19 nicklas 172   */
7604 25 Feb 19 nicklas 173   Item.prototype.setSelected = function(selected)
7604 25 Feb 19 nicklas 174   {
7604 25 Feb 19 nicklas 175     this.selected = selected;
7604 25 Feb 19 nicklas 176     Doc.addOrRemoveClass(this.getTag(), this.list.selectedItemClass, selected);
7604 25 Feb 19 nicklas 177   }
7604 25 Feb 19 nicklas 178   
7604 25 Feb 19 nicklas 179   /**
7604 25 Feb 19 nicklas 180     Mark the item as linked. Do not call this method. Use drawLink/hideLink 
7604 25 Feb 19 nicklas 181     instead.
7604 25 Feb 19 nicklas 182   */
7604 25 Feb 19 nicklas 183   Item.prototype.setLinked = function(linked)
7604 25 Feb 19 nicklas 184   {
7604 25 Feb 19 nicklas 185     this.linked = linked;
7604 25 Feb 19 nicklas 186     Doc.addOrRemoveClass(this.getTag(), this.list.linkedItemClass, linked);
7604 25 Feb 19 nicklas 187   }
7604 25 Feb 19 nicklas 188   
7604 25 Feb 19 nicklas 189   /**
7604 25 Feb 19 nicklas 190     Draw a link from the item to the well it is mapped to. If
7604 25 Feb 19 nicklas 191     the item is not mapped, no link is drawn.
7604 25 Feb 19 nicklas 192     
7604 25 Feb 19 nicklas 193     @param graphics A jsGraphics object
7604 25 Feb 19 nicklas 194     @param pen A jsGraphics pen object
7604 25 Feb 19 nicklas 195     @param overwrite TRUE to overwrite existing link, FALSE to not draw if there already is a link
7604 25 Feb 19 nicklas 196   */
7604 25 Feb 19 nicklas 197   Item.prototype.drawLink = function(graphics, pen, overwrite)
7604 25 Feb 19 nicklas 198   {
7604 25 Feb 19 nicklas 199     if (!this.mappedWell) return;
7604 25 Feb 19 nicklas 200     if (this.linkDiv) 
7604 25 Feb 19 nicklas 201     {
7604 25 Feb 19 nicklas 202       if (!overwrite) return;
7604 25 Feb 19 nicklas 203       this.hideLink(graphics);
7604 25 Feb 19 nicklas 204     }
7604 25 Feb 19 nicklas 205     
7604 25 Feb 19 nicklas 206     var itemPos = Doc.getElementPosition(this.getTag());
7604 25 Feb 19 nicklas 207     var wellPos = Doc.getElementPosition(this.mappedWell.getTag());
7604 25 Feb 19 nicklas 208     var listPos = Doc.getElementPosition(this.list.getTag());
7604 25 Feb 19 nicklas 209     // Do not draw the link if the item is not visible
7604 25 Feb 19 nicklas 210     if (itemPos.top < listPos.top || (itemPos.bottom) > (listPos.bottom)) return;
7604 25 Feb 19 nicklas 211     
7604 25 Feb 19 nicklas 212     var points = new Array();
7604 25 Feb 19 nicklas 213     points[0] = new jsPoint(itemPos.right, itemPos.top+itemPos.height/2);
7604 25 Feb 19 nicklas 214     points[1] = new jsPoint(wellPos.left, wellPos.top+wellPos.height/2);
7604 25 Feb 19 nicklas 215     this.linkDiv = graphics.drawLine(pen, points[0], points[1]);
7604 25 Feb 19 nicklas 216     this.setLinked(true);
7604 25 Feb 19 nicklas 217     this.mappedWell.setLinked(true);
7604 25 Feb 19 nicklas 218   }
7604 25 Feb 19 nicklas 219   
7604 25 Feb 19 nicklas 220   /**
7604 25 Feb 19 nicklas 221     Hide the link from the item to the well it is mapped to.
7604 25 Feb 19 nicklas 222   */
7604 25 Feb 19 nicklas 223   Item.prototype.hideLink = function(graphics)
7604 25 Feb 19 nicklas 224   {
7604 25 Feb 19 nicklas 225     if (!this.linkDiv) return;
7604 25 Feb 19 nicklas 226     graphics.clearDrawing(this.linkDiv);
7604 25 Feb 19 nicklas 227     this.linkDiv = null;
7604 25 Feb 19 nicklas 228     this.setLinked(false);
7604 25 Feb 19 nicklas 229     if (this.mappedWell)
7604 25 Feb 19 nicklas 230     {
7604 25 Feb 19 nicklas 231       this.mappedWell.setLinked(false);
7604 25 Feb 19 nicklas 232     }
7604 25 Feb 19 nicklas 233   }
7604 25 Feb 19 nicklas 234   
7604 25 Feb 19 nicklas 235   /**
7604 25 Feb 19 nicklas 236     Map the item to the given well. Existing mapping for the
7604 25 Feb 19 nicklas 237     current item and well are automatically removed. The
7604 25 Feb 19 nicklas 238     item's info tag is updated with the coordinate of the well.
7604 25 Feb 19 nicklas 239   */
7604 25 Feb 19 nicklas 240   Item.prototype.mapToWell = function(well)
7604 25 Feb 19 nicklas 241   {
7604 25 Feb 19 nicklas 242     this.unmapWell();
7604 25 Feb 19 nicklas 243     well.unmapItem();
7604 25 Feb 19 nicklas 244     this.mappedWell = well;
7604 25 Feb 19 nicklas 245     well.mappedItem = this;
7604 25 Feb 19 nicklas 246     this.setInfo(well.getCoordinate());
7604 25 Feb 19 nicklas 247     this.addClass(this.list.mappedItemClass);
7604 25 Feb 19 nicklas 248     well.addClass(well.plate.mappedWellClass);
7604 25 Feb 19 nicklas 249   }
7604 25 Feb 19 nicklas 250   
7604 25 Feb 19 nicklas 251   /**
7604 25 Feb 19 nicklas 252     Remove the current mapping.
7604 25 Feb 19 nicklas 253   */
7604 25 Feb 19 nicklas 254   Item.prototype.unmapWell = function()
7604 25 Feb 19 nicklas 255   {
7604 25 Feb 19 nicklas 256     if (!this.mappedWell) return;
7604 25 Feb 19 nicklas 257     this.setInfo('');
7604 25 Feb 19 nicklas 258     this.removeClass(this.list.mappedItemClass);
7604 25 Feb 19 nicklas 259     this.mappedWell.removeClass(this.mappedWell.plate.mappedWellClass);
7604 25 Feb 19 nicklas 260     this.mappedWell.mappedItem = null;
7604 25 Feb 19 nicklas 261     this.mappedWell = null;
7604 25 Feb 19 nicklas 262   }
7604 25 Feb 19 nicklas 263   
7604 25 Feb 19 nicklas 264   /**
7604 25 Feb 19 nicklas 265     Scroll the list so that this item comes into view. If the item is already visible
7604 25 Feb 19 nicklas 266     nothing is changed
7604 25 Feb 19 nicklas 267   */
7604 25 Feb 19 nicklas 268   Item.prototype.scrollIntoView = function()
7604 25 Feb 19 nicklas 269   {
7604 25 Feb 19 nicklas 270     var itemTag = this.getTag();
7604 25 Feb 19 nicklas 271     var itemPos = Doc.getElementPosition(itemTag);
7604 25 Feb 19 nicklas 272     var listTag = this.list.getTag();
7604 25 Feb 19 nicklas 273     var listPos = Doc.getElementPosition(listTag);
7604 25 Feb 19 nicklas 274     
7604 25 Feb 19 nicklas 275     if (itemPos.top < listPos.top)
7604 25 Feb 19 nicklas 276     {
7604 25 Feb 19 nicklas 277       // Scroll up
7604 25 Feb 19 nicklas 278       listTag.scrollTop = listTag.scrollTop - (listPos.top - itemPos.top);
7604 25 Feb 19 nicklas 279     }
7604 25 Feb 19 nicklas 280     else if (itemPos.bottom > listPos.bottom)
7604 25 Feb 19 nicklas 281     {
7604 25 Feb 19 nicklas 282       // Scroll down
7604 25 Feb 19 nicklas 283       listTag.scrollTop = listTag.scrollTop + (itemPos.bottom - listPos.bottom);
7604 25 Feb 19 nicklas 284     }
7604 25 Feb 19 nicklas 285   }
7604 25 Feb 19 nicklas 286 }
7604 25 Feb 19 nicklas 287
7604 25 Feb 19 nicklas 288 /**
7604 25 Feb 19 nicklas 289   Represents a plate for storing biomaterial.
7604 25 Feb 19 nicklas 290   
7604 25 Feb 19 nicklas 291    @param prefix Prefix used to find DOM tags for the wells
7604 25 Feb 19 nicklas 292   @param id The id of the plate
7604 25 Feb 19 nicklas 293   @param name The name of the plate
7604 25 Feb 19 nicklas 294   @param rows The number of rows on the plate
7604 25 Feb 19 nicklas 295   @param columns The number of columns on the plate
7604 25 Feb 19 nicklas 296   @param isSourcePlate If the given plate is a source plate or destination plate
7604 25 Feb 19 nicklas 297 */
7604 25 Feb 19 nicklas 298 function Plate(prefix, id, name, rows, columns, isSourcePlate)
7604 25 Feb 19 nicklas 299 {
7604 25 Feb 19 nicklas 300   this.prefix = prefix;
7604 25 Feb 19 nicklas 301   this.id = id;
7604 25 Feb 19 nicklas 302   this.name = name;
7604 25 Feb 19 nicklas 303   this.rows = rows;
7604 25 Feb 19 nicklas 304   this.columns = columns;
7604 25 Feb 19 nicklas 305   this.isSourcePlate = isSourcePlate;
7604 25 Feb 19 nicklas 306   this.selectedWellClass = 'selected';
7604 25 Feb 19 nicklas 307   this.linkedWellClass = 'linked';
7604 25 Feb 19 nicklas 308   this.mappedWellClass = 'mapped';
7604 25 Feb 19 nicklas 309   this.wells = new Array();
7604 25 Feb 19 nicklas 310   
7604 25 Feb 19 nicklas 311   /**
7604 25 Feb 19 nicklas 312     Get the well on the given coordinate. If the coordinate it outside the
7604 25 Feb 19 nicklas 313     plate boundaries, null is returned, otherwise a Well object.
7604 25 Feb 19 nicklas 314   */
7604 25 Feb 19 nicklas 315   Plate.prototype.getWell = function(row, column)
7604 25 Feb 19 nicklas 316   {
7604 25 Feb 19 nicklas 317     if (row < 0 || row >= this.rows) return null;
7604 25 Feb 19 nicklas 318     if (column < 0 || column >= this.columns) return null;
7604 25 Feb 19 nicklas 319     var well = this.wells[row+':'+column];
7604 25 Feb 19 nicklas 320     if (!well)
7604 25 Feb 19 nicklas 321     {
7604 25 Feb 19 nicklas 322       well = new Well(this, row, column);
7604 25 Feb 19 nicklas 323       this.wells[this.wells.length] = well;
7604 25 Feb 19 nicklas 324       this.wells[row + ':' + column] = well;
7604 25 Feb 19 nicklas 325     }
7604 25 Feb 19 nicklas 326     return well;
7604 25 Feb 19 nicklas 327   }
7604 25 Feb 19 nicklas 328   
7604 25 Feb 19 nicklas 329   Plate.prototype.unmapAll = function(graphics)
7604 25 Feb 19 nicklas 330   {
7604 25 Feb 19 nicklas 331     for (var i = 0; i < this.wells.length; i++)
7604 25 Feb 19 nicklas 332     {
7604 25 Feb 19 nicklas 333       var well = this.wells[i];
7604 25 Feb 19 nicklas 334       well.hideLink(graphics);
7604 25 Feb 19 nicklas 335       well.unmapWell();
7604 25 Feb 19 nicklas 336     }
7604 25 Feb 19 nicklas 337   }
7604 25 Feb 19 nicklas 338
7604 25 Feb 19 nicklas 339 }
7604 25 Feb 19 nicklas 340
7604 25 Feb 19 nicklas 341 /**
7604 25 Feb 19 nicklas 342   A well on a plate.
7604 25 Feb 19 nicklas 343   @param plate The plate
7604 25 Feb 19 nicklas 344   @param row The well's row coordinate
7604 25 Feb 19 nicklas 345   @param column The well's column coordinate
7604 25 Feb 19 nicklas 346   @returns
7604 25 Feb 19 nicklas 347 */
7604 25 Feb 19 nicklas 348 function Well(plate, row, column)
7604 25 Feb 19 nicklas 349 {
7604 25 Feb 19 nicklas 350   this.plate = plate;
7604 25 Feb 19 nicklas 351   this.row = row;
7604 25 Feb 19 nicklas 352   this.column = column;
7604 25 Feb 19 nicklas 353   this.selected = false;
7604 25 Feb 19 nicklas 354   this.linked = false;
7604 25 Feb 19 nicklas 355   this.mappedItem = null;
7604 25 Feb 19 nicklas 356   
7604 25 Feb 19 nicklas 357   /**
7604 25 Feb 19 nicklas 358     Get the DOM tag that represents the well. The element should have an
7604 25 Feb 19 nicklas 359     ID combined of 'plate-prefix.row.column'.
7604 25 Feb 19 nicklas 360    */
7604 25 Feb 19 nicklas 361   Well.prototype.getTag = function()
7604 25 Feb 19 nicklas 362   {
7604 25 Feb 19 nicklas 363     if (!this.tag)
7604 25 Feb 19 nicklas 364     {
7604 25 Feb 19 nicklas 365       this.tag = Doc.element(this.plate.prefix+'.'+this.row+'.'+this.column);
7604 25 Feb 19 nicklas 366     }
7604 25 Feb 19 nicklas 367     return this.tag;
7604 25 Feb 19 nicklas 368   }
7604 25 Feb 19 nicklas 369   
7604 25 Feb 19 nicklas 370   /**
7604 25 Feb 19 nicklas 371     Add a CSS class to the well DOM tag.
7604 25 Feb 19 nicklas 372   */
7604 25 Feb 19 nicklas 373   Well.prototype.addClass = function(cls)
7604 25 Feb 19 nicklas 374   {
7604 25 Feb 19 nicklas 375     Doc.addClass(this.getTag(), cls);
7604 25 Feb 19 nicklas 376   }
7604 25 Feb 19 nicklas 377   
7604 25 Feb 19 nicklas 378   /**
7604 25 Feb 19 nicklas 379     Remove a CSS class from the item's DOM tag.
7604 25 Feb 19 nicklas 380   */
7604 25 Feb 19 nicklas 381   Well.prototype.removeClass = function(cls)
7604 25 Feb 19 nicklas 382   {
7604 25 Feb 19 nicklas 383     Doc.removeClass(this.getTag(), cls);
7604 25 Feb 19 nicklas 384   }
7604 25 Feb 19 nicklas 385   
7604 25 Feb 19 nicklas 386   /**
7604 25 Feb 19 nicklas 387     Get the coordinate of the well as a string. Rows are alphabetically
7604 25 Feb 19 nicklas 388     numbered.
7604 25 Feb 19 nicklas 389    */
7604 25 Feb 19 nicklas 390   Well.prototype.getCoordinate = function()
7604 25 Feb 19 nicklas 391   {
7604 25 Feb 19 nicklas 392     return Plates.toAlphaCoordinate[this.row] + (this.column+1);
7604 25 Feb 19 nicklas 393   }
7604 25 Feb 19 nicklas 394
7604 25 Feb 19 nicklas 395   /**
7604 25 Feb 19 nicklas 396     Set the contents of the well element. The tag should have an ID combined
7604 25 Feb 19 nicklas 397     of 'plate-prefix.row.column.info'.
7604 25 Feb 19 nicklas 398   */
7604 25 Feb 19 nicklas 399   Well.prototype.setInfo = function(info)
7604 25 Feb 19 nicklas 400   {
7604 25 Feb 19 nicklas 401     var infoTag = Doc.element(this.plate.prefix+'.'+this.row+'.'+this.column + '.info');
7604 25 Feb 19 nicklas 402     if (!infoTag) return;
7604 25 Feb 19 nicklas 403     infoTag.innerHTML = info;
7604 25 Feb 19 nicklas 404   }
7604 25 Feb 19 nicklas 405   
7604 25 Feb 19 nicklas 406   /**
7604 25 Feb 19 nicklas 407     Mark the well as selected/deselected.
7604 25 Feb 19 nicklas 408   */
7604 25 Feb 19 nicklas 409   Well.prototype.setSelected = function(selected)
7604 25 Feb 19 nicklas 410   {
7604 25 Feb 19 nicklas 411     this.selected = selected;
7604 25 Feb 19 nicklas 412     Doc.addOrRemoveClass(this.getTag(), this.plate.selectedWellClass, selected);
7604 25 Feb 19 nicklas 413   }
7604 25 Feb 19 nicklas 414
7604 25 Feb 19 nicklas 415   /**
7604 25 Feb 19 nicklas 416     Mark the well as linked. Do not call this method. Use drawLink/hideLink 
7604 25 Feb 19 nicklas 417     instead.
7604 25 Feb 19 nicklas 418   */
7604 25 Feb 19 nicklas 419   Well.prototype.setLinked = function(linked)
7604 25 Feb 19 nicklas 420   {
7604 25 Feb 19 nicklas 421     this.linked = linked;
7604 25 Feb 19 nicklas 422     Doc.addOrRemoveClass(this.getTag(), this.plate.linkedWellClass, linked);
7604 25 Feb 19 nicklas 423   }
7604 25 Feb 19 nicklas 424
7604 25 Feb 19 nicklas 425   
7604 25 Feb 19 nicklas 426   /**
7604 25 Feb 19 nicklas 427     Draw a link from the well to the item it is mapped to. If
7604 25 Feb 19 nicklas 428     the well is not mapped, no link is drawn.
7604 25 Feb 19 nicklas 429     
7604 25 Feb 19 nicklas 430     @param graphics A jsGraphics object
7604 25 Feb 19 nicklas 431     @param pen A jsGraphics pen object
7604 25 Feb 19 nicklas 432     @param overwrite TRUE to overwrite existing link, FALSE to not draw if there already is a link
7604 25 Feb 19 nicklas 433   */
7604 25 Feb 19 nicklas 434   Well.prototype.drawLink = function(graphics, pen, overwrite)
7604 25 Feb 19 nicklas 435   {
7604 25 Feb 19 nicklas 436     if (this.mappedItem)
7604 25 Feb 19 nicklas 437     {
7604 25 Feb 19 nicklas 438       this.mappedItem.drawLink(graphics, pen, overwrite);
7604 25 Feb 19 nicklas 439     }
7604 25 Feb 19 nicklas 440     else if (this.mappedWell)
7604 25 Feb 19 nicklas 441     {
7604 25 Feb 19 nicklas 442       if (this.mappedWell.plate.isSourcePlate)
7604 25 Feb 19 nicklas 443       {
7604 25 Feb 19 nicklas 444         this.mappedWell.drawLink(graphics, pen, overwrite);
7604 25 Feb 19 nicklas 445       }
7604 25 Feb 19 nicklas 446       else
7604 25 Feb 19 nicklas 447       {
7604 25 Feb 19 nicklas 448         if (this.linkDiv) 
7604 25 Feb 19 nicklas 449         {
7604 25 Feb 19 nicklas 450           if (!overwrite) return;
7604 25 Feb 19 nicklas 451           this.hideLink(graphics);
7604 25 Feb 19 nicklas 452         }
7604 25 Feb 19 nicklas 453         
7604 25 Feb 19 nicklas 454         var srcPos = Doc.getElementPosition(this.getTag());
7604 25 Feb 19 nicklas 455         var destPos = Doc.getElementPosition(this.mappedWell.getTag());
7604 25 Feb 19 nicklas 456         var points = new Array();
7604 25 Feb 19 nicklas 457         points[0] = new jsPoint(srcPos.left + srcPos.width, srcPos.top+srcPos.height/2);
7604 25 Feb 19 nicklas 458         points[1] = new jsPoint(destPos.left, destPos.top+destPos.height/2);
7604 25 Feb 19 nicklas 459         this.linkDiv = graphics.drawLine(pen, points[0], points[1]);
7604 25 Feb 19 nicklas 460         this.setLinked(true);
7604 25 Feb 19 nicklas 461         this.mappedWell.setLinked(true);
7604 25 Feb 19 nicklas 462       }
7604 25 Feb 19 nicklas 463     }
7604 25 Feb 19 nicklas 464   }
7604 25 Feb 19 nicklas 465   
7604 25 Feb 19 nicklas 466   /**
7604 25 Feb 19 nicklas 467     Hide the link from the well to the item/well it is mapped to.
7604 25 Feb 19 nicklas 468   */
7604 25 Feb 19 nicklas 469   Well.prototype.hideLink = function(graphics)
7604 25 Feb 19 nicklas 470   {
7604 25 Feb 19 nicklas 471     if (this.mappedItem)
7604 25 Feb 19 nicklas 472     {
7604 25 Feb 19 nicklas 473       this.mappedItem.hideLink(graphics);
7604 25 Feb 19 nicklas 474     }
7604 25 Feb 19 nicklas 475     if (this.linkDiv)
7604 25 Feb 19 nicklas 476     {
7604 25 Feb 19 nicklas 477       graphics.clearDrawing(this.linkDiv);
7604 25 Feb 19 nicklas 478       this.linkDiv = null;
7604 25 Feb 19 nicklas 479       this.setLinked(false);
7604 25 Feb 19 nicklas 480       if (this.mappedWell)
7604 25 Feb 19 nicklas 481       {
7604 25 Feb 19 nicklas 482         this.mappedWell.setLinked(false);
7604 25 Feb 19 nicklas 483       }
7604 25 Feb 19 nicklas 484     }
7604 25 Feb 19 nicklas 485     else if (this.mappedWell && this.mappedWell.plate.isSourcePlate)
7604 25 Feb 19 nicklas 486     {
7604 25 Feb 19 nicklas 487       this.mappedWell.hideLink(graphics);
7604 25 Feb 19 nicklas 488     }
7604 25 Feb 19 nicklas 489   }
7604 25 Feb 19 nicklas 490   
7604 25 Feb 19 nicklas 491   /**
7604 25 Feb 19 nicklas 492     Remove the current mapping.
7604 25 Feb 19 nicklas 493   */
7604 25 Feb 19 nicklas 494   Well.prototype.unmapItem = function()
7604 25 Feb 19 nicklas 495   {
7604 25 Feb 19 nicklas 496     if (!this.mappedItem) return;
7604 25 Feb 19 nicklas 497     this.mappedItem.unmapWell(this);
7604 25 Feb 19 nicklas 498   }
7604 25 Feb 19 nicklas 499   
7604 25 Feb 19 nicklas 500   /**
7604 25 Feb 19 nicklas 501     Map this *source* well to the other *destination* well.
7604 25 Feb 19 nicklas 502     An existing mapping for the current well is automatically removed. 
7604 25 Feb 19 nicklas 503   */
7604 25 Feb 19 nicklas 504   Well.prototype.mapToWell = function(well)
7604 25 Feb 19 nicklas 505   {
7604 25 Feb 19 nicklas 506     this.unmapWell();
7604 25 Feb 19 nicklas 507     well.unmapWell();
7604 25 Feb 19 nicklas 508     this.mappedWell = well;
7604 25 Feb 19 nicklas 509     well.mappedWell = this;
7604 25 Feb 19 nicklas 510     this.addClass(this.plate.mappedWellClass);
7604 25 Feb 19 nicklas 511     well.addClass(well.plate.mappedWellClass);
7604 25 Feb 19 nicklas 512     well.setInfo(this.getCoordinate());
7604 25 Feb 19 nicklas 513   }
7604 25 Feb 19 nicklas 514
7604 25 Feb 19 nicklas 515   /**
7604 25 Feb 19 nicklas 516     Remove the current mapping to another well.
7604 25 Feb 19 nicklas 517   */
7604 25 Feb 19 nicklas 518   Well.prototype.unmapWell = function()
7604 25 Feb 19 nicklas 519   {
7604 25 Feb 19 nicklas 520     if (!this.mappedWell) return;
7604 25 Feb 19 nicklas 521     this.mappedWell.setInfo('');
7604 25 Feb 19 nicklas 522     this.removeClass(this.plate.mappedWellClass);
7604 25 Feb 19 nicklas 523     this.mappedWell.removeClass(this.mappedWell.plate.mappedWellClass);
7604 25 Feb 19 nicklas 524     this.mappedWell.mappedWell = null;
7604 25 Feb 19 nicklas 525     this.mappedWell = null;
7604 25 Feb 19 nicklas 526   }
7604 25 Feb 19 nicklas 527   
7604 25 Feb 19 nicklas 528 }
7604 25 Feb 19 nicklas 529
7604 25 Feb 19 nicklas 530 // Namespace for utility functions
7604 25 Feb 19 nicklas 531 var Plates = {};
7604 25 Feb 19 nicklas 532
7604 25 Feb 19 nicklas 533 Plates.toAlphaCoordinate = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
7604 25 Feb 19 nicklas 534                             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
7604 25 Feb 19 nicklas 535
7604 25 Feb 19 nicklas 536
7604 25 Feb 19 nicklas 537