galaxy-dev
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
September 2009
- 15 participants
- 140 discussions
25 Sep '09
details: http://www.bx.psu.edu/hg/galaxy/rev/2257980c5a58
changeset: 2761:2257980c5a58
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Thu Sep 24 12:21:41 2009 -0400
description:
Performance improvements in delete_datasets method in cleanup_datasets script ( hopefully enough ).
1 file(s) affected in this change:
scripts/cleanup_datasets/cleanup_datasets.py
diffs (82 lines):
diff -r 3e194c33f219 -r 2257980c5a58 scripts/cleanup_datasets/cleanup_datasets.py
--- a/scripts/cleanup_datasets/cleanup_datasets.py Thu Sep 24 11:55:55 2009 -0400
+++ b/scripts/cleanup_datasets/cleanup_datasets.py Thu Sep 24 12:21:41 2009 -0400
@@ -204,32 +204,42 @@
def delete_datasets( app, cutoff_time, remove_from_disk, info_only = False, force_retry = False ):
# Marks datasets as deleted if associated items are all deleted.
- print '# The following datasets have been marked deleted'
+ print "######### Starting delete_datasets #########\n"
start = time.clock()
if force_retry:
- datasets = app.model.Dataset.filter( app.model.LibraryDatasetDatasetAssociation.table.c.update_time < cutoff_time ).all() + app.model.Dataset.filter( app.model.HistoryDatasetAssociation.table.c.update_time < cutoff_time ).all()
- else:
- datasets = app.model.Dataset.filter( and_( app.model.HistoryDatasetAssociation.table.c.deleted==True,
- app.model.Dataset.table.c.deleted == False,
- app.model.HistoryDatasetAssociation.table.c.update_time < cutoff_time ) ).all()
- datasets = datasets + app.model.Dataset.filter( and_( app.model.LibraryDatasetDatasetAssociation.table.c.deleted==True,
- app.model.Dataset.table.c.deleted == False,
- app.model.LibraryDatasetDatasetAssociation.table.c.update_time < cutoff_time ) ).all()
+ history_datasets = app.model.Dataset.options( eagerload( "history_associations" ) ) \
+ .filter( app.model.HistoryDatasetAssociation.table.c.update_time < cutoff_time ).all()
+ library_datasets = app.model.Dataset.options( eagerload( "library_associations" ) ) \
+ .filter( app.model.LibraryDatasetDatasetAssociation.table.c.update_time < cutoff_time ).all()
+ else:
+ history_datasets = app.model.Dataset.filter_by( deleted = False ) \
+ .options( eagerload( "history_associations" ) ) \
+ .filter( and_( app.model.HistoryDatasetAssociation.table.c.update_time < cutoff_time,
+ app.model.HistoryDatasetAssociation.table.c.deleted==True ) ).all()
+ library_datasets = app.model.Dataset.filter_by( deleted = False ) \
+ .options( eagerload( "library_associations" ) ) \
+ .filter( and_( app.model.LibraryDatasetDatasetAssociation.table.c.update_time < cutoff_time,
+ app.model.LibraryDatasetDatasetAssociation.table.c.deleted==True ) ).all()
+ print "Time to query history and library datasets: ", time.clock() - start, "\n"
+ print "Processing ", len( history_datasets ), " history datasets and ", len( library_datasets ), " library datasets...\n\n"
+ datasets = history_datasets + library_datasets
skip = []
deleted_dataset_count = 0
deleted_instance_count = 0
for dataset in datasets:
+ print "Processing dataset id:", dataset.id, "\n"
if dataset.id not in skip and _dataset_is_deletable( dataset ):
deleted_dataset_count += 1
- print "Dataset:", dataset.id
for dataset_instance in dataset.history_associations + dataset.library_associations:
- print "\tAssociated Dataset instance:", dataset_instance.__class__.__name__, dataset_instance.id
- _purge_dataset_instance( dataset_instance, app, remove_from_disk, include_children = True, info_only = info_only )
+ print "Associated Dataset instance: ", dataset_instance.__class__.__name__, dataset_instance.id, "\n"
+ _purge_dataset_instance( dataset_instance, app, remove_from_disk, include_children=True, info_only=info_only, is_deletable=True )
deleted_instance_count += 1
skip.append( dataset.id )
- print
- print '# Examined %d datasets, marked %d as deleted and purged %d dataset instances\n' % ( len( skip ), deleted_dataset_count, deleted_instance_count )
- print "Elapsed time: ", time.clock() - start, "\n"
+ print "Time to process dataset id: ", dataset.id, " - ", time.clock() - start, "\n\n"
+ print "Time to mark datasets deleted: ", time.clock() - start, "\n\n"
+ print "Examined %d datasets, marked %d as deleted and purged %d dataset instances\n" % ( len( skip ), deleted_dataset_count, deleted_instance_count )
+ print "Total elapsed time: ", time.clock() - start, "\n"
+ print "######### Finished delete_datasets #########\n"
def purge_datasets( app, cutoff_time, remove_from_disk, info_only = False, force_retry = False ):
# Purges deleted datasets whose update_time is older than cutoff_time. Files may or may
@@ -262,15 +272,16 @@
print "Elapsed time: ", stop - start, "\n"
-def _purge_dataset_instance( dataset_instance, app, remove_from_disk, include_children = True, info_only = False ):
- #purging a dataset instance marks the instance as deleted,
- #and marks the dataset as deleted if it is not associated with another DatsetInstance that is not deleted
+def _purge_dataset_instance( dataset_instance, app, remove_from_disk, include_children=True, info_only=False, is_deletable=False ):
+ # A dataset_instance is either a HDA or an LDDA. Purging a dataset instance marks the instance as deleted,
+ # and marks the associated dataset as deleted if it is not associated with another active DatsetInstance.
if not info_only:
dataset_instance.mark_deleted( include_children = include_children )
dataset_instance.clear_associated_files()
dataset_instance.flush()
dataset_instance.dataset.refresh()
- if _dataset_is_deletable( dataset_instance.dataset ):
+ if is_deletable or _dataset_is_deletable( dataset_instance.dataset ):
+ # Calling methods may have already checked _dataset_is_deletable, if so, is_deletable should be True
_delete_dataset( dataset_instance.dataset, app, remove_from_disk, info_only = info_only )
#need to purge children here
if include_children:
1
0
25 Sep '09
details: http://www.bx.psu.edu/hg/galaxy/rev/509390d4e719
changeset: 2758:509390d4e719
user: Kanwei Li <kanwei(a)gmail.com>
date: Wed Sep 23 17:32:16 2009 -0400
description:
trackster: natural sort for chroms list, disable zooming when no data, can click on labels when selecting datasets
3 file(s) affected in this change:
lib/galaxy/web/controllers/tracks.py
static/scripts/trackster.js
templates/tracks/new_browser.mako
diffs (80 lines):
diff -r dcdbb13b0c76 -r 509390d4e719 lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py Wed Sep 23 17:16:13 2009 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Wed Sep 23 17:32:16 2009 -0400
@@ -15,7 +15,7 @@
need to support that, but need to make user defined build support better)
"""
-import math, logging
+import math, re, logging
log = logging.getLogger(__name__)
from galaxy.util.json import to_json_string
@@ -48,6 +48,9 @@
# FIXME: hardcoding this for now, but it should be derived from the available
# converters
browsable_types = set( ["wig" ] )
+
+# For natural sort
+NUM_RE = re.compile('([0-9]+)')
class TracksController( BaseController ):
"""
@@ -116,10 +119,16 @@
@web.json
def chroms(self, trans, dbkey=None ):
+ """
+ Returns a naturally sorted list of chroms/contigs for the given dbkey
+ """
+ def split_by_number(s):
+ return [ int(c) if c.isdigit() else c for c in NUM_RE.split(s) ]
+
chroms = self._chroms( trans, dbkey )
- unsorted = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()]
- unsorted.sort( lambda a,b: cmp(a['chrom'], b['chrom']) )
- return unsorted
+ to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()]
+ to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) ))
+ return to_sort
def _chroms( self, trans, dbkey ):
"""
diff -r dcdbb13b0c76 -r 509390d4e719 static/scripts/trackster.js
--- a/static/scripts/trackster.js Wed Sep 23 17:16:13 2009 -0400
+++ b/static/scripts/trackster.js Wed Sep 23 17:32:16 2009 -0400
@@ -67,6 +67,9 @@
this.high = Math.min( this.length, Math.ceil( new_high ) );
},
zoom_in: function ( factor, point ) {
+ console.log(this.max_high);
+ if (this.max_high == 0) return;
+
var range = this.high - this.low;
var diff = range / factor / 2;
@@ -92,6 +95,7 @@
}
},
zoom_out: function ( factor ) {
+ if (this.max_high == 0) return;
var center = ( this.low + this.high ) / 2;
var range = this.high - this.low;
var diff = range * factor / 2;
diff -r dcdbb13b0c76 -r 509390d4e719 templates/tracks/new_browser.mako
--- a/templates/tracks/new_browser.mako Wed Sep 23 17:16:13 2009 -0400
+++ b/templates/tracks/new_browser.mako Wed Sep 23 17:32:16 2009 -0400
@@ -32,10 +32,10 @@
</div>
<div class="form-row">
<label for="dataset_ids">Datasets to include: </label>
- %for key,value in datasets.items():
+ %for dataset_id, dataset_name in datasets.items():
<div>
- <input type="checkbox" name="dataset_ids" value="${key}" />
- ${value}
+ <input type="checkbox" id="${dataset_id}" name="dataset_ids" value="${dataset_id}" />
+ <label style="display:inline; font-weight: normal" for="${dataset_id}">${dataset_name}</label>
</div>
%endfor
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/cbb7103283fe
changeset: 2759:cbb7103283fe
user: Kanwei Li <kanwei(a)gmail.com>
date: Wed Sep 23 19:11:12 2009 -0400
description:
minor trackster
3 file(s) affected in this change:
static/scripts/trackster.js
templates/tracks/browser.mako
templates/tracks/new_browser.mako
diffs (59 lines):
diff -r 509390d4e719 -r cbb7103283fe static/scripts/trackster.js
--- a/static/scripts/trackster.js Wed Sep 23 17:32:16 2009 -0400
+++ b/static/scripts/trackster.js Wed Sep 23 19:11:12 2009 -0400
@@ -67,7 +67,6 @@
this.high = Math.min( this.length, Math.ceil( new_high ) );
},
zoom_in: function ( factor, point ) {
- console.log(this.max_high);
if (this.max_high == 0) return;
var range = this.high - this.low;
diff -r 509390d4e719 -r cbb7103283fe templates/tracks/browser.mako
--- a/templates/tracks/browser.mako Wed Sep 23 17:32:16 2009 -0400
+++ b/templates/tracks/browser.mako Wed Sep 23 19:11:12 2009 -0400
@@ -99,7 +99,7 @@
});
(function () {
$.getJSON( "${h.url_for( action='chroms' )}", { dbkey: "${dbkey}" }, function ( data ) {
- var chrom_options = '<option value=""></option>';
+ var chrom_options = '<option value="">Select Chrom/Contig</option>';
for (i in data) {
chrom = data[i]['chrom']
if( chrom == view.chrom ) {
@@ -133,18 +133,15 @@
<div id="nav-labeltrack"></div>
<div id="nav-controls">
<form name="chr" id="chr" method="get">
+ <select id="chrom" name="chrom">
+ <option value="">Loading</option>
+ </select>
<input type="hidden" name="dataset_ids" value="${dataset_ids}" />
<a href="#" onclick="javascript:view.left(5);view.redraw();"><<</a>
<a href="#" onclick="javascript:view.left(2);view.redraw();"><</a>
- <select id="chrom" name="chrom">
- <option value="">Loading</option>
- </select>
<span id="low">0</span>—<span id="high">${LEN}</span>
- <span style="display: inline-block; width: 10em;">
- <a href="#" onclick="javascript:view.zoom_in(2);view.redraw();">+</a>
- <a href="#" onclick="javascript:view.zoom_out(2);view.redraw();">-</a>
- </span>
-
+ <a href="#" onclick="javascript:view.zoom_in(2);view.redraw();">+</a>
+ <a href="#" onclick="javascript:view.zoom_out(2);view.redraw();">-</a>
<a href="#" onclick="javascript:view.right(2);view.redraw();">></a>
<a href="#" onclick="javascript:view.right(5);view.redraw();">>></a>
</form>
diff -r 509390d4e719 -r cbb7103283fe templates/tracks/new_browser.mako
--- a/templates/tracks/new_browser.mako Wed Sep 23 17:32:16 2009 -0400
+++ b/templates/tracks/new_browser.mako Wed Sep 23 19:11:12 2009 -0400
@@ -22,7 +22,7 @@
%for tmp_dbkey in dbkey_set:
<option value="${tmp_dbkey}"
%if tmp_dbkey == dbkey:
- selected="true"
+ selected="selected"
%endif
>${tmp_dbkey}</option>
%endfor
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/fbd7d0a0f596
changeset: 2756:fbd7d0a0f596
user: Dan Blankenberg <dan(a)bx.psu.edu>
date: Wed Sep 23 17:01:04 2009 -0400
description:
Two MAF related bug fixes.
2 file(s) affected in this change:
lib/galaxy/datatypes/sequence.py
lib/galaxy/tools/util/maf_utilities.py
diffs (23 lines):
diff -r 69615210cf99 -r fbd7d0a0f596 lib/galaxy/datatypes/sequence.py
--- a/lib/galaxy/datatypes/sequence.py Wed Sep 23 13:25:22 2009 -0400
+++ b/lib/galaxy/datatypes/sequence.py Wed Sep 23 17:01:04 2009 -0400
@@ -406,6 +406,7 @@
"""
#these metadata values are not accessable by users, always overwrite
indexes, species, species_chromosomes = COPIED_build_maf_index_species_chromosomes( dataset.file_name )
+ if indexes is None: return #this is not a MAF file
dataset.metadata.species = species
#only overwrite the contents if our newly determined chromosomes don't match stored
diff -r 69615210cf99 -r fbd7d0a0f596 lib/galaxy/tools/util/maf_utilities.py
--- a/lib/galaxy/tools/util/maf_utilities.py Wed Sep 23 13:25:22 2009 -0400
+++ b/lib/galaxy/tools/util/maf_utilities.py Wed Sep 23 17:01:04 2009 -0400
@@ -504,7 +504,7 @@
def get_species_in_maf( maf_filename ):
species = []
- for block in maf.Reader( open( maf_filename ) ):
+ for block in bx.align.maf.Reader( open( maf_filename ) ):
for spec in get_species_in_block( block ):
if spec not in species:
species.append( spec )
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/dcdbb13b0c76
changeset: 2757:dcdbb13b0c76
user: rc
date: Wed Sep 23 17:16:13 2009 -0400
description:
Cleaned up new/edit request code.
2 file(s) affected in this change:
lib/galaxy/web/controllers/requests.py
lib/galaxy/web/controllers/requests_admin.py
diffs (211 lines):
diff -r fbd7d0a0f596 -r dcdbb13b0c76 lib/galaxy/web/controllers/requests.py
--- a/lib/galaxy/web/controllers/requests.py Wed Sep 23 17:01:04 2009 -0400
+++ b/lib/galaxy/web/controllers/requests.py Wed Sep 23 17:16:13 2009 -0400
@@ -462,31 +462,16 @@
helptext='(Optional)'))
# libraries selectbox
- all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted == False ) \
- .order_by( trans.app.model.Library.name ).all()
- user, roles = trans.get_user_and_roles()
- actions_to_check = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ]
- # The libraries dictionary looks like: { library : '1,2' }, library : '3' }
- # Its keys are the libraries that should be displayed for the current user and whose values are a
- # string of comma-separated folder ids, of the associated folders the should NOT be displayed.
- # The folders that should not be displayed may not be a complete list, but it is ultimately passed
- # to the calling method to keep from re-checking the same folders when the library / folder
- # select lists are rendered.
- libraries = odict()
- for library in all_libraries:
- can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
- if can_show:
- libraries[ library ] = hidden_folder_ids
- libui = self.__library_ui(trans, libraries, **kwd)
+ libui = self.__library_ui(trans, request=None, **kwd)
widgets = widgets + libui
- widgets = widgets + request_type.request_form.get_widgets( user, **kwd )
+ widgets = widgets + request_type.request_form.get_widgets( trans.user, **kwd )
return trans.fill_template( '/requests/new_request.mako',
select_request_type=select_request_type,
request_type=request_type,
widgets=widgets,
msg=msg,
messagetype=messagetype)
- def __library_ui(self, trans, libraries, request=None, **kwd):
+ def __library_ui(self, trans, request=None, **kwd):
params = util.Params( kwd )
lib_id = params.get( 'library_id', 'none' )
# if editing a request
@@ -497,6 +482,16 @@
else:
# new request
selected_lib = None
+ # get all permitted libraries for this user
+ all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted == False ) \
+ .order_by( trans.app.model.Library.name ).all()
+ user, roles = trans.get_user_and_roles()
+ actions_to_check = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ]
+ libraries = odict()
+ for library in all_libraries:
+ can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
+ if can_show:
+ libraries[ library ] = hidden_folder_ids
lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
lib_list = SelectField( 'library_id', refresh_on_change=True, refresh_on_change_values=lib_id_list )
# fill up the options in the Library selectfield
@@ -513,7 +508,7 @@
else:
lib_list.add_option(lib.name, lib.id)
lib_list.refresh_on_change_values.append(lib.id)
- # new library
+ # new library option
if lib_id == 'new':
lib_list.add_option('Create a new data library', 'new', selected=True)
else:
@@ -539,8 +534,6 @@
else:
folder_list.add_option('Select one', 'none')
# get all show-able folders for the selected library
- user, roles = trans.get_user_and_roles()
- actions_to_check = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ]
showable_folders = trans.app.security_agent.get_showable_folders( user, roles,
selected_lib,
actions_to_check,
@@ -724,25 +717,9 @@
widget=TextField('desc', 40, desc),
helptext='(Optional)'))
# libraries selectbox
- all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted == False ) \
- .order_by( trans.app.model.Library.name ).all()
- user, roles = trans.get_user_and_roles()
- actions_to_check = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ]
- # The libraries dictionary looks like:
- # { library : '1,2' }, library : '3' }
- # Its keys are the libraries that should be displayed for the current user and whose values are a
- # string of comma-separated folder ids, of the associated folders the should NOT be displayed.
- # The folders that should not be displayed may not be a complete list, but it is ultimately passed
- # to the calling method to keep from re-checking the same folders when the library / folder
- # select lists are rendered.
- libraries = {}
- for library in all_libraries:
- can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
- if can_show:
- libraries[ library ] = hidden_folder_ids
- libui = self.__library_ui(trans, libraries, request, **kwd)
+ libui = self.__library_ui(trans, request, **kwd)
widgets = widgets + libui
- widgets = widgets + request.type.request_form.get_widgets( user, request.values.content, **kwd )
+ widgets = widgets + request.type.request_form.get_widgets( trans.user, request.values.content, **kwd )
return trans.fill_template( '/requests/edit_request.mako',
select_request_type=select_request_type,
request_type=request.type,
diff -r fbd7d0a0f596 -r dcdbb13b0c76 lib/galaxy/web/controllers/requests_admin.py
--- a/lib/galaxy/web/controllers/requests_admin.py Wed Sep 23 17:01:04 2009 -0400
+++ b/lib/galaxy/web/controllers/requests_admin.py Wed Sep 23 17:16:13 2009 -0400
@@ -720,9 +720,20 @@
"""
params = util.Params( kwd )
lib_id = params.get( 'library_id', 'none' )
+ # if editing a request
+ if request and lib_id == 'none':
+ if request.library:
+ lib_id = str(request.library.id)
+ selected_lib = request.library
+ else:
+ # new request
+ selected_lib = None
+ # if new request no user is selected initially, none of the libraries are
+ # listed in the selectfield
if not user:
libraries = {}
else:
+ # get all permitted libraries for this user
all_libraries = trans.app.model.Library.filter( trans.app.model.Library.table.c.deleted == False ) \
.order_by( trans.app.model.Library.name ).all()
roles = user.all_roles()
@@ -733,43 +744,38 @@
# The folders that should not be displayed may not be a complete list, but it is ultimately passed
# to the calling method to keep from re-checking the same folders when the library / folder
# select lists are rendered.
- #
- # TODO: RC, when you add the folders select list to your request form, take advantage of the hidden_folder_ids
- # so that you do not need to check those same folders yet again when populating the select list.
- #
libraries = {}
for library in all_libraries:
can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
if can_show:
libraries[ library ] = hidden_folder_ids
+ # create the selectfield
lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
lib_list = SelectField( 'library_id', refresh_on_change=True, refresh_on_change_values=lib_id_list )
- folders = []
- if request and lib_id == 'none':
- if request.library:
- lib_id = str(request.library.id)
+ # first option
if lib_id == 'none':
lib_list.add_option('Select one', 'none', selected=True)
else:
lib_list.add_option('Select one', 'none')
+ # all the libraries available to the selected user
for lib, hidden_folder_ids in libraries.items():
if str(lib.id) == lib_id:
lib_list.add_option(lib.name, lib.id, selected=True)
- folders.append( lib.root_folder )
- for f in lib.root_folder.folders:
- if str(f.id) not in hidden_folder_ids.split(','):
- folders.append( f )
+ selected_lib, selected_hidden_folder_ids = lib, hidden_folder_ids.split(',')
else:
lib_list.add_option(lib.name, lib.id)
lib_list.refresh_on_change_values.append(lib.id)
+ # new data library option
if lib_id == 'new':
lib_list.add_option('Create a new data library', 'new', selected=True)
else:
lib_list.add_option('Create a new data library', 'new')
+ # widget
lib_widget = dict(label='Data library',
widget=lib_list,
helptext='Data library where the resultant dataset will be stored.')
- if folders:
+ if selected_lib:
+ # when editing a request
if request:
if request.folder:
current_fid = request.folder.id
@@ -778,11 +784,22 @@
else:
current_fid = params.get( 'folder_id', 'none' )
folder_list = SelectField( 'folder_id')
- for f in folders:
- if str(f.id) == current_fid:
+ # first option
+ if lib_id == 'none':
+ folder_list.add_option('Select one', 'none', selected=True)
+ else:
+ folder_list.add_option('Select one', 'none')
+ # get all show-able folders for the selected library
+ showable_folders = trans.app.security_agent.get_showable_folders( user, roles,
+ selected_lib,
+ actions_to_check,
+ selected_hidden_folder_ids )
+ for f in showable_folders:
+ if str(f.id) == str(current_fid):
folder_list.add_option(f.name, f.id, selected=True)
else:
folder_list.add_option(f.name, f.id)
+ # folder widget
folder_widget = dict(label='Folder',
widget=folder_list,
helptext='Folder of the selected data library where the resultant dataset will be stored.')
@@ -793,7 +810,7 @@
helptext='Enter a name here to request a new data library')
return [lib_widget, new_lib]
else:
- if folders:
+ if selected_lib:
return [lib_widget, folder_widget]
else:
return [lib_widget]
1
0
25 Sep '09
details: http://www.bx.psu.edu/hg/galaxy/rev/c7446ed27839
changeset: 2754:c7446ed27839
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Wed Sep 23 11:08:36 2009 -0400
description:
Added new get_showable_folders() method to the security agent for use by the sample requests. The sample request UI is now a bit broken.
2 file(s) affected in this change:
lib/galaxy/security/__init__.py
lib/galaxy/web/controllers/requests.py
diffs (94 lines):
diff -r be3c27418de9 -r c7446ed27839 lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py Wed Sep 23 09:24:10 2009 -0400
+++ b/lib/galaxy/security/__init__.py Wed Sep 23 11:08:36 2009 -0400
@@ -425,7 +425,8 @@
comma-separated string of folder ids whose folders do NOT meet the criteria for showing. Along with
the string, True is returned if the current user has permission to perform any 1 of actions_to_check
on library_item. Otherwise, cycle through all sub-folders in library_item until one is found that meets
- this criteria, if it exists.
+ this criteria, if it exists. This method does not necessarily scan the entire library as it returns
+ when it finds the first library_item that allows user to perform any one action in actions_to_check.
"""
for action in actions_to_check:
if self.allow_library_item_action( user, roles, action, library_item ):
@@ -442,6 +443,22 @@
else:
hidden_folder_ids = '%d' % folder.id
return False, hidden_folder_ids
+ def get_showable_folders( self, user, roles, library_item, actions_to_check, showable_folders=[] ):
+ """
+ This method must be sent an instance of Library(), all the folders of which are scanned to determine if
+ user is allowed to perform any action in actions_to_check. A list of showable folders is generated.
+ This method scans the entire library.
+ """
+ if isinstance( library_item, self.model.Library ):
+ return self.get_showable_folders( user, roles, library_item.root_folder, actions_to_check, showable_folders=showable_folders )
+ if isinstance( library_item, self.model.LibraryFolder ):
+ for action in actions_to_check:
+ if self.allow_library_item_action( user, roles, action, library_item ):
+ showable_folders.append( library_item )
+ break
+ for folder in library_item.active_folders:
+ self.get_showable_folders( user, roles, folder, actions_to_check, showable_folders=showable_folders )
+ return showable_folders
def set_entity_user_associations( self, users=[], roles=[], groups=[], delete_existing_assocs=True ):
for user in users:
if delete_existing_assocs:
@@ -495,6 +512,8 @@
comma-separated string of folder ids whose folders do NOT meet the criteria for showing. Along
with the string, True is returned if the current user has permission to access folder. Otherwise,
cycle through all sub-folders in folder until one is found that meets this criteria, if it exists.
+ This method does not necessarily scan the entire library as it returns when it finds the first
+ folder that is accessible to user.
"""
action = self.permitted_actions.DATASET_ACCESS
lddas = self.sa_session.query( self.model.LibraryDatasetDatasetAssociation ) \
diff -r be3c27418de9 -r c7446ed27839 lib/galaxy/web/controllers/requests.py
--- a/lib/galaxy/web/controllers/requests.py Wed Sep 23 09:24:10 2009 -0400
+++ b/lib/galaxy/web/controllers/requests.py Wed Sep 23 11:08:36 2009 -0400
@@ -474,9 +474,9 @@
# select lists are rendered.
libraries = odict()
for library in all_libraries:
- can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
- if can_show:
- libraries[ library ] = hidden_folder_ids
+ showable_folders = trans.app.security_agent.get_showable_folders( user, roles, library, actions_to_check )
+ if showable_folders:
+ libraries[ library ] = showable_folders
libui = self.__library_ui(libraries, **kwd)
widgets = widgets + libui
widgets = widgets + request_type.request_form.get_widgets( user, **kwd )
@@ -491,7 +491,6 @@
lib_id = params.get( 'library_id', 'none' )
lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
lib_list = SelectField( 'library_id', refresh_on_change=True, refresh_on_change_values=lib_id_list )
- folders = []
if request and lib_id == 'none':
if request.library:
lib_id = str(request.library.id)
@@ -499,13 +498,9 @@
lib_list.add_option('Select one', 'none', selected=True)
else:
lib_list.add_option('Select one', 'none')
- for lib, hidden_folder_ids in libraries.items():
+ for lib, folders in libraries.items():
if str(lib.id) == lib_id:
lib_list.add_option(lib.name, lib.id, selected=True)
- folders.append( lib.root_folder )
- for f in lib.root_folder.folders:
- if str(f.id) not in hidden_folder_ids.split(','):
- folders.append( f )
else:
lib_list.add_option(lib.name, lib.id)
lib_list.refresh_on_change_values.append(lib.id)
@@ -516,7 +511,8 @@
lib_widget = dict(label='Data library',
widget=lib_list,
helptext='Data library where the resultant dataset will be stored.')
- if folders:
+ selected, value = lib_widget[ 'widget' ].get_selected()
+ if selected not in [ 'new', 'none' ]:
if request:
if request.folder:
current_fid = request.folder.id
1
0
25 Sep '09
details: http://www.bx.psu.edu/hg/galaxy/rev/69615210cf99
changeset: 2755:69615210cf99
user: rc
date: Wed Sep 23 13:25:22 2009 -0400
description:
Fixed a bug in the new/edit request code. Now user can select all permitted folders & subfolders of a selected library when creating or editing a request.
2 file(s) affected in this change:
lib/galaxy/security/__init__.py
lib/galaxy/web/controllers/requests.py
diffs (150 lines):
diff -r c7446ed27839 -r 69615210cf99 lib/galaxy/security/__init__.py
--- a/lib/galaxy/security/__init__.py Wed Sep 23 11:08:36 2009 -0400
+++ b/lib/galaxy/security/__init__.py Wed Sep 23 13:25:22 2009 -0400
@@ -443,19 +443,21 @@
else:
hidden_folder_ids = '%d' % folder.id
return False, hidden_folder_ids
- def get_showable_folders( self, user, roles, library_item, actions_to_check, showable_folders=[] ):
+ def get_showable_folders( self, user, roles, library_item, actions_to_check, hidden_folder_ids=[], showable_folders=[] ):
"""
This method must be sent an instance of Library(), all the folders of which are scanned to determine if
- user is allowed to perform any action in actions_to_check. A list of showable folders is generated.
- This method scans the entire library.
+ user is allowed to perform any action in actions_to_check. The param hidden_folder_ids, if passed, should
+ contain a list of folder IDs which was generated when the library was previously scanned
+ using the same actions_to_check. A list of showable folders is generated. This method scans the entire library.
"""
if isinstance( library_item, self.model.Library ):
- return self.get_showable_folders( user, roles, library_item.root_folder, actions_to_check, showable_folders=showable_folders )
+ return self.get_showable_folders( user, roles, library_item.root_folder, actions_to_check, showable_folders=[] )
if isinstance( library_item, self.model.LibraryFolder ):
- for action in actions_to_check:
- if self.allow_library_item_action( user, roles, action, library_item ):
- showable_folders.append( library_item )
- break
+ if library_item.id not in hidden_folder_ids:
+ for action in actions_to_check:
+ if self.allow_library_item_action( user, roles, action, library_item ):
+ showable_folders.append( library_item )
+ break
for folder in library_item.active_folders:
self.get_showable_folders( user, roles, folder, actions_to_check, showable_folders=showable_folders )
return showable_folders
diff -r c7446ed27839 -r 69615210cf99 lib/galaxy/web/controllers/requests.py
--- a/lib/galaxy/web/controllers/requests.py Wed Sep 23 11:08:36 2009 -0400
+++ b/lib/galaxy/web/controllers/requests.py Wed Sep 23 13:25:22 2009 -0400
@@ -474,45 +474,57 @@
# select lists are rendered.
libraries = odict()
for library in all_libraries:
- showable_folders = trans.app.security_agent.get_showable_folders( user, roles, library, actions_to_check )
- if showable_folders:
- libraries[ library ] = showable_folders
- libui = self.__library_ui(libraries, **kwd)
+ can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
+ if can_show:
+ libraries[ library ] = hidden_folder_ids
+ libui = self.__library_ui(trans, libraries, **kwd)
widgets = widgets + libui
widgets = widgets + request_type.request_form.get_widgets( user, **kwd )
return trans.fill_template( '/requests/new_request.mako',
select_request_type=select_request_type,
- request_type=request_type,
+ request_type=request_type,
widgets=widgets,
msg=msg,
messagetype=messagetype)
- def __library_ui(self, libraries, request=None, **kwd):
+ def __library_ui(self, trans, libraries, request=None, **kwd):
params = util.Params( kwd )
lib_id = params.get( 'library_id', 'none' )
- lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
- lib_list = SelectField( 'library_id', refresh_on_change=True, refresh_on_change_values=lib_id_list )
+ # if editing a request
if request and lib_id == 'none':
if request.library:
lib_id = str(request.library.id)
+ selected_lib = request.library
+ else:
+ # new request
+ selected_lib = None
+ lib_id_list = ['new'] + [str(lib.id) for lib in libraries.keys()]
+ lib_list = SelectField( 'library_id', refresh_on_change=True, refresh_on_change_values=lib_id_list )
+ # fill up the options in the Library selectfield
+ # first option
if lib_id == 'none':
lib_list.add_option('Select one', 'none', selected=True)
else:
lib_list.add_option('Select one', 'none')
- for lib, folders in libraries.items():
+ # all the libraries available to the user
+ for lib, hidden_folder_ids in libraries.items():
if str(lib.id) == lib_id:
lib_list.add_option(lib.name, lib.id, selected=True)
+ selected_lib, selected_hidden_folder_ids = lib, hidden_folder_ids.split(',')
else:
lib_list.add_option(lib.name, lib.id)
lib_list.refresh_on_change_values.append(lib.id)
+ # new library
if lib_id == 'new':
lib_list.add_option('Create a new data library', 'new', selected=True)
else:
lib_list.add_option('Create a new data library', 'new')
+ # data library widget
lib_widget = dict(label='Data library',
widget=lib_list,
helptext='Data library where the resultant dataset will be stored.')
- selected, value = lib_widget[ 'widget' ].get_selected()
- if selected not in [ 'new', 'none' ]:
+ # show the folder widget only if the user has selected a valid library above
+ if selected_lib:
+ # when editing a request
if request:
if request.folder:
current_fid = request.folder.id
@@ -521,11 +533,24 @@
else:
current_fid = params.get( 'folder_id', 'none' )
folder_list = SelectField( 'folder_id')
- for f in folders:
- if str(f.id) == current_fid:
+ # first option
+ if lib_id == 'none':
+ folder_list.add_option('Select one', 'none', selected=True)
+ else:
+ folder_list.add_option('Select one', 'none')
+ # get all show-able folders for the selected library
+ user, roles = trans.get_user_and_roles()
+ actions_to_check = [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ]
+ showable_folders = trans.app.security_agent.get_showable_folders( user, roles,
+ selected_lib,
+ actions_to_check,
+ selected_hidden_folder_ids )
+ for f in showable_folders:
+ if str(f.id) == str(current_fid):
folder_list.add_option(f.name, f.id, selected=True)
else:
folder_list.add_option(f.name, f.id)
+ # folder widget
folder_widget = dict(label='Folder',
widget=folder_list,
helptext='Folder of the selected data library where the resultant dataset will be stored.')
@@ -536,7 +561,7 @@
helptext='Enter a name here to request a new data library')
return [lib_widget, new_lib]
else:
- if folders:
+ if selected_lib:
return [lib_widget, folder_widget]
else:
return [lib_widget]
@@ -715,7 +740,7 @@
can_show, hidden_folder_ids = trans.app.security_agent.show_library_item( user, roles, library, actions_to_check )
if can_show:
libraries[ library ] = hidden_folder_ids
- libui = self.__library_ui(libraries, request, **kwd)
+ libui = self.__library_ui(trans, libraries, request, **kwd)
widgets = widgets + libui
widgets = widgets + request.type.request_form.get_widgets( user, request.values.content, **kwd )
return trans.fill_template( '/requests/edit_request.mako',
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/9118054983c3
changeset: 2751:9118054983c3
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Tue Sep 22 14:47:47 2009 -0400
description:
Eliminate the encode data functional test.
1 file(s) affected in this change:
test/functional/test_get_data.py
diffs (27 lines):
diff -r d42c5698798b -r 9118054983c3 test/functional/test_get_data.py
--- a/test/functional/test_get_data.py Tue Sep 22 14:04:48 2009 -0400
+++ b/test/functional/test_get_data.py Tue Sep 22 14:47:47 2009 -0400
@@ -57,23 +57,3 @@
self.check_history_for_string( 'Pasted Entry' )
self.check_history_for_string( 'hello world' )
self.delete_history( id=self.security.encode_id( history2.id ) )
- def test_010_upload_encode_data( self ):
- """Test uploading encode data"""
- # Deleting the current history should have created a new history
- self.check_history_for_string( 'Your history is empty' )
- history3 = galaxy.model.History.filter( and_( galaxy.model.History.table.c.deleted==False,
- galaxy.model.History.table.c.user_id==admin_user.id ) ) \
- .order_by( desc( galaxy.model.History.table.c.create_time ) ).first()
- self.run_tool( 'encode_import_chromatin_and_chromosomes1', hg17=['cc.EarlyRepSeg.20051216.bed'] )
- self.wait()
- hda7 = galaxy.model.HistoryDatasetAssociation.query() \
- .order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ).first()
- assert hda7 is not None, "Problem retrieving hda7 from database"
- self.verify_dataset_correctness( 'cc.EarlyRepSeg.20051216.bed', hid=str( hda7.hid ) )
- self.run_tool('encode_import_gencode1', hg17=['gencode.CDS.20051206.bed'])
- self.wait()
- hda8 = galaxy.model.HistoryDatasetAssociation.query() \
- .order_by( desc( galaxy.model.HistoryDatasetAssociation.table.c.create_time ) ).first()
- assert hda8 is not None, "Problem retrieving hda8 from database"
- self.verify_dataset_correctness( 'sc_3D_cds.bed', hid=str( hda8.hid ) )
- self.delete_history( id=self.security.encode_id( history3.id ) )
1
0
25 Sep '09
details: http://www.bx.psu.edu/hg/galaxy/rev/be3c27418de9
changeset: 2753:be3c27418de9
user: Greg Von Kuster <greg(a)bx.psu.edu>
date: Wed Sep 23 09:24:10 2009 -0400
description:
Fix bug in security helpers encode_id and decode_id methods that resulted in overriding the Python built in id - resolves ticket # 167.
1 file(s) affected in this change:
lib/galaxy/web/security/__init__.py
diffs (23 lines):
diff -r afa7946a126c -r be3c27418de9 lib/galaxy/web/security/__init__.py
--- a/lib/galaxy/web/security/__init__.py Tue Sep 22 21:51:11 2009 -0400
+++ b/lib/galaxy/web/security/__init__.py Wed Sep 23 09:24:10 2009 -0400
@@ -34,15 +34,15 @@
def __init__( self, **config ):
self.id_secret = config['id_secret']
self.id_cipher = Blowfish.new( self.id_secret )
- def encode_id( self, id ):
+ def encode_id( self, obj_id ):
# Convert to string
- s = str( id )
+ s = str( obj_id )
# Pad to a multiple of 8 with leading "!"
s = ( "!" * ( 8 - len(s) % 8 ) ) + s
# Encrypt
return self.id_cipher.encrypt( s ).encode( 'hex' )
- def decode_id( self, id ):
- return int( self.id_cipher.decrypt( id.decode( 'hex' ) ).lstrip( "!" ) )
+ def decode_id( self, obj_id ):
+ return int( self.id_cipher.decrypt( obj_id.decode( 'hex' ) ).lstrip( "!" ) )
def encode_session_key( self, session_key ):
# Session keys are strings
# Pad to a multiple of 8 with leading "!"
1
0
details: http://www.bx.psu.edu/hg/galaxy/rev/afa7946a126c
changeset: 2752:afa7946a126c
user: Kanwei Li <kanwei(a)gmail.com>
date: Tue Sep 22 21:51:11 2009 -0400
description:
new trackster lands
10 file(s) affected in this change:
lib/galaxy/visualization/tracks/data/array_tree.py
lib/galaxy/web/controllers/tracks.py
static/scripts/jquery.mousewheel.js
static/scripts/packed/autocomplete_tagging.js
static/scripts/packed/jquery.mousewheel.js
static/scripts/packed/trackster.js
static/scripts/trackster.js
static/trackster.css
templates/tracks/browser.mako
templates/tracks/new_browser.mako
diffs (1182 lines):
diff -r 9118054983c3 -r afa7946a126c lib/galaxy/visualization/tracks/data/array_tree.py
--- a/lib/galaxy/visualization/tracks/data/array_tree.py Tue Sep 22 14:47:47 2009 -0400
+++ b/lib/galaxy/visualization/tracks/data/array_tree.py Tue Sep 22 21:51:11 2009 -0400
@@ -18,6 +18,17 @@
class ArrayTreeDataProvider( object ):
def __init__( self, dataset ):
self.dataset = dataset
+
+ def get_stats( self, chrom ):
+ d = FileArrayTreeDict( open( self.dataset.file_name ) )
+ try:
+ chrom_array_tree = d[chrom]
+ except KeyError:
+ return None
+
+ root_summary = chrom_array_tree.get_summary( 0, chrom_array_tree.levels )
+ return { 'max': float( max(root_summary.maxs) ), 'min': float( min(root_summary.mins) ) }
+
def get_data( self, chrom, start, end ):
start = int( start )
end = int( end )
diff -r 9118054983c3 -r afa7946a126c lib/galaxy/web/controllers/tracks.py
--- a/lib/galaxy/web/controllers/tracks.py Tue Sep 22 14:47:47 2009 -0400
+++ b/lib/galaxy/web/controllers/tracks.py Tue Sep 22 21:51:11 2009 -0400
@@ -15,7 +15,8 @@
need to support that, but need to make user defined build support better)
"""
-import math
+import math, logging
+log = logging.getLogger(__name__)
from galaxy.util.json import to_json_string
from galaxy.web.base.controller import *
@@ -100,7 +101,7 @@
tracks.append( {
"type": dataset.datatype.get_track_type(),
"name": dataset.name,
- "id": dataset.id
+ "dataset_id": dataset.id
} )
dbkey = dataset.dbkey
chrom_lengths = self._chroms( trans, dbkey )
@@ -111,18 +112,20 @@
tracks=tracks,
chrom=chrom,
dbkey=dbkey,
- LEN=chrom_lengths.get( chrom, 0 ) )
+ LEN=chrom_lengths.get(chrom, 0) )
@web.json
def chroms(self, trans, dbkey=None ):
- return self._chroms( trans, dbkey )
+ chroms = self._chroms( trans, dbkey )
+ unsorted = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()]
+ unsorted.sort( lambda a,b: cmp(a['chrom'], b['chrom']) )
+ return unsorted
def _chroms( self, trans, dbkey ):
"""
Called by the browser to get a list of valid chromosomes and lengths
"""
- # If there is any dataset in the history of extension `len`, this will
- # use it
+ # If there is any dataset in the history of extension `len`, this will use it
db_manifest = trans.db_dataset_for( dbkey )
if not db_manifest:
db_manifest = os.path.join( trans.app.config.tool_data_path, 'shared','ucsc','chrom', "%s.len" % dbkey )
@@ -139,7 +142,7 @@
return manifest
@web.json
- def data( self, trans, dataset_id, track_type, chrom, low, high ):
+ def data( self, trans, dataset_id, track_type, chrom, low, high, stats=False ):
"""
Called by the browser to request a block of data
"""
@@ -169,6 +172,10 @@
# We have a dataset in the right format that is ready to use, wrap in
# a data provider that knows how to access it
data_provider = dataset_type_to_data_provider[ converted_dataset_type ]( converted_dataset )
+
+ # Return stats if we need them
+ if stats: return data_provider.get_stats( chrom )
+
# Get the requested chunk of data
data = data_provider.get_data( chrom, low, high )
# Pack into a dictionary and return
diff -r 9118054983c3 -r afa7946a126c static/scripts/jquery.mousewheel.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/jquery.mousewheel.js Tue Sep 22 21:51:11 2009 -0400
@@ -0,0 +1,60 @@
+/*! Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ *
+ * Requires: 1.2.2+
+ */
+
+(function($) {
+
+var types = ['DOMMouseScroll', 'mousewheel'];
+
+$.event.special.mousewheel = {
+ setup: function() {
+ if ( this.addEventListener )
+ for ( var i=types.length; i; )
+ this.addEventListener( types[--i], handler, false );
+ else
+ this.onmousewheel = handler;
+ },
+
+ teardown: function() {
+ if ( this.removeEventListener )
+ for ( var i=types.length; i; )
+ this.removeEventListener( types[--i], handler, false );
+ else
+ this.onmousewheel = null;
+ }
+};
+
+$.fn.extend({
+ mousewheel: function(fn) {
+ return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+ },
+
+ unmousewheel: function(fn) {
+ return this.unbind("mousewheel", fn);
+ }
+});
+
+
+function handler(event) {
+ var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true;
+
+ event = $.event.fix(event || window.event);
+ event.type = "mousewheel";
+
+ if ( event.wheelDelta ) delta = event.wheelDelta/120;
+ if ( event.detail ) delta = -event.detail/3;
+
+ // Add events and delta to the front of the arguments
+ args.unshift(event, delta);
+
+ return $.event.handle.apply(this, args);
+}
+
+})(jQuery);
\ No newline at end of file
diff -r 9118054983c3 -r afa7946a126c static/scripts/packed/autocomplete_tagging.js
--- a/static/scripts/packed/autocomplete_tagging.js Tue Sep 22 14:47:47 2009 -0400
+++ b/static/scripts/packed/autocomplete_tagging.js Tue Sep 22 21:51:11 2009 -0400
@@ -1,1 +1,1 @@
-var ac_tag_area_id_gen=1;jQuery.fn.autocomplete_tagging=function(c){var e={get_toggle_link_text_fn:function(u){var w="";var v=o(u);if(v!=0){w=v+(v!=0?" Tags":" Tag")}else{w="Add tags"}return w},tag_click_fn:function(u){},input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var p=jQuery.extend(e,c);var k="tag-area-"+(ac_tag_area_id_gen)++;var m=$("<div>").attr("id",k).addClass("tag-area");this.append(m);var o=function(u){if(u.length){return u.length}var v=0;for(element in u){v++}return v};var b=function(){var u=p.get_toggle_link_text_fn(p.tags);var v=$("<a href='/history/tags'>").text(u).addClass("toggle-link");v.click(function(){var w=(m.css("display")=="none");var x;if(w){x=function(){var y=o(p.tags);if(y==0){m.click()}}}else{x=function(){m.blur()}}m.slideToggle("fast",x);return false});return v};var s=b();if(p.us
e_toggle_link){this.prepend(s)}var t=function(u){var v=new Array();for(key in u){v[v.length]=key+"-->"+u[key]}return"{"+v.join(",")+"}"};var a=function(v,u){return v+((u!=""&&u)?":"+u:"")};var h=function(u){return u.split(":")};var i=function(u){var v=$("<img src='"+p.add_tag_img+"' rollover='"+p.add_tag_img_rollover+"'/>").addClass("add-tag-button");v.click(function(){$(this).hide();m.click();return false});return v};var j=function(u){var v=$("<img src='"+p.delete_tag_img+"'/>").addClass("delete-tag-img");v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)});v.click(function(){var D=$(this).parent();var C=D.find(".tag-name").eq(0);var B=C.text();var z=h(B);var F=z[0];var y=z[1];var E=D.prev();D.remove();delete p.tags[F];var A=p.get_toggle_link_text_fn(p.tags);s.text(A);$.ajax({url:p.ajax_delete_tag_url,data:{tag_name:F},error:function(){p.tags[F]=y;if(E.hasClass("tag-button")){E.after(D)}else{m
.prepend(D)}var G=p.get_toggle_link_text_fn(p.tags);alert("Remove tag failed");s.text(G);v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)})},success:function(){}});return true});var w=$("<span>").text(u).addClass("tag-name");w.click(function(){p.tag_click_fn(u);return true});var x=$("<span></span>").addClass("tag-button");x.append(w);x.append(v);return x};var d=function(v){var u;if(p.in_form){u=$("<textarea id='history-tag-input' rows='1' cols='"+p.input_size+"' value='"+escape(v)+"'></textarea>")}else{u=$("<input id='history-tag-input' type='text' size='"+p.input_size+"' value='"+escape(v)+"'></input>")}u.keyup(function(D){if(D.keyCode==27){$(this).trigger("blur")}else{if((D.keyCode==13)||(D.keyCode==188)||(D.keyCode==32)){new_value=this.value;if(return_key_pressed_for_autocomplete==true){return_key_pressed_for_autocomplete=false;return false}if(new_value.indexOf(": ",new_value.length-2)!=-1
){this.value=new_value.substring(0,new_value.length-1);return false}if((D.keyCode==188)||(D.keyCode==32)){new_value=new_value.substring(0,new_value.length-1)}new_value=new_value.replace(/^\s+|\s+$/g,"");if(new_value.length<3){return false}this.value="";var A=j(new_value);var z=m.children(".tag-button");if(z.length!=0){var E=z.slice(z.length-1);E.after(A)}else{m.prepend(A)}var y=new_value.split(":");p.tags[y[0]]=y[1];var B=p.get_toggle_link_text_fn(p.tags);s.text(B);var C=$(this);$.ajax({url:p.ajax_add_tag_url,data:{new_tag:new_value},error:function(){A.remove();delete p.tags[y[0]];var F=p.get_toggle_link_text_fn(p.tags);s.text(F);alert("Add tag failed")},success:function(){C.flushCache()}});return false}}});var w=function(A,z,y,C,B){tag_name_and_value=C.split(":");return(tag_name_and_value.length==1?tag_name_and_value[0]:tag_name_and_value[1])};var x={selectFirst:false,formatItem:w,autoFill:false,highlight:false};u.autocomplete(p.ajax_autocomplete_tag_url,x);u.addClass("tag-
input");return u};for(tag_name in p.tags){var q=p.tags[tag_name];var l=a(tag_name,q);var g=j(l,s,p.tags);m.append(g)}var n=d("");var f=i(n);m.blur(function(u){r=o(p.tags);if(r!=0){f.show();n.hide();m.removeClass("active-tag-area")}else{}});m.append(f);m.append(n);n.hide();m.click(function(w){var v=$(this).hasClass("active-tag-area");if($(w.target).hasClass("delete-tag-img")&&!v){return false}if($(w.target).hasClass("tag-name")&&!v){return false}$(this).addClass("active-tag-area");f.hide();n.show();n.focus();var u=function(y){var x=m.attr("id");if(($(y.target).attr("id")!=x)&&($(y.target).parents().filter(x).length==0)){m.blur();$(document).unbind("click",u)}};$(window).click(u);return false});if(p.use_toggle_link){m.hide()}else{var r=o(p.tags);if(r==0){f.hide();n.show()}}return this.addClass("tag-element")};
\ No newline at end of file
+var ac_tag_area_id_gen=1;jQuery.fn.autocomplete_tagging=function(c){var e={get_toggle_link_text_fn:function(u){var w="";var v=o(u);if(v!=0){w=v+(v!=0?" Tags":" Tag")}else{w="Add tags"}return w},tag_click_fn:function(u,v){},input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var p=jQuery.extend(e,c);var k="tag-area-"+(ac_tag_area_id_gen)++;var m=$("<div>").attr("id",k).addClass("tag-area");this.append(m);var o=function(u){if(u.length){return u.length}var v=0;for(element in u){v++}return v};var b=function(){var u=p.get_toggle_link_text_fn(p.tags);var v=$("<a href='/history/tags'>").text(u).addClass("toggle-link");v.click(function(){var w=(m.css("display")=="none");var x;if(w){x=function(){var y=o(p.tags);if(y==0){m.click()}}}else{x=function(){m.blur()}}m.slideToggle("fast",x);return false});return v};var s=b();if(p.
use_toggle_link){this.prepend(s)}var t=function(u){var v=new Array();for(key in u){v[v.length]=key+"-->"+u[key]}return"{"+v.join(",")+"}"};var a=function(v,u){return v+((u!=""&&u)?":"+u:"")};var h=function(u){return u.split(":")};var i=function(u){var v=$("<img src='"+p.add_tag_img+"' rollover='"+p.add_tag_img_rollover+"'/>").addClass("add-tag-button");v.click(function(){$(this).hide();m.click();return false});return v};var j=function(u){var v=$("<img src='"+p.delete_tag_img+"'/>").addClass("delete-tag-img");v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)});v.click(function(){var D=$(this).parent();var C=D.find(".tag-name").eq(0);var B=C.text();var z=h(B);var F=z[0];var y=z[1];var E=D.prev();D.remove();delete p.tags[F];var A=p.get_toggle_link_text_fn(p.tags);s.text(A);$.ajax({url:p.ajax_delete_tag_url,data:{tag_name:F},error:function(){p.tags[F]=y;if(E.hasClass("tag-button")){E.after(D)}else
{m.prepend(D)}var G=p.get_toggle_link_text_fn(p.tags);alert("Remove tag failed");s.text(G);v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)})},success:function(){}});return true});var w=$("<span>").text(u).addClass("tag-name");w.click(function(){tag_name_and_value=u.split(":");p.tag_click_fn(tag_name_and_value[0],tag_name_and_value[1]);return true});var x=$("<span></span>").addClass("tag-button");x.append(w);x.append(v);return x};var d=function(v){var u;if(p.in_form){u=$("<textarea id='history-tag-input' rows='1' cols='"+p.input_size+"' value='"+escape(v)+"'></textarea>")}else{u=$("<input id='history-tag-input' type='text' size='"+p.input_size+"' value='"+escape(v)+"'></input>")}u.keyup(function(D){if(D.keyCode==27){$(this).trigger("blur")}else{if((D.keyCode==13)||(D.keyCode==188)||(D.keyCode==32)){new_value=this.value;if(return_key_pressed_for_autocomplete==true){return_key_pressed_for_autoc
omplete=false;return false}if(new_value.indexOf(": ",new_value.length-2)!=-1){this.value=new_value.substring(0,new_value.length-1);return false}if((D.keyCode==188)||(D.keyCode==32)){new_value=new_value.substring(0,new_value.length-1)}new_value=new_value.replace(/^\s+|\s+$/g,"");if(new_value.length<3){return false}this.value="";var A=j(new_value);var z=m.children(".tag-button");if(z.length!=0){var E=z.slice(z.length-1);E.after(A)}else{m.prepend(A)}var y=new_value.split(":");p.tags[y[0]]=y[1];var B=p.get_toggle_link_text_fn(p.tags);s.text(B);var C=$(this);$.ajax({url:p.ajax_add_tag_url,data:{new_tag:new_value},error:function(){A.remove();delete p.tags[y[0]];var F=p.get_toggle_link_text_fn(p.tags);s.text(F);alert("Add tag failed")},success:function(){C.flushCache()}});return false}}});var w=function(A,z,y,C,B){tag_name_and_value=C.split(":");return(tag_name_and_value.length==1?tag_name_and_value[0]:tag_name_and_value[1])};var x={selectFirst:false,formatItem:w,autoFill:false,hig
hlight:false};u.autocomplete(p.ajax_autocomplete_tag_url,x);u.addClass("tag-input");return u};for(tag_name in p.tags){var q=p.tags[tag_name];var l=a(tag_name,q);var g=j(l,s,p.tags);m.append(g)}var n=d("");var f=i(n);m.blur(function(u){r=o(p.tags);if(r!=0){f.show();n.hide();m.removeClass("active-tag-area")}else{}});m.append(f);m.append(n);n.hide();m.click(function(w){var v=$(this).hasClass("active-tag-area");if($(w.target).hasClass("delete-tag-img")&&!v){return false}if($(w.target).hasClass("tag-name")&&!v){return false}$(this).addClass("active-tag-area");f.hide();n.show();n.focus();var u=function(y){var x=m.attr("id");if(($(y.target).attr("id")!=x)&&($(y.target).parents().filter(x).length==0)){m.blur();$(document).unbind("click",u)}};$(window).click(u);return false});if(p.use_toggle_link){m.hide()}else{var r=o(p.tags);if(r==0){f.hide();n.show()}}return this.addClass("tag-element")};
\ No newline at end of file
diff -r 9118054983c3 -r afa7946a126c static/scripts/packed/jquery.mousewheel.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/packed/jquery.mousewheel.js Tue Sep 22 21:51:11 2009 -0400
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ *
+ * Version: 3.0.2
+ *
+ * Requires: 1.2.2+
+ */
+(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
\ No newline at end of file
diff -r 9118054983c3 -r afa7946a126c static/scripts/packed/trackster.js
--- a/static/scripts/packed/trackster.js Tue Sep 22 14:47:47 2009 -0400
+++ b/static/scripts/packed/trackster.js Tue Sep 22 21:51:11 2009 -0400
@@ -1,1 +1,1 @@
-var DENSITY=1000;var View=function(b,c,a,d){this.chr=b;this.length=c;this.low=a;this.high=d};$.extend(View.prototype,{move:function(b,a){this.low=Math.max(0,Math.floor(b));this.high=Math.min(this.length,Math.ceil(a))},zoom_in:function(c){var a=(this.low+this.high)/2;var b=this.high-this.low;var d=b/c/2;this.low=Math.floor(a-d);this.high=Math.ceil(a+d);if(this.high-this.low<1){this.high=this.low+1}},zoom_out:function(c){var a=(this.low+this.high)/2;var b=this.high-this.low;var d=b*c/2;this.low=Math.floor(Math.max(0,a-d));this.high=Math.ceil(Math.min(this.length,a+d))},left:function(b){var a=this.high-this.low;var c=Math.floor(a/b);if(this.low-c<0){this.low=0;this.high=this.low+a}else{this.low-=c;this.high-=c}},right:function(b){var a=this.high-this.low;var c=Math.floor(a/b);if(this.high+c>this.length){this.high=this.length;this.low=this.high-a}else{this.low+=c;this.high+=c}}});var Track=function(b,a,c){this.name=b;this.view=a;this.parent_element=c;this.make_container()};$.ext
end(Track.prototype,{make_container:function(){this.header_div=$("<div class='track-header'>");this.header_div.text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div class='track'></div>");this.container_div.append(this.header_div);this.container_div.append(this.content_div);this.parent_element.append(this.container_div)}});var TiledTrack=function(b,a,c){Track.call(this,b,a,c);this.last_resolution=null;this.last_w_scale=null;this.tile_cache={}};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var k=this.view.low,c=this.view.high,e=c-k;var b=Math.pow(10,Math.ceil(Math.log(e/DENSITY)/Math.log(10)));b=Math.max(b,1);b=Math.min(b,100000);var o=$("<div style='position: relative;'></div>");this.content_div.children(":first").remove();this.content_div.append(o);var m=this.content_div.width(),d=this.content_div.height(),p=m/e,l={},n={};if(this.last_resolution==b&&this.last_w_scale==p){l=this.tile_cache}var g;var a=Math.floor(k/b/DEN
SITY);var j=0;while((a*1000*b)<c){if(a in l){g=l[a];var f=a*DENSITY*b;g.css({left:(f-this.view.low)*p});o.append(g)}else{g=this.draw_tile(b,a,o,p,d)}if(g){n[a]=g;j=Math.max(j,g.height())}a+=1}o.css("height",j);this.last_resolution=b;this.last_w_scale=p;this.tile_cache=n}});var DataCache=function(c,b,a){this.type=c;this.track=b;this.view=a;this.cache=Object()};$.extend(DataCache.prototype,{get:function(d,b){var c=this.cache;if(!(c[d]&&c[d][b])){if(!c[d]){c[d]=Object()}var a=b*DENSITY*d;var f=(b+1)*DENSITY*d;c[d][b]={state:"loading"};var e=function(g){return function(){$.getJSON(TRACKSTER_DATA_URL+g.type,{chrom:g.view.chr,low:a,high:f,dataset_id:g.track.dataset_id},function(h){if(h=="pending"){setTimeout(e,5000)}else{c[d][b]={state:"loaded",values:h}}$(document).trigger("redraw")})}}(this);e()}return c[d][b]}});var LineTrack=function(c,b,d,a){Track.call(this,c,b,d);this.container_div.addClass("line-track");this.dataset_id=a;this.cache=new DataCache("",this,b)};$.extend(LineTra
ck.prototype,TiledTrack.prototype,{make_container:function(){Track.prototype.make_container.call(this);this.content_div.css("height",100)},draw_tile:function(n,q,g,j,h){var s=q*DENSITY*n,d=(q+1)*DENSITY*n,a=DENSITY*n;var k=this.cache.get(n,q);var b;if(k.state=="loading"){b=$("<div class='loading tile'></div>")}else{b=$("<canvas class='tile'></canvas>")}b.css({position:"absolute",top:0,left:(s-this.view.low)*j,width:Math.ceil(a*j),height:100});g.append(b);if(k.state=="loading"){l=false;return null}var f=b;f.get(0).width=f.width();f.get(0).height=f.height();var m=f.get(0).getContext("2d");var l=false;m.beginPath();var t=k.values;for(var o=0;o<t.length-1;o++){var r=t[o][0]-s;var e=t[o][1];var p=t[o+1][0]-s;var c=t[o+1][1];console.log(r,e,p,c);if(isNaN(e)||isNaN(c)){l=false}else{r=r*j;p=p*j;e=h-e*(h);c=h-c*(h);if(l){m.lineTo(r,e,p,c)}else{m.moveTo(r,e,p,c);l=true}}}m.stroke();return b}});var LabelTrack=function(a,b){Track.call(this,null,a,b);this.container_div.addClass("label-tr
ack")};$.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'>"+a+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var itemHeight=13,itemPad=3,thinHeight=7,thinOffset=3;var FeatureTrack=function(c,b,d,a){Track.call(this,c,b,d);this.container_div.addClass("feature-track");this.dataset_id=a;this.cache=new DataCache("",this,b)};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{get_data_async:function(){var a=this;$.getJSON("data",{chr:this.view.chr,dataset_id:this.dataset_id},function(b){a.values=b;a.draw()})},draw_tile:function(x,y,h,m,l){var z=y*DENSITY*x,c=(y+1)*DENSITY*x,a=DENSITY*x;var q=this.view,s=q.high-q.low,u=
this.content_div.width(),p=[],A=$("<div class='tile' style='position: relative;'></div>");var o=this.cache.get(x,y);if(o.state=="loading"){h.addClass("loading");return null}else{h.removeClass("loading")}var b=o.values;for(var k in b){var v=b[k];var f=v[1],e=v[2],t=v[5];var g=(f-z)*m;var n=(e-z)*m;var w=n-g;var j=g;var d=p.length;for(i in p){if(p[i]<j){d=i;break}}p[d]=Math.ceil(n);var r=$("<div class='feature'></div>").css({position:"absolute",left:g,top:(d*(itemHeight+itemPad)),height:itemHeight,width:Math.max(w,1)});A.append(r)}A.css({position:"absolute",top:0,left:(z-this.view.low)*m,width:Math.ceil(a*m),height:p.length*(itemHeight+itemPad)+itemPad});h.append(A);return A}});var TrackLayout=function(a){this.view=a;this.tracks=[]};$.extend(TrackLayout.prototype,{add:function(a){this.tracks.push(a)},redraw:function(){for(var a in this.tracks){this.tracks[a].draw()}$("#overview-box").css({left:(this.view.low/this.view.length)*$("#overview-viewport").width(),width:Math.max(1,((
this.view.high-this.view.low)/this.view.length)*$("#overview-viewport").width())}).show();$("#low").text(this.view.low);$("#high").text(this.view.high)}});
\ No newline at end of file
+var DENSITY=1000;var DataCache=function(b,a){this.type=b;this.track=a;this.cache=Object()};$.extend(DataCache.prototype,{get:function(d,b){var c=this.cache;if(!(c[d]&&c[d][b])){if(!c[d]){c[d]=Object()}var a=b*DENSITY*d;var e=(b+1)*DENSITY*d;c[d][b]={state:"loading"};$.getJSON(data_url,{track_type:this.track.track_type,chrom:this.track.view.chrom,low:a,high:e,dataset_id:this.track.dataset_id},function(f){if(f=="pending"){setTimeout(fetcher,5000)}else{c[d][b]={state:"loaded",values:f}}$(document).trigger("redraw")})}return c[d][b]}});var View=function(a,b){this.chrom=a;this.tracks=[];this.max_low=0;this.max_high=b;this.low=this.max_low;this.high=this.max_high;this.length=this.max_high-this.max_low};$.extend(View.prototype,{add_track:function(a){a.view=this;this.tracks.push(a);if(a.init){a.init()}},redraw:function(){$("#overview-box").css({left:(this.low/this.length)*$("#overview-viewport").width(),width:Math.max(4,((this.high-this.low)/this.length)*$("#overview-viewport").widt
h())}).show();$("#low").text(this.low);$("#high").text(this.high);for(var a in this.tracks){this.tracks[a].draw()}$("#bottom-spacer").remove();$("#viewport").append('<div id="bottom-spacer" style="height: 200px;"></div>')},move:function(b,a){this.low=Math.max(this.max_low,Math.floor(b));this.high=Math.min(this.length,Math.ceil(a))},zoom_in:function(d,b){var c=this.high-this.low;var e=c/d/2;if(b==undefined){var a=(this.low+this.high)/2}else{var a=this.low+c*b/$(document).width()}this.low=Math.floor(a-e);this.high=Math.ceil(a+e);if(this.low<this.max_low){this.low=this.max_low;this.high=c/d}else{if(this.high>this.max_high){this.high=this.max_high;this.low=this.max_high-c/d}}if(this.high-this.low<1){this.high=this.low+1}},zoom_out:function(c){var a=(this.low+this.high)/2;var b=this.high-this.low;var d=b*c/2;this.low=Math.floor(Math.max(0,a-d));this.high=Math.ceil(Math.min(this.length,a+d))},left:function(b){var a=this.high-this.low;var c=Math.floor(a/b);if(this.low-c<0){this.low
=0;this.high=this.low+a}else{this.low-=c;this.high-=c}},right:function(b){var a=this.high-this.low;var c=Math.floor(a/b);if(this.high+c>this.length){this.high=this.length;this.low=this.high-a}else{this.low+=c;this.high+=c}}});var Track=function(a,b){this.name=a;this.parent_element=b;this.make_container()};$.extend(Track.prototype,{make_container:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div class='track'></div>").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)}});var TiledTrack=function(){this.last_resolution=null;this.last_w_scale=null;this.tile_cache={}};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var k=this.view.low,c=this.view.high,e=c-k;var b=Math.pow(10,Math.ceil(Math.log(e/DENSITY)/Math.log(10)));b=Math.max(b,1);b=Math.min(b,100000);var o=$("<div style='position: relative;'></div>");this.content_di
v.children(":first").remove();this.content_div.append(o);var m=this.content_div.width(),d=this.content_div.height(),p=m/e,l={},n={};if(this.last_resolution==b&&this.last_w_scale==p){l=this.tile_cache}var g;var a=Math.floor(k/b/DENSITY);var i=0;while((a*1000*b)<c){if(a in l){g=l[a];var f=a*DENSITY*b;g.css({left:(f-this.view.low)*p});o.append(g)}else{g=this.draw_tile(b,a,o,p,d)}if(g){n[a]=g;i=Math.max(i,g.height())}a+=1}o.css("height",i);this.last_resolution=b;this.last_w_scale=p;this.tile_cache=n}});var LineTrack=function(c,b,a){Track.call(this,c,$("#viewport"));this.track_type="line";this.height_px=(a?a:100);this.container_div.addClass("line-track");this.dataset_id=b;this.cache=new DataCache("",this)};$.extend(LineTrack.prototype,TiledTrack.prototype,{make_container:function(){Track.prototype.make_container.call(this);this.content_div.css("height",this.height_px)},init:function(){track=this;$.getJSON(data_url,{stats:true,track_type:track.track_type,chrom:this.view.chrom,low:
null,high:null,dataset_id:this.dataset_id},function(a){if(a){track.min_value=a.min;track.max_value=a.max;track.vertical_range=track.max_value-track.min_value;track.view.redraw()}})},draw_tile:function(d,a,o,s,p){if(!this.vertical_range){return}var k=a*DENSITY*d,r=(a+1)*DENSITY*d,c=DENSITY*d;var n=this.cache.get(d,a);var h;if(n.state=="loading"){h=$("<div class='loading tile'></div>")}else{h=$("<canvas class='tile'></canvas>")}h.css({position:"absolute",top:0,left:(k-this.view.low)*s,});o.append(h);if(n.state=="loading"){e=false;return null}var b=h;b.get(0).width=Math.ceil(c*s);b.get(0).height=this.height_px;var q=b.get(0).getContext("2d");var e=false;q.beginPath();var g=n.values;if(!g){return}for(var f=0;f<g.length-1;f++){var m=g[f][0]-k;var l=g[f][1];if(isNaN(l)){e=false}else{m=m*s;y_above_min=l-this.min_value;l=y_above_min/this.vertical_range*this.height_px;if(e){q.lineTo(m,l)}else{q.moveTo(m,l);e=true}}}q.stroke();return h}});var LabelTrack=function(a){Track.call(this,nul
l,a);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'>"+a+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var itemHeight=13,itemPad=3,thinHeight=7,thinOffset=3;var FeatureTrack=function(b,a){Track.call(this,b,$("#viewport"));this.track_type="feature";this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots=new Object();this.show_labels_scale=0.01;this.showing_labels=false};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{calc_slots:function(d){end_ary=new Array();var c=this.container_div.width()/(this.view.high-this.view.low);if(d){this.zi_slots=
new Object()}var b=$("<canvas></canvas>").get(0).getContext("2d");for(var a in this.values){feature=this.values[a];f_start=Math.floor(Math.max(this.view.max_low,(feature.start-this.view.max_low)*c));if(d){f_start-=b.measureText(feature.name).width}f_end=Math.ceil(Math.min(this.view.max_high,(feature.end-this.view.max_low)*c));j=0;while(true){if(end_ary[j]==undefined||end_ary[j]<f_start){end_ary[j]=f_end;if(d){this.zi_slots[feature.name]=j}else{this.zo_slots[feature.name]=j}break}j++}}},init:function(){var a=this;$.getJSON("getfeature",{start:this.view.max_low,end:this.view.max_high,dataset_id:this.dataset_id,chrom:this.view.chrom},function(b){a.values=b;a.calc_slots();a.slots=a.zo_slots;a.draw()})},draw_tile:function(q,t,e,g,f){if(!this.values){return null}if(g>this.show_labels_scale&&!this.showing_labels){this.showing_labels=true;if(!this.zi_slots){this.calc_slots(true)}this.slots=this.zi_slots}else{if(g<=this.show_labels_scale&&this.showing_labels){this.showing_labels=fals
e;this.slots=this.zo_slots}}var u=t*DENSITY*q,c=(t+1)*DENSITY*q,b=DENSITY*q;var k=this.view,m=k.high-k.low,o=Math.ceil(b*g),h=new Array(),n=200,l=$("<canvas class='tile'></canvas>");l.css({position:"absolute",top:0,left:(u-this.view.low)*g,"border-right":"1px solid #ddd"});l.get(0).width=o;l.get(0).height=n;var p=l.get(0).getContext("2d");var r=0;for(var s in this.values){feature=this.values[s];if(feature.start<=c&&feature.end>=u){f_start=Math.floor(Math.max(0,(feature.start-u)*g));f_end=Math.ceil(Math.min(o,(feature.end-u)*g));p.fillStyle="#000";p.fillRect(f_start,this.slots[feature.name]*10+5,f_end-f_start,1);if(this.showing_labels&&p.fillText){p.font="10px monospace";p.textAlign="right";p.fillText(feature.name,f_start,this.slots[feature.name]*10+8)}if(feature.exon_start&&feature.exon_end){var d=Math.floor(Math.max(0,(feature.exon_start-u)*g));var w=Math.ceil(Math.min(o,(feature.exon_end-u)*g))}for(var s in feature.blocks){block=feature.blocks[s];block_start=Math.floor(Mat
h.max(0,(block[0]-u)*g));block_end=Math.ceil(Math.min(o,(block[1]-u)*g));var a=3,v=4;if(d&&block_start>=d&&block_end<=w){a=5,v=3}p.fillRect(d,this.slots[feature.name]*10+v,block_end-block_start,a)}r++}}e.append(l);return l},});
\ No newline at end of file
diff -r 9118054983c3 -r afa7946a126c static/scripts/trackster.js
--- a/static/scripts/trackster.js Tue Sep 22 14:47:47 2009 -0400
+++ b/static/scripts/trackster.js Tue Sep 22 21:51:11 2009 -0400
@@ -1,26 +1,92 @@
+/* Trackster
+ 2009, James Taylor, Kanwei Li
+*/
+
var DENSITY = 1000;
-var BLOCK_SIZE = 1000;
+var DataCache = function( type, track ) {
+ this.type = type;
+ this.track = track;
+ this.cache = Object();
+};
+$.extend( DataCache.prototype, {
+ get: function( resolution, position ) {
+ var cache = this.cache;
+ if ( !( cache[resolution] && cache[resolution][position] ) ) {
+ if ( !cache[resolution] ) {
+ cache[resolution] = Object();
+ }
+ var low = position * DENSITY * resolution;
+ var high = ( position + 1 ) * DENSITY * resolution;
+ cache[resolution][position] = { state: "loading" };
+
+ $.getJSON( data_url, { track_type: this.track.track_type, chrom: this.track.view.chrom, low: low, high: high, dataset_id: this.track.dataset_id }, function ( data ) {
+ if( data == "pending" ) {
+ setTimeout( fetcher, 5000 );
+ } else {
+ cache[resolution][position] = { state: "loaded", values: data };
+ }
+ $(document).trigger( "redraw" );
+ });
+ }
+ return cache[resolution][position];
+ }
+});
-var log = function( x, b ) { return Math.log( x ) / Math.log( b ) }
-
-var View = function( chr, length, low, high ) {
- this.chr = chr;
- this.length = length;
- this.low = low;
- this.high = high;
+var View = function( chrom, max_length ) {
+ this.chrom = chrom;
+ this.tracks = [];
+ this.max_low = 0;
+ this.max_high = max_length;
+ this.low = this.max_low;
+ this.high = this.max_high;
+ this.length = this.max_high - this.max_low;
};
$.extend( View.prototype, {
+ add_track: function ( track ) {
+ track.view = this;
+ this.tracks.push( track );
+ if (track.init) { track.init(); }
+ },
+ redraw: function () {
+ // Overview
+ $("#overview-box").css( {
+ left: ( this.low / this.length ) * $("#overview-viewport").width(),
+ width: Math.max( 4, ( ( this.high - this.low ) / this.length ) * $("#overview-viewport").width() )
+ }).show();
+ $("#low").text( this.low );
+ $("#high").text( this.high );
+ for ( var i in this.tracks ) {
+ this.tracks[i].draw();
+ }
+ $("#bottom-spacer").remove();
+ $("#viewport").append('<div id="bottom-spacer" style="height: 200px;"></div>');
+ },
move: function ( new_low, new_high ) {
- this.low = Math.max( 0, Math.floor( new_low ) );
+ this.low = Math.max( this.max_low, Math.floor( new_low ) );
this.high = Math.min( this.length, Math.ceil( new_high ) );
},
- zoom_in: function ( factor ) {
- var center = ( this.low + this.high ) / 2;
+ zoom_in: function ( factor, point ) {
var range = this.high - this.low;
var diff = range / factor / 2;
+
+ if (point == undefined) {
+ var center = ( this.low + this.high ) / 2;
+ } else {
+ // console.log(100*point/$(document).width());
+ var center = this.low + range * point / $(document).width();
+ }
+ // console.log(center);
this.low = Math.floor( center - diff );
this.high = Math.ceil( center + diff );
+ if (this.low < this.max_low) {
+ this.low = this.max_low;
+ this.high = range / factor;
+ } else if (this.high > this.max_high) {
+ this.high = this.max_high;
+ this.low = this.max_high - range / factor;
+ // console.log(this.high, this.low);
+ }
if (this.high - this.low < 1 ) {
this.high = this.low + 1;
}
@@ -56,27 +122,21 @@
}
});
-var Track = function ( name, view, parent_element ) {
+var Track = function ( name, parent_element ) {
this.name = name;
- this.view = view;
this.parent_element = parent_element;
this.make_container();
};
$.extend( Track.prototype, {
- make_container : function () {
- this.header_div = $("<div class='track-header'>");
- this.header_div.text( this.name );
+ make_container: function () {
+ this.header_div = $("<div class='track-header'>").text( this.name );;
this.content_div = $("<div class='track-content'>");
- this.container_div = $("<div class='track'></div>");
- this.container_div.append( this.header_div );
- this.container_div.append( this.content_div );
+ this.container_div = $("<div class='track'></div>").append( this.header_div ).append( this.content_div );
this.parent_element.append( this.container_div );
}
});
-var TiledTrack = function( name, view, parent_element ) {
- Track.call( this, name, view, parent_element );
- // For caching
+var TiledTrack = function() {
this.last_resolution = null;
this.last_w_scale = null;
this.tile_cache = {};
@@ -87,23 +147,20 @@
high = this.view.high,
range = high - low;
- var resolution = Math.pow( BLOCK_SIZE, Math.floor( log( range, BLOCK_SIZE ) ) );
- // Math.pow( 10, Math.ceil( Math.log( range / DENSITY ) / Math.log( 10 ) ) );
-
- console//.log( "resolution:", resolution );
+ var resolution = Math.pow( 10, Math.ceil( Math.log( range / DENSITY ) / Math.log( 10 ) ) );
resolution = Math.max( resolution, 1 );
- resolution = Math.min( resolution, 1000000 );
+ resolution = Math.min( resolution, 100000 );
- var parent_element = $("<div style='position: relative;'></div>");
- this.content_div.children( ":first" ).remove();
- this.content_div.append( parent_element );
+ var parent_element = $("<div style='position: relative;'></div>");
+ this.content_div.children( ":first" ).remove();
+ this.content_div.append( parent_element );
var w = this.content_div.width(),
h = this.content_div.height(),
- w_scale = w / range,
- old_tiles = {},
+ w_scale = w / range,
+ old_tiles = {},
new_tiles = {};
-
+
// If resolution and scale are unchanged, try to reuse tiles
if ( this.last_resolution == resolution && this.last_w_scale == w_scale ) {
old_tiles = this.tile_cache;
@@ -125,10 +182,10 @@
// Our responsibility to move the element to the new parent
parent_element.append( tile_element );
} else {
- // console.log( "new tile" );
tile_element = this.draw_tile( resolution, tile_index, parent_element, w_scale, h );
}
if ( tile_element ) {
+ // console.log( typeof(tile_element) );
new_tiles[tile_index] = tile_element;
max_height = Math.max( max_height, tile_element.height() );
}
@@ -143,53 +200,37 @@
}
});
-var DataCache = function( type, track, view ) {
- this.type = type;
- this.track = track;
- this.view = view;
- this.cache = Object();
-};
-$.extend( DataCache.prototype, {
- get: function( resolution, position ) {
- var cache = this.cache;
- if ( ! ( cache[resolution] && cache[resolution][position] ) ) {
- if ( ! cache[resolution] ) {
- cache[resolution] = Object();
- }
- var low = position * DENSITY * resolution;
- var high = ( position + 1 ) * DENSITY * resolution;
- cache[resolution][position] = { state: "loading" };
- // use closure to preserve this and parameters for getJSON
- var fetcher = function (ref) {
- return function () {
- $.getJSON( TRACKSTER_DATA_URL, { track_type: ref.type, chrom: ref.view.chr, low: low, high: high, dataset_id: ref.track.dataset_id }, function ( data ) {
- if( data == "pending" ) {
- setTimeout( fetcher, 5000 );
- } else {
- cache[resolution][position] = { state: "loaded", values: data };
- }
- $(document).trigger( "redraw" );
- });
- };
- }(this);
- fetcher();
- }
- return cache[resolution][position];
- }
-});
-
-var LineTrack = function ( name, view, parent_element, dataset_id ) {
- Track.call( this, name, view, parent_element );
+var LineTrack = function ( name, dataset_id, height ) {
+ Track.call( this, name, $("#viewport") );
+
+ this.track_type = "line";
+ this.height_px = (height ? height : 100);
this.container_div.addClass( "line-track" );
this.dataset_id = dataset_id;
- this.cache = new DataCache( "line", this, view );
+ this.cache = new DataCache( "", this );
};
$.extend( LineTrack.prototype, TiledTrack.prototype, {
make_container: function () {
- Track.prototype.make_container.call( this );
- this.content_div.css( "height", 100 );
+ Track.prototype.make_container.call(this);
+ // console.log("height:", this.height_px);
+ this.content_div.css( "height", this.height_px );
+ },
+ init: function() {
+ track = this;
+ $.getJSON( data_url, { stats: true, track_type: track.track_type, chrom: this.view.chrom, low: null, high: null, dataset_id: this.dataset_id }, function ( data ) {
+ // console.log(data);
+ if (data) {
+ track.min_value = data['min'];
+ track.max_value = data['max'];
+ track.vertical_range = track.max_value - track.min_value;
+ track.view.redraw();
+ }
+ });
},
draw_tile: function( resolution, tile_index, parent_element, w_scale, h_scale ) {
+ if (!this.vertical_range) // We don't have the necessary information yet
+ return;
+
var tile_low = tile_index * DENSITY * resolution,
tile_high = ( tile_index + 1 ) * DENSITY * resolution,
tile_length = DENSITY * resolution;
@@ -204,71 +245,64 @@
position: "absolute",
top: 0,
left: ( tile_low - this.view.low ) * w_scale,
- width: Math.ceil( tile_length * w_scale ),
- height: 100
});
parent_element.append( element );
- // Chunk is still loading, do noting
+ // Chunk is still loading, do nothing
if ( chunk.state == "loading" ) {
in_path = false;
return null;
}
var canvas = element;
- canvas.get(0).width = canvas.width();
- canvas.get(0).height = canvas.height();
- var data = chunk.values;
- if ( data ) {
- var ctx = canvas.get(0).getContext("2d");
- var in_path = false;
- ctx.beginPath();
- // console.log( "Drawing tile" );
- for ( var i = 0; i < data.length - 1; i++ ) {
- var x1 = data[i][0] - tile_low;
- var y1 = data[i][1];
- var x2 = data[i+1][0] - tile_low;
- var y2 = data[i+1][1];
- // Missing data causes us to stop drawing
- if ( isNaN( y1 ) || isNaN( y2 ) ) {
- in_path = false;
- } else {
- // Translate
- x1 = x1 * w_scale;
- x2 = x2 * w_scale;
- y1 = h_scale - y1 * ( h_scale );
- y2 = h_scale - y2 * ( h_scale );
- if ( in_path ) {
- ctx.lineTo( x1, y1, x2, y2 );
- } else {
- ctx.moveTo( x1, y1, x2, y2 );
- in_path = true;
- }
- }
- }
- ctx.stroke();
- }
- return element;
+ canvas.get(0).width = Math.ceil( tile_length * w_scale );
+ canvas.get(0).height = this.height_px;
+ var ctx = canvas.get(0).getContext("2d");
+ var in_path = false;
+ ctx.beginPath();
+ var data = chunk.values;
+ if (!data) return;
+ for ( var i = 0; i < data.length - 1; i++ ) {
+ var x = data[i][0] - tile_low;
+ var y = data[i][1];
+ // Missing data causes us to stop drawing
+ if ( isNaN( y ) ) {
+ in_path = false;
+ } else {
+ // Translate
+ x = x * w_scale;
+ y_above_min = y - this.min_value;
+ y = y_above_min / this.vertical_range * this.height_px;
+ if ( in_path ) {
+ ctx.lineTo( x, y );
+ } else {
+ ctx.moveTo( x, y );
+ in_path = true;
+ }
+ }
+ }
+ ctx.stroke();
+ return element;
}
});
-var LabelTrack = function ( view, parent_element ) {
- Track.call( this, null, view, parent_element );
+var LabelTrack = function ( parent_element ) {
+ Track.call( this, null, parent_element );
this.container_div.addClass( "label-track" );
};
$.extend( LabelTrack.prototype, Track.prototype, {
draw: function() {
var view = this.view,
- range = view.high - view.low,
- tickDistance = Math.floor( Math.pow( 10, Math.floor( Math.log( range ) / Math.log( 10 ) ) ) ),
- position = Math.floor( view.low / tickDistance ) * tickDistance,
- width = this.content_div.width(),
- new_div = $("<div style='position: relative; height: 1.3em;'></div>");
+ range = view.high - view.low,
+ tickDistance = Math.floor( Math.pow( 10, Math.floor( Math.log( range ) / Math.log( 10 ) ) ) ),
+ position = Math.floor( view.low / tickDistance ) * tickDistance,
+ width = this.content_div.width(),
+ new_div = $("<div style='position: relative; height: 1.3em;'></div>");
while ( position < view.high ) {
var screenPosition = ( position - view.low ) / range * width;
new_div.append( $("<div class='label'>" + position + "</div>").css( {
position: "absolute",
// Reduce by one to account for border
left: screenPosition - 1
- }) );
+ }));
position += tickDistance;
}
this.content_div.children( ":first" ).remove();
@@ -281,96 +315,137 @@
thinHeight = 7,
thinOffset = 3;
-var FeatureTrack = function ( name, view, parent_element,dataset_id ) {
- Track.call( this, name, view, parent_element );
+var FeatureTrack = function ( name, dataset_id ) {
+ Track.call( this, name, $("#viewport") );
+ this.track_type = "feature";
this.container_div.addClass( "feature-track" );
this.dataset_id = dataset_id;
- this.cache = new DataCache( "", this, view );
+ this.zo_slots = new Object();
+ this.show_labels_scale = 0.01;
+ this.showing_labels = false;
};
$.extend( FeatureTrack.prototype, TiledTrack.prototype, {
- get_data_async: function() {
+
+ calc_slots: function( include_labels ) {
+ // console.log("num vals: " + this.values.length);
+ end_ary = new Array();
+ var scale = this.container_div.width() / (this.view.high - this.view.low);
+ // console.log(scale);
+ if (include_labels) this.zi_slots = new Object();
+ var dummy_canvas = $("<canvas></canvas>").get(0).getContext("2d");
+ for (var i in this.values) {
+
+ feature = this.values[i];
+ f_start = Math.floor( Math.max(this.view.max_low, (feature.start - this.view.max_low) * scale) );
+ if (include_labels) {
+ f_start -= dummy_canvas.measureText(feature.name).width;
+ }
+
+ f_end = Math.ceil( Math.min(this.view.max_high, (feature.end - this.view.max_low) * scale) );
+ // if (include_labels) { console.log(f_start, f_end); }
+ j = 0;
+ while (true) {
+ if (end_ary[j] == undefined || end_ary[j] < f_start) {
+ end_ary[j] = f_end;
+ if (include_labels) {
+ this.zi_slots[feature.name] = j;
+ } else {
+ this.zo_slots[feature.name] = j;
+ }
+ break;
+ }
+ j++;
+ }
+ }
+ },
+
+ init: function() {
var track = this;
- $.getJSON( "data", { chr: this.view.chr, dataset_id: this.dataset_id }, function ( data ) {
+ $.getJSON( "getfeature", { 'start': this.view.max_low, 'end': this.view.max_high, 'dataset_id': this.dataset_id, 'chrom': this.view.chrom }, function ( data ) {
track.values = data;
+ track.calc_slots();
+ track.slots = track.zo_slots;
+ // console.log(track.zo_slots);
track.draw();
});
},
+
draw_tile: function( resolution, tile_index, parent_element, w_scale, h_scale ) {
+ if (!this.values) // Still loading
+ return null;
+
+ if (w_scale > this.show_labels_scale && !this.showing_labels) {
+ this.showing_labels = true;
+ if (!this.zi_slots) this.calc_slots(true); // Once we zoom in enough, show name labels
+ this.slots = this.zi_slots;
+ } else if (w_scale <= this.show_labels_scale && this.showing_labels) {
+ this.showing_labels = false;
+ this.slots = this.zo_slots;
+ }
+ // console.log(this.slots);
+
var tile_low = tile_index * DENSITY * resolution,
tile_high = ( tile_index + 1 ) * DENSITY * resolution,
tile_length = DENSITY * resolution;
-
+ // console.log(tile_low, tile_high, tile_length, w_scale);
var view = this.view,
range = view.high - view.low,
- width = this.content_div.width(),
- slots = [],
- new_div = $("<div class='tile' style='position: relative;'></div>");
-
- var chunk = this.cache.get( resolution, tile_index );
- if ( chunk.state == "loading" ) {
- parent_element.addClass("loading");
- return null;
- } else {
- parent_element.removeClass("loading");
- }
- var values = chunk.values;
-
- for ( var index in values ) {
- var value = values[index];
- var start = value[1], end = value[2], strand = value[5];
- // Determine slot based on entire feature and label
- var screenStart = ( start - tile_low ) * w_scale;
- var screenEnd = ( end - tile_low ) * w_scale;
- var screenWidth = screenEnd - screenStart;
- var screenStartWithLabel = screenStart;
- // Determine slot
- var slot = slots.length;
- for ( i in slots ) {
- if ( slots[i] < screenStartWithLabel ) {
- slot = i;
- break;
- }
- }
- slots[slot] = Math.ceil( screenEnd );
- var feature_div = $("<div class='feature'></div>").css( {
- position: 'absolute',
- left: screenStart,
- top: (slot*(itemHeight+itemPad)),
- height: itemHeight,
- width: Math.max( screenWidth, 1 )
- });
- new_div.append( feature_div );
- }
- new_div.css( {
+ width = Math.ceil( tile_length * w_scale ),
+ slots = new Array(),
+ height = 200,
+ new_canvas = $("<canvas class='tile'></canvas>");
+
+ new_canvas.css({
position: "absolute",
top: 0,
left: ( tile_low - this.view.low ) * w_scale,
- width: Math.ceil( tile_length * w_scale ),
- height: slots.length * ( itemHeight + itemPad ) + itemPad
+ "border-right": "1px solid #ddd"
});
- parent_element.append( new_div );
- return new_div;
- }
+ new_canvas.get(0).width = width;
+ new_canvas.get(0).height = height;
+ // console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
+ var ctx = new_canvas.get(0).getContext("2d");
+
+ var j = 0;
+ for (var i in this.values) {
+ feature = this.values[i];
+ if (feature.start <= tile_high && feature.end >= tile_low) {
+ f_start = Math.floor( Math.max(0, (feature.start - tile_low) * w_scale) );
+ f_end = Math.ceil( Math.min(width, (feature.end - tile_low) * w_scale) );
+ // console.log(feature.start, feature.end, f_start, f_end, j);
+ ctx.fillStyle = "#000";
+ ctx.fillRect(f_start, this.slots[feature.name] * 10 + 5, f_end - f_start, 1);
+
+ if (this.showing_labels && ctx.fillText) {
+ ctx.font = "10px monospace";
+ ctx.textAlign = "right";
+ ctx.fillText(feature.name, f_start, this.slots[feature.name] * 10 + 8);
+ }
+
+ if (feature.exon_start && feature.exon_end) {
+ var exon_start = Math.floor( Math.max(0, (feature.exon_start - tile_low) * w_scale) );
+ var exon_end = Math.ceil( Math.min(width, (feature.exon_end - tile_low) * w_scale) );
+ // ctx.fillRect(exon_start, j * 10 + 3, exon_end - exon_start, 5);
+ // ctx.fillRect(exon_start, this.slots[feature.name] * 10 + 3, exon_end - exon_start, 3);
+ }
+
+ for (var i in feature.blocks) {
+ block = feature.blocks[i];
+ block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) );
+ block_end = Math.ceil( Math.min(width, (block[1] - tile_low) * w_scale) );
+ var thickness = 3, y_start = 4;
+ if (exon_start && block_start >= exon_start && block_end <= exon_end) {
+ thickness = 5, y_start = 3;
+ }
+ ctx.fillRect(exon_start, this.slots[feature.name] * 10 + y_start, block_end - block_start, thickness);
+ // console.log(block_start, block_end);
+ }
+
+ j++;
+ }
+ }
+
+ parent_element.append( new_canvas );
+ return new_canvas;
+ },
});
-
-var TrackLayout = function ( view ) {
- this.view = view;
- this.tracks = [];
-};
-$.extend( TrackLayout.prototype, {
- add: function ( track ) {
- this.tracks.push( track );
- },
- redraw : function () {
- for ( var index in this.tracks ) {
- this.tracks[index].draw();
- }
- // Overview
- $("#overview-box").css( {
- left: ( this.view.low / this.view.length ) * $("#overview-viewport").width(),
- width: Math.max( 1, ( ( this.view.high - this.view.low ) / this.view.length ) * $("#overview-viewport").width() )
- }).show();
- $("#low").text( this.view.low );
- $("#high").text( this.view.high );
- }
-});
\ No newline at end of file
diff -r 9118054983c3 -r afa7946a126c static/trackster.css
--- a/static/trackster.css Tue Sep 22 14:47:47 2009 -0400
+++ b/static/trackster.css Tue Sep 22 21:51:11 2009 -0400
@@ -3,7 +3,7 @@
padding: 0;
font-family: verdana;
font-size: 75%;
- overflow-y: scroll;
+ overflow-y: hidden;
}
#content {
@@ -15,21 +15,18 @@
}
#nav {
- padding: 1em;
position: fixed;
bottom: 0;
width: 100%;
- background: rgb( 64, 64, 64 );
+ background: #333;
color: white;
font-weight: bold;
text-align: center;
}
-#nav > div
-{
- margin: 0 0;
+#nav-controls {
+ padding: 15px 0;
}
-
#nav-controls a {
color: white;
padding: 0.1em 0.4em;
@@ -42,26 +39,30 @@
#overview {
width: 100%;
- padding: 1em 0;
- background: rgb( 64, 64, 64 );
+ padding: 10px 0 0 0;
+ margin: 0px;
+ background: #333;
color: white;
font-weight: bold;
}
#overview-viewport {
- position: relative;
height: 10px;
- border-top: solid gray 1px;
- border-bottom: solid gray 1px;
+ border-top: solid #666 1px;
+ border-bottom: solid #666 1px;
+ background: #888;
}
#overview-box {
position: absolute;
height: 10px;
- background: white;
+ background: #ddd;
}
#viewport {
- min-height: 100%;
+ overflow: hidden;
+ background-color: #fff;
+/* overflow: scroll;*/
+/* border-bottom: 2px solid black;*/
}
#viewport-canvas {
@@ -70,14 +71,12 @@
}
.track {
- border-top: solid gray 1px;
+/* border-top: solid gray 1px;*/
border-bottom: solid gray 1px;
- margin: 5px 0;
}
.track-header {
text-align: center;
- padding: 0.1 0 0.3em 0;
}
.track-content {
@@ -92,12 +91,12 @@
}
.label-track .label {
- border-left: solid grey 1px;
+ border-left: solid gray 1px;
padding-left: 2px;
}
.feature-track .feature {
- background: brown;
+
}
.feature-track .feature .forward {
diff -r 9118054983c3 -r afa7946a126c templates/tracks/browser.mako
--- a/templates/tracks/browser.mako Tue Sep 22 14:47:47 2009 -0400
+++ b/templates/tracks/browser.mako Tue Sep 22 21:51:11 2009 -0400
@@ -7,36 +7,81 @@
<%def name="javascripts()">
${parent.javascripts()}
-<script type="text/javascript" src="/static/scripts/jquery.event.drag.js"></script>
-<script type="text/javascript" src="/static/scripts/trackster.js"></script>
+${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster" )}
+
<script type="text/javascript">
- ## HACK
- TRACKSTER_DATA_URL = "${h.url_for( action='data' )}";
-
- var view = new View( "${chrom}", ${LEN}, 0, ${max(LEN,1)} );
- var tracks = new TrackLayout( view );
- var dbkey = "${dbkey}";
+ var data_url = "${h.url_for( action='data' )}";
+ var view = new View( "${chrom}", ${LEN} );
$(function() {
- tracks.add( new LabelTrack( view, $("#viewport" ) ) );
- %for track in tracks:
- tracks.add( new ${track["type"]}( "${track["name"]}", view, $("#viewport" ), ${track["id"]} ) );
- %endfor
+ view.add_track( new LabelTrack( $("#overview" ) ) );
+ view.add_track( new LabelTrack( $("#nav-labeltrack" ) ) );
+
+ %for track in tracks:
+ view.add_track( new ${track["type"]}( "${track['name']}", ${track['dataset_id']} ) );
+ %endfor
$(document).bind( "redraw", function( e ) {
- tracks.redraw();
- });
-
- $(window).resize( function( e ) {
- tracks.redraw();
+ view.redraw();
});
+ $(document).bind("mousewheel", function(e, delta) {
+ if (delta > 0) {
+ view.zoom_in(2, e.pageX);
+ view.redraw();
+ } else {
+ view.zoom_out(2);
+ view.redraw();
+ }
+ });
+
+ $(document).bind("dblclick", function(e) {
+ view.zoom_in(2, e.pageX);
+ view.redraw();
+ });
+
+ $("#overview-box").bind("dragstart", function(e) {
+ this.current_x = e.offsetX;
+ }).bind("drag", function(e) {
+ var delta = e.offsetX - this.current_x;
+ this.current_x = e.offsetX;
+
+ var delta_chrom = Math.round(delta / $(document).width() * (view.max_high - view.max_low));
+ var view_range = view.high - view.low;
+
+ var new_low = view.low += delta_chrom;
+ var new_high = view.high += delta_chrom;
+ if (new_low < view.max_low) {
+ new_low = 0;
+ new_high = view_range;
+ } else if (new_high > view.max_high) {
+ new_high = view.max_high;
+ new_low = view.max_high - view_range;
+ }
+ view.low = new_low;
+ view.high = new_high;
+ view.redraw();
+ });
+
+ $(window).resize( function( e ) {
+ $("#viewport").height( $(window).height() - 120 );
+ view.redraw();
+ });
+
$("#viewport").bind( "dragstart", function ( e ) {
this.original_low = view.low;
+ this.current_height = e.clientY;
}).bind( "drag", function( e ) {
var move_amount = ( e.offsetX - this.offsetLeft ) / this.offsetWidth;
+ var new_scroll = $(this).scrollTop() - (e.clientY - this.current_height);
+
+ if ( new_scroll < $(this).get(0).scrollHeight - $(this).height() - 200) {
+ $(this).scrollTop(new_scroll);
+
+ }
+ this.current_height = e.clientY;
var range = view.high - view.low;
var move_bases = Math.round( range * move_amount );
var new_low = this.original_low - move_bases;
@@ -50,83 +95,58 @@
}
view.low = new_low;
view.high = new_high;
- tracks.redraw();
+ view.redraw();
});
- tracks.redraw();
- load_chroms();
+ (function () {
+ $.getJSON( "${h.url_for( action='chroms' )}", { dbkey: "${dbkey}" }, function ( data ) {
+ var chrom_options = '<option value=""></option>';
+ for (i in data) {
+ chrom = data[i]['chrom']
+ if( chrom == view.chrom ) {
+ chrom_options += '<option value="' + chrom + '" selected="true">' + chrom + '</option>';
+ } else {
+ chrom_options += '<option value="' + chrom + '">' + chrom + '</option>';
+ }
+ }
+ $("#chrom").html(chrom_options);
+ $("#chrom").bind( "change", function () {
+ $("#chr").submit();
+ });
+ });
+ })();
+ view.redraw();
+ $(window).trigger("resize");
});
-
- var load_chroms = function () {
- var fetcher = function (ref) {
- return function () {
- $.getJSON( "${h.url_for( action='chroms' )}", { dbkey: dbkey }, function ( data ) {
- // Hacky - check length of "object"
- var chrom_length = 0;
- for (key in data) chrom_length++;
- if( chrom_length == 0 ) {
- setTimeout( fetcher, 5000 );
- } else {
- var chrom_options = '';
- for (key in data) {
- if( key == view.chr ) {
- chrom_options += '<option value="' + key + '" selected="true">' + key + '</option>';
- } else {
- chrom_options += '<option value="' + key + '">' + key + '</option>';
- }
- }
- $("#chrom").html(chrom_options);
- $("#chrom").bind( "change", function ( e ) {
- $("#chr").submit();
- });
- if( view.chr == "" ) {
- $("#chrom option:first").attr("selected", true);
- $("#chrom").trigger( "change" );
- }
- }
- });
- };
- }(this);
- fetcher();
- };
</script>
</%def>
+<div id="content">
+ <div id="overview">
+ <div id="overview-viewport">
+ <div id="overview-box"></div>
+ </div>
+ </div>
+ <div id="viewport"></div>
+</div>
+<div id="nav">
+ <div id="nav-labeltrack"></div>
+ <div id="nav-controls">
+ <form name="chr" id="chr" method="get">
+ <input type="hidden" name="dataset_ids" value="${dataset_ids}" />
+ <a href="#" onclick="javascript:view.left(5);view.redraw();"><<</a>
+ <a href="#" onclick="javascript:view.left(2);view.redraw();"><</a>
+ <select id="chrom" name="chrom">
+ <option value="">Loading</option>
+ </select>
+ <span id="low">0</span>—<span id="high">${LEN}</span>
+ <span style="display: inline-block; width: 10em;">
+ <a href="#" onclick="javascript:view.zoom_in(2);view.redraw();">+</a>
+ <a href="#" onclick="javascript:view.zoom_out(2);view.redraw();">-</a>
+ </span>
-<div id="content">
-
- <div id="overview">
- <div id="overview-viewport">
- <div id="overview-box"></div>
- </div>
+ <a href="#" onclick="javascript:view.right(2);view.redraw();">></a>
+ <a href="#" onclick="javascript:view.right(5);view.redraw();">>></a>
+ </form>
</div>
-
-
- <div id="viewport">
- </div>
-
</div>
- <div id="nav">
-
- <div id="nav-controls">
- <form name="chr" id="chr" method="GET">
- <input type="hidden" name="dataset_ids" value="${dataset_ids}" />
- <a href="#" onclick="javascript:view.left(5);tracks.redraw();"><<</a>
- <a href="#" onclick="javascript:view.left(2);tracks.redraw();"><</a>
- <span style="display: inline-block; width: 30em; text-align: center;">Viewing
- <select id="chrom" name="chrom">
- <option value="">loading</option>
- </select>
- <span id="low">0</span>-<span id="high">180857866</span></span>
- <span style="display: inline-block; width: 10em;">
- <a href="#" onclick="javascript:view.zoom_in(2);tracks.redraw();">+</a>
- <a href="#" onclick="javascript:view.zoom_out(2);tracks.redraw();">-</a>
- </span>
-
- <a href="#" onclick="javascript:view.right(2);tracks.redraw();">></a>
- <a href="#" onclick="javascript:view.right(5);tracks.redraw();">>></a>
- </form>
- </div>
-
- </div>
-
diff -r 9118054983c3 -r afa7946a126c templates/tracks/new_browser.mako
--- a/templates/tracks/new_browser.mako Tue Sep 22 14:47:47 2009 -0400
+++ b/templates/tracks/new_browser.mako Tue Sep 22 21:51:11 2009 -0400
@@ -12,39 +12,38 @@
</%def>
<div class="form">
- <div class="form-title">Select datasets to include in browser</div>
- <div id="dbkey" class="form-body">
- <form id="form" method="POST">
- <div class="form-row">
- <label for="dbkey">Reference genome build (dbkey): </label>
- <div class="form-row-input">
- <select name="dbkey" id="dbkey" refresh_on_change="true">
- %for tmp_dbkey in dbkey_set:
- <option value="${tmp_dbkey}"
- %if tmp_dbkey == dbkey:
- selected="true"
- %endif
- >${tmp_dbkey}</option>
- %endfor
- </select>
- </div>
- <div style="clear: both;"></div>
- </div>
- <div class="form-row">
- <label for="dataset_ids">Datasets to include: </label>
- %for key,value in datasets.items():
- <div>
- <input type="checkbox" name="dataset_ids" value="${key}" />
- ${value}
- </div>
- %endfor
-
- <div style="clear: both;"></div>
- </div>
- </div>
- <div class="form-row">
- <input type="submit" name="browse" value="Browse"/>
- </div>
+ <div class="form-title">Select datasets to include in browser</div>
+ <div id="dbkey" class="form-body">
+ <form id="form" method="POST">
+ <div class="form-row">
+ <label for="dbkey">Reference genome build (dbkey): </label>
+ <div class="form-row-input">
+ <select name="dbkey" id="dbkey" refresh_on_change="true">
+ %for tmp_dbkey in dbkey_set:
+ <option value="${tmp_dbkey}"
+ %if tmp_dbkey == dbkey:
+ selected="true"
+ %endif
+ >${tmp_dbkey}</option>
+ %endfor
+ </select>
+ </div>
+ <div style="clear: both;"></div>
+ </div>
+ <div class="form-row">
+ <label for="dataset_ids">Datasets to include: </label>
+ %for key,value in datasets.items():
+ <div>
+ <input type="checkbox" name="dataset_ids" value="${key}" />
+ ${value}
+ </div>
+ %endfor
+
+ <div style="clear: both;"></div>
+ </div>
+ </div>
+ <div class="form-row">
+ <input type="submit" name="browse" value="Browse"/>
+ </div>
</form>
- </div>
</div>
1
0