[hg] galaxy 3592: - Simple converter dependency system where con...
details: http://www.bx.psu.edu/hg/galaxy/rev/f29af7c51377 changeset: 3592:f29af7c51377 user: Kanwei Li <kanwei@gmail.com> date: Thu Apr 01 14:24:47 2010 -0400 description: - Simple converter dependency system where converter won't run until its deps finish - Fix issue with trying to treat binary data as unicode trackster: - Make BAM use summary tree - Refactor converter code diffstat: datatypes_conf.xml.sample | 2 +- lib/galaxy/datatypes/binary.py | 2 +- lib/galaxy/datatypes/converters/bam_to_bai.xml | 8 +- lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.py | 32 +--- lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml | 4 +- lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py | 2 +- lib/galaxy/datatypes/data.py | 14 +- lib/galaxy/datatypes/display_applications/parameters.py | 2 +- lib/galaxy/datatypes/interval.py | 4 +- lib/galaxy/datatypes/registry.py | 12 +- lib/galaxy/model/__init__.py | 51 +++++- lib/galaxy/visualization/tracks/data/array_tree.py | 3 + lib/galaxy/visualization/tracks/data/bam.py | 5 +- lib/galaxy/visualization/tracks/data/interval_index.py | 2 +- lib/galaxy/web/controllers/tracks.py | 82 ++------- static/scripts/packed/trackster.js | 2 +- static/scripts/trackster.js | 12 +- 17 files changed, 118 insertions(+), 121 deletions(-) diffs (513 lines): diff -r 40e8c99829e0 -r f29af7c51377 datatypes_conf.xml.sample --- a/datatypes_conf.xml.sample Thu Apr 01 13:08:48 2010 -0400 +++ b/datatypes_conf.xml.sample Thu Apr 01 14:24:47 2010 -0400 @@ -5,7 +5,7 @@ <datatype extension="axt" type="galaxy.datatypes.sequence:Axt" display_in_upload="true"/> <datatype extension="bam" type="galaxy.datatypes.binary:Bam" mimetype="application/octet-stream" display_in_upload="true"> <converter file="bam_to_bai.xml" target_datatype="bai"/> - <converter file="bam_to_summary_tree_converter.xml" target_datatype="summary_tree"/> + <converter file="bam_to_summary_tree_converter.xml" target_datatype="summary_tree" depends_on="bai"/> <display file="ucsc/bam.xml" /> </datatype> <datatype extension="bed" type="galaxy.datatypes.interval:Bed" display_in_upload="true"> diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/binary.py --- a/lib/galaxy/datatypes/binary.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/binary.py Thu Apr 01 14:24:47 2010 -0400 @@ -139,7 +139,7 @@ except: return "Binary bam alignments file (%s)" % ( data.nice_size( dataset.get_size() ) ) def get_track_type( self ): - return "ReadTrack", ["bai", "summary_tree"] + return "ReadTrack", {"data": "bai", "index": "summary_tree"} class Binseq( Binary ): """Class describing a zip archive of binary sequence files""" diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/converters/bam_to_bai.xml --- a/lib/galaxy/datatypes/converters/bam_to_bai.xml Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/converters/bam_to_bai.xml Thu Apr 01 14:24:47 2010 -0400 @@ -1,12 +1,12 @@ -<tool id="INDEXER_Bam_Bai_0" name="Bam to Bai"> - <command>samtools index $input $output</command> +<tool id="CONVERTER_Bam_Bai_0" name="Bam to Bai"> + <command>samtools index $input1 $output1</command> <inputs> <page> - <param format="bam" name="input" type="data" label="Choose BAM"/> + <param format="bam" name="input1" type="data" label="Choose BAM"/> </page> </inputs> <outputs> - <data format="bai" name="output"/> + <data format="bai" name="output1"/> </outputs> <help> </help> diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.py --- a/lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.py Thu Apr 01 14:24:47 2010 -0400 @@ -4,26 +4,10 @@ import sys from galaxy import eggs -import pkg_resources; pkg_resources.require( "bx-python" ); pkg_resources.require( "pysam" ) +import pkg_resources; pkg_resources.require( "pysam" ) from pysam import csamtools -from bx.arrays.array_tree import * - -BLOCK_SIZE = 1000 - -class BamReader: - def __init__( self, input_fname, index_fname ): - self.bamfile = csamtools.Samfile( filename=input_fname, mode='rb', index_filename=index_fname ) - self.iterator = self.bamfile.fetch() - - def __iter__( self ): - return self - - def __next__( self ): - while True: - read = self.iterator.next() - return read.rname, read.mpos, read.pos + read.rlen, None, mapq - +from galaxy.visualization.tracks.summary import * def main(): @@ -31,15 +15,13 @@ index_fname = sys.argv[2] out_fname = sys.argv[3] - reader = BamReader( input_fname, index_fname ) + bamfile = csamtools.Samfile( filename=input_fname, mode='rb', index_filename=index_fname ) - # Fill array from reader - d = array_tree_dict_from_reader( reader, {}, block_size = BLOCK_SIZE ) + st = SummaryTree(block_size=100, levels=4, draw_cutoff=100, detail_cutoff=20) + for read in bamfile.fetch(): + st.insert_range(read.rname, read.mpos, read.pos + read.rlen) - for array_tree in d.itervalues(): - array_tree.root.build_summary() - - FileArrayTreeDict.dict_to_file( d, open( out_fname, "w" ), no_leaves=True ) + st.write(out_fname) if __name__ == "__main__": main() \ No newline at end of file diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml --- a/lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/converters/bam_to_summary_tree_converter.xml Thu Apr 01 14:24:47 2010 -0400 @@ -1,10 +1,10 @@ <tool id="CONVERTER_bam_to_summary_tree_0" name="Convert BAM to Summary Tree" version="1.0.0"> <!-- <description>__NOT_USED_CURRENTLY_FOR_CONVERTERS__</description> --> - <command interpreter="python">bam_to_summary_tree_converter.py $input1 $output1</command> + <command interpreter="python">bam_to_summary_tree_converter.py $input1 $bai $output1</command> <inputs> <page> <param format="bam" name="input1" type="data" label="Choose BAM file"/> - <param format="bai" name="index" type="data" label="BAM index file"/> + <param format="bai" name="bai" type="data" label="BAI index file"/> </page> </inputs> <outputs> diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py --- a/lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/converters/bed_to_summary_tree_converter.py Thu Apr 01 14:24:47 2010 -0400 @@ -19,7 +19,7 @@ for chrom, chrom_start, chrom_end, name, score in reader: st.insert_range(chrom, chrom_start, chrom_end) - st.write(out_fname) + st.write(out_fname) if __name__ == "__main__": main() \ No newline at end of file diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/data.py --- a/lib/galaxy/datatypes/data.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/data.py Thu Apr 01 14:24:47 2010 -0400 @@ -251,9 +251,10 @@ def find_conversion_destination( self, dataset, accepted_formats, datatypes_registry, **kwd ): """Returns ( target_ext, existing converted dataset )""" return datatypes_registry.find_conversion_destination_for_dataset_by_extensions( dataset, accepted_formats, **kwd ) - def convert_dataset(self, trans, original_dataset, target_type, return_output = False, visible = True ): + def convert_dataset(self, trans, original_dataset, target_type, return_output = False, visible = True, deps=None): """This function adds a job to the queue to convert a dataset to another type. Returns a message about success/failure.""" converter = trans.app.datatypes_registry.get_converter_by_target_type( original_dataset.ext, target_type ) + if converter is None: raise Exception( "A converter does not exist for %s to %s." % ( original_dataset.ext, target_type ) ) #Generate parameter dictionary @@ -261,9 +262,11 @@ #determine input parameter name and add to params input_name = 'input1' for key, value in converter.inputs.items(): - if value.type == 'data': + if value.name in deps: + params[value.name] = deps[value.name] + elif value.type == 'data': input_name = key - break + params[input_name] = original_dataset #Run converter, job is dispatched through Queue converted_dataset = converter.execute( trans, incoming = params, set_output_hid = visible )[1] @@ -481,5 +484,8 @@ if file_type in [ 'gzipped', 'binary' ]: text = "%s file" % file_type else: - text = unicode( '\n'.join( lines ), 'utf-8' ) + try: + text = unicode( '\n'.join( lines ), 'utf-8' ) + except UnicodeDecodeError: + text = "binary/unknown file" return text diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/display_applications/parameters.py --- a/lib/galaxy/datatypes/display_applications/parameters.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/display_applications/parameters.py Thu Apr 01 14:24:47 2010 -0400 @@ -73,7 +73,7 @@ for ext in self.extensions: rval = data.get_converted_files_by_type( ext ) if rval: - return rval[0] + return rval assert data.find_conversion_destination( self.formats )[0] is not None, "No conversion path found for data param: %s" % self.name return None return data diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/interval.py --- a/lib/galaxy/datatypes/interval.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/interval.py Thu Apr 01 14:24:47 2010 -0400 @@ -504,7 +504,7 @@ except: return False def get_track_type( self ): - return "FeatureTrack", ["interval_index", "summary_tree"] + return "FeatureTrack", {"data": "interval_index", "index": "summary_tree"} class BedStrict( Bed ): """Tab delimited data in strict BED format - no non-standard columns allowed""" @@ -965,7 +965,7 @@ resolution = max( resolution, 1 ) return resolution def get_track_type( self ): - return "LineTrack", ["array_tree"] + return "LineTrack", {"data": "array_tree"} class CustomTrack ( Tabular ): """UCSC CustomTrack""" diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/datatypes/registry.py --- a/lib/galaxy/datatypes/registry.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/datatypes/registry.py Thu Apr 01 14:24:47 2010 -0400 @@ -19,6 +19,7 @@ self.datatype_converters = odict() self.datatype_indexers = odict() self.converters = [] + self.converter_deps = {} self.available_tracks = [] self.set_external_metadata_tool = None self.indexers = [] @@ -68,6 +69,11 @@ # into the calling app's toolbox. converter_config = converter.get( 'file', None ) target_datatype = converter.get( 'target_datatype', None ) + depends_on = converter.get( 'depends_on', None ) + if depends_on and target_datatype: + if extension not in self.converter_deps: + self.converter_deps[extension] = {} + self.converter_deps[extension][target_datatype] = depends_on.split(',') if converter_config and target_datatype: self.converters.append( ( converter_config, extension, target_datatype ) ) for indexer in elem.findall( 'indexer' ): @@ -363,9 +369,9 @@ """Returns ( target_ext, existing converted dataset )""" for convert_ext in self.get_converters_by_datatype( dataset.ext ): if isinstance( self.get_datatype_by_extension( convert_ext ), accepted_formats ): - datasets = dataset.get_converted_files_by_type( convert_ext ) - if datasets: - ret_data = datasets[0] + dataset = dataset.get_converted_files_by_type( convert_ext ) + if dataset: + ret_data = dataset elif not converter_safe: continue else: diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/model/__init__.py --- a/lib/galaxy/model/__init__.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/model/__init__.py Thu Apr 01 14:24:47 2010 -0400 @@ -577,11 +577,54 @@ def display_info( self ): return self.datatype.display_info( self ) def get_converted_files_by_type( self, file_type ): - valid = [] for assoc in self.implicitly_converted_datasets: if not assoc.deleted and assoc.type == file_type: - valid.append( assoc.dataset ) - return valid + return assoc.dataset + return None + def get_converted_dataset(self, trans, target_ext): + """ + Return converted dataset(s) if they exist. If not converted yet, do so and return None (the first time). + If unconvertible, raise exception. + """ + # See if we can convert the dataset + if target_ext not in self.get_converter_types(): + raise ValueError("Conversion from '%s' to '%s' not possible", self.extension, target_ext) + + # See if converted dataset already exists + converted_dataset = self.get_converted_files_by_type( target_ext ) + if converted_dataset: + return converted_dataset + + # Conversion is possible but hasn't been done yet, run converter. + # Check if we have dependencies + deps = {} + try: + fail_dependencies = False + depends_on = trans.app.datatypes_registry.converter_deps[self.extension][target_ext] + for dependency in depends_on: + dep_dataset = self.get_converted_dataset(trans, dependency) + if dep_dataset is None or dep_dataset.state != trans.app.model.Job.states.OK: + fail_dependencies = True + else: + deps[dependency] = dep_dataset + if fail_dependencies: + return None + except ValueError: + log.debug("WTF") + raise ValueError("A dependency could not be converted.") + except KeyError: + pass # No deps + + assoc = ImplicitlyConvertedDatasetAssociation( parent=self, file_type=target_ext, metadata_safe=False ) + new_dataset = self.datatype.convert_dataset( trans, self, target_ext, return_output=True, visible=False, deps=deps ).values()[0] + new_dataset.hid = self.hid + new_dataset.name = self.name + trans.sa_session.add( new_dataset ) + trans.sa_session.flush() + assoc.dataset = new_dataset + trans.sa_session.add( assoc ) + trans.sa_session.flush() + return None def clear_associated_files( self, metadata_safe = False, purge = False ): raise 'Unimplemented' def get_child_by_designation(self, designation): @@ -590,7 +633,7 @@ return child return None def get_converter_types(self): - return self.datatype.get_converter_types( self, datatypes_registry) + return self.datatype.get_converter_types( self, datatypes_registry ) def find_conversion_destination( self, accepted_formats, **kwd ): """Returns ( target_ext, existing converted dataset )""" return self.datatype.find_conversion_destination( self, accepted_formats, datatypes_registry, **kwd ) diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/visualization/tracks/data/array_tree.py --- a/lib/galaxy/visualization/tracks/data/array_tree.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/visualization/tracks/data/array_tree.py Thu Apr 01 14:24:47 2010 -0400 @@ -44,6 +44,9 @@ return float(n) def get_data( self, chrom, start, end, **kwargs ): + if 'stats' in kwargs: + return self.get_stats(chrom) + f = open( self.dataset.file_name ) d = FileArrayTreeDict( f ) diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/visualization/tracks/data/bam.py --- a/lib/galaxy/visualization/tracks/data/bam.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/visualization/tracks/data/bam.py Thu Apr 01 14:24:47 2010 -0400 @@ -1,5 +1,6 @@ """ Visualization data provider for BAM format. +Kanwei Li, 2010 """ import pkg_resources; pkg_resources.require( "pysam" ) @@ -7,7 +8,7 @@ from pysam import csamtools from math import floor, ceil, log import logging -# log = logging.getLogger(__name__) +log = logging.getLogger(__name__) class BamDataProvider( object ): """ @@ -36,7 +37,7 @@ # Encode reads as list of dictionaries results = [] for read in data: - payload = { 'uid': str(read.pos) + str(read.seq), 'start': read.pos, 'end': read.pos + read.rlen, 'name': read.seq } + payload = [ str(read.pos) + str(read.seq), read.pos, read.pos + read.rlen, read.seq ] results.append(payload) bamfile.close() return results diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/visualization/tracks/data/interval_index.py --- a/lib/galaxy/visualization/tracks/data/interval_index.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/visualization/tracks/data/interval_index.py Thu Apr 01 14:24:47 2010 -0400 @@ -1,6 +1,6 @@ """ Interval index data provider for the Galaxy track browser. -Kanwei Li, 2009 +Kanwei Li, 2010 Payload format: [ uid (offset), start, end, name, strand, thick_start, thick_end, blocks ] """ diff -r 40e8c99829e0 -r f29af7c51377 lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py Thu Apr 01 13:08:48 2010 -0400 +++ b/lib/galaxy/web/controllers/tracks.py Thu Apr 01 14:24:47 2010 -0400 @@ -199,78 +199,38 @@ if dataset.state != trans.app.model.Job.states.OK: return messages.PENDING - track_type, indexes = dataset.datatype.get_track_type() - converted = dict([ (index, self.__dataset_as_type( trans, dataset, index )) for index in indexes ]) - extra_info = None - - for index, converted_dataset in converted.iteritems(): - if not converted_dataset: + track_type, data_sources = dataset.datatype.get_track_type() + for source_type, data_source in data_sources.iteritems(): + try: + converted_dataset = dataset.get_converted_dataset(trans, data_source) + except ValueError: return messages.NO_CONVERTER # Need to check states again for the converted version + if not converted_dataset or converted_dataset.state != model.Dataset.states.OK: + return messages.PENDING + if converted_dataset.state == model.Dataset.states.ERROR: return messages.ERROR - if converted_dataset.state != model.Dataset.states.OK: - return messages.PENDING - - if len(converted) > 1: - # Have to choose between array_tree and other provider - summary_tree = SummaryTreeDataProvider( converted['summary_tree'], dataset ) - freqs = summary_tree.get_summary( chrom, low, high, **kwargs ) - if freqs is not None: - frequencies, max_v, avg_v = freqs + + extra_info = None + if 'index' in data_sources: + # Have to choose between indexer and data provider + indexer = dataset_type_to_data_provider[data_sources['index']]( dataset.get_converted_dataset(trans, data_sources['index']), dataset ) + summary = indexer.get_summary( chrom, low, high, **kwargs ) + if summary is not None: + frequencies, max_v, avg_v = summary if frequencies != "no_detail": - return { "dataset_type": "summary_tree", "data": frequencies, "max": max_v, "avg": avg_v } + return { "dataset_type": data_sources['index'], "data": frequencies, "max": max_v, "avg": avg_v } else: kwargs["no_detail"] = True # meh extra_info = "no_detail" - dataset_type = "interval_index" - else: - dataset_type = converted.keys()[0] - - data_provider = dataset_type_to_data_provider[ dataset_type ]( converted[dataset_type], dataset ) + + dataset_type = data_sources['data'] + data_provider = dataset_type_to_data_provider[ dataset_type ]( dataset.get_converted_dataset(trans, dataset_type), dataset ) - if 'stats' in kwargs: - data = data_provider.get_stats( chrom ) - else: - data = data_provider.get_data( chrom, low, high, **kwargs ) - + data = data_provider.get_data( chrom, low, high, **kwargs ) return { "dataset_type": dataset_type, "extra_info": extra_info, "data": data } - - def __dataset_as_type( self, trans, dataset, type ): - """ - Given a dataset, try to find a way to adapt it to a different type. If the - dataset is already of that type it is returned, if it can be converted a - converted dataset (possibly new) is returned, if it cannot be converted, - None is returned. - """ - # Already of correct type - if dataset.extension == type: - return dataset - # See if we can convert the dataset - if type not in dataset.get_converter_types(): - log.debug( "Conversion from '%s' to '%s' not possible", dataset.extension, type ) - return None - # See if converted dataset already exists - converted_datasets = [c for c in dataset.get_converted_files_by_type( type ) if c != None] - if converted_datasets: - if converted_datasets[0].state != 'error': - return converted_datasets[0] - else: - return None - - # Conversion is possible but hasn't been done yet, run converter here - # FIXME: this is largely duplicated from DefaultToolAction - assoc = model.ImplicitlyConvertedDatasetAssociation( parent = dataset, file_type = type, metadata_safe = False ) - new_dataset = dataset.datatype.convert_dataset( trans, dataset, type, return_output = True, visible = False ).values()[0] - new_dataset.hid = dataset.hid # Hrrmmm.... - new_dataset.name = dataset.name - trans.sa_session.add( new_dataset ) - trans.sa_session.flush() - assoc.dataset = new_dataset - trans.sa_session.add( assoc ) - trans.sa_session.flush() - return new_dataset @web.json def save( self, trans, **kwargs ): diff -r 40e8c99829e0 -r f29af7c51377 static/scripts/packed/trackster.js --- a/static/scripts/packed/trackster.js Thu Apr 01 13:08:48 2010 -0400 +++ b/static/scripts/packed/trackster.js Thu Apr 01 14:24:47 2010 -0400 @@ -1,1 +1,1 @@ -var DEBUG=false;var DENSITY=1000,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=20,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src="../images/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src="../images/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src="../images/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv! ,"repeat")};var left_img_inv=new Image();left_img_inv.src="../images/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var Drawer=function(){};$.extend(Drawer.prototype,{intensity:function(b,a,c){},});drawer=new Drawer();var View=function(b,d,c,a){this.vis_id=c;this.dbkey=a;this.title=d;this.chrom=b;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_! high=0;this.center=(this.max_high-this.max_low)/2;this.zoom_factor=3;t his.zoom_level=0;this.track_id_counter=0};$.extend(View.prototype,{add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[a]},update_options:function(){var b=$("ul#sortable-ul").sortable("toArray");var d=[];var c=$("#viewport > div").sort(function(g,f){return b.indexOf($(g).attr("id"))>b.indexOf($(f).attr("id"))});$("#viewport > div").remove();$("#viewport").html(c);for(var e in view.tracks){var a=view.tracks[e];if(a.update_options){a.update_options(e)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.center=this.center=(this.max_high-this.max_low)/2;this.zoom_level=0;$(".yaxislabel").remove()},redraw:function(f){this.span=this.max_high-this.max_low;var d=this.sp! an/Math.pow(this.zoom_factor,this.zoom_level),b=this.center-(d/2),e=b+d;if(b<0){b=0;e=b+d}else{if(e>this.max_high){e=this.max_high;b=e-d}}this.low=Math.floor(b);this.high=Math.ceil(e);this.center=Math.round(this.low+(this.high-this.low)/2);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));$("#overview-box").css({left:(this.low/this.span)*$("#overview-viewport").width(),width:Math.max(12,((this.high-this.low)/this.span)*$("#overview-viewport").width())}).show();$("#low").val(commatize(this.low));$("#high").val(commatize(this.high));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(a,b){if(this.max_high===0||this.high-this.low<30){return}if(a){this.center=a/b.width()*(this.! high-this.low)+this.low}this.zoom_level+=1;this.redraw()},zoom_out:fun ction(){if(this.max_high===0){return}if(this.zoom_level<=0){this.zoom_level=0;return}this.zoom_level-=1;this.redraw()}});var Track=function(a,b){this.name=a;this.parent_element=b;this.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div></div>").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.content_div.css("height","30px");a.content_div.text(DATA_LOADING);a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if((d.da! ta&&d.data.length===0)||d==="no data"){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var i=this.view.low,e=this.view.high,f=e-i,d=this.view.resolution;if(DEBUG){$("#debug").text(d+" "+this.view.zoom_res)}var k=$("<div style='position: relative;'></div>");this.content_div.children(":first").remove();this.content_div.append(k);var l=this.content_div.width()/f;var h;var a=Math.floor(i/d/DENSITY);while((a*DENSITY*d)<e){var j=this.content_div.width()+"_"+this.view.zoom_level+"_"+a;var c=this.tile_cache.get(j);if(c){var g=a*DENSITY*d;var b=(g-i)*l;if(this.left_offse! t){b-=this.left_offset}c.css({left:b});k.append(c);this.max_height=Mat h.max(this.max_height,c.height())}else{this.delayed_draw(this,j,i,e,a,d,k,l)}a+=1}},delayed_draw:function(c,e,a,f,b,d,g,h){setTimeout(function(){if(!(a>c.view.high||f<c.view.low)){tile_element=c.draw_tile(d,b,g,h);if(tile_element){c.tile_cache.set(e,tile_element);c.max_height=Math.max(c.max_height,tile_element.height());c.content_div.css("height",c.max_height+"px")}}},50)}});var LabelTrack=function(a){Track.call(this,null,a);this.track_type="LabelTrack";this.hidden=true;this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.app! end(b)}});var LineTrack=function(c,a,b){this.track_type="LineTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("line-track");this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_value:undefined,max_value:undefined,mode:"line"};if(b.min_value!==undefined){this.prefs.min_value=b.min_value}if(b.max_value!==undefined){this.prefs.max_value=b.max_value}if(b.max_value!==undefined){this.prefs.mode=b.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.max_value=data.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.pre! fs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.t otal_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var d=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px"});e.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,q,c,e){if(this.vertical_range===undefined){return}var r=q*DENSITY*o,a=DENSITY*o,b=$("<canvas class! ='tile'></canvas>"),u=o+"_"+q;if(!this.data_cache.get(u)){this.get_data(o,q);return}var t=this.data_cache.get(u);b.css({position:"absolute",top:0,left:(r-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),k=false,l=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,s=this.total_frequency,d=this.height_px;n.beginPath();if(t.length>1){var f=Math.ceil((t[1][0]-t[0][0])*e)}else{var f=10}for(var p=0;p<t.length;p++){var j=t[p][0]-r;var h=t[p][1];if(this.prefs.mode=="intensity"){if(h===null){continue}j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(j,0,f,30)}else{if(h===null){k=false;continue}else{j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/m*d);if(k){n.lineTo(j,h)}else{n.moveTo(j,h);k=true}}}}n.stroke();c.append(b);return b},gen_options:function(n){var a=$("<div></div>").addClass("form-row");var h="track_"+n+"_minval",k="tra! ck_"+n+"_maxval",e="track_"+n+"_mode",l=$("<label></label>").attr("for ",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),m=$("<input></input>").attr("id",h).val(b),g=$("<label></label>").attr("for",k).text("Max value:"),j=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",k).val(j),d=$("<label></label>").attr("for",e).text("Display mode:"),i=(this.prefs.mode===undefined?"line":this.prefs.mode),c=$('<select id="'+e+'"><option value="line" id="mode_line">Line</option><option value="intensity" id="mode_intensity">Intensity</option></select>');$("#"+e+" #mode_"+i).attr("selected","selected");return a.append(l).append(m).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!=this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertica! l_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(c,a,b){this.track_type="FeatureTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.default_font="9px Monaco, Lucida Console, monospace";this.left_offset=200;this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:true};if(b.block_color!==undefined){this.prefs.block_color=b.block_color}if(b.label_color!==undefined){this.prefs.label_color=b.label_color}if(b.show_counts!==undefined){this.pre! fs.show_counts=b.show_counts}};$.extend(FeatureTrack.prototype,TiledTr ack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(c){a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,c){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,u=[],h=0,b=$("<canvas></canvas>").get(0).getContext("2d"),n=this.view.max_low;var d,f,w=[];for(var r=0,s=g.length;r<s;r++){var e=g[r],l=e[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);w.push(this.inc_slots[a][l])}else{u.push(r)}}for(var r=0,s=u.length;r<s;r++){var e=g[u[r]];! l=e[0],feature_start=e[1],feature_end=e[2],feature_name=e[3];d=Math.floor((feature_start-n)*m);if(!c){d-=b.measureText(feature_name).width}f=Math.ceil((feature_end-n)*m);var q=0;while(true){var o=true;if(this.s_e_by_tile[a][q]!==undefined){for(var p=0,v=this.s_e_by_tile[a][q].length;p<v;p++){var t=this.s_e_by_tile[a][q][p];if(f>t[0]&&d<t[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][q]===undefined){this.s_e_by_tile[a][q]=[]}this.s_e_by_tile[a][q].push([d,f]);this.inc_slots[a][l]=q;h=Math.max(h,q);break}q++}}return h},draw_tile:function(R,h,m,ae){var z=h*DENSITY*R,X=(h+1)*DENSITY*R,w=DENSITY*R;var ac,ad,p;var Y=z+"_"+X;var ac=this.data_cache.get(Y);if(!ac){this.data_queue[[z,X]]=true;this.get_data(z,X);return}if(ac.dataset_type=="array_tree"){p=30}else{var P=(ac.extra_info==="no_detail");var af=(P?this.vertical_nodetail_px:this.vertical_detail_px);p=this.incremental_slots(this.view.zoom_res,ac.data,P)*af+15;m.parent().css("height",Math.max(this.height_px,p)+"px");ad=this.! inc_slots[this.view.zoom_res]}var a=Math.ceil(w*ae),F=$("<canvas class ='tile'></canvas>"),T=this.prefs.label_color,f=this.prefs.block_color,J=this.left_offset;F.css({position:"absolute",top:0,left:(z-this.view.low)*ae-J});F.get(0).width=a+J;F.get(0).height=p;var t=F.get(0).getContext("2d");t.fillStyle=this.prefs.block_color;t.font=this.default_font;t.textAlign="right";var C=55,W=255-C,g=W*2/3;if(ac.dataset_type=="summary_tree"){var L=ac.data;var v=ac.max;var l=ac.avg;if(ac.data.length>2){var b=Math.ceil((L[1][0]-L[0][0])*ae)}else{var b=50}for(var aa=0,s=L.length;aa<s;aa++){var N=Math.ceil((L[aa][0]-z)*ae);var M=L[aa][1];if(!M){continue}var E=Math.floor(W-(M/v)*W);t.fillStyle="rgb("+E+","+E+","+E+")";t.fillRect(N+J,0,b,20);if(this.prefs.show_counts){if(E>g){t.fillStyle="black"}else{t.fillStyle="#ddd"}t.textAlign="center";t.fillText(L[aa][1],N+J+(b/2),12)}}m.append(F);return F}var ac=ac.data;var Z=0;for(var aa=0,s=ac.length;aa<s;aa++){var G=ac[aa],D=G[0],ab=G[1],O=G[2],A=G[3];if(ab<=X&&O>=z){var Q=Math.floor(Math.max(0,(ab-z)*ae)),u=Math.ceil(Ma! th.min(a,(O-z)*ae)),K=ad[D]*af;if(P){t.fillRect(Q+J,K+5,u-Q,1)}else{var r=G[4],I=G[5],S=G[6],e=G[7];var q,U,B=null,ag=null;if(I&&S){B=Math.floor(Math.max(0,(I-z)*ae));ag=Math.ceil(Math.min(a,(S-z)*ae))}if(ab>z){t.fillStyle=T;t.fillText(A,Q-1+J,K+8);t.fillStyle=f}if(e){if(r){if(r=="+"){t.fillStyle=RIGHT_STRAND}else{if(r=="-"){t.fillStyle=LEFT_STRAND}}t.fillRect(Q+J,K,u-Q,10);t.fillStyle=f}for(var Y=0,d=e.length;Y<d;Y++){var n=e[Y],c=Math.floor(Math.max(0,(n[0]-z)*ae)),H=Math.ceil(Math.min(a,(n[1]-z)*ae));if(c>H){continue}q=5;U=3;t.fillRect(c+J,K+U,H-c,q);if(B!==undefined&&!(c>ag||H<B)){q=9;U=1;var V=Math.max(c,B),o=Math.min(H,ag);t.fillRect(V+J,K+U,o-V,q)}}}else{q=9;U=1;t.fillRect(Q+J,K+U,u-Q,q);if(G.strand){if(G.strand=="+"){t.fillStyle=RIGHT_STRAND_INV}else{if(G.strand=="-"){t.fillStyle=LEFT_STRAND_INV}}t.fillRect(Q+J,K,u-Q,10);t.fillStyle=prefs.block_color}}}Z++}}m.append(F);return F},gen_options:function(h){var a=$("<div></div>").addClass("form-row");var d="track_"+h+"_b! lock_color",j=$("<label></label>").attr("for",d).text("Block color:"), k=$("<input></input>").attr("id",d).attr("name",d).val(this.prefs.block_color),i="track_"+h+"_label_color",f=$("<label></label>").attr("for",i).text("Text color:"),g=$("<input></input>").attr("id",i).attr("name",i).val(this.prefs.label_color),e="track_"+h+"_show_count",c=$("<label></label>").attr("for",e).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",e).attr("name",e).attr("checked",this.prefs.show_counts);return a.append(j).append(k).append(f).append(g).append(b).append(c)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!=this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(c,a,b){this.track_type="ReadTrack";this.tile_cache=new Cache(CACHED_TILES_FEATUR! E);Track.call(this,c,$("#viewport"));TiledTrack.call(this);FeatureTrack.call(this,c,a,b)};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{draw_tile:function(v,z,m,n){if(!this.values){return}var A=z*DENSITY*v,e=(z+1)*DENSITY*v,q=DENSITY*v;var D,p,h;h=this.height_px;p=this.zo_slots;D=this.values;var t=Math.ceil(q*n),r=$("<canvas class='tile'></canvas>");r.css({position:"absolute",top:0,left:(A-this.view.low)*n-this.left_offset});r.get(0).width=t+this.left_offset;r.get(0).height=h;var u=r.get(0).getContext("2d");u.fillStyle=this.prefs.block_color;u.font=this.default_font;u.textAlign="right";var s=u.measureText("A").width;var w=0;for(var x=0,y=D.length;x<y;x++){var l=D[x];if(l.start<=e&&l.end>=A){var g=Math.floor(Math.max(0,(l.start-A)*n)),k=Math.ceil(Math.min(t,(l.end-A)*n)),f=p[l.uid]*this.vertical_detail_px;var a,E,d=null,o=null;if(n>s){for(var B=0,b=l.name.length;B<b;B++){var C=Math.floor(Math.max(0,(l.start+B-A)*n));u.fillText(l.name[B],C+this.lef! t_offset,f+8)}}else{u.fillRect(g+this.left_offset,f+4,k-g,3)}}}m.appen d(r);return r}}); \ No newline at end of file +var DEBUG=false;var DENSITY=1000,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=20,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src="../images/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src="../images/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src="../images/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv! ,"repeat")};var left_img_inv=new Image();left_img_inv.src="../images/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function commatize(b){b+="";var a=/(\d+)(\d{3})/;while(a.test(b)){b=b.replace(a,"$1,$2")}return b}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var Drawer=function(){};$.extend(Drawer.prototype,{intensity:function(b,a,c){},});drawer=new Drawer();var View=function(b,d,c,a){this.vis_id=c;this.dbkey=a;this.title=d;this.chrom=b;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_! high=0;this.center=(this.max_high-this.max_low)/2;this.zoom_factor=3;t his.zoom_level=0;this.track_id_counter=0};$.extend(View.prototype,{add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[a]},update_options:function(){var b=$("ul#sortable-ul").sortable("toArray");var d=[];var c=$("#viewport > div").sort(function(g,f){return b.indexOf($(g).attr("id"))>b.indexOf($(f).attr("id"))});$("#viewport > div").remove();$("#viewport").html(c);for(var e in view.tracks){var a=view.tracks[e];if(a.update_options){a.update_options(e)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.center=this.center=(this.max_high-this.max_low)/2;this.zoom_level=0;$(".yaxislabel").remove()},redraw:function(f){this.span=this.max_high-this.max_low;var d=this.sp! an/Math.pow(this.zoom_factor,this.zoom_level),b=this.center-(d/2),e=b+d;if(b<0){b=0;e=b+d}else{if(e>this.max_high){e=this.max_high;b=e-d}}this.low=Math.floor(b);this.high=Math.ceil(e);this.center=Math.round(this.low+(this.high-this.low)/2);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));$("#overview-box").css({left:(this.low/this.span)*$("#overview-viewport").width(),width:Math.max(12,((this.high-this.low)/this.span)*$("#overview-viewport").width())}).show();$("#low").val(commatize(this.low));$("#high").val(commatize(this.high));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(a,b){if(this.max_high===0||this.high-this.low<30){return}if(a){this.center=a/b.width()*(this.! high-this.low)+this.low}this.zoom_level+=1;this.redraw()},zoom_out:fun ction(){if(this.max_high===0){return}if(this.zoom_level<=0){this.zoom_level=0;return}this.zoom_level-=1;this.redraw()}});var Track=function(a,b){this.name=a;this.parent_element=b;this.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div></div>").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.content_div.css("height","30px");a.content_div.text(DATA_LOADING);a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR)}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if((d.da! ta&&d.data.length===0)||d==="no data"){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var i=this.view.low,e=this.view.high,f=e-i,d=this.view.resolution;if(DEBUG){$("#debug").text(d+" "+this.view.zoom_res)}var k=$("<div style='position: relative;'></div>");this.content_div.children(":first").remove();this.content_div.append(k);var l=this.content_div.width()/f;var h;var a=Math.floor(i/d/DENSITY);while((a*DENSITY*d)<e){var j=this.content_div.width()+"_"+this.view.zoom_level+"_"+a;var c=this.tile_cache.get(j);if(c){var g=a*DENSITY*d;var b=(g-i)*l;if(this.left_offse! t){b-=this.left_offset}c.css({left:b});k.append(c);this.max_height=Mat h.max(this.max_height,c.height())}else{this.delayed_draw(this,j,i,e,a,d,k,l)}a+=1}},delayed_draw:function(c,e,a,f,b,d,g,h){setTimeout(function(){if(!(a>c.view.high||f<c.view.low)){tile_element=c.draw_tile(d,b,g,h);if(tile_element){c.tile_cache.set(e,tile_element);c.max_height=Math.max(c.max_height,tile_element.height());c.content_div.css("height",c.max_height+"px")}}},50)}});var LabelTrack=function(a){Track.call(this,null,a);this.track_type="LabelTrack";this.hidden=true;this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.app! end(b)}});var LineTrack=function(c,a,b){this.track_type="LineTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("line-track");this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_value:undefined,max_value:undefined,mode:"line"};if(b.min_value!==undefined){this.prefs.min_value=b.min_value}if(b.max_value!==undefined){this.prefs.max_value=b.max_value}if(b.max_value!==undefined){this.prefs.mode=b.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.max_value=data.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.pre! fs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.t otal_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var d=$("<div></div>").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px"});e.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,q,c,e){if(this.vertical_range===undefined){return}var r=q*DENSITY*o,a=DENSITY*o,b=$("<canvas class! ='tile'></canvas>"),u=o+"_"+q;if(!this.data_cache.get(u)){this.get_data(o,q);return}var t=this.data_cache.get(u);b.css({position:"absolute",top:0,left:(r-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),k=false,l=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,s=this.total_frequency,d=this.height_px;n.beginPath();if(t.length>1){var f=Math.ceil((t[1][0]-t[0][0])*e)}else{var f=10}for(var p=0;p<t.length;p++){var j=t[p][0]-r;var h=t[p][1];if(this.prefs.mode=="intensity"){if(h===null){continue}j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(j,0,f,30)}else{if(h===null){k=false;continue}else{j=j*e;if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/m*d);if(k){n.lineTo(j,h)}else{n.moveTo(j,h);k=true}}}}n.stroke();c.append(b);return b},gen_options:function(n){var a=$("<div></div>").addClass("form-row");var h="track_"+n+"_minval",k="tra! ck_"+n+"_maxval",e="track_"+n+"_mode",l=$("<label></label>").attr("for ",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),m=$("<input></input>").attr("id",h).val(b),g=$("<label></label>").attr("for",k).text("Max value:"),j=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",k).val(j),d=$("<label></label>").attr("for",e).text("Display mode:"),i=(this.prefs.mode===undefined?"line":this.prefs.mode),c=$('<select id="'+e+'"><option value="line" id="mode_line">Line</option><option value="intensity" id="mode_intensity">Intensity</option></select>');$("#"+e+" #mode_"+i).attr("selected","selected");return a.append(l).append(m).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!=this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertica! l_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(c,a,b){this.track_type="FeatureTrack";Track.call(this,c,$("#viewport"));TiledTrack.call(this);this.height_px=100;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.default_font="9px Monaco, Lucida Console, monospace";this.left_offset=200;this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:true};if(b.block_color!==undefined){this.prefs.block_color=b.block_color}if(b.label_color!==undefined){this.prefs.label_color=b.label_color}if(b.show_counts!==undefined){this.pre! fs.show_counts=b.show_counts}};$.extend(FeatureTrack.prototype,TiledTr ack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(c){a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,c){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,u=[],h=0,b=$("<canvas></canvas>").get(0).getContext("2d"),n=this.view.max_low;var d,f,w=[];for(var r=0,s=g.length;r<s;r++){var e=g[r],l=e[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);w.push(this.inc_slots[a][l])}else{u.push(r)}}for(var r=0,s=u.length;r<s;r++){var e=g[u[r]];! l=e[0],feature_start=e[1],feature_end=e[2],feature_name=e[3];d=Math.floor((feature_start-n)*m);if(!c){d-=b.measureText(feature_name).width}f=Math.ceil((feature_end-n)*m);var q=0;while(true){var o=true;if(this.s_e_by_tile[a][q]!==undefined){for(var p=0,v=this.s_e_by_tile[a][q].length;p<v;p++){var t=this.s_e_by_tile[a][q][p];if(f>t[0]&&d<t[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][q]===undefined){this.s_e_by_tile[a][q]=[]}this.s_e_by_tile[a][q].push([d,f]);this.inc_slots[a][l]=q;h=Math.max(h,q);break}q++}}return h},draw_tile:function(R,h,m,ae){var z=h*DENSITY*R,X=(h+1)*DENSITY*R,w=DENSITY*R;var ac,ad,p;var Y=z+"_"+X;var ac=this.data_cache.get(Y);if(!ac){this.data_queue[[z,X]]=true;this.get_data(z,X);return}if(ac.dataset_type=="array_tree"){p=30}else{var P=(ac.extra_info==="no_detail");var af=(P?this.vertical_nodetail_px:this.vertical_detail_px);p=this.incremental_slots(this.view.zoom_res,ac.data,P)*af+15;m.parent().css("height",Math.max(this.height_px,p)+"px");ad=this.! inc_slots[this.view.zoom_res]}var a=Math.ceil(w*ae),F=$("<canvas class ='tile'></canvas>"),T=this.prefs.label_color,f=this.prefs.block_color,J=this.left_offset;F.css({position:"absolute",top:0,left:(z-this.view.low)*ae-J});F.get(0).width=a+J;F.get(0).height=p;var t=F.get(0).getContext("2d");t.fillStyle=this.prefs.block_color;t.font=this.default_font;t.textAlign="right";var C=55,W=255-C,g=W*2/3;if(ac.dataset_type=="summary_tree"){var L=ac.data;var v=ac.max;var l=ac.avg;if(ac.data.length>2){var b=Math.ceil((L[1][0]-L[0][0])*ae)}else{var b=50}for(var aa=0,s=L.length;aa<s;aa++){var N=Math.ceil((L[aa][0]-z)*ae);var M=L[aa][1];if(!M){continue}var E=Math.floor(W-(M/v)*W);t.fillStyle="rgb("+E+","+E+","+E+")";t.fillRect(N+J,0,b,20);if(this.prefs.show_counts){if(E>g){t.fillStyle="black"}else{t.fillStyle="#ddd"}t.textAlign="center";t.fillText(L[aa][1],N+J+(b/2),12)}}m.append(F);return F}var ac=ac.data;var Z=0;for(var aa=0,s=ac.length;aa<s;aa++){var G=ac[aa],D=G[0],ab=G[1],O=G[2],A=G[3];if(ab<=X&&O>=z){var Q=Math.floor(Math.max(0,(ab-z)*ae)),u=Math.ceil(Ma! th.min(a,(O-z)*ae)),K=ad[D]*af;if(P){t.fillRect(Q+J,K+5,u-Q,1)}else{var r=G[4],I=G[5],S=G[6],e=G[7];var q,U,B=null,ag=null;if(I&&S){B=Math.floor(Math.max(0,(I-z)*ae));ag=Math.ceil(Math.min(a,(S-z)*ae))}if(ab>z){t.fillStyle=T;t.fillText(A,Q-1+J,K+8);t.fillStyle=f}if(e){if(r){if(r=="+"){t.fillStyle=RIGHT_STRAND}else{if(r=="-"){t.fillStyle=LEFT_STRAND}}t.fillRect(Q+J,K,u-Q,10);t.fillStyle=f}for(var Y=0,d=e.length;Y<d;Y++){var n=e[Y],c=Math.floor(Math.max(0,(n[0]-z)*ae)),H=Math.ceil(Math.min(a,(n[1]-z)*ae));if(c>H){continue}q=5;U=3;t.fillRect(c+J,K+U,H-c,q);if(B!==undefined&&!(c>ag||H<B)){q=9;U=1;var V=Math.max(c,B),o=Math.min(H,ag);t.fillRect(V+J,K+U,o-V,q)}}}else{q=9;U=1;t.fillRect(Q+J,K+U,u-Q,q);if(G.strand){if(G.strand=="+"){t.fillStyle=RIGHT_STRAND_INV}else{if(G.strand=="-"){t.fillStyle=LEFT_STRAND_INV}}t.fillRect(Q+J,K,u-Q,10);t.fillStyle=prefs.block_color}}}Z++}}m.append(F);return F},gen_options:function(h){var a=$("<div></div>").addClass("form-row");var d="track_"+h+"_b! lock_color",j=$("<label></label>").attr("for",d).text("Block color:"), k=$("<input></input>").attr("id",d).attr("name",d).val(this.prefs.block_color),i="track_"+h+"_label_color",f=$("<label></label>").attr("for",i).text("Text color:"),g=$("<input></input>").attr("id",i).attr("name",i).val(this.prefs.label_color),e="track_"+h+"_show_count",c=$("<label></label>").attr("for",e).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",e).attr("name",e).attr("checked",this.prefs.show_counts);return a.append(j).append(k).append(f).append(g).append(b).append(c)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!=this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(c,a,b){FeatureTrack.call(this,c,a,b);this.track_type="ReadTrack"};$.extend(ReadT! rack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{}); \ No newline at end of file diff -r 40e8c99829e0 -r f29af7c51377 static/scripts/trackster.js --- a/static/scripts/trackster.js Thu Apr 01 13:08:48 2010 -0400 +++ b/static/scripts/trackster.js Thu Apr 01 14:24:47 2010 -0400 @@ -89,7 +89,6 @@ drawer = new Drawer(); - var View = function( chrom, title, vis_id, dbkey ) { this.vis_id = vis_id; this.dbkey = dbkey; @@ -852,7 +851,7 @@ } j++; } - } + } parent_element.append( new_canvas ); return new_canvas; @@ -885,15 +884,12 @@ }); var ReadTrack = function ( name, dataset_id, prefs ) { + FeatureTrack.call( this, name, dataset_id, prefs ); this.track_type = "ReadTrack"; - this.tile_cache = new Cache(CACHED_TILES_FEATURE); - Track.call( this, name, $("#viewport") ); - TiledTrack.call( this ); - FeatureTrack.call( this, name, dataset_id, prefs ); }; $.extend( ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, { - draw_tile: function( resolution, tile_index, parent_element, w_scale ) { + /*draw_tile: function( resolution, tile_index, parent_element, w_scale ) { if (!this.values) { return; } @@ -947,5 +943,5 @@ parent_element.append( new_canvas ); return new_canvas; - } + }*/ });
participants (1)
-
Greg Von Kuster