galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 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
- 15302 discussions
commit/galaxy-central: dannon: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
by commits-noreply@bitbucket.org 26 Aug '14
by commits-noreply@bitbucket.org 26 Aug '14
26 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b7fb63b19736/
Changeset: b7fb63b19736
User: dannon
Date: 2014-08-26 17:26:31
Summary: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
Workflow UUIDs
Affected #: 6 files
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,8 +4,9 @@
from __future__ import absolute_import
+import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -432,11 +433,23 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/e9152659a0be/
Changeset: e9152659a0be
Branch: workflow-uuid
User: kellrott
Date: 2014-08-20 23:10:43
Summary: Refactoring work to add in Workflow UUIDs
Affected #: 6 files
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,6 +4,7 @@
from __future__ import absolute_import
+import uuid
import logging
from sqlalchemy import desc, or_
from galaxy import exceptions, util
@@ -437,6 +438,17 @@
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r b6ae7b6283c30bcb58e87003066102bfa5af5e11 -r e9152659a0be5e932e6eea591bd6c99977983854 scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
https://bitbucket.org/galaxy/galaxy-central/commits/80dfc96a9666/
Changeset: 80dfc96a9666
Branch: workflow-uuid
User: kellrott
Date: 2014-08-20 23:27:56
Summary: Fixing some small bugs to get the code to work
Affected #: 1 file
diff -r e9152659a0be5e932e6eea591bd6c99977983854 -r 80dfc96a96665052fdd213b77008d88c6935506b lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -6,7 +6,7 @@
import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -433,8 +433,8 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
@@ -447,6 +447,7 @@
)).first()
if stored_workflow is None:
raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
except:
pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
https://bitbucket.org/galaxy/galaxy-central/commits/b7fb63b19736/
Changeset: b7fb63b19736
User: dannon
Date: 2014-08-26 17:26:31
Summary: Merged in kellrott/galaxy-farm/workflow-uuid (pull request #471)
Workflow UUIDs
Affected #: 6 files
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -2974,6 +2974,7 @@
tag_str += ":" + tag.user_value
tags_str_list.append( tag_str )
rval['tags'] = tags_str_list
+ rval['latest_workflow_uuid'] = ( lambda uuid: str( uuid ) if self.latest_workflow.uuid else None )( self.latest_workflow.uuid )
return rval
@@ -2982,12 +2983,16 @@
dict_collection_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
dict_element_visible_keys = ( 'name', 'has_cycles', 'has_errors' )
- def __init__( self ):
+ def __init__( self, uuid=None ):
self.user = None
self.name = None
self.has_cycles = None
self.has_errors = None
self.steps = []
+ if uuid is None:
+ self.uuid = uuid4()
+ else:
+ self.uuid = UUID(str(uuid))
def has_outputs_defined(self):
"""
@@ -2998,6 +3003,11 @@
return True
return False
+ def to_dict( self, view='collection', value_mapper=None):
+ rval = super( Workflow, self ).to_dict( view=view, value_mapper = value_mapper )
+ rval['uuid'] = ( lambda uuid: str( uuid ) if uuid else None )( self.uuid )
+ return rval
+
class WorkflowStep( object ):
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/mapping.py
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -690,7 +690,8 @@
Column( "stored_workflow_id", Integer, ForeignKey( "stored_workflow.id" ), index=True, nullable=False ),
Column( "name", TEXT ),
Column( "has_cycles", Boolean ),
- Column( "has_errors", Boolean )
+ Column( "has_errors", Boolean ),
+ Column( "uuid", UUIDType, nullable=True )
)
model.WorkflowStep.table = Table( "workflow_step", metadata,
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0121_workflow_uuids.py
@@ -0,0 +1,55 @@
+"""
+Add UUIDs to workflows
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+from galaxy.model.custom_types import UUIDType, TrimmedString
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData()
+
+
+
+"""
+Because both workflow and job requests can be determined
+based the a fixed data structure, their IDs are based on
+hashing the data structure
+"""
+workflow_uuid_column = Column( "uuid", UUIDType, nullable=True )
+
+
+def display_migration_details():
+ print "This migration script adds a UUID column to workflows"
+
+def upgrade(migrate_engine):
+ print __doc__
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Add the uuid colum to the workflow table
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid_column.create( workflow_table )
+ assert workflow_uuid_column is workflow_table.c.uuid
+ except Exception, e:
+ print str(e)
+ log.error( "Adding column 'uuid' to workflow table failed: %s" % str( e ) )
+ return
+
+def downgrade(migrate_engine):
+ metadata.bind = migrate_engine
+ metadata.reflect()
+
+ # Drop the workflow table's uuid column.
+ try:
+ workflow_table = Table( "workflow", metadata, autoload=True )
+ workflow_uuid = workflow_table.c.uuid
+ workflow_uuid.drop()
+ except Exception, e:
+ log.debug( "Dropping 'uuid' column from workflow table failed: %s" % ( str( e ) ) )
+
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -1791,6 +1791,8 @@
data['format-version'] = "0.1"
data['name'] = workflow.name
data['annotation'] = annotation_str
+ if workflow.uuid is not None:
+ data['uuid'] = str(workflow.uuid)
data['steps'] = {}
# For each step, rebuild the form and encode the state
for step in workflow.steps:
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e lib/galaxy/webapps/galaxy/api/workflows.py
--- a/lib/galaxy/webapps/galaxy/api/workflows.py
+++ b/lib/galaxy/webapps/galaxy/api/workflows.py
@@ -4,8 +4,9 @@
from __future__ import absolute_import
+import uuid
import logging
-from sqlalchemy import desc, or_
+from sqlalchemy import desc, or_, and_
from galaxy import exceptions, util
from galaxy.model.item_attrs import UsesAnnotations
from galaxy.managers import histories
@@ -432,11 +433,23 @@
return stored_workflow
def __get_stored_workflow( self, trans, workflow_id ):
- workflow_id = self.__decode_id( trans, workflow_id )
try:
+ workflow_id = self.__decode_id( trans, workflow_id )
query = trans.sa_session.query( trans.app.model.StoredWorkflow )
stored_workflow = query.get( workflow_id )
except Exception:
+ try:
+ #see if they have passed in the UUID for a workflow that is attached to a stored workflow
+ workflow_uuid = uuid.UUID(workflow_id)
+ stored_workflow = trans.sa_session.query(trans.app.model.StoredWorkflow).filter( and_(
+ trans.app.model.StoredWorkflow.latest_workflow_id == trans.app.model.Workflow.id,
+ trans.app.model.Workflow.uuid == workflow_uuid
+ )).first()
+ if stored_workflow is None:
+ raise exceptions.ObjectNotFound( "Workflow not found: %s" % workflow_id )
+ return stored_workflow
+ except:
+ pass #let the outer raise exception happen
raise exceptions.ObjectNotFound( "No such workflow found - invalid workflow identifier." )
if stored_workflow is None:
raise exceptions.ObjectNotFound( "No such workflow found." )
diff -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea -r b7fb63b197362424b39c2cc73d1589a0e383443e scripts/cleanup_datasets/populate_uuid.py
--- a/scripts/cleanup_datasets/populate_uuid.py
+++ b/scripts/cleanup_datasets/populate_uuid.py
@@ -33,6 +33,12 @@
row.uuid = uuid.uuid4()
print "Setting dataset:", row.id, " UUID to ", row.uuid
model.context.flush()
+
+ for row in model.context.query( model.Workflow ):
+ if row.uuid is None:
+ row.uuid = uuid.uuid4()
+ print "Setting Workflow:", row.id, " UUID to ", row.uuid
+ model.context.flush()
if __name__ == "__main__":
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
5 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/567d72ce3a8b/
Changeset: 567d72ce3a8b
User: dannon
Date: 2014-08-26 16:28:00
Summary: Merge 'recent jobs' view from PR466/467. Work in progress.
Affected #: 2 files
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1089,6 +1089,11 @@
trans.app.model.Job.state == trans.app.model.Job.states.RUNNING,
trans.app.model.Job.state == trans.app.model.Job.states.UPLOAD ) ) ) \
.order_by( trans.app.model.Job.table.c.update_time.desc() )
+ recent_jobs = trans.sa_session.query( trans.app.model.Job ) \
+ .filter( and_( trans.app.model.Job.table.c.update_time > cutoff_time,
+ or_( trans.app.model.Job.state == trans.app.model.Job.states.ERROR,
+ trans.app.model.Job.state == trans.app.model.Job.states.OK) ) ) \
+ .order_by( trans.app.model.Job.table.c.update_time.desc() )
last_updated = {}
for job in jobs:
delta = datetime.utcnow() - job.update_time
@@ -1096,14 +1101,35 @@
last_updated[job.id] = '%s hours' % int( delta.seconds / 60 / 60 )
else:
last_updated[job.id] = '%s minutes' % int( delta.seconds / 60 )
+ finished = {}
+ for job in recent_jobs:
+ delta = datetime.utcnow() - job.update_time
+ if delta > timedelta( minutes=60 ):
+ finished[job.id] = '%s hours' % int( delta.seconds / 60 / 60 )
+ else:
+ finished[job.id] = '%s minutes' % int( delta.seconds / 60 )
return trans.fill_template( '/admin/jobs.mako',
jobs = jobs,
+ recent_jobs = recent_jobs,
last_updated = last_updated,
+ finished = finished,
cutoff = cutoff,
msg = msg,
status = status,
job_lock = job_lock)
+
+ @web.expose
+ @web.require_admin
+ def job_info( self, trans, jobid=None ):
+ job = None
+ if jobid is not None:
+ job = trans.sa_session.query( trans.app.model.Job ).get(jobid)
+ return trans.fill_template( '/webapps/reports/job_info.mako',
+ job=job,
+ message="<a href='jobs'>Back</a>" )
+
+
## ---- Utility methods -------------------------------------------------------
def get_user( trans, user_id ):
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -109,6 +109,52 @@
<div class="infomessage">There are no unfinished jobs to show with current cutoff time.</div><p/>
%endif
+
+%if recent_jobs:
+ <p>
+ Recent Jobs: These jobs have completed
+ </p>
+ <table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr class="header">
+ <td>Job ID</td>
+ <td>User</td>
+ <td>Finished</td>
+ <td>Tool</td>
+ <td>State</td>
+ <td>Inputs</td>
+ <td>Command Line</td>
+ <td>Job Runner</td>
+ <td>PID/Cluster ID</td>
+ </tr>
+ %for job in recent_jobs:
+ <td><a href="${h.url_for( controller="admin", action="job_info" )}?jobid=${job.id}">${job.id}</a></td>
+ %if job.history and job.history.user:
+ <td>${job.history.user.email}</td>
+ %else:
+ <td>anonymous</td>
+ %endif
+ <td>${finished[job.id]} ago</td>
+ <td>${job.tool_id}</td>
+ <td>${job.state}</td>
+ <%
+ try:
+ inputs = ", ".join( [ '%s %s' % ( da.dataset.id, da.dataset.state ) for da in job.input_datasets ] )
+ except:
+ inputs = 'Unable to determine inputs'
+ %>
+ <td>${inputs}</td>
+ <td>${job.command_line}</td>
+ <td>${job.job_runner_name}</td>
+ <td>${job.job_runner_external_id}</td>
+ </tr>
+ %endfor
+ </table>
+ <p/>
+%else:
+ <div class="infomessage">There are no recently finished jobs to show with current cutoff time.</div>
+ <p/>
+%endif
+
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST"><div class="toolForm"><div class="toolFormTitle">
https://bitbucket.org/galaxy/galaxy-central/commits/44fe3904feb4/
Changeset: 44fe3904feb4
User: dannon
Date: 2014-08-26 16:28:38
Summary: Remove extra p tag from jobs admin.
Affected #: 1 file
diff -r 567d72ce3a8b4ab3d07e677692d04499bf4c4e36 -r 44fe3904feb44dd465f79934f999bc5c3bf99cc7 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -33,9 +33,6 @@
report this error".
</p>
-
-<p/>
-
%if jobs:
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST"><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%">
https://bitbucket.org/galaxy/galaxy-central/commits/81e2b1d1984e/
Changeset: 81e2b1d1984e
User: dannon
Date: 2014-08-26 16:34:31
Summary: Fix (old) bug causing Jobs grid to display even when there were no jobs to show in it. Issue was 'jobs' (and the new recent_jobs) was actually a Query object and not an empty list of results, causing 'if jobs' to evaluate True regardless of whether or not there were jobs.
Affected #: 1 file
diff -r 44fe3904feb44dd465f79934f999bc5c3bf99cc7 -r 81e2b1d1984e8f4bcdd2d1f82055e815cbced985 lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1088,12 +1088,12 @@
trans.app.model.Job.state == trans.app.model.Job.states.QUEUED,
trans.app.model.Job.state == trans.app.model.Job.states.RUNNING,
trans.app.model.Job.state == trans.app.model.Job.states.UPLOAD ) ) ) \
- .order_by( trans.app.model.Job.table.c.update_time.desc() )
+ .order_by( trans.app.model.Job.table.c.update_time.desc() ).all()
recent_jobs = trans.sa_session.query( trans.app.model.Job ) \
.filter( and_( trans.app.model.Job.table.c.update_time > cutoff_time,
or_( trans.app.model.Job.state == trans.app.model.Job.states.ERROR,
trans.app.model.Job.state == trans.app.model.Job.states.OK) ) ) \
- .order_by( trans.app.model.Job.table.c.update_time.desc() )
+ .order_by( trans.app.model.Job.table.c.update_time.desc() ).all()
last_updated = {}
for job in jobs:
delta = datetime.utcnow() - job.update_time
https://bitbucket.org/galaxy/galaxy-central/commits/314326446ec5/
Changeset: 314326446ec5
User: dannon
Date: 2014-08-26 16:48:12
Summary: Clarify wording, explain cutoff. Add headers to better segment the page and prevent confusion between the two grids.
Affected #: 1 file
diff -r 81e2b1d1984e8f4bcdd2d1f82055e815cbced985 -r 314326446ec51483341eaacae7902fff44c8ac02 templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -22,9 +22,11 @@
%endif
<p>
- All unfinished jobs are displayed here. To display only jobs that have not
- had their job state updated recently, set a cutoff value in the 'cutoff'
- box below.
+ Unfinished and recently finished jobs are displayed on this page. The
+ 'cutoff' input box will do two things -- it will limit the display of
+ unfinished jobs to only those jobs that have not had their job state
+ updated recently, and it will limit the recently finished jobs list to only
+ displaying jobs that have finished since the cutoff.
</p><p>
If any jobs are displayed, you may choose to stop them. Your stop message
@@ -35,6 +37,9 @@
%if jobs:
<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST">
+ <h4>
+ Unfinished Jobs: These jobs are unfinished and have had their state updated in the previous ${cutoff} seconds.
+ </h4><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><td><input type="checkbox" onClick="toggle_all(this)"/></td>
@@ -108,9 +113,9 @@
%endif
%if recent_jobs:
- <p>
- Recent Jobs: These jobs have completed
- </p>
+ <h4>
+ Recent Jobs: These jobs have completed in the previous ${cutoff} seconds.
+ </h4><table class="manage-table colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><td>Job ID</td>
https://bitbucket.org/galaxy/galaxy-central/commits/3a51eaf209f2/
Changeset: 3a51eaf209f2
User: dannon
Date: 2014-08-26 16:48:35
Summary: Merge.
Affected #: 11 files
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e4d21621ce12e13ebbdf9fd3259df58c3ef124c latest_2014.08.11
+7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,7 +24,7 @@
from galaxy.web.framework import form
from galaxy.web.framework.helpers import grids, time_ago
from galaxy.web.framework.helpers import to_unicode
-from galaxy.workflow.modules import module_factory
+from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
from galaxy.workflow.extract import summarize
@@ -836,8 +836,8 @@
steps_by_external_id = {}
errors = []
for key, step_dict in data['steps'].iteritems():
- is_input = step_dict[ 'type' ] in [ 'data_input', 'data_collection_input' ]
- if not is_input and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
+ is_tool = is_tool_module_type( step_dict[ 'type' ] )
+ if is_tool and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
errors.append("Step %s requires tool '%s'." % (step_dict['id'], step_dict['tool_id']))
if errors:
return dict( name=workflow.name,
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -71,9 +71,18 @@
## ---- Configuration time -----------------------------------------------
def get_state( self ):
+ """ Return a serializable representation of the persistable state of
+ the step - for tools it DefaultToolState.encode returns a string and
+ for inputs a json description is dumped out.
+ """
return None
def get_errors( self ):
+ """ It seems like this is effectively just used as boolean - some places
+ in the tool shed self.errors is set to boolean, other places 'unavailable',
+ likewise in Galaxy it stores a list containing a string with an unrecognized
+ tool id error message.
+ """
return None
def get_data_inputs( self ):
@@ -292,6 +301,9 @@
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans, tool_id )
+ if module.tool is None:
+ error_message = "Attempted to create new workflow module for invalid tool_id, no tool with id - %s." % tool_id
+ raise Exception( error_message )
module.state = module.tool.new_state( trans, all_pages=True )
return module
@@ -536,5 +548,14 @@
type = step.type
return self.module_types[type].from_workflow_step( trans, step )
-module_types = dict( data_input=InputDataModule, data_collection_input=InputDataCollectionModule, tool=ToolModule )
+
+def is_tool_module_type( module_type ):
+ return not module_type or module_type == "tool"
+
+
+module_types = dict(
+ data_input=InputDataModule,
+ data_collection_input=InputDataCollectionModule,
+ tool=ToolModule,
+)
module_factory = WorkflowModuleFactory( module_types )
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -71,7 +71,7 @@
self.trans.sa_session.add( workflow_invocation )
# Not flushing in here, because web controller may create multiple
- # invokations.
+ # invocations.
return self.outputs
def _invoke_step( self, step ):
@@ -211,10 +211,9 @@
"""
replacement = None
if prefixed_name in step.input_connections_by_name:
- outputs = self.outputs
connection = step.input_connections_by_name[ prefixed_name ]
if input.multiple:
- replacement = [ outputs[ c.output_step.id ][ c.output_name ] for c in connection ]
+ replacement = [ self._replacement_for_connection( c ) for c in connection ]
# If replacement is just one dataset collection, replace tool
# input with dataset collection - tool framework will extract
# datasets properly.
@@ -222,9 +221,12 @@
if isinstance( replacement[ 0 ], model.HistoryDatasetCollectionAssociation ):
replacement = replacement[ 0 ]
else:
- replacement = outputs[ connection[ 0 ].output_step.id ][ connection[ 0 ].output_name ]
+ replacement = self._replacement_for_connection( connection[ 0 ] )
return replacement
+ def _replacement_for_connection( self, connection ):
+ return self.outputs[ connection.output_step.id ][ connection.output_name ]
+
def _populate_state( self ):
# Build the state for each step
for step in self.workflow.steps:
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid].slot:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/packed/viz/trackster/slotting.js
--- a/static/scripts/packed/viz/trackster/slotting.js
+++ b/static/scripts/packed/viz/trackster/slotting.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(b){var e=b.extend;var c=2,a=5;var d=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(d.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(c+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}});return{FeatureSlotter:d}});
\ No newline at end of file
+define(["libs/underscore"],function(c){var f=c.extend;var d=2,b=5;var a=function(h,g){this.slot=h;this.feature=g};var e=function(j,i,g,h){this.slots={};this.start_end_dct={};this.w_scale=j;this.mode=i;this.include_label=(i==="Pack");this.max_rows=g;this.measureText=h};f(e.prototype,{_get_draw_coords:function(j){var h=Math.floor(j[1]*this.w_scale),i=Math.ceil(j[2]*this.w_scale),g=j[3],k;if(g!==undefined&&this.include_label){var l=this.measureText(g).width+(d+b);if(h-l>=0){h-=l;k="left"}else{i+=l;k="right"}}return[h,i]},_find_slot:function(j){var o=j[0],n=j[1];for(var l=0;l<=this.max_rows;l++){var p=false,m=this.start_end_dct[l];if(m!==undefined){for(var g=0,h=m.length;g<h;g++){var i=m[g];if(n>i[0]&&o<i[1]){p=true;break}}}if(!p){return l}}return -1},slot_features:function(h){var q=this.start_end_dct,v=[],m=0,x,l;for(var o=0,t=h.length;o<t;o++){x=h[o];l=x[0];var g=this.slots[l];if(g){if(x[1]<g.feature[1]||g.feature[2]<x[2]){console.log(x[3],g.slot,this._find_slot(this._get_draw_coords(x)));var s=this._get_draw_coords(g.feature),p=this._get_draw_coords(x),j=this.start_end_dct[g.slot];for(var n=0;n<j.length;n++){var w=j[n];if(w[0]===s[0]&&w[1]===s[1]){j[n]=p}}}m=Math.max(m,this.slots[l].slot)}else{v.push(o)}}for(var o=0,t=v.length;o<t;o++){x=h[v[o]];l=x[0];var r=this._get_draw_coords(x);var u=this._find_slot(r);if(u>=0){if(q[u]===undefined){q[u]=[]}q[u].push(r);this.slots[l]=new a(u,x);m=Math.max(m,u)}}return m+1}});return{FeatureSlotter:e}});
\ No newline at end of file
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -396,7 +396,7 @@
feature_end = feature[2],
// Slot valid only if features are slotted and this feature is slotted;
// feature may not be due to lack of space.
- slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
+ slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid].slot : null);
// Draw feature if (a) mode is dense or feature is slotted (as it must be for all non-dense modes) and
// (b) there's overlap between the feature and drawing region.
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea static/scripts/viz/trackster/slotting.js
--- a/static/scripts/viz/trackster/slotting.js
+++ b/static/scripts/viz/trackster/slotting.js
@@ -7,6 +7,14 @@
PACK_SPACING = 5;
/**
+ * Hold slotting information for a feature.
+ */
+var SlottedInfo = function(slot, feature) {
+ this.slot = slot;
+ this.feature = feature;
+};
+
+/**
* FeatureSlotter determines slots in which to draw features for vertical
* packing.
*
@@ -28,118 +36,148 @@
* the largest slot required for the passed set of features is returned
*/
extend( FeatureSlotter.prototype, {
+ /**
+ * Get drawing coordinate for a feature.
+ */
+ _get_draw_coords: function(feature) {
+ // Get initial draw coordinates using w_scale.
+ var draw_start = Math.floor(feature[1] * this.w_scale),
+ draw_end = Math.ceil(feature[2] * this.w_scale),
+ f_name = feature[3],
+ text_align;
+
+ // Update start, end drawing locations to include feature name.
+ // Try to put the name on the left, if not, put on right.
+ if (f_name !== undefined && this.include_label ) {
+ // Add gap for label spacing and extra pack space padding
+ // TODO: Fix constants
+ var text_len = this.measureText(f_name).width + (LABEL_SPACING + PACK_SPACING);
+ if (draw_start - text_len >= 0) {
+ draw_start -= text_len;
+ text_align = "left";
+ } else {
+ draw_end += text_len;
+ text_align = "right";
+ }
+ }
+
+ /*
+ if (slot_num < 0) {
+
+ TODO: this is not yet working --
+ console.log(feature_uid, "looking for slot with text on the right");
+ // Slot not found. If text was on left, try on right and see
+ // if slot can be found.
+ // TODO: are there any checks we need to do to ensure that text
+ // will fit on tile?
+ if (text_align === "left") {
+ draw_start -= text_len;
+ draw_end -= text_len;
+ text_align = "right";
+ slot_num = find_slot(draw_start, draw_end);
+ }
+ if (slot_num >= 0) {
+ console.log(feature_uid, "found slot with text on the right");
+ }
+
+ }
+ */
+
+ return [draw_start, draw_end];
+ },
+
+ /**
+ * Find the first slot such that current feature doesn't overlap any other features in that slot.
+ * Returns -1 if no slot was found.
+ */
+ _find_slot: function(draw_coords) {
+ // TODO: Use a data structure for faster searching of available slots.
+ var draw_start = draw_coords[0],
+ draw_end = draw_coords[1];
+ for (var slot_num = 0; slot_num <= this.max_rows; slot_num++) {
+ var has_overlap = false,
+ slot = this.start_end_dct[slot_num];
+ if (slot !== undefined) {
+ // Iterate through features already in slot to see if current feature will fit.
+ for (var k = 0, k_len = slot.length; k < k_len; k++) {
+ var s_e = slot[k];
+ if (draw_end > s_e[0] && draw_start < s_e[1]) {
+ // There is overlap
+ has_overlap = true;
+ break;
+ }
+ }
+ }
+ if (!has_overlap) {
+ return slot_num;
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Slot features.
+ */
slot_features: function( features ) {
- var w_scale = this.w_scale,
- start_end_dct = this.start_end_dct,
+ var start_end_dct = this.start_end_dct,
undone = [],
- slotted = [],
- highest_slot = 0,
- max_rows = this.max_rows;
-
- // If feature already exists in slots (from previously seen tiles), use the same slot,
- // otherwise if not seen, add to "undone" list for slot calculation.
-
- // TODO: Should calculate zoom tile index, which will improve performance
- // by only having to look at a smaller subset
- // if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
+ highest_slot = 0,
+ feature,
+ feature_uid;
+
+ // Loop through features to (a) find those that are not yet slotted and (b) update
+ // those that are slotted if new information is availabe. For (a), features already
+ // slotted (based on slotting from other tiles) will retain their current slot.
for (var i = 0, len = features.length; i < len; i++) {
- var feature = features[i],
- feature_uid = feature[0];
- if (this.slots[feature_uid] !== undefined) {
- highest_slot = Math.max(highest_slot, this.slots[feature_uid]);
- slotted.push(this.slots[feature_uid]);
- } else {
+ feature = features[i];
+ feature_uid = feature[0];
+ var slotted_info = this.slots[feature_uid];
+
+ // Separate and handle slotted vs. unslotted features.
+ if (slotted_info) {
+ // Feature is slotted; if feature now has larger start/end coordinates,
+ // update drawing coordinates.
+ if (feature[1] < slotted_info.feature[1] || slotted_info.feature[2] < feature[2]) {
+ console.log(feature[3], slotted_info.slot, this._find_slot(this._get_draw_coords(feature)));
+ // Feature has changed (e.g. a single read now has its pair), so recalculate its
+ // drawing coordinates.
+ var old_draw_coords = this._get_draw_coords(slotted_info.feature),
+ new_draw_coords = this._get_draw_coords(feature),
+ slotted_coords = this.start_end_dct[slotted_info.slot];
+ for (var k = 0; k < slotted_coords.length; k++) {
+ var dc = slotted_coords[k];
+ if (dc[0] === old_draw_coords[0] && dc[1] === old_draw_coords[1]) {
+ // Replace old drawing coordinates with new ones.
+ slotted_coords[k] = new_draw_coords;
+ }
+ }
+ }
+ highest_slot = Math.max(highest_slot, this.slots[feature_uid].slot);
+ }
+ else {
undone.push(i);
}
}
-
+
// Slot unslotted features.
- // Find the first slot such that current feature doesn't overlap any other features in that slot.
- // Returns -1 if no slot was found.
- var find_slot = function(f_start, f_end) {
- // TODO: Fix constants
- for (var slot_num = 0; slot_num <= max_rows; slot_num++) {
- var has_overlap = false,
- slot = start_end_dct[slot_num];
- if (slot !== undefined) {
- // Iterate through features already in slot to see if current feature will fit.
- for (var k = 0, k_len = slot.length; k < k_len; k++) {
- var s_e = slot[k];
- if (f_end > s_e[0] && f_start < s_e[1]) {
- // There is overlap
- has_overlap = true;
- break;
- }
- }
- }
- if (!has_overlap) {
- return slot_num;
- }
- }
- return -1;
- };
-
// Do slotting.
for (var i = 0, len = undone.length; i < len; i++) {
- var feature = features[undone[i]],
- feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- feature_name = feature[3],
- // Where to start, end drawing on screen.
- f_start = Math.floor( feature_start * w_scale ),
- f_end = Math.ceil( feature_end * w_scale ),
- text_len = this.measureText(feature_name).width,
- text_align;
-
- // Update start, end drawing locations to include feature name.
- // Try to put the name on the left, if not, put on right.
- if (feature_name !== undefined && this.include_label ) {
- // Add gap for label spacing and extra pack space padding
- // TODO: Fix constants
- text_len += (LABEL_SPACING + PACK_SPACING);
- if (f_start - text_len >= 0) {
- f_start -= text_len;
- text_align = "left";
- } else {
- f_end += text_len;
- text_align = "right";
- }
- }
+ feature = features[undone[i]];
+ feature_uid = feature[0];
+ var draw_coords = this._get_draw_coords(feature);
// Find slot.
- var slot_num = find_slot(f_start, f_end);
+ var slot_num = this._find_slot(draw_coords);
- /*
- if (slot_num < 0) {
-
- TODO: this is not yet working --
- console.log(feature_uid, "looking for slot with text on the right");
- // Slot not found. If text was on left, try on right and see
- // if slot can be found.
- // TODO: are there any checks we need to do to ensure that text
- // will fit on tile?
- if (text_align === "left") {
- f_start -= text_len;
- f_end -= text_len;
- text_align = "right";
- slot_num = find_slot(f_start, f_end);
- }
- if (slot_num >= 0) {
- console.log(feature_uid, "found slot with text on the right");
- }
-
- }
- */
// Do slotting.
if (slot_num >= 0) {
// Add current feature to slot.
if (start_end_dct[slot_num] === undefined) {
start_end_dct[slot_num] = [];
}
- start_end_dct[slot_num].push([f_start, f_end]);
- this.slots[feature_uid] = slot_num;
+ start_end_dct[slot_num].push(draw_coords);
+ this.slots[feature_uid] = new SlottedInfo(slot_num, feature);
highest_slot = Math.max(highest_slot, slot_num);
}
}
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea test/unit/workflows/test_modules.py
--- /dev/null
+++ b/test/unit/workflows/test_modules.py
@@ -0,0 +1,39 @@
+from galaxy import eggs
+eggs.require( "mock" )
+
+
+import mock
+
+from galaxy.workflow import modules
+from .workflow_support import MockTrans
+
+
+def test_input_has_no_errors():
+ trans = MockTrans()
+ input_step_module = modules.module_factory.new( trans, 'data_input' )
+ assert not input_step_module.get_errors()
+
+
+def test_valid_new_tool_has_no_errors():
+ trans = MockTrans()
+ mock_tool = mock.Mock()
+ trans.app.toolbox.tools[ "cat1" ] = mock_tool
+ tool_module = modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ assert not tool_module.get_errors()
+
+
+def test_missing_tool_has_errors():
+ trans = MockTrans()
+ tool_dict = { "type": "tool", "tool_id": "cat1" }
+ tool_module = modules.module_factory.from_dict( trans, tool_dict )
+ assert tool_module.get_errors()
+
+
+def test_cannot_create_tool_modules_for_missing_tools():
+ trans = MockTrans()
+ exception = False
+ try:
+ modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ except Exception:
+ exception = True
+ assert exception
diff -r 314326446ec51483341eaacae7902fff44c8ac02 -r 3a51eaf209f2502bf32dbb421ecabb7fe46243ea test/unit/workflows/workflow_support.py
--- a/test/unit/workflows/workflow_support.py
+++ b/test/unit/workflows/workflow_support.py
@@ -17,3 +17,14 @@
"sqlite:///:memory:",
create_tables=True
)
+ self.toolbox = TestToolbox()
+
+
+class TestToolbox( object ):
+
+ def __init__( self ):
+ self.tools = {}
+
+ def get_tool( self, tool_id ):
+ # Real tool box returns None of missing tool also
+ return self.tools.get( tool_id, None )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/94e8e0d8bb6c/
Changeset: 94e8e0d8bb6c
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Doc spelling fix in lib/galaxy/workflow/run.py.
Affected #: 1 file
diff -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -71,7 +71,7 @@
self.trans.sa_session.add( workflow_invocation )
# Not flushing in here, because web controller may create multiple
- # invokations.
+ # invocations.
return self.outputs
def _invoke_step( self, step ):
https://bitbucket.org/galaxy/galaxy-central/commits/d15f9a1b4782/
Changeset: d15f9a1b4782
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Some very basic unit tests and docs for workflow modules.
Just a start - I need to keep going with this and test and document all methods.
Affected #: 3 files
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -71,9 +71,18 @@
## ---- Configuration time -----------------------------------------------
def get_state( self ):
+ """ Return a serializable representation of the persistable state of
+ the step - for tools it DefaultToolState.encode returns a string and
+ for inputs a json description is dumped out.
+ """
return None
def get_errors( self ):
+ """ It seems like this is effectively just used as boolean - some places
+ in the tool shed self.errors is set to boolean, other places 'unavailable',
+ likewise in Galaxy it stores a list containing a string with an unrecognized
+ tool id error message.
+ """
return None
def get_data_inputs( self ):
@@ -292,6 +301,9 @@
@classmethod
def new( Class, trans, tool_id=None ):
module = Class( trans, tool_id )
+ if module.tool is None:
+ error_message = "Attempted to create new workflow module for invalid tool_id, no tool with id - %s." % tool_id
+ raise Exception( error_message )
module.state = module.tool.new_state( trans, all_pages=True )
return module
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec test/unit/workflows/test_modules.py
--- /dev/null
+++ b/test/unit/workflows/test_modules.py
@@ -0,0 +1,39 @@
+from galaxy import eggs
+eggs.require( "mock" )
+
+
+import mock
+
+from galaxy.workflow import modules
+from .workflow_support import MockTrans
+
+
+def test_input_has_no_errors():
+ trans = MockTrans()
+ input_step_module = modules.module_factory.new( trans, 'data_input' )
+ assert not input_step_module.get_errors()
+
+
+def test_valid_new_tool_has_no_errors():
+ trans = MockTrans()
+ mock_tool = mock.Mock()
+ trans.app.toolbox.tools[ "cat1" ] = mock_tool
+ tool_module = modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ assert not tool_module.get_errors()
+
+
+def test_missing_tool_has_errors():
+ trans = MockTrans()
+ tool_dict = { "type": "tool", "tool_id": "cat1" }
+ tool_module = modules.module_factory.from_dict( trans, tool_dict )
+ assert tool_module.get_errors()
+
+
+def test_cannot_create_tool_modules_for_missing_tools():
+ trans = MockTrans()
+ exception = False
+ try:
+ modules.module_factory.new( trans, 'tool', tool_id="cat1" )
+ except Exception:
+ exception = True
+ assert exception
diff -r 94e8e0d8bb6c2d9d4a941ba5706a057570f25741 -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec test/unit/workflows/workflow_support.py
--- a/test/unit/workflows/workflow_support.py
+++ b/test/unit/workflows/workflow_support.py
@@ -17,3 +17,14 @@
"sqlite:///:memory:",
create_tables=True
)
+ self.toolbox = TestToolbox()
+
+
+class TestToolbox( object ):
+
+ def __init__( self ):
+ self.tools = {}
+
+ def get_tool( self, tool_id ):
+ # Real tool box returns None of missing tool also
+ return self.tools.get( tool_id, None )
https://bitbucket.org/galaxy/galaxy-central/commits/abcccd35b958/
Changeset: abcccd35b958
User: jmchilton
Date: 2014-08-26 16:02:49
Summary: Couple simple refactors making it slightly cleaner to create new module types.
Also slightly reduces shared logic galaxy.workflow.run.
Affected #: 3 files
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/webapps/galaxy/controllers/workflow.py
--- a/lib/galaxy/webapps/galaxy/controllers/workflow.py
+++ b/lib/galaxy/webapps/galaxy/controllers/workflow.py
@@ -24,7 +24,7 @@
from galaxy.web.framework import form
from galaxy.web.framework.helpers import grids, time_ago
from galaxy.web.framework.helpers import to_unicode
-from galaxy.workflow.modules import module_factory
+from galaxy.workflow.modules import module_factory, is_tool_module_type
from galaxy.workflow.run import invoke
from galaxy.workflow.run import WorkflowRunConfig
from galaxy.workflow.extract import summarize
@@ -836,8 +836,8 @@
steps_by_external_id = {}
errors = []
for key, step_dict in data['steps'].iteritems():
- is_input = step_dict[ 'type' ] in [ 'data_input', 'data_collection_input' ]
- if not is_input and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
+ is_tool = is_tool_module_type( step_dict[ 'type' ] )
+ if is_tool and step_dict['tool_id'] not in trans.app.toolbox.tools_by_id:
errors.append("Step %s requires tool '%s'." % (step_dict['id'], step_dict['tool_id']))
if errors:
return dict( name=workflow.name,
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/workflow/modules.py
--- a/lib/galaxy/workflow/modules.py
+++ b/lib/galaxy/workflow/modules.py
@@ -548,5 +548,14 @@
type = step.type
return self.module_types[type].from_workflow_step( trans, step )
-module_types = dict( data_input=InputDataModule, data_collection_input=InputDataCollectionModule, tool=ToolModule )
+
+def is_tool_module_type( module_type ):
+ return not module_type or module_type == "tool"
+
+
+module_types = dict(
+ data_input=InputDataModule,
+ data_collection_input=InputDataCollectionModule,
+ tool=ToolModule,
+)
module_factory = WorkflowModuleFactory( module_types )
diff -r d15f9a1b4782e55c5619932c7fabf97052d5a6ec -r abcccd35b958bbbf3ad97debe029b8c5452f5d32 lib/galaxy/workflow/run.py
--- a/lib/galaxy/workflow/run.py
+++ b/lib/galaxy/workflow/run.py
@@ -211,10 +211,9 @@
"""
replacement = None
if prefixed_name in step.input_connections_by_name:
- outputs = self.outputs
connection = step.input_connections_by_name[ prefixed_name ]
if input.multiple:
- replacement = [ outputs[ c.output_step.id ][ c.output_name ] for c in connection ]
+ replacement = [ self._replacement_for_connection( c ) for c in connection ]
# If replacement is just one dataset collection, replace tool
# input with dataset collection - tool framework will extract
# datasets properly.
@@ -222,9 +221,12 @@
if isinstance( replacement[ 0 ], model.HistoryDatasetCollectionAssociation ):
replacement = replacement[ 0 ]
else:
- replacement = outputs[ connection[ 0 ].output_step.id ][ connection[ 0 ].output_name ]
+ replacement = self._replacement_for_connection( connection[ 0 ] )
return replacement
+ def _replacement_for_connection( self, connection ):
+ return self.outputs[ connection.output_step.id ][ connection.output_name ]
+
def _populate_state( self ):
# Build the state for each step
for step in self.workflow.steps:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Update tag latest_2014.08.11 for changeset 9a4b43021fd1
by commits-noreply@bitbucket.org 26 Aug '14
by commits-noreply@bitbucket.org 26 Aug '14
26 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/51de5214e6f9/
Changeset: 51de5214e6f9
Branch: stable
User: natefoo
Date: 2014-08-26 15:00:14
Summary: Update tag latest_2014.08.11 for changeset 9a4b43021fd1
Affected #: 1 file
diff -r 9a4b43021fd1c5808c17329da7b6acbfd9ae27ed -r 51de5214e6f9e59b9bad5a05ae6a79d6e8944a9e .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
+9a4b43021fd1c5808c17329da7b6acbfd9ae27ed latest_2014.08.11
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
26 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0dc11a77b3cd/
Changeset: 0dc11a77b3cd
User: jmchilton
Date: 2014-08-25 21:35:45
Summary: Merge latest stable.
Affected #: 6 files
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a .hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -18,4 +18,4 @@
81fbe25bd02edcd53065e8e4476dd1dfb5a72cf2 latest_2013.11.04
2a756ca2cb1826db7796018e77d12e2dd7b67603 latest_2014.02.10
ca45b78adb4152fc6e7395514d46eba6b7d0b838 release_2014.08.11
-7e4d21621ce12e13ebbdf9fd3259df58c3ef124c latest_2014.08.11
+7e22f35798522100ff03e1fdd4eced962b292360 latest_2014.08.11
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/packed/viz/trackster/painters.js
--- a/static/scripts/packed/viz/trackster/painters.js
+++ b/static/scripts/packed/viz/trackster/painters.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid]:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
+define(["libs/underscore"],function(_){var BEFORE=1001,CONTAINS=1002,OVERLAP_START=1003,OVERLAP_END=1004,CONTAINED_BY=1005,AFTER=1006;var compute_overlap=function(first_region,second_region){var first_start=first_region[0],first_end=first_region[1],second_start=second_region[0],second_end=second_region[1],overlap;if(first_start<second_start){if(first_end<=second_start){overlap=BEFORE}else{if(first_end<=second_end){overlap=OVERLAP_START}else{overlap=CONTAINS}}}else{if(first_start>second_end){overlap=AFTER}else{if(first_end<=second_end){overlap=CONTAINED_BY}else{overlap=OVERLAP_END}}}return overlap};var is_overlap=function(first_region,second_region){var overlap=compute_overlap(first_region,second_region);return(overlap!==BEFORE&&overlap!==AFTER)};var dashedLine=function(ctx,x1,y1,x2,y2,dashLen){if(dashLen===undefined){dashLen=4}var dX=x2-x1;var dY=y2-y1;var dashes=Math.floor(Math.sqrt(dX*dX+dY*dY)/dashLen);var dashX=dX/dashes;var dashY=dY/dashes;var q;for(q=0;q<dashes;q++,x1+=dashX,y1+=dashY){if(q%2!==0){continue}ctx.fillRect(x1,y1,dashLen,1)}};var drawDownwardEquilateralTriangle=function(ctx,down_vertex_x,down_vertex_y,side_len){var x1=down_vertex_x-side_len/2,x2=down_vertex_x+side_len/2,y=down_vertex_y-Math.sqrt(side_len*3/2);ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.lineTo(down_vertex_x,down_vertex_y);ctx.lineTo(x1,y);ctx.strokeStyle=this.fillStyle;ctx.fill();ctx.stroke();ctx.closePath()};var Scaler=function(default_val){this.default_val=(default_val?default_val:1)};Scaler.prototype.gen_val=function(input){return this.default_val};var DrawResults=function(options){this.incomplete_features=options.incomplete_features;this.feature_mapper=options.feature_mapper};var Painter=function(data,view_start,view_end,prefs,mode){this.data=data;this.view_start=view_start;this.view_end=view_end;this.prefs=_.extend({},this.default_prefs,prefs);this.mode=mode};Painter.prototype.default_prefs={};Painter.prototype.draw=function(ctx,width,height,w_scale){};var LinePainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);if(this.prefs.min_value===undefined){this.prefs.min_value=_.min(_.map(this.data,function(d){return d[1]}))||0}if(this.prefs.max_value===undefined){this.prefs.max_value=_.max(_.map(this.data,function(d){return d[1]}))||0}};LinePainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Histogram",color:"#000",overflow_color:"#F66"};LinePainter.prototype.draw=function(ctx,width,height,w_scale){var in_path=false,min_value=this.prefs.min_value,max_value=this.prefs.max_value,vertical_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data;ctx.save();var y_zero=Math.round(height+min_value/vertical_range*height);if(mode!=="Intensity"){ctx.fillStyle="#aaa";ctx.fillRect(0,y_zero,width,1)}ctx.beginPath();var x_scaled,y,delta_x_px;if(data.length>1){delta_x_px=Math.ceil((data[1][0]-data[0][0])*w_scale)}else{delta_x_px=10}var painter_color=this.prefs.block_color||this.prefs.color,pref_color=parseInt(painter_color.slice(1),16),pref_r=(pref_color&16711680)>>16,pref_g=(pref_color&65280)>>8,pref_b=pref_color&255,top_overflow=false,bot_overflow=false;for(var i=0,len=data.length;i<len;i++){ctx.fillStyle=ctx.strokeStyle=painter_color;top_overflow=bot_overflow=false;x_scaled=Math.ceil((data[i][0]-view_start)*w_scale);y=data[i][1];if(y===null){if(in_path&&mode==="Filled"){ctx.lineTo(x_scaled,height_px)}in_path=false;continue}if(y<min_value){bot_overflow=true;y=min_value}else{if(y>max_value){top_overflow=true;y=max_value}}if(mode==="Histogram"){y=Math.round(y/vertical_range*height_px);ctx.fillRect(x_scaled,y_zero,delta_x_px,-y)}else{if(mode==="Intensity"){var saturation=(y-min_value)/vertical_range,new_r=Math.round(pref_r+(255-pref_r)*(1-saturation)),new_g=Math.round(pref_g+(255-pref_g)*(1-saturation)),new_b=Math.round(pref_b+(255-pref_b)*(1-saturation));ctx.fillStyle="rgb("+new_r+","+new_g+","+new_b+")";ctx.fillRect(x_scaled,0,delta_x_px,height_px)}else{y=Math.round(height_px-(y-min_value)/vertical_range*height_px);if(in_path){ctx.lineTo(x_scaled,y)}else{in_path=true;if(mode==="Filled"){ctx.moveTo(x_scaled,height_px);ctx.lineTo(x_scaled,y)}else{ctx.moveTo(x_scaled,y)}}}}ctx.fillStyle=this.prefs.overflow_color;if(top_overflow||bot_overflow){var overflow_x;if(mode==="Histogram"||mode==="Intensity"){overflow_x=delta_x_px}else{x_scaled-=2;overflow_x=4}if(top_overflow){ctx.fillRect(x_scaled,0,overflow_x,3)}if(bot_overflow){ctx.fillRect(x_scaled,height_px-3,overflow_x,3)}}ctx.fillStyle=painter_color}if(mode==="Filled"){if(in_path){ctx.lineTo(x_scaled,y_zero);ctx.lineTo(0,y_zero)}ctx.fill()}else{ctx.stroke()}ctx.restore()};var FeaturePositionMapper=function(slot_height){this.feature_positions={};this.slot_height=slot_height;this.translation=0;this.y_translation=0};FeaturePositionMapper.prototype.map_feature_data=function(feature_data,slot,x_start,x_end){if(!this.feature_positions[slot]){this.feature_positions[slot]=[]}this.feature_positions[slot].push({data:feature_data,x_start:x_start,x_end:x_end})};FeaturePositionMapper.prototype.get_feature_data=function(x,y){var slot=Math.floor((y-this.y_translation)/this.slot_height),feature_dict;if(!this.feature_positions[slot]){return null}x+=this.translation;for(var i=0;i<this.feature_positions[slot].length;i++){feature_dict=this.feature_positions[slot][i];if(x>=feature_dict.x_start&&x<=feature_dict.x_end){return feature_dict.data}}};var FeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){Painter.call(this,data,view_start,view_end,prefs,mode);this.alpha_scaler=(alpha_scaler?alpha_scaler:new Scaler());this.height_scaler=(height_scaler?height_scaler:new Scaler());this.max_label_length=200};FeaturePainter.prototype.default_prefs={block_color:"#FFF",connector_color:"#FFF"};_.extend(FeaturePainter.prototype,{get_required_height:function(rows_required,width){var required_height=this.get_row_height(),y_scale=required_height,mode=this.mode;if(mode==="no_detail"||mode==="Squish"||mode==="Pack"){required_height=rows_required*y_scale}return required_height+this.get_top_padding(width)},get_top_padding:function(width){return 0},draw:function(ctx,width,height,w_scale,slots){var data=this.data,view_start=this.view_start,view_end=this.view_end;ctx.save();ctx.fillStyle=this.prefs.block_color;ctx.textAlign="right";var y_scale=this.get_row_height(),feature_mapper=new FeaturePositionMapper(y_scale),x_draw_coords,incomplete_features=[];for(var i=0,len=data.length;i<len;i++){var feature=data[i],feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],slot=(slots&&slots[feature_uid]!==undefined?slots[feature_uid].slot:null);if((this.mode==="Dense"||slot!==null)&&(feature_start<view_end&&feature_end>view_start)){x_draw_coords=this.draw_element(ctx,this.mode,feature,slot,view_start,view_end,w_scale,y_scale,width);feature_mapper.map_feature_data(feature,slot,x_draw_coords[0],x_draw_coords[1]);if(feature_start<view_start||feature_end>view_end){incomplete_features.push(feature)}}}ctx.restore();feature_mapper.y_translation=this.get_top_padding(width);return new DrawResults({incomplete_features:incomplete_features,feature_mapper:feature_mapper})},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){return[0,0]}});var DENSE_TRACK_HEIGHT=10,NO_DETAIL_TRACK_HEIGHT=3,SQUISH_TRACK_HEIGHT=5,PACK_TRACK_HEIGHT=10,NO_DETAIL_FEATURE_HEIGHT=1,DENSE_FEATURE_HEIGHT=9,SQUISH_FEATURE_HEIGHT=3,PACK_FEATURE_HEIGHT=9,LABEL_SPACING=2,CONNECTOR_COLOR="#ccc";var LinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.draw_background_connector=true;this.draw_individual_connectors=false};_.extend(LinkedFeaturePainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="no_detail"){height=NO_DETAIL_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}}return height},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],feature_strand=feature[4],f_start=Math.floor(Math.max(0,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),draw_start=f_start,draw_end=f_end,y_start=(mode==="Dense"?0:(0+slot))*y_scale+this.get_top_padding(width),thickness,y_start,thick_start=null,thick_end=null,block_color=(!feature_strand||feature_strand==="+"||feature_strand==="."?this.prefs.block_color:this.prefs.reverse_strand_color);label_color=this.prefs.label_color;ctx.globalAlpha=this.alpha_scaler.gen_val(feature);if(mode==="Dense"){slot=1}if(mode==="no_detail"){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+5,f_end-f_start,NO_DETAIL_FEATURE_HEIGHT)}else{var feature_ts=feature[5],feature_te=feature[6],feature_blocks=feature[7],full_height=true;if(feature_ts&&feature_te){thick_start=Math.floor(Math.max(0,(feature_ts-tile_low)*w_scale));thick_end=Math.ceil(Math.min(width,Math.max(0,(feature_te-tile_low)*w_scale)))}var thin_height,thick_height;if(mode==="Squish"){thin_height=1;thick_height=SQUISH_FEATURE_HEIGHT;full_height=false}else{if(mode==="Dense"){thin_height=5;thick_height=DENSE_FEATURE_HEIGHT}else{thin_height=5;thick_height=PACK_FEATURE_HEIGHT}}if(!feature_blocks){ctx.fillStyle=block_color;ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height);if(feature_strand&&full_height){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}ctx.fillRect(f_start,y_start+1,f_end-f_start,thick_height)}}else{var cur_y_start,cur_height;if(mode==="Squish"||mode==="Dense"){cur_y_start=y_start+Math.floor(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}else{if(feature_strand){cur_y_start=y_start;cur_height=thick_height}else{cur_y_start+=(SQUISH_FEATURE_HEIGHT/2)+1;cur_height=1}}if(this.draw_background_connector){if(mode==="Squish"||mode==="Dense"){ctx.fillStyle=CONNECTOR_COLOR}else{if(feature_strand){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand")}}}else{ctx.fillStyle=CONNECTOR_COLOR}}ctx.fillRect(f_start,cur_y_start,f_end-f_start,cur_height)}var start_and_height;for(var k=0,k_len=feature_blocks.length;k<k_len;k++){var block=feature_blocks[k],block_start=Math.floor(Math.max(0,(block[0]-tile_low-0.5)*w_scale)),block_end=Math.ceil(Math.min(width,Math.max((block[1]-tile_low-0.5)*w_scale))),last_block_start,last_block_end;if(block_start>block_end){continue}ctx.fillStyle=block_color;ctx.fillRect(block_start,y_start+(thick_height-thin_height)/2+1,block_end-block_start,thin_height);if(thick_start!==undefined&&feature_te>feature_ts&&!(block_start>thick_end||block_end<thick_start)){var block_thick_start=Math.max(block_start,thick_start),block_thick_end=Math.min(block_end,thick_end);ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height);if(feature_blocks.length===1&&mode==="Pack"){if(feature_strand==="+"){ctx.fillStyle=ctx.canvas.manager.get_pattern("right_strand_inv")}else{if(feature_strand==="-"){ctx.fillStyle=ctx.canvas.manager.get_pattern("left_strand_inv")}}if(block_thick_start+14<block_thick_end){block_thick_start+=2;block_thick_end-=2}ctx.fillRect(block_thick_start,y_start+1,block_thick_end-block_thick_start,thick_height)}}if(this.draw_individual_connectors&&last_block_start){this.draw_connector(ctx,last_block_start,last_block_end,block_start,block_end,y_start)}last_block_start=block_start;last_block_end=block_end}if(mode==="Pack"){ctx.globalAlpha=1;ctx.fillStyle="white";var hscale_factor=this.height_scaler.gen_val(feature),new_height=Math.ceil(thick_height*hscale_factor),ws_height=Math.round((thick_height-new_height)/2);if(hscale_factor!==1){ctx.fillRect(f_start,cur_y_start+1,f_end-f_start,ws_height);ctx.fillRect(f_start,cur_y_start+thick_height-ws_height+1,f_end-f_start,ws_height)}}}ctx.globalAlpha=1;if(feature_name&&mode==="Pack"&&feature_start>tile_low){ctx.fillStyle=label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+8,this.max_label_length);draw_end+=ctx.measureText(feature_name).width+LABEL_SPACING}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+8,this.max_label_length);draw_start-=ctx.measureText(feature_name).width+LABEL_SPACING}}}ctx.globalAlpha=1;return[draw_start,draw_end]}});var ReadPainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler,ref_seq,base_color_fn){FeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.ref_seq=(ref_seq?ref_seq.data:null);this.base_color_fn=base_color_fn};_.extend(ReadPainter.prototype,FeaturePainter.prototype,{get_row_height:function(){var height,mode=this.mode;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT;if(this.prefs.show_insertions){height*=2}}}return height},_parse_cigar:function(cigar_str){var cigar_ops="MIDNSHP=X";var blocks=[[0,0]],cur_block=blocks[0],base_pos=0,parsed_cigar=_.map(cigar_str.match(/[0-9]+[MIDNSHP=X]/g),function(op){var op_len=parseInt(op.slice(0,-1),10),op_char=op.slice(-1);if(op_char==="N"){if(cur_block[1]!==0){cur_block=[base_pos+op_len,base_pos+op_len];blocks.push(cur_block)}}else{if("ISHP".indexOf(op_char)===-1){cur_block[1]+=op_len;base_pos+=op_len}}return[cigar_ops.indexOf(op_char),op_len]});return{blocks:blocks,cigar:parsed_cigar}},draw_read:function(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,cigar,strand,read_seq){var update_base_offset=function(offset,cig_op,cig_len){if("M=NXD".indexOf(cig_op)!==-1){offset+=cig_len}return offset},update_seq_offset=function(offset,cig_op,cig_len){if("IX".indexOf(cig_op)!==-1){offset+=cig_len}return offset},get_draw_coord=function(sequence_coord){return Math.floor(Math.max(0,(sequence_coord-tile_low-0.5)*w_scale))};ctx.textAlign="center";var tile_region=[tile_low,tile_high],base_offset=0,seq_offset=0,gap=Math.round(w_scale/2),char_width_px=ctx.canvas.manager.char_width_px,block_color=(strand==="+"?this.prefs.detail_block_color:this.prefs.reverse_strand_color),pack_mode=(mode==="Pack"),draw_height=(pack_mode?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),rect_y=y_start+1,paint_utils=new ReadPainterUtils(ctx,draw_height,w_scale,mode),drawing_blocks=[],s_start,s_end;var draw_last=[];var t=this._parse_cigar(cigar);cigar=t.cigar;drawing_blocks=t.blocks;for(var i=0;i<drawing_blocks.length;i++){var block=drawing_blocks[i];if(is_overlap([feature_start+block[0],feature_start+block[1]],tile_region)){s_start=get_draw_coord(feature_start+block[0]);s_end=get_draw_coord(feature_start+block[1]);if(s_start===s_end){s_end+=1}ctx.fillStyle=block_color;ctx.fillRect(s_start,rect_y,s_end-s_start,draw_height)}}for(var cig_id=0,len=cigar.length;cig_id<len;cig_id++){var cig=cigar[cig_id],cig_op="MIDNSHP=X"[cig[0]],cig_len=cig[1];var seq_start=feature_start+base_offset;s_start=get_draw_coord(seq_start);s_end=get_draw_coord(seq_start+cig_len);if(!is_overlap([seq_start,seq_start+cig_len],tile_region)){base_offset=update_base_offset(base_offset,cig_op,cig_len);seq_offset=update_seq_offset(seq_offset,cig_op,cig_len);continue}if(s_start===s_end){s_end+=1}switch(cig_op){case"H":case"S":case"P":break;case"M":base_offset+=cig_len;break;case"=":case"X":var cur_seq="";if(cig_op==="X"){cur_seq=read_seq.slice(seq_offset,seq_offset+cig_len)}else{if(this.ref_seq){cur_seq=this.ref_seq.slice(Math.max(0,seq_start-tile_low),Math.min(seq_start-tile_low+cig_len,tile_high-tile_low))}}var start_pos=Math.max(seq_start,tile_low);for(var c=0;c<cur_seq.length;c++){if(cur_seq&&!this.prefs.show_differences||cig_op==="X"){var c_start=Math.floor(Math.max(0,(start_pos+c-tile_low)*w_scale));ctx.fillStyle=this.base_color_fn(cur_seq[c]);if(pack_mode&&w_scale>char_width_px){ctx.fillText(cur_seq[c],c_start,y_start+9)}else{if(w_scale>0.05){ctx.fillRect(c_start-gap,rect_y,Math.max(1,Math.round(w_scale)),draw_height)}}}}if(cig_op==="X"){seq_offset+=cig_len}base_offset+=cig_len;break;case"N":ctx.fillStyle=CONNECTOR_COLOR;ctx.fillRect(s_start,rect_y+(draw_height-1)/2,s_end-s_start,1);base_offset+=cig_len;break;case"D":paint_utils.draw_deletion(s_start,rect_y,cig_len);base_offset+=cig_len;break;case"I":var insert_x_coord=s_start-gap;if(is_overlap([seq_start,seq_start+cig_len],tile_region)){var seq=read_seq.slice(seq_offset,seq_offset+cig_len);if(this.prefs.show_insertions){var x_center=s_start-(s_end-s_start)/2;if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){ctx.fillStyle="yellow";ctx.fillRect(x_center-gap,y_start-9,s_end-s_start,9);draw_last[draw_last.length]={type:"triangle",data:[insert_x_coord,y_start+4,5]};ctx.fillStyle=CONNECTOR_COLOR;switch(compute_overlap([seq_start,seq_start+cig_len],tile_region)){case (OVERLAP_START):seq=seq.slice(tile_low-seq_start);break;case (OVERLAP_END):seq=seq.slice(0,seq_start-tile_high);break;case (CONTAINED_BY):break;case (CONTAINS):seq=seq.slice(tile_low-seq_start,seq_start-tile_high);break}for(var c=0,str_len=seq.length;c<str_len;c++){var c_start=Math.floor(Math.max(0,(seq_start+c-tile_low)*w_scale));ctx.fillText(seq[c],c_start-(s_end-s_start)/2,y_start)}}else{ctx.fillStyle="yellow";ctx.fillRect(x_center,y_start+(this.mode!=="Dense"?2:5),s_end-s_start,(mode!=="Dense"?SQUISH_FEATURE_HEIGHT:DENSE_FEATURE_HEIGHT))}}else{if((mode==="Pack"||this.mode==="Auto")&&read_seq!==undefined&&w_scale>char_width_px){draw_last.push({type:"text",data:[seq.length,insert_x_coord,y_start+9]})}else{}}}seq_offset+=cig_len;break}}ctx.fillStyle="yellow";var item,type,data;for(var i=0;i<draw_last.length;i++){item=draw_last[i];type=item.type;data=item.data;if(type==="text"){ctx.save();ctx.font="bold "+ctx.font;ctx.fillText(data[0],data[1],data[2]);ctx.restore()}else{if(type==="triangle"){drawDownwardEquilateralTriangle(ctx,data[0],data[1],data[2])}}}},draw_element:function(ctx,mode,feature,slot,tile_low,tile_high,w_scale,y_scale,width){var feature_uid=feature[0],feature_start=feature[1],feature_end=feature[2],feature_name=feature[3],f_start=Math.floor(Math.max(-0.5*w_scale,(feature_start-tile_low-0.5)*w_scale)),f_end=Math.ceil(Math.min(width,Math.max(0,(feature_end-tile_low-0.5)*w_scale))),y_start=(mode==="Dense"?0:(0+slot))*y_scale,draw_height=(mode==="Pack"?PACK_FEATURE_HEIGHT:SQUISH_FEATURE_HEIGHT),label_color=this.prefs.label_color;if(feature[5] instanceof Array){var connector=true;if(feature[4][1]>=tile_low&&feature[4][0]<=tile_high&&feature[4][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[4][0],feature[4][2],feature[4][3],feature[4][4])}else{connector=false}if(feature[5][1]>=tile_low&&feature[5][0]<=tile_high&&feature[5][2]){this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature[5][0],feature[5][2],feature[5][3],feature[5][4])}else{connector=false}var b1_end=Math.ceil(Math.min(width,Math.max(-0.5*w_scale,(feature[4][1]-tile_low-0.5)*w_scale))),b2_start=Math.floor(Math.max(-0.5*w_scale,(feature[5][0]-tile_low-0.5)*w_scale));if(connector&&b2_start>b1_end){ctx.fillStyle=CONNECTOR_COLOR;var line_height=y_start+1+(draw_height-1)/2;dashedLine(ctx,b1_end,line_height,b2_start,line_height)}}else{this.draw_read(ctx,mode,w_scale,y_start,tile_low,tile_high,feature_start,feature[4],feature[5],feature[6])}if(mode==="Pack"&&feature_start>=tile_low&&feature_name!=="."){ctx.fillStyle=this.prefs.label_color;if(tile_low===0&&f_start-ctx.measureText(feature_name).width<0){ctx.textAlign="left";ctx.fillText(feature_name,f_end+LABEL_SPACING,y_start+9,this.max_label_length)}else{ctx.textAlign="right";ctx.fillText(feature_name,f_start-LABEL_SPACING,y_start+9,this.max_label_length)}}return[0,0]}});var ArcLinkedFeaturePainter=function(data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler){LinkedFeaturePainter.call(this,data,view_start,view_end,prefs,mode,alpha_scaler,height_scaler);this.longest_feature_length=this.calculate_longest_feature_length();this.draw_background_connector=false;this.draw_individual_connectors=true};_.extend(ArcLinkedFeaturePainter.prototype,FeaturePainter.prototype,LinkedFeaturePainter.prototype,{calculate_longest_feature_length:function(){var longest_feature_length=0;for(var i=0,len=this.data.length;i<len;i++){var feature=this.data[i],feature_start=feature[1],feature_end=feature[2];longest_feature_length=Math.max(longest_feature_length,feature_end-feature_start)}return longest_feature_length},get_top_padding:function(width){var view_range=this.view_end-this.view_start,w_scale=width/view_range;return Math.min(128,Math.ceil((this.longest_feature_length/2)*w_scale))},draw_connector:function(ctx,block1_start,block1_end,block2_start,block2_end,y_start){var x_center=(block1_end+block2_start)/2,radius=block2_start-x_center;var angle1=Math.PI,angle2=0;if(radius>0){ctx.beginPath();ctx.arc(x_center,y_start,block2_start-x_center,Math.PI,0);ctx.stroke()}}});var Color=function(rgb,a){if(Array.isArray(rgb)){this.rgb=rgb}else{if(rgb.length==6){this.rgb=rgb.match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{if(rgb.length==7){this.rgb=rgb.substring(1,7).match(/.{2}/g).map(function(c){return parseInt(c,16)})}else{this.rgb=rgb.split("").map(function(c){return parseInt(c+c,16)})}}}this.alpha=typeof(a)==="number"?a:1};Color.prototype={eval:function(){return this},toCSS:function(){if(this.alpha<1){return"rgba("+this.rgb.map(function(c){return Math.round(c)}).concat(this.alpha).join(", ")+")"}else{return"#"+this.rgb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")}},toHSL:function(){var r=this.rgb[0]/255,g=this.rgb[1]/255,b=this.rgb[2]/255,a=this.alpha;var max=Math.max(r,g,b),min=Math.min(r,g,b);var h,s,l=(max+min)/2,d=max-min;if(max===min){h=s=0}else{s=l>0.5?d/(2-max-min):d/(max+min);switch(max){case r:h=(g-b)/d+(g<b?6:0);break;case g:h=(b-r)/d+2;break;case b:h=(r-g)/d+4;break}h/=6}return{h:h*360,s:s,l:l,a:a}},toARGB:function(){var argb=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+argb.map(function(i){i=Math.round(i);i=(i>255?255:(i<0?0:i)).toString(16);return i.length===1?"0"+i:i}).join("")},mix:function(color2,weight){color1=this;var p=weight;var w=p*2-1;var a=color1.toHSL().a-color2.toHSL().a;var w1=(((w*a==-1)?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;var rgb=[color1.rgb[0]*w1+color2.rgb[0]*w2,color1.rgb[1]*w1+color2.rgb[1]*w2,color1.rgb[2]*w1+color2.rgb[2]*w2];var alpha=color1.alpha*p+color2.alpha*(1-p);return new Color(rgb,alpha)}};var LinearRamp=function(start_color,end_color,start_value,end_value){this.start_color=new Color(start_color);this.end_color=new Color(end_color);this.start_value=start_value;this.end_value=end_value;this.value_range=end_value-start_value};LinearRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);value=(value-this.start_value)/this.value_range;return this.start_color.mix(this.end_color,1-value).toCSS()};var SplitRamp=function(start_color,middle_color,end_color,start_value,end_value){this.positive_ramp=new LinearRamp(middle_color,end_color,0,end_value);this.negative_ramp=new LinearRamp(middle_color,start_color,0,-start_value);this.start_value=start_value;this.end_value=end_value};SplitRamp.prototype.map_value=function(value){value=Math.max(value,this.start_value);value=Math.min(value,this.end_value);if(value>=0){return this.positive_ramp.map_value(value)}else{return this.negative_ramp.map_value(-value)}};var DiagonalHeatmapPainter=function(data,view_start,view_end,prefs,mode){Painter.call(this,data,view_start,view_end,prefs,mode);var i,len;if(this.prefs.min_value===undefined){var min_value=Infinity;for(i=0,len=this.data.length;i<len;i++){min_value=Math.min(min_value,this.data[i][5])}this.prefs.min_value=min_value}if(this.prefs.max_value===undefined){var max_value=-Infinity;for(i=0,len=this.data.length;i<len;i++){max_value=Math.max(max_value,this.data[i][5])}this.prefs.max_value=max_value}};DiagonalHeatmapPainter.prototype.default_prefs={min_value:undefined,max_value:undefined,mode:"Heatmap",pos_color:"#FF8C00",neg_color:"#4169E1"};DiagonalHeatmapPainter.prototype.draw=function(ctx,width,height,w_scale){var min_value=this.prefs.min_value,max_value=this.prefs.max_value,value_range=max_value-min_value,height_px=height,view_start=this.view_start,mode=this.mode,data=this.data,invsqrt2=1/Math.sqrt(2);var ramp=(new SplitRamp(this.prefs.neg_color,"#FFFFFF",this.prefs.pos_color,min_value,max_value));var d,s1,e1,s2,e2,value;var scale=function(p){return(p-view_start)*w_scale};ctx.save();ctx.rotate(-45*Math.PI/180);ctx.scale(invsqrt2,invsqrt2);for(var i=0,len=data.length;i<len;i++){d=data[i];s1=scale(d[1]);e1=scale(d[2]);s2=scale(d[4]);e2=scale(d[5]);value=d[6];ctx.fillStyle=(ramp.map_value(value));ctx.fillRect(s1,s2,(e1-s1),(e2-s2))}ctx.restore()};var ReadPainterUtils=function(ctx,row_height,px_per_base,mode){this.ctx=ctx;this.row_height=row_height;this.px_per_base=px_per_base;this.draw_details=(mode==="Pack"||mode==="Auto")&&(px_per_base>=ctx.canvas.manager.char_width_px);this.delete_details_thickness=0.2};_.extend(ReadPainterUtils.prototype,{draw_deletion:function(x,y,len){this.ctx.fillStyle="black";var thickness=(this.draw_details?this.delete_details_thickness:1)*this.row_height;y+=0.5*(this.row_height-thickness);this.ctx.fillRect(x,y,len*this.px_per_base,thickness)}});var VariantPainter=function(data,view_start,view_end,prefs,mode,base_color_fn){Painter.call(this,data,view_start,view_end,prefs,mode);this.base_color_fn=base_color_fn;this.divider_height=1};_.extend(VariantPainter.prototype,Painter.prototype,{get_row_height:function(){var mode=this.mode,height;if(mode==="Dense"){height=DENSE_TRACK_HEIGHT}else{if(mode==="Squish"){height=SQUISH_TRACK_HEIGHT}else{height=PACK_TRACK_HEIGHT}}return height},get_required_height:function(num_samples){var height=this.prefs.summary_height;if(num_samples>1&&this.prefs.show_sample_data){height+=this.divider_height+num_samples*this.get_row_height()}return height},draw:function(ctx,width,height,w_scale){ctx.save();var get_deletion_info=function(ref,alt){var ref_len=ref.length,alt_len=alt.length,start=0,len=1,is_delete=false;if(alt==="-"){is_delete=true;len=ref.length}else{if(ref.indexOf(alt)===0&&ref_len>alt_len){is_delete=true;len=ref_len=alt_len;start+=alt_len}}return(is_delete?{start:start,len:len}:null)};var locus_data,pos,id,ref,alt,qual,filter,sample_gts,allele_counts,variant,draw_x_start,char_x_start,draw_y_start,genotype,base_px=Math.max(1,Math.floor(w_scale)),num_samples=(this.data.length?this.data[0][7].split(",").length:0),row_height=(this.mode==="Squish"?SQUISH_TRACK_HEIGHT:PACK_TRACK_HEIGHT),feature_height=(w_scale<0.1?row_height:(this.mode==="Squish"?SQUISH_FEATURE_HEIGHT:PACK_FEATURE_HEIGHT)),draw_summary=true,paint_utils=new ReadPainterUtils(ctx,row_height,w_scale,this.mode),j;if(num_samples===1){row_height=feature_height=(w_scale<ctx.canvas.manager.char_width_px?this.prefs.summary_height:row_height);paint_utils.row_height=row_height;draw_summary=false}if(this.prefs.show_sample_data&&draw_summary){ctx.fillStyle="#F3F3F3";ctx.globalAlpha=1;ctx.fillRect(0,this.prefs.summary_height-this.divider_height,width,this.divider_height)}ctx.textAlign="center";for(var i=0;i<this.data.length;i++){locus_data=this.data[i];pos=locus_data[1];ref=locus_data[3];alt=[locus_data[4].split(",")];sample_gts=locus_data[7].split(",");allele_counts=locus_data.slice(8);alt=_.map(_.flatten(alt),function(a){var type,alt_info={},delete_info=get_deletion_info(ref,a);if(delete_info){type="deletion";_.extend(alt_info,delete_info)}else{type="snp"}return _.extend(alt_info,{type:type,value:a,})});if(pos<this.view_start||pos>this.view_end){continue}draw_x_start=Math.floor(Math.max(-0.5*w_scale,(pos-this.view_start-0.5)*w_scale));char_x_start=Math.floor(Math.max(0,(pos-this.view_start)*w_scale));if(draw_summary){ctx.fillStyle="#999999";ctx.globalAlpha=1;ctx.fillRect(draw_x_start,0,base_px,this.prefs.summary_height);draw_y_start=this.prefs.summary_height;for(j=0;j<alt.length;j++){ctx.fillStyle=(alt[j].type==="deletion"?"black":this.base_color_fn(alt[j].value));allele_frac=allele_counts/sample_gts.length;draw_height=Math.ceil(this.prefs.summary_height*allele_frac);ctx.fillRect(draw_x_start,draw_y_start-draw_height,base_px,draw_height);draw_y_start-=draw_height}}if(!this.prefs.show_sample_data){continue}draw_y_start=(draw_summary?this.prefs.summary_height+this.divider_height:0);for(j=0;j<sample_gts.length;j++,draw_y_start+=row_height){genotype=(sample_gts[j]?sample_gts[j].split(/\/|\|/):["0","0"]);variant=null;if(genotype[0]===genotype[1]){if(genotype[0]==="."){}else{if(genotype[0]!=="0"){variant=alt[parseInt(genotype[0],10)-1];ctx.globalAlpha=1}}}else{variant=(genotype[0]!=="0"?genotype[0]:genotype[1]);variant=alt[parseInt(variant,10)-1];ctx.globalAlpha=0.5}if(variant){if(variant.type==="snp"){var snp=variant.value;ctx.fillStyle=this.base_color_fn(snp);if(paint_utils.draw_details){ctx.fillText(snp,char_x_start,draw_y_start+row_height)}else{ctx.fillRect(draw_x_start,draw_y_start+1,base_px,feature_height)}}else{if(variant.type==="deletion"){paint_utils.draw_deletion(draw_x_start+base_px*variant.start,draw_y_start+1,variant.len)}else{}}}}}ctx.restore()}});return{Scaler:Scaler,LinePainter:LinePainter,LinkedFeaturePainter:LinkedFeaturePainter,ReadPainter:ReadPainter,ArcLinkedFeaturePainter:ArcLinkedFeaturePainter,DiagonalHeatmapPainter:DiagonalHeatmapPainter,VariantPainter:VariantPainter}});
\ No newline at end of file
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/packed/viz/trackster/slotting.js
--- a/static/scripts/packed/viz/trackster/slotting.js
+++ b/static/scripts/packed/viz/trackster/slotting.js
@@ -1,1 +1,1 @@
-define(["libs/underscore"],function(b){var e=b.extend;var c=2,a=5;var d=function(i,h,f,g){this.slots={};this.start_end_dct={};this.w_scale=i;this.mode=h;this.include_label=(h==="Pack");this.max_rows=f;this.measureText=g};e(d.prototype,{slot_features:function(m){var p=this.w_scale,h=this.start_end_dct,x=[],z=[],n=0,y=this.max_rows;for(var v=0,w=m.length;v<w;v++){var k=m[v],o=k[0];if(this.slots[o]!==undefined){n=Math.max(n,this.slots[o]);z.push(this.slots[o])}else{x.push(v)}}var q=function(E,F){for(var D=0;D<=y;D++){var B=false,G=h[D];if(G!==undefined){for(var A=0,C=G.length;A<C;A++){var i=G[A];if(F>i[0]&&E<i[1]){B=true;break}}}if(!B){return D}}return -1};for(var v=0,w=x.length;v<w;v++){var k=m[x[v]],o=k[0],t=k[1],f=k[2],r=k[3],g=Math.floor(t*p),l=Math.ceil(f*p),u=this.measureText(r).width,j;if(r!==undefined&&this.include_label){u+=(c+a);if(g-u>=0){g-=u;j="left"}else{l+=u;j="right"}}var s=q(g,l);if(s>=0){if(h[s]===undefined){h[s]=[]}h[s].push([g,l]);this.slots[o]=s;n=Math.max(n,s)}}return n+1}});return{FeatureSlotter:d}});
\ No newline at end of file
+define(["libs/underscore"],function(c){var f=c.extend;var d=2,b=5;var a=function(h,g){this.slot=h;this.feature=g};var e=function(j,i,g,h){this.slots={};this.start_end_dct={};this.w_scale=j;this.mode=i;this.include_label=(i==="Pack");this.max_rows=g;this.measureText=h};f(e.prototype,{_get_draw_coords:function(j){var h=Math.floor(j[1]*this.w_scale),i=Math.ceil(j[2]*this.w_scale),g=j[3],k;if(g!==undefined&&this.include_label){var l=this.measureText(g).width+(d+b);if(h-l>=0){h-=l;k="left"}else{i+=l;k="right"}}return[h,i]},_find_slot:function(j){var o=j[0],n=j[1];for(var l=0;l<=this.max_rows;l++){var p=false,m=this.start_end_dct[l];if(m!==undefined){for(var g=0,h=m.length;g<h;g++){var i=m[g];if(n>i[0]&&o<i[1]){p=true;break}}}if(!p){return l}}return -1},slot_features:function(h){var q=this.start_end_dct,v=[],m=0,x,l;for(var o=0,t=h.length;o<t;o++){x=h[o];l=x[0];var g=this.slots[l];if(g){if(x[1]<g.feature[1]||g.feature[2]<x[2]){console.log(x[3],g.slot,this._find_slot(this._get_draw_coords(x)));var s=this._get_draw_coords(g.feature),p=this._get_draw_coords(x),j=this.start_end_dct[g.slot];for(var n=0;n<j.length;n++){var w=j[n];if(w[0]===s[0]&&w[1]===s[1]){j[n]=p}}}m=Math.max(m,this.slots[l].slot)}else{v.push(o)}}for(var o=0,t=v.length;o<t;o++){x=h[v[o]];l=x[0];var r=this._get_draw_coords(x);var u=this._find_slot(r);if(u>=0){if(q[u]===undefined){q[u]=[]}q[u].push(r);this.slots[l]=new a(u,x);m=Math.max(m,u)}}return m+1}});return{FeatureSlotter:e}});
\ No newline at end of file
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/viz/trackster/painters.js
--- a/static/scripts/viz/trackster/painters.js
+++ b/static/scripts/viz/trackster/painters.js
@@ -396,7 +396,7 @@
feature_end = feature[2],
// Slot valid only if features are slotted and this feature is slotted;
// feature may not be due to lack of space.
- slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid] : null);
+ slot = (slots && slots[feature_uid] !== undefined ? slots[feature_uid].slot : null);
// Draw feature if (a) mode is dense or feature is slotted (as it must be for all non-dense modes) and
// (b) there's overlap between the feature and drawing region.
diff -r c665ed80227c76001c0a2e767e66d992ed72b4ad -r 0dc11a77b3cd2003e542c3183539ebdb38b7f65a static/scripts/viz/trackster/slotting.js
--- a/static/scripts/viz/trackster/slotting.js
+++ b/static/scripts/viz/trackster/slotting.js
@@ -7,6 +7,14 @@
PACK_SPACING = 5;
/**
+ * Hold slotting information for a feature.
+ */
+var SlottedInfo = function(slot, feature) {
+ this.slot = slot;
+ this.feature = feature;
+};
+
+/**
* FeatureSlotter determines slots in which to draw features for vertical
* packing.
*
@@ -28,118 +36,148 @@
* the largest slot required for the passed set of features is returned
*/
extend( FeatureSlotter.prototype, {
+ /**
+ * Get drawing coordinate for a feature.
+ */
+ _get_draw_coords: function(feature) {
+ // Get initial draw coordinates using w_scale.
+ var draw_start = Math.floor(feature[1] * this.w_scale),
+ draw_end = Math.ceil(feature[2] * this.w_scale),
+ f_name = feature[3],
+ text_align;
+
+ // Update start, end drawing locations to include feature name.
+ // Try to put the name on the left, if not, put on right.
+ if (f_name !== undefined && this.include_label ) {
+ // Add gap for label spacing and extra pack space padding
+ // TODO: Fix constants
+ var text_len = this.measureText(f_name).width + (LABEL_SPACING + PACK_SPACING);
+ if (draw_start - text_len >= 0) {
+ draw_start -= text_len;
+ text_align = "left";
+ } else {
+ draw_end += text_len;
+ text_align = "right";
+ }
+ }
+
+ /*
+ if (slot_num < 0) {
+
+ TODO: this is not yet working --
+ console.log(feature_uid, "looking for slot with text on the right");
+ // Slot not found. If text was on left, try on right and see
+ // if slot can be found.
+ // TODO: are there any checks we need to do to ensure that text
+ // will fit on tile?
+ if (text_align === "left") {
+ draw_start -= text_len;
+ draw_end -= text_len;
+ text_align = "right";
+ slot_num = find_slot(draw_start, draw_end);
+ }
+ if (slot_num >= 0) {
+ console.log(feature_uid, "found slot with text on the right");
+ }
+
+ }
+ */
+
+ return [draw_start, draw_end];
+ },
+
+ /**
+ * Find the first slot such that current feature doesn't overlap any other features in that slot.
+ * Returns -1 if no slot was found.
+ */
+ _find_slot: function(draw_coords) {
+ // TODO: Use a data structure for faster searching of available slots.
+ var draw_start = draw_coords[0],
+ draw_end = draw_coords[1];
+ for (var slot_num = 0; slot_num <= this.max_rows; slot_num++) {
+ var has_overlap = false,
+ slot = this.start_end_dct[slot_num];
+ if (slot !== undefined) {
+ // Iterate through features already in slot to see if current feature will fit.
+ for (var k = 0, k_len = slot.length; k < k_len; k++) {
+ var s_e = slot[k];
+ if (draw_end > s_e[0] && draw_start < s_e[1]) {
+ // There is overlap
+ has_overlap = true;
+ break;
+ }
+ }
+ }
+ if (!has_overlap) {
+ return slot_num;
+ }
+ }
+ return -1;
+ },
+
+ /**
+ * Slot features.
+ */
slot_features: function( features ) {
- var w_scale = this.w_scale,
- start_end_dct = this.start_end_dct,
+ var start_end_dct = this.start_end_dct,
undone = [],
- slotted = [],
- highest_slot = 0,
- max_rows = this.max_rows;
-
- // If feature already exists in slots (from previously seen tiles), use the same slot,
- // otherwise if not seen, add to "undone" list for slot calculation.
-
- // TODO: Should calculate zoom tile index, which will improve performance
- // by only having to look at a smaller subset
- // if (this.start_end_dct[0] === undefined) { this.start_end_dct[0] = []; }
+ highest_slot = 0,
+ feature,
+ feature_uid;
+
+ // Loop through features to (a) find those that are not yet slotted and (b) update
+ // those that are slotted if new information is availabe. For (a), features already
+ // slotted (based on slotting from other tiles) will retain their current slot.
for (var i = 0, len = features.length; i < len; i++) {
- var feature = features[i],
- feature_uid = feature[0];
- if (this.slots[feature_uid] !== undefined) {
- highest_slot = Math.max(highest_slot, this.slots[feature_uid]);
- slotted.push(this.slots[feature_uid]);
- } else {
+ feature = features[i];
+ feature_uid = feature[0];
+ var slotted_info = this.slots[feature_uid];
+
+ // Separate and handle slotted vs. unslotted features.
+ if (slotted_info) {
+ // Feature is slotted; if feature now has larger start/end coordinates,
+ // update drawing coordinates.
+ if (feature[1] < slotted_info.feature[1] || slotted_info.feature[2] < feature[2]) {
+ console.log(feature[3], slotted_info.slot, this._find_slot(this._get_draw_coords(feature)));
+ // Feature has changed (e.g. a single read now has its pair), so recalculate its
+ // drawing coordinates.
+ var old_draw_coords = this._get_draw_coords(slotted_info.feature),
+ new_draw_coords = this._get_draw_coords(feature),
+ slotted_coords = this.start_end_dct[slotted_info.slot];
+ for (var k = 0; k < slotted_coords.length; k++) {
+ var dc = slotted_coords[k];
+ if (dc[0] === old_draw_coords[0] && dc[1] === old_draw_coords[1]) {
+ // Replace old drawing coordinates with new ones.
+ slotted_coords[k] = new_draw_coords;
+ }
+ }
+ }
+ highest_slot = Math.max(highest_slot, this.slots[feature_uid].slot);
+ }
+ else {
undone.push(i);
}
}
-
+
// Slot unslotted features.
- // Find the first slot such that current feature doesn't overlap any other features in that slot.
- // Returns -1 if no slot was found.
- var find_slot = function(f_start, f_end) {
- // TODO: Fix constants
- for (var slot_num = 0; slot_num <= max_rows; slot_num++) {
- var has_overlap = false,
- slot = start_end_dct[slot_num];
- if (slot !== undefined) {
- // Iterate through features already in slot to see if current feature will fit.
- for (var k = 0, k_len = slot.length; k < k_len; k++) {
- var s_e = slot[k];
- if (f_end > s_e[0] && f_start < s_e[1]) {
- // There is overlap
- has_overlap = true;
- break;
- }
- }
- }
- if (!has_overlap) {
- return slot_num;
- }
- }
- return -1;
- };
-
// Do slotting.
for (var i = 0, len = undone.length; i < len; i++) {
- var feature = features[undone[i]],
- feature_uid = feature[0],
- feature_start = feature[1],
- feature_end = feature[2],
- feature_name = feature[3],
- // Where to start, end drawing on screen.
- f_start = Math.floor( feature_start * w_scale ),
- f_end = Math.ceil( feature_end * w_scale ),
- text_len = this.measureText(feature_name).width,
- text_align;
-
- // Update start, end drawing locations to include feature name.
- // Try to put the name on the left, if not, put on right.
- if (feature_name !== undefined && this.include_label ) {
- // Add gap for label spacing and extra pack space padding
- // TODO: Fix constants
- text_len += (LABEL_SPACING + PACK_SPACING);
- if (f_start - text_len >= 0) {
- f_start -= text_len;
- text_align = "left";
- } else {
- f_end += text_len;
- text_align = "right";
- }
- }
+ feature = features[undone[i]];
+ feature_uid = feature[0];
+ var draw_coords = this._get_draw_coords(feature);
// Find slot.
- var slot_num = find_slot(f_start, f_end);
+ var slot_num = this._find_slot(draw_coords);
- /*
- if (slot_num < 0) {
-
- TODO: this is not yet working --
- console.log(feature_uid, "looking for slot with text on the right");
- // Slot not found. If text was on left, try on right and see
- // if slot can be found.
- // TODO: are there any checks we need to do to ensure that text
- // will fit on tile?
- if (text_align === "left") {
- f_start -= text_len;
- f_end -= text_len;
- text_align = "right";
- slot_num = find_slot(f_start, f_end);
- }
- if (slot_num >= 0) {
- console.log(feature_uid, "found slot with text on the right");
- }
-
- }
- */
// Do slotting.
if (slot_num >= 0) {
// Add current feature to slot.
if (start_end_dct[slot_num] === undefined) {
start_end_dct[slot_num] = [];
}
- start_end_dct[slot_num].push([f_start, f_end]);
- this.slots[feature_uid] = slot_num;
+ start_end_dct[slot_num].push(draw_coords);
+ this.slots[feature_uid] = new SlottedInfo(slot_num, feature);
highest_slot = Math.max(highest_slot, slot_num);
}
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jmchilton: Bugfix for 0750859: Don't generate duplicate workflow slugs for private workflows.
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9a4b43021fd1/
Changeset: 9a4b43021fd1
Branch: stable
User: jmchilton
Date: 2014-08-25 18:36:34
Summary: Bugfix for 0750859: Don't generate duplicate workflow slugs for private workflows.
See full conversation on https://bitbucket.org/galaxy/galaxy-central/commits/07508592cb65845474b9f3e….
Would like to better and allow slugs of deleted items to be reused - they cannot be for workflows for instance. Because the slugs are not really handled uniformly though - pages do not have this problem and deleted pages can have their slugs reused because this is included in a check in the web controller which directly assigns valid slugs at that point. Slugs for deleted histories cannot be re-used - but they couldn't be prior to this commit - so this isn't making things worse in that respect.
Affected #: 1 file
diff -r d86834553f0e2d3636b3f545f61ae3250ead31e9 -r 9a4b43021fd1c5808c17329da7b6acbfd9ae27ed lib/galaxy/web/base/controller.py
--- a/lib/galaxy/web/base/controller.py
+++ b/lib/galaxy/web/base/controller.py
@@ -27,7 +27,7 @@
from galaxy.web.form_builder import AddressField, CheckboxField, SelectField, TextArea, TextField
from galaxy.web.form_builder import build_select_field, HistoryField, PasswordField, WorkflowField, WorkflowMappingField
from galaxy.workflow.modules import module_factory
-from galaxy.model.orm import eagerload, eagerload_all, desc
+from galaxy.model.orm import eagerload, eagerload_all, desc, not_
from galaxy.security.validate_user_input import validate_publicname
from galaxy.util.sanitize_html import sanitize_html
from galaxy.model.item_attrs import Dictifiable, UsesAnnotations
@@ -2694,7 +2694,7 @@
item = self.get_item( trans, id )
if item:
# Only update slug if slug is not already in use.
- if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() == 0:
+ if trans.sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug ).count() == 0:
item.slug = new_slug
trans.sa_session.flush()
@@ -2729,7 +2729,9 @@
# add integer to end.
new_slug = slug_base
count = 1
- while sa_session.query( item.__class__ ).filter_by( user=item.user, slug=new_slug, importable=True ).count() != 0:
+ # Ensure unique across model class and user and don't include this item
+ # in the check in case it has previously been assigned a valid slug.
+ while sa_session.query( item.__class__ ).filter( item.__class__.user == item.user, item.__class__.slug == new_slug, item.__class__.id != item.id).count() != 0:
# Slug taken; choose a new slug based on count. This approach can
# handle numerous items with the same name gracefully.
new_slug = '%s-%i' % ( slug_base, count )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: guerler: ToolForm: Add repeat blocks, refactor conditionals, fix styles, pack scripts
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/c665ed80227c/
Changeset: c665ed80227c
User: guerler
Date: 2014-08-25 18:27:18
Summary: ToolForm: Add repeat blocks, refactor conditionals, fix styles, pack scripts
Affected #: 11 files
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/tools/tools-form.js
--- a/static/scripts/mvc/tools/tools-form.js
+++ b/static/scripts/mvc/tools/tools-form.js
@@ -1,8 +1,8 @@
-define(['mvc/ui/ui-portlet', 'mvc/ui/ui-table', 'mvc/ui/ui-misc',
+define(['mvc/ui/ui-portlet', 'mvc/ui/ui-misc',
'mvc/citation/citation-model', 'mvc/citation/citation-view',
- 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets'],
- function(Portlet, Table, Ui, CitationModel, CitationView,
- Tools, ToolTemplate, ToolDatasets) {
+ 'mvc/tools', 'mvc/tools/tools-template', 'mvc/tools/tools-datasets', 'mvc/tools/tools-section'],
+ function(Portlet, Ui, CitationModel, CitationView,
+ Tools, ToolTemplate, ToolDatasets, ToolSection) {
// create tool model
var Model = Backbone.Model.extend({
@@ -39,9 +39,19 @@
// initialize tool form
_initializeToolForm: function() {
+
+ // reset field list
+ this.field_list = {};
+
+ // reset sequential input definition list
+ this.inputs_sequential = {};
+
// fetch model and render form
var self = this;
this.model.fetch({
+ error: function(response) {
+ console.debug('tools-form::_initializeToolForm() : Attempt to fetch tool model failed.');
+ },
success: function() {
// inputs
self.inputs = self.model.get('inputs');
@@ -62,9 +72,6 @@
}
});
- // create table
- self.table = new Table.View();
-
// create message
self.message = new Ui.Message();
self.portlet.append(self.message.$el);
@@ -92,380 +99,14 @@
// configure portlet and form table
self.setElement(self.portlet.content());
- self.portlet.append(self.table.$el);
- self.render();
- }
- });
- },
-
- // update
- render: function() {
- // reset table
- this.table.delAll();
-
- // reset field list
- this.field_list = {};
-
- // reset sequential input definition list
- this.inputs_sequential = {};
-
- // model
- var data = new Backbone.Model();
-
- // load settings elements into table
- for (var id in this.inputs) {
- this._add(this.inputs[id], data);
- }
-
- // trigger change
- for (var id in this.field_list) {
- this.field_list[id].trigger('change');
- }
- },
-
- // add table row
- _add: function(inputs_def, data) {
- // identify field type
- var type = inputs_def.type;
- switch(type) {
- // conditional field
- case 'conditional':
- // add label to input definition root
- inputs_def.label = inputs_def.test_param.label;
-
- // add id to input definition root
- inputs_def.name = inputs_def.test_param.name;
-
- // build options field
- this._addRow('conditional', inputs_def, data);
- // add fields
- for (var i in inputs_def.cases) {
- var cases = inputs_def.cases[i];
- for (var j in cases.inputs) {
- // add element to form
- this._add(cases.inputs[j], data);
- }
- }
- break;
-
- // default single element row
- default:
- this._addRow(type, inputs_def, data);
- }
- },
-
- // add table row
- _addRow: function(field_type, inputs_def, data) {
- // get id
- var id = inputs_def.name;
-
- // field wrapper
- var field = null;
-
- // identify field type
- switch(field_type) {
- // text input field
- case 'text' :
- field = this._field_text(inputs_def, data);
- break;
-
- // select field
- case 'select' :
- field = this._field_select(inputs_def, data);
- break;
-
- // radiobox field
- case 'radiobutton' :
- field = this._field_radio(inputs_def, data);
- break;
-
- // dataset
- case 'data':
- field = this._field_data(inputs_def, data);
- break;
-
- // dataset column
- case 'data_column':
- field = this._field_column(inputs_def, data);
- break;
-
- // text area field
- case 'textarea' :
- field = this._field_textarea(inputs_def, data);
- break;
-
- // conditional select field
- case 'conditional':
- field = this._field_conditional(inputs_def, data);
- break;
- }
-
- // check if field type was detected
- if (!field) {
- console.debug('tools-form::_addRow() : Unmatched field type (' + field_type + ').');
- return;
- }
-
- // set value
- if (!data.get(id)) {
- data.set(id, inputs_def.value);
- }
- field.value(data.get(id));
-
- // add to field list
- this.field_list[id] = field;
-
- // add to input definition into sequential list
- this.inputs_sequential[id] = inputs_def;
-
- // combine field and info
- var $input = $('<div/>');
- $input.append(field.$el);
- if (inputs_def.info) {
- $input.append('<div class="ui-table-form-info">' + inputs_def.info + '</div>');
- }
-
- // add row to table
- this.table.add('<span class="ui-table-form-title">' + inputs_def.label + '</span>', '25%');
- this.table.add($input);
-
- // add to table
- this.table.append(id);
-
- // show/hide
- if (inputs_def.hide) {
- this.table.get(id).hide();
- }
- },
-
- // text input field
- _field_text : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.Input({
- id : 'field-' + id,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // text area
- _field_textarea : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.Textarea({
- id : 'field-' + id,
- onchange : function() {
- data.set(id, field.value());
- }
- });
- },
-
- // conditional input field
- _field_conditional : function(inputs_def, data) {
- // link this
- var self = this;
-
- // configure options fields
- var options = [];
- for (var i in inputs_def.test_param.options) {
- var option = inputs_def.test_param.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // select field
- var id = inputs_def.name;
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- // update value
- data.set(id, value);
-
- // recursively hide/show options
- function _updateVisibility(root, show) {
- // loop through all inputs
- for (var i in root.inputs) {
- // get input element
- var element = root.inputs[i];
-
- // identify element name
- var element_id = element.name;
-
- // identify row
- var element_row = self.table.get(element_id);
-
- // show/hide row
- if (show) {
- element_row.fadeIn();
- } else {
- element_row.hide();
- }
-
- // check if its a nested conditional
- if (element.type == 'conditional') {
- // identify all cases
- for (var j in element.cases) {
- _updateVisibility(element.cases[j], show);
- }
- }
- }
- }
-
- // check value in order to hide/show options
- for (var i in inputs_def.cases) {
- var case_def = inputs_def.cases[i];
- _updateVisibility(case_def, case_def.value == value);
- }
- }
- });
- },
-
- // data input field
- _field_data : function(inputs_def, data) {
- // link this
- var self = this;
-
- // get element id
- var id = inputs_def.name;
-
- // get datasets
- var datasets = this.datasets.filterType();
-
- // configure options fields
- var options = [];
- for (var i in datasets) {
- options.push({
- label: datasets[i].get('name'),
- value: datasets[i].get('id')
- });
- }
-
- // select field
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : options[0].value,
- onchange : function(value) {
- // update value
- data.set(id, value);
-
- // find referenced columns
- var column_list = _.where(self.inputs_sequential, {
- data_ref : id,
- type : 'data_column'
+ // create tool form section
+ self.section = new ToolSection.View(self, {
+ inputs : self.model.get('inputs')
});
- // find selected dataset
- var dataset = self.datasets.filter(value);
-
- // check dataset
- if (dataset && column_list.length > 0) {
- // log selection
- console.debug('tool-form::field_data() - Selected dataset ' + value + '.');
-
- // get meta data
- var meta = dataset.get('metadata_column_types');
-
- // check meta data
- if (!meta) {
- console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.');
- }
-
- // load column options
- var columns = [];
- for (var key in meta) {
- // add to selection
- columns.push({
- 'label' : 'Column: ' + (parseInt(key) + 1) + ' [' + meta[key] + ']',
- 'value' : key
- });
- }
-
- // update referenced columns
- for (var i in column_list) {
- var column_field = self.field_list[column_list[i].name]
- if (column_field) {
- column_field.update(columns);
- column_field.value(column_field.first());
- }
- }
- } else {
- // log failure
- console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.');
- }
- }
- });
- },
-
- // select field
- _field_column : function (inputs_def, data) {
- // configure options fields
- var options = [];
- for (var i in inputs_def.options) {
- var option = inputs_def.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // select field
- var id = inputs_def.name;
- return new Ui.Select.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // select field
- _field_select : function (inputs_def, data) {
- // configure options fields
- var options = [];
- for (var i in inputs_def.options) {
- var option = inputs_def.options[i];
- options.push({
- label: option[0],
- value: option[1]
- });
- }
-
- // identify display type
- var SelectClass = Ui.Select;
- if (inputs_def.display == 'checkboxes') {
- SelectClass = Ui.Checkbox;
- }
-
- // select field
- var id = inputs_def.name;
- return new SelectClass.View({
- id : 'field-' + id,
- data : options,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
- }
- });
- },
-
- // radio field
- _field_radio : function(inputs_def, data) {
- var id = inputs_def.name;
- return new Ui.RadioButton({
- id : 'field-' + id,
- data : inputs_def.data,
- value : data.get(id),
- onchange : function(value) {
- data.set(id, value);
+ // append tool section
+ self.portlet.append(self.section.$el);
}
});
}
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/tools/tools-section.js
--- /dev/null
+++ b/static/scripts/mvc/tools/tools-section.js
@@ -0,0 +1,409 @@
+define(['mvc/ui/ui-table', 'mvc/ui/ui-misc', 'mvc/ui/ui-tabs'], function(Table, Ui, Tabs) {
+
+ // create form view
+ var View = Backbone.View.extend({
+ // initialize
+ initialize: function(app, options) {
+ // link app
+ this.app = app;
+
+ // link inputs
+ this.inputs = options.inputs;
+
+ // link datasets
+ this.datasets = app.datasets;
+
+ // create table
+ this.table = new Table.View(options);
+
+ // configure portlet and form table
+ this.setElement(this.table.$el);
+
+ // render tool section
+ this.render();
+ },
+
+ // update
+ render: function() {
+ // reset table
+ this.table.delAll();
+
+ // model
+ var data = new Backbone.Model();
+
+ // load settings elements into table
+ for (var id in this.inputs) {
+ this._add(this.inputs[id], data);
+ }
+
+ // trigger change
+ for (var id in this.app.field_list) {
+ this.app.field_list[id].trigger('change');
+ }
+ },
+
+ // add table row
+ _add: function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // identify field type
+ var type = inputs_def.type;
+ switch(type) {
+ // conditional field
+ case 'conditional':
+ // add label to input definition root
+ inputs_def.label = inputs_def.test_param.label;
+
+ // add id to input definition root
+ inputs_def.name = inputs_def.test_param.name;
+
+ // build options field
+ this._addRow('conditional', inputs_def, data);
+
+ // add fields
+ for (var i in inputs_def.cases) {
+ // create sub section
+ var sub_section = new View(this.app, {
+ inputs : inputs_def.cases[i].inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // append sub section
+ this.table.add('');
+ this.table.add(sub_section.$el);
+ this.table.append(inputs_def.name + '_formsection_' + i);
+ }
+ break;
+ // repeat block
+ case 'repeat':
+ // create tab field
+ var tabs = new Tabs.View({
+ title_new : 'Add Group',
+ onnew : function() {
+ // create sub section
+ var sub_section = new View(self.app, {
+ inputs : inputs_def.inputs,
+ cls : 'ui-table-plain'
+ });
+
+ // create id tag
+ var sub_section_id = inputs_def.name + '_formsection_' + tabs.size();
+
+ // add new tab
+ tabs.add({
+ id : sub_section_id,
+ title : 'Repeat',
+ $el : sub_section.$el,
+ ondel : function() {
+ tabs.del(sub_section_id);
+ }
+ });
+
+ // show tab
+ tabs.show(sub_section_id);
+ }
+ });
+
+ // append sub section
+ this.table.add(inputs_def.title);
+ this.table.add(tabs.$el);
+ this.table.append(inputs_def.name);
+ break;
+ // default single element row
+ default:
+ this._addRow(type, inputs_def, data);
+ }
+ },
+
+ // add table row
+ _addRow: function(field_type, inputs_def, data) {
+ // get id
+ var id = inputs_def.name;
+
+ // field wrapper
+ var field = null;
+
+ // identify field type
+ switch(field_type) {
+ // text input field
+ case 'text' :
+ field = this._field_text(inputs_def, data);
+ break;
+
+ // select field
+ case 'select' :
+ field = this._field_select(inputs_def, data);
+ break;
+
+ // radiobox field
+ case 'radiobutton' :
+ field = this._field_radio(inputs_def, data);
+ break;
+
+ // dataset
+ case 'data':
+ field = this._field_data(inputs_def, data);
+ break;
+
+ // dataset column
+ case 'data_column':
+ field = this._field_column(inputs_def, data);
+ break;
+
+ // text area field
+ case 'textarea' :
+ field = this._field_textarea(inputs_def, data);
+ break;
+
+ // conditional select field
+ case 'conditional':
+ field = this._field_conditional(inputs_def, data);
+ break;
+ }
+
+ // check if field type was detected
+ if (!field) {
+ console.debug('tools-form::_addRow() : Unmatched field type (' + field_type + ').');
+ return;
+ }
+
+ // set value
+ if (!data.get(id)) {
+ data.set(id, inputs_def.value);
+ }
+ field.value(data.get(id));
+
+ // add to field list
+ this.app.field_list[id] = field;
+
+ // add to input definition into sequential list
+ this.app.inputs_sequential[id] = inputs_def;
+
+ // combine field and info
+ var $input = $('<div/>');
+ $input.append(field.$el);
+ if (inputs_def.help) {
+ $input.append('<div class="ui-table-form-info">' + inputs_def.help + '</div>');
+ }
+
+ // add row to table
+ this.table.add('<span class="ui-table-form-title">' + inputs_def.label + '</span>', '25%');
+ this.table.add($input);
+
+ // add to table
+ this.table.append(id);
+
+ // show/hide
+ if (inputs_def.hide) {
+ this.table.get(id).hide();
+ }
+ },
+
+ // text input field
+ _field_text : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Input({
+ id : 'field-' + id,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // text area
+ _field_textarea : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Textarea({
+ id : 'field-' + id,
+ onchange : function() {
+ data.set(id, field.value());
+ }
+ });
+ },
+
+ // conditional input field
+ _field_conditional : function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // configure options fields
+ var options = [];
+ for (var i in inputs_def.test_param.options) {
+ var option = inputs_def.test_param.options[i];
+ options.push({
+ label: option[0],
+ value: option[1]
+ });
+ }
+
+ // select field
+ var id = inputs_def.name;
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ data : options,
+ value : data.get(id),
+ onchange : function(value) {
+ // update value
+ data.set(id, value);
+
+ // check value in order to hide/show options
+ for (var i in inputs_def.cases) {
+ // get case
+ var case_def = inputs_def.cases[i];
+
+ // identify subsection name
+ var section_id = inputs_def.name + '_formsection_' + i;
+
+ // identify row
+ var section_row = self.table.get(section_id);
+
+ // check
+ if (case_def.value == value) {
+ section_row.show();
+ } else {
+ section_row.hide();
+ }
+ }
+ }
+ });
+ },
+
+ // data input field
+ _field_data : function(inputs_def, data) {
+ // link this
+ var self = this;
+
+ // get element id
+ var id = inputs_def.name;
+
+ // get datasets
+ var datasets = this.datasets.filterType();
+
+ // configure options fields
+ var options = [];
+ for (var i in datasets) {
+ options.push({
+ label: datasets[i].get('name'),
+ value: datasets[i].get('id')
+ });
+ }
+
+ // select field
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ data : options,
+ value : options[0].value,
+ onchange : function(value) {
+ // update value
+ data.set(id, value);
+
+ // find referenced columns
+ var column_list = _.where(self.app.inputs_sequential, {
+ data_ref : id,
+ type : 'data_column'
+ });
+
+ // find selected dataset
+ var dataset = self.datasets.filter(value);
+
+ // check dataset
+ if (dataset && column_list.length > 0) {
+ // log selection
+ console.debug('tool-form::field_data() - Selected dataset ' + value + '.');
+
+ // get meta data
+ var meta = dataset.get('metadata_column_types');
+
+ // check meta data
+ if (!meta) {
+ console.debug('tool-form::field_data() - FAILED: Could not find metadata for dataset ' + value + '.');
+ }
+
+ // load column options
+ var columns = [];
+ for (var key in meta) {
+ // add to selection
+ columns.push({
+ 'label' : 'Column: ' + (parseInt(key) + 1) + ' [' + meta[key] + ']',
+ 'value' : key
+ });
+ }
+
+ // update referenced columns
+ for (var i in column_list) {
+ var column_field = self.app.field_list[column_list[i].name]
+ if (column_field) {
+ column_field.update(columns);
+ column_field.value(column_field.first());
+ }
+ }
+ } else {
+ // log failure
+ console.debug('tool-form::field_data() - FAILED: Could not find dataset ' + value + '.');
+ }
+ }
+ });
+ },
+
+ // column selection field
+ _field_column : function (inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.Select.View({
+ id : 'field-' + id,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // select field
+ _field_select : function (inputs_def, data) {
+ // configure options fields
+ var options = [];
+ for (var i in inputs_def.options) {
+ var option = inputs_def.options[i];
+ options.push({
+ label: option[0],
+ value: option[1]
+ });
+ }
+
+ // identify display type
+ var SelectClass = Ui.Select;
+ if (inputs_def.display == 'checkboxes') {
+ SelectClass = Ui.Checkbox;
+ }
+
+ // select field
+ var id = inputs_def.name;
+ return new SelectClass.View({
+ id : 'field-' + id,
+ data : options,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ },
+
+ // radio field
+ _field_radio : function(inputs_def, data) {
+ var id = inputs_def.name;
+ return new Ui.RadioButton({
+ id : 'field-' + id,
+ data : inputs_def.data,
+ value : data.get(id),
+ onchange : function(value) {
+ data.set(id, value);
+ }
+ });
+ }
+ });
+
+ return {
+ View: View
+ };
+});
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/ui/ui-table.js
--- a/static/scripts/mvc/ui/ui-table.js
+++ b/static/scripts/mvc/ui/ui-table.js
@@ -17,7 +17,7 @@
onchange : null,
ondblclick : null,
onconfirm : null,
- cls : ''
+ cls : 'ui-table'
},
// events
@@ -198,12 +198,11 @@
},
// load html template
- _template: function(options)
- {
+ _template: function(options) {
return '<div>' +
- '<table class="ui-table ' + options.cls + '">' +
+ '<table class="' + options.cls + '">' +
'<thead></thead>' +
- '<tbody style="cursor: pointer;"></tbody>' +
+ '<tbody></tbody>' +
'</table>' +
'<tmessage>' + options.content + '</tmessage>' +
'<div>';
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/mvc/ui/ui-tabs.js
--- a/static/scripts/mvc/ui/ui-tabs.js
+++ b/static/scripts/mvc/ui/ui-tabs.js
@@ -2,8 +2,7 @@
define(['utils/utils'], function(Utils) {
// return
-var View = Backbone.View.extend(
-{
+var View = Backbone.View.extend({
// defaults options
optionsDefault: {
title_new : '',
@@ -65,6 +64,11 @@
}
},
+ // size
+ size: function() {
+ return _.size(this.list);
+ },
+
// append
add: function(options) {
// self
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/galaxy.menu.js
--- a/static/scripts/packed/galaxy.menu.js
+++ b/static/scripts/packed/galaxy.menu.js
@@ -1,1 +1,1 @@
-define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Biostar",content:this.options.biostar_url_redirect,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});if(this.options.use_remote_user&&this.options.remote_user_logout_href){k.add({title:"Logout",content:this.options.remote_user_logout_href,target:"_top"})}else{k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true})}k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
+define(["galaxy.masthead"],function(b){var a=Backbone.Model.extend({options:null,masthead:null,initialize:function(c){this.options=c.config;this.masthead=c.masthead;this.create()},create:function(){var e=new b.GalaxyMastheadTab({id:"analysis",title:"Analyze Data",content:"root/index",title_attribute:"Analysis home view"});this.masthead.append(e);var g={id:"workflow",title:"Workflow",content:"workflow",title_attribute:"Chain tools into workflows"};if(!this.options.user.valid){g.disabled=true}var d=new b.GalaxyMastheadTab(g);this.masthead.append(d);var i=new b.GalaxyMastheadTab({id:"shared",title:"Shared Data",content:"library/index",title_attribute:"Access published resources"});i.add({title:"Data Libraries",content:"library/index"});i.add({title:"Data Libraries Beta",content:"library/list",divider:true});i.add({title:"Published Histories",content:"history/list_published"});i.add({title:"Published Workflows",content:"workflow/list_published"});i.add({title:"Published Visualizations",content:"visualization/list_published"});i.add({title:"Published Pages",content:"page/list_published"});this.masthead.append(i);if(this.options.user.requests){var j=new b.GalaxyMastheadTab({id:"lab",title:"Lab"});j.add({title:"Sequencing Requests",content:"requests/index"});j.add({title:"Find Samples",content:"requests/find_samples_index"});j.add({title:"Help",content:this.options.lims_doc_url});this.masthead.append(j)}var c={id:"visualization",title:"Visualization",content:"visualization/list",title_attribute:"Visualize datasets"};if(!this.options.user.valid){c.disabled=true}var m=new b.GalaxyMastheadTab(c);if(this.options.user.valid){m.add({title:"New Track Browser",content:"visualization/trackster",target:"_frame"});m.add({title:"Saved Visualizations",content:"visualization/list",target:"_frame"})}this.masthead.append(m);if(this.options.enable_cloud_launch){var f=new b.GalaxyMastheadTab({id:"cloud",title:"Cloud",content:"cloudlaunch/index"});f.add({title:"New Cloud Cluster",content:"cloudlaunch/index"});this.masthead.append(f)}if(this.options.is_admin_user){var h=new b.GalaxyMastheadTab({id:"admin",title:"Admin",content:"admin/index",extra_class:"admin-only",title_attribute:"Administer this Galaxy"});this.masthead.append(h)}var l=new b.GalaxyMastheadTab({id:"help",title:"Help",title_attribute:"Support, contact, and community hubs"});if(this.options.biostar_url){l.add({title:"Galaxy Biostar",content:this.options.biostar_url_redirect,target:"_blank"});l.add({title:"Ask a question",content:"biostar/biostar_question_redirect",target:"_blank"})}l.add({title:"Support",content:this.options.support_url,target:"_blank"});l.add({title:"Search",content:this.options.search_url,target:"_blank"});l.add({title:"Mailing Lists",content:this.options.mailing_lists,target:"_blank"});l.add({title:"Videos",content:this.options.screencasts_url,target:"_blank"});l.add({title:"Wiki",content:this.options.wiki_url,target:"_blank"});l.add({title:"How to Cite Galaxy",content:this.options.citation_url,target:"_blank"});if(this.options.terms_url){l.add({title:"Terms and Conditions",content:this.options.terms_url,target:"_blank"})}this.masthead.append(l);if(!this.options.user.valid){var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedout-only",title_attribute:"Account registration or login"});k.add({title:"Login",content:"user/login",target:"galaxy_main"});if(this.options.allow_user_creation){k.add({title:"Register",content:"user/create",target:"galaxy_main"})}this.masthead.append(k)}else{var k=new b.GalaxyMastheadTab({id:"user",title:"User",extra_class:"loggedin-only",title_attribute:"Account preferences and saved data"});k.add({title:"Logged in as "+this.options.user.email});k.add({title:"Preferences",content:"user?cntrller=user",target:"galaxy_main"});k.add({title:"Custom Builds",content:"user/dbkeys",target:"galaxy_main"});k.add({title:"Logout",content:"user/logout",target:"_top",divider:true});k.add({title:"Saved Histories",content:"history/list",target:"galaxy_main"});k.add({title:"Saved Datasets",content:"dataset/list",target:"galaxy_main"});k.add({title:"Saved Pages",content:"page/list",target:"_top"});k.add({title:"API Keys",content:"user/api_keys?cntrller=user",target:"galaxy_main"});if(this.options.use_remote_user){k.add({title:"Public Name",content:"user/edit_username?cntrller=user",target:"galaxy_main"})}this.masthead.append(k)}if(this.options.active_view){this.masthead.highlight(this.options.active_view)}}});return{GalaxyMenu:a}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/tools/tools-form.js
--- a/static/scripts/packed/mvc/tools/tools-form.js
+++ b/static/scripts/packed/mvc/tools/tools-form.js
@@ -1,1 +1,1 @@
-define(["mvc/ui/ui-portlet","mvc/ui/ui-table","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets"],function(f,i,j,h,a,e,c,g){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){var k=this;this.model.fetch({success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.table=new i.View();k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.portlet.append(k.table.$el);k.render()}})},render:function(){this.table.delAll();this.field_list={};this.inputs_sequential={};var k=new Backbone.Model();for(var l in this.inputs){this._add(this.inputs[l],k)}for(var l in this.field_list){this.field_list[l].trigger("change")}},_add:function(l,p){var n=l.type;switch(n){case"conditional":l.label=l.test_param.label;l.name=l.test_param.name;this._addRow("conditional",l,p);for(var m in l.cases){var o=l.cases[m];for(var k in o.inputs){this._add(o.inputs[k],p)}}break;default:this._addRow(n,l,p)}},_addRow:function(n,k,l){var p=k.name;var m=null;switch(n){case"text":m=this._field_text(k,l);break;case"select":m=this._field_select(k,l);break;case"radiobutton":m=this._field_radio(k,l);break;case"data":m=this._field_data(k,l);break;case"data_column":m=this._field_column(k,l);break;case"textarea":m=this._field_textarea(k,l);break;case"conditional":m=this._field_conditional(k,l);break}if(!m){console.debug("tools-form::_addRow() : Unmatched field type ("+n+").");return}if(!l.get(p)){l.set(p,k.value)}m.value(l.get(p));this.field_list[p]=m;this.inputs_sequential[p]=k;var o=$("<div/>");o.append(m.$el);if(k.info){o.append('<div class="ui-table-form-info">'+k.info+"</div>")}this.table.add('<span class="ui-table-form-title">'+k.label+"</span>","25%");this.table.add(o);this.table.append(p);if(k.hide){this.table.get(p).hide()}},_field_text:function(k,l){var m=k.name;return new j.Input({id:"field-"+m,value:l.get(m),onchange:function(n){l.set(m,n)}})},_field_textarea:function(k,l){var m=k.name;return new j.Textarea({id:"field-"+m,onchange:function(){l.set(m,field.value())}})},_field_conditional:function(m,p){var k=this;var l=[];for(var n in m.test_param.options){var o=m.test_param.options[n];l.push({label:o[0],value:o[1]})}var q=m.name;return new j.Select.View({id:"field-"+q,data:l,value:p.get(q),onchange:function(u){p.set(q,u);function t(x,w){for(var A in x.inputs){var z=x.inputs[A];var v=z.name;var B=k.table.get(v);if(w){B.fadeIn()}else{B.hide()}if(z.type=="conditional"){for(var y in z.cases){t(z.cases[y],w)}}}}for(var s in m.cases){var r=m.cases[s];t(r,r.value==u)}}})},_field_data:function(m,p){var k=this;var q=m.name;var o=this.datasets.filterType();var l=[];for(var n in o){l.push({label:o[n].get("name"),value:o[n].get("id")})}return new j.Select.View({id:"field-"+q,data:l,value:l[0].value,onchange:function(w){p.set(q,w);var s=_.where(k.inputs_sequential,{data_ref:q,type:"data_column"});var y=k.datasets.filter(w);if(y&&s.length>0){console.debug("tool-form::field_data() - Selected dataset "+w+".");var x=y.get("metadata_column_types");if(!x){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+w+".")}var v=[];for(var u in x){v.push({label:"Column: "+(parseInt(u)+1)+" ["+x[u]+"]",value:u})}for(var t in s){var r=k.field_list[s[t].name];if(r){r.update(v);r.value(r.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+w+".")}}})},_field_column:function(l,o){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var p=l.name;return new j.Select.View({id:"field-"+p,data:k,value:o.get(p),onchange:function(q){o.set(p,q)}})},_field_select:function(l,p){var k=[];for(var m in l.options){var n=l.options[m];k.push({label:n[0],value:n[1]})}var o=j.Select;if(l.display=="checkboxes"){o=j.Checkbox}var q=l.name;return new o.View({id:"field-"+q,data:k,value:p.get(q),onchange:function(r){p.set(q,r)}})},_field_radio:function(k,l){var m=k.name;return new j.RadioButton({id:"field-"+m,data:k.data,value:l.get(m),onchange:function(n){l.set(m,n)}})}});return{View:b}});
\ No newline at end of file
+define(["mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/citation/citation-model","mvc/citation/citation-view","mvc/tools","mvc/tools/tools-template","mvc/tools/tools-datasets","mvc/tools/tools-section"],function(f,j,h,a,e,c,g,i){var d=Backbone.Model.extend({initialize:function(k){this.url=galaxy_config.root+"api/tools/"+k.id+"?io_details=true"}});var b=Backbone.View.extend({main_el:"body",initialize:function(l){var k=this;this.options=l;this.model=new d({id:l.id});this.datasets=new g({success:function(){k._initializeToolForm()}})},_initializeToolForm:function(){this.field_list={};this.inputs_sequential={};var k=this;this.model.fetch({error:function(l){console.debug("tools-form::_initializeToolForm() : Attempt to fetch tool model failed.")},success:function(){k.inputs=k.model.get("inputs");k.portlet=new f.View({icon:"fa-wrench",title:"<b>"+k.model.get("name")+"</b> "+k.model.get("description"),buttons:{execute:new j.ButtonIcon({icon:"fa-check",tooltip:"Execute the tool",title:"Execute",floating:"clear",onclick:function(){}})}});k.message=new j.Message();k.portlet.append(k.message.$el);$(k.main_el).append(k.portlet.$el);if(k.options.help!=""){$(k.main_el).append(c.help(k.options.help))}if(k.options.citations){$(k.main_el).append(c.citations());var l=new h.ToolCitationCollection();l.tool_id=k.options.id;var m=new a.CitationListView({collection:l});m.render();l.fetch()}k.setElement(k.portlet.content());k.section=new i.View(k,{inputs:k.model.get("inputs")});k.portlet.append(k.section.$el)}})}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/tools/tools-section.js
--- /dev/null
+++ b/static/scripts/packed/mvc/tools/tools-section.js
@@ -0,0 +1,1 @@
+define(["mvc/ui/ui-table","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(b,d,a){var c=Backbone.View.extend({initialize:function(f,e){this.app=f;this.inputs=e.inputs;this.datasets=f.datasets;this.table=new b.View(e);this.setElement(this.table.$el);this.render()},render:function(){this.table.delAll();var e=new Backbone.Model();for(var f in this.inputs){this._add(this.inputs[f],e)}for(var f in this.app.field_list){this.app.field_list[f].trigger("change")}},_add:function(f,k){var e=this;var j=f.type;switch(j){case"conditional":f.label=f.test_param.label;f.name=f.test_param.name;this._addRow("conditional",f,k);for(var h in f.cases){var l=new c(this.app,{inputs:f.cases[h].inputs,cls:"ui-table-plain"});this.table.add("");this.table.add(l.$el);this.table.append(f.name+"_formsection_"+h)}break;case"repeat":var g=new a.View({title_new:"Add Group",onnew:function(){var m=new c(e.app,{inputs:f.inputs,cls:"ui-table-plain"});var i=f.name+"_formsection_"+g.size();g.add({id:i,title:"Repeat",$el:m.$el,ondel:function(){g.del(i)}});g.show(i)}});this.table.add(f.title);this.table.add(g.$el);this.table.append(f.name);break;default:this._addRow(j,f,k)}},_addRow:function(h,e,f){var j=e.name;var g=null;switch(h){case"text":g=this._field_text(e,f);break;case"select":g=this._field_select(e,f);break;case"radiobutton":g=this._field_radio(e,f);break;case"data":g=this._field_data(e,f);break;case"data_column":g=this._field_column(e,f);break;case"textarea":g=this._field_textarea(e,f);break;case"conditional":g=this._field_conditional(e,f);break}if(!g){console.debug("tools-form::_addRow() : Unmatched field type ("+h+").");return}if(!f.get(j)){f.set(j,e.value)}g.value(f.get(j));this.app.field_list[j]=g;this.app.inputs_sequential[j]=e;var i=$("<div/>");i.append(g.$el);if(e.help){i.append('<div class="ui-table-form-info">'+e.help+"</div>")}this.table.add('<span class="ui-table-form-title">'+e.label+"</span>","25%");this.table.add(i);this.table.append(j);if(e.hide){this.table.get(j).hide()}},_field_text:function(e,f){var g=e.name;return new d.Input({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_textarea:function(e,f){var g=e.name;return new d.Textarea({id:"field-"+g,onchange:function(){f.set(g,field.value())}})},_field_conditional:function(g,k){var e=this;var f=[];for(var h in g.test_param.options){var j=g.test_param.options[h];f.push({label:j[0],value:j[1]})}var l=g.name;return new d.Select.View({id:"field-"+l,data:f,value:k.get(l),onchange:function(q){k.set(l,q);for(var p in g.cases){var n=g.cases[p];var o=g.name+"_formsection_"+p;var m=e.table.get(o);if(n.value==q){m.show()}else{m.hide()}}}})},_field_data:function(g,k){var e=this;var l=g.name;var j=this.datasets.filterType();var f=[];for(var h in j){f.push({label:j[h].get("name"),value:j[h].get("id")})}return new d.Select.View({id:"field-"+l,data:f,value:f[0].value,onchange:function(r){k.set(l,r);var n=_.where(e.app.inputs_sequential,{data_ref:l,type:"data_column"});var t=e.datasets.filter(r);if(t&&n.length>0){console.debug("tool-form::field_data() - Selected dataset "+r+".");var s=t.get("metadata_column_types");if(!s){console.debug("tool-form::field_data() - FAILED: Could not find metadata for dataset "+r+".")}var q=[];for(var p in s){q.push({label:"Column: "+(parseInt(p)+1)+" ["+s[p]+"]",value:p})}for(var o in n){var m=e.app.field_list[n[o].name];if(m){m.update(q);m.value(m.first())}}}else{console.debug("tool-form::field_data() - FAILED: Could not find dataset "+r+".")}}})},_field_column:function(e,f){var g=e.name;return new d.Select.View({id:"field-"+g,value:f.get(g),onchange:function(h){f.set(g,h)}})},_field_select:function(f,k){var e=[];for(var g in f.options){var h=f.options[g];e.push({label:h[0],value:h[1]})}var j=d.Select;if(f.display=="checkboxes"){j=d.Checkbox}var l=f.name;return new j.View({id:"field-"+l,data:e,value:k.get(l),onchange:function(i){k.set(l,i)}})},_field_radio:function(e,f){var g=e.name;return new d.RadioButton({id:"field-"+g,data:e.data,value:f.get(g),onchange:function(h){f.set(g,h)}})}});return{View:c}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/ui/ui-table.js
--- a/static/scripts/packed/mvc/ui/ui-table.js
+++ b/static/scripts/packed/mvc/ui/ui-table.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:""},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=$("<tr></tr>")},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=$("<tr></tr>");this.row_count++;this._refresh()},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="ui-table '+c.cls+'"><thead></thead><tbody style="cursor: pointer;"></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({row:null,row_count:0,optionsDefault:{content:"No content available.",onchange:null,ondblclick:null,onconfirm:null,cls:"ui-table"},events:{click:"_onclick",dblclick:"_ondblclick"},initialize:function(c){this.options=a.merge(c,this.optionsDefault);var d=$(this._template(this.options));this.$thead=d.find("thead");this.$tbody=d.find("tbody");this.$tmessage=d.find("tmessage");this.setElement(d);this.row=$("<tr></tr>")},addHeader:function(c){var d=$("<th></th>");d.append(c);this.row.append(d)},appendHeader:function(){this.$thead.append(this.row);this.row=$("<tr></tr>")},add:function(c,d,f){var e=$("<td></td>");if(d){e.css("width",d)}if(f){e.css("text-align",f)}e.append(c);this.row.append(e)},append:function(c){this._commit(c)},prepend:function(c){this._commit(c,true)},get:function(c){return this.$el.find("#"+c)},del:function(d){var c=this.$tbody.find("#"+d);if(c.length>0){c.remove();this.row_count--;this._refresh()}},delAll:function(){this.$tbody.empty();this.row_count=0;this._refresh()},value:function(c){this.before=this.$tbody.find(".current").attr("id");if(c!==undefined){this.$tbody.find("tr").removeClass("current");if(c){this.$tbody.find("#"+c).addClass("current")}}var d=this.$tbody.find(".current").attr("id");if(d===undefined){return null}else{if(d!=this.before&&this.options.onchange){this.options.onchange(c)}return d}},size:function(){return this.$tbody.find("tr").length},_commit:function(d,c){this.del(d);this.row.attr("id",d);if(c){this.$tbody.prepend(this.row)}else{this.$tbody.append(this.row)}this.row=$("<tr></tr>");this.row_count++;this._refresh()},_onclick:function(f){var c=this.value();var d=$(f.target).closest("tr").attr("id");if(d!=""){if(d&&c!=d){if(this.options.onconfirm){this.options.onconfirm(d)}else{this.value(d)}}}},_ondblclick:function(d){var c=this.value();if(c&&this.options.ondblclick){this.options.ondblclick(c)}},_refresh:function(){if(this.row_count==0){this.$tmessage.show()}else{this.$tmessage.hide()}},_template:function(c){return'<div><table class="'+c.cls+'"><thead></thead><tbody></tbody></table><tmessage>'+c.content+"</tmessage><div>"}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/scripts/packed/mvc/ui/ui-tabs.js
--- a/static/scripts/packed/mvc/ui/ui-tabs.js
+++ b/static/scripts/packed/mvc/ui/ui-tabs.js
@@ -1,1 +1,1 @@
-define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#tab-content-"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}},delRemovable:function(){for(var c in this.list){if(this.list[c]){this.del(c)}}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#tab-content-"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#tab-content-'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="tab-content-'+c.id+'" class="tab-pane"/>'}});return{View:b}});
\ No newline at end of file
+define(["utils/utils"],function(a){var b=Backbone.View.extend({optionsDefault:{title_new:"",operations:null,onnew:null},initialize:function(e){this.visible=false;this.$nav=null;this.$content=null;this.first_tab=null;this.options=a.merge(e,this.optionsDefault);var c=$(this._template(this.options));this.$nav=c.find(".tab-navigation");this.$content=c.find(".tab-content");this.setElement(c);this.list={};var d=this;if(this.options.operations){$.each(this.options.operations,function(g,h){h.$el.prop("id",g);d.$nav.find(".operations").append(h.$el)})}if(this.options.onnew){var f=$(this._template_tab_new(this.options));this.$nav.append(f);f.tooltip({title:"Add a new tab",placement:"bottom",container:d.$el});f.on("click",function(g){f.tooltip("hide");d.options.onnew()})}},size:function(){return _.size(this.list)},add:function(f){var e=this;var h=f.id;var g=$(this._template_tab(f));var d=$(this._template_tab_content(f));this.list[h]=f.ondel?true:false;if(this.options.onnew){this.$nav.find("#new-tab").before(g)}else{this.$nav.append(g)}d.append(f.$el);this.$content.append(d);if(_.size(this.list)==1){g.addClass("active");d.addClass("active");this.first_tab=h}if(f.ondel){var c=g.find("#delete");c.tooltip({title:"Delete this tab",placement:"bottom",container:e.$el});c.on("click",function(){c.tooltip("destroy");e.$el.find(".tooltip").remove();f.ondel();return false})}g.on("click",function(i){i.preventDefault();if(f.onclick){f.onclick()}else{e.show(h)}})},del:function(c){this.$el.find("#tab-"+c).remove();this.$el.find("#tab-content-"+c).remove();if(this.first_tab==c){this.first_tab=null}if(this.first_tab!=null){this.show(this.first_tab)}},delRemovable:function(){for(var c in this.list){if(this.list[c]){this.del(c)}}},show:function(c){this.$el.fadeIn("fast");this.visible=true;if(c){this.$el.find(".tab-element").removeClass("active");this.$el.find(".tab-pane").removeClass("active");this.$el.find("#tab-"+c).addClass("active");this.$el.find("#tab-content-"+c).addClass("active")}},hide:function(){this.$el.fadeOut("fast");this.visible=false},hideOperation:function(c){this.$nav.find("#"+c).hide()},showOperation:function(c){this.$nav.find("#"+c).show()},setOperation:function(e,d){var c=this.$nav.find("#"+e);c.off("click");c.on("click",d)},title:function(e,d){var c=this.$el.find("#tab-title-text-"+e);if(d){c.html(d)}return c.html()},_template:function(c){return'<div class="ui-tabs tabbable tabs-left"><ul id="tab-navigation" class="tab-navigation nav nav-tabs"><div class="operations" style="float: right; margin-bottom: 4px;"></div></ul><div id="tab-content" class="tab-content"/></div>'},_template_tab_new:function(c){return'<li id="new-tab"><a href="javascript:void(0);"><i class="ui-tabs-add fa fa-plus-circle"/>'+c.title_new+"</a></li>"},_template_tab:function(d){var c='<li id="tab-'+d.id+'" class="tab-element"><a id="tab-title-link-'+d.id+'" title="" href="#tab-content-'+d.id+'" data-original-title=""><span id="tab-title-text-'+d.id+'">'+d.title+"</span>";if(d.ondel){c+='<i id="delete" class="ui-tabs-delete fa fa-minus-circle"/>'}c+="</a></li>";return c},_template_tab_content:function(c){return'<div id="tab-content-'+c.id+'" class="tab-pane"/>'}});return{View:b}});
\ No newline at end of file
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/style/blue/base.css
--- a/static/style/blue/base.css
+++ b/static/style/blue/base.css
@@ -1279,6 +1279,9 @@
.upload-ftp .upload-ftp-warning{text-align:center;margin-top:20px}
.upload-settings .upload-settings-cover{position:absolute;width:100%;height:100%;top:0px;left:0px;background:#fff;opacity:0.4;cursor:no-drop}
.ui-radiobutton label{height:23px;line-height:1em}
+.ui-table tbody{cursor:pointer}
+.ui-table-plain tbody td{padding:5px 0px 5px 5px !important;border:none !important}
+.ui-table-plain tbody{cursor:auto !important}
.ui-table-form-separator{font-weight:bold;font-size:0.9em}
.ui-label{font-weight:bold}
.ui-message{padding:2px 2px 2px 10px}
@@ -1528,13 +1531,13 @@
.grid-header{padding-bottom:1em}
.grid-header h2{margin:0;margin-bottom:0.5em}
.grid-header .title{font-weight:bold}
-.grid,.ui-table{padding-top:1em;border-collapse:collapse;width:100%}
+.grid,.ui-table,.ui-table-plain{padding-top:1em;border-collapse:collapse;width:100%}
.grid tbody td,.ui-table tbody td{line-height:1.428571429;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
.grid tbody td:empty{padding:0}
.grid thead tr{height:2em}
.grid thead th{line-height:1.428571429;background:#ebd9b2;color:#000;border-top:solid #d6b161 1px;border-bottom:solid #d6b161 1px;padding:5px;text-align:left;white-space:nowrap}
.grid tfoot td{background-color:#F8F8F8;border-top:solid #DDDDDD 1px;border-bottom:solid #DDDDDD 1px;padding:5px}
-.grid .current,.ui-table .current{background-color:#EEEEFF}
+.grid .current{background-color:#EEEEFF}
.count-box{min-width:1.1em;padding:5px;border-width:1px;border-style:solid;text-align:center;display:inline-block}
.text-filter-val{border:solid 1px #AAAAAA;padding:1px 2px 1px 3px;margin-right:5px;-moz-border-radius:.5em;-webkit-border-radius:.5em;font-style:italic}
.page-link a,.inactive-link{padding:0px 7px 0px 7px;color:#555}
diff -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 -r c665ed80227c76001c0a2e767e66d992ed72b4ad static/style/src/less/ui.less
--- a/static/style/src/less/ui.less
+++ b/static/style/src/less/ui.less
@@ -11,8 +11,22 @@
tbody td {
&:extend(.grid tbody td);
}
- .current {
- &:extend(.grid .current);
+
+ tbody {
+ cursor: pointer;
+ }
+}
+
+.ui-table-plain {
+ &:extend(.grid);
+
+ tbody td {
+ padding: 5px 0px 5px 5px !important;
+ border: none !important;
+ }
+
+ tbody {
+ cursor: auto !important;
}
}
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dannon: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
by commits-noreply@bitbucket.org 25 Aug '14
by commits-noreply@bitbucket.org 25 Aug '14
25 Aug '14
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/261471d04763/
Changeset: 261471d04763
User: dannon
Date: 2014-08-25 15:28:26
Summary: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
Enabling UUID in file upload
Affected #: 3 files
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6cb895d18331/
Changeset: 6cb895d18331
Branch: upload_uuid
User: kellrott
Date: 2014-08-15 02:08:29
Summary: Enabling UUID in file upload
Affected #: 3 files
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r d301ac50aa86a94e230d44eb2ae10c6c0e354b88 -r 6cb895d18331fa542b7e3e95598c59de63724246 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="text" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
https://bitbucket.org/galaxy/galaxy-central/commits/67dbeb43ebd2/
Changeset: 67dbeb43ebd2
Branch: upload_uuid
User: kellrott
Date: 2014-08-19 01:37:30
Summary: Hiding UUID input for upload tool
Affected #: 1 file
diff -r 6cb895d18331fa542b7e3e95598c59de63724246 -r 67dbeb43ebd21ebad8ad579315f3bf807692f9c8 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,7 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
- <param name="uuid" type="text" required="False" />
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
https://bitbucket.org/galaxy/galaxy-central/commits/261471d04763/
Changeset: 261471d04763
User: dannon
Date: 2014-08-25 15:28:26
Summary: Merged in kellrott/galaxy-farm/upload_uuid (pull request #463)
Enabling UUID in file upload
Affected #: 3 files
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/actions/upload_common.py
--- a/lib/galaxy/tools/actions/upload_common.py
+++ b/lib/galaxy/tools/actions/upload_common.py
@@ -243,6 +243,7 @@
else:
data.extension = uploaded_dataset.file_type
data.dbkey = uploaded_dataset.dbkey
+ data.uuid = uploaded_dataset.uuid
trans.sa_session.add( data )
trans.sa_session.flush()
if library_bunch:
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 lib/galaxy/tools/parameters/grouping.py
--- a/lib/galaxy/tools/parameters/grouping.py
+++ b/lib/galaxy/tools/parameters/grouping.py
@@ -278,6 +278,7 @@
ftp_files = context['ftp_files']
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
+ uuid = context.get( 'uuid', None )
warnings = []
to_posix_lines = False
if context.get( 'to_posix_lines', None ) not in [ "None", None, False ]:
@@ -316,12 +317,14 @@
break
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
+ file_bunch.uuid = uuid
return file_bunch, warnings
def get_filenames( context ):
rval = []
data_file = context['file_data']
url_paste = context['url_paste']
ftp_files = context['ftp_files']
+ uuid = context.get( 'uuid', None )
name = context.get( 'NAME', None )
info = context.get( 'INFO', None )
to_posix_lines = False
@@ -332,12 +335,14 @@
space_to_tab = True
warnings = []
file_bunch = get_data_file_filename( data_file, override_name = name, override_info = info )
+ file_bunch.uuid = uuid
if file_bunch.path:
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
for file_bunch in get_url_paste_urls_or_filename( context, override_name = name, override_info = info ):
if file_bunch.path:
+ file_bunch.uuid = uuid
file_bunch.to_posix_lines = to_posix_lines
file_bunch.space_to_tab = space_to_tab
rval.append( file_bunch )
diff -r 9d8b9171a945341e36aae88572d4d37dd9b12ef2 -r 261471d0476328d8bbdbe71b9d6a954abf032ad7 tools/data_source/upload.xml
--- a/tools/data_source/upload.xml
+++ b/tools/data_source/upload.xml
@@ -41,6 +41,7 @@
<!-- Swap the following parameter for the select one that follows to
enable the to_posix_lines option in the Web GUI. See Bitbucket
Pull Request 171 for more information. -->
+ <param name="uuid" type="hidden" required="False" /><param name="to_posix_lines" type="hidden" value="Yes" /><!--
<param name="to_posix_lines" type="select" display="checkboxes" multiple="True" label="Convert universal line endings to Posix line endings" help="Turn this option off if you upload a gzip, bz2 or zip archive which contains a binary file." value="Yes">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0