mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
trackster:
- Can save configs - Make track configs look like history items instead of tool configs - Small performance tweaks - Implemented "Add Track" grid (doesn't actually add track yet) Grids: - Lowercase when sorting so that we sort strings case-independent - Can click on text to toggle appropriate checkbox
This commit is contained in:
@@ -7,13 +7,14 @@ import pkg_resources; pkg_resources.require( "pysam" )
|
||||
from pysam import csamtools
|
||||
from math import floor, ceil, log
|
||||
import logging
|
||||
# log = logging.getLogger(__name__)
|
||||
|
||||
class BamDataProvider( object ):
|
||||
"""
|
||||
Provides access to intervals from a sorted indexed BAM file.
|
||||
"""
|
||||
def __init__( self, index, original_dataset ):
|
||||
# self.log = logging.getLogger(__name__)
|
||||
|
||||
self.index = index
|
||||
self.original_dataset = original_dataset
|
||||
|
||||
@@ -27,8 +28,7 @@ class BamDataProvider( object ):
|
||||
try:
|
||||
data = bamfile.fetch(start=start, end=end, reference=chrom)
|
||||
except ValueError, e:
|
||||
# Some BAM files do not prefix chromosome names with chr, try
|
||||
# without
|
||||
# Some BAM files do not prefix chromosome names with chr, try without
|
||||
if chrom.startswith( 'chr' ):
|
||||
data = bamfile.fetch( start=start, end=end, reference=chrom[3:] )
|
||||
else:
|
||||
|
||||
@@ -19,6 +19,7 @@ log = logging.getLogger(__name__)
|
||||
from galaxy.util.json import to_json_string
|
||||
from galaxy.web.base.controller import *
|
||||
from galaxy.web.framework import simplejson
|
||||
from galaxy.web.framework.helpers import time_ago, grids
|
||||
from galaxy.util.bunch import Bunch
|
||||
|
||||
from galaxy.visualization.tracks.data.array_tree import ArrayTreeDataProvider
|
||||
@@ -43,12 +44,40 @@ dataset_type_to_data_provider = {
|
||||
"bai": BamDataProvider
|
||||
}
|
||||
|
||||
class DatasetSelectionGrid( grids.Grid ):
|
||||
# Grid definition.
|
||||
available_tracks = None
|
||||
title = "Add Tracks"
|
||||
template = "/tracks/add_tracks.mako"
|
||||
async_template = "/page/select_histories_grid_async.mako"
|
||||
model_class = model.HistoryDatasetAssociation
|
||||
default_filter = { "deleted" : "False" , "shared" : "All" }
|
||||
default_sort_key = "name"
|
||||
use_async = True
|
||||
use_paging = False
|
||||
columns = [
|
||||
grids.TextColumn( "Name", key="name", model_class=model.HistoryDatasetAssociation ),
|
||||
# grids.IndividualTagsColumn( "Tags", "tags", model.History, model.HistoryTagAssociation, filterable="advanced"),
|
||||
grids.GridColumn( "Filetype", key="extension" ),
|
||||
# Columns that are valid for filtering but are not visible.
|
||||
# SharingColumn( "Shared", key="shared", visible=False, filterable="advanced" )
|
||||
]
|
||||
def apply_default_filter( self, trans, query, **kwargs ):
|
||||
if self.available_tracks is None:
|
||||
self.available_tracks = trans.app.datatypes_registry.get_available_tracks()
|
||||
return query.select_from( model.HistoryDatasetAssociation.table \
|
||||
.join( model.History.table ) ) \
|
||||
.filter( model.History.user == trans.user ) \
|
||||
.filter( model.HistoryDatasetAssociation.extension.in_(self.available_tracks) )
|
||||
|
||||
class TracksController( BaseController ):
|
||||
"""
|
||||
Controller for track browser interface. Handles building a new browser from
|
||||
datasets in the current history, and display of the resulting browser.
|
||||
"""
|
||||
|
||||
|
||||
available_tracks = None
|
||||
|
||||
@web.expose
|
||||
def index( self, trans ):
|
||||
return trans.fill_template( "tracks/index.mako" )
|
||||
@@ -98,12 +127,13 @@ class TracksController( BaseController ):
|
||||
# Find all datasets in the current history that are of that dbkey
|
||||
# and can be displayed
|
||||
datasets = {}
|
||||
available_tracks = trans.app.datatypes_registry.get_available_tracks()
|
||||
if self.available_tracks is None:
|
||||
self.available_tracks = trans.app.datatypes_registry.get_available_tracks()
|
||||
for dataset in session.query( model.HistoryDatasetAssociation ).filter_by( deleted=False, history_id=trans.history.id ):
|
||||
if dataset.metadata.dbkey == dbkey and dataset.extension in available_tracks:
|
||||
if dataset.metadata.dbkey == dbkey and dataset.extension in self.available_tracks:
|
||||
datasets[dataset.id] = (dataset.extension, dataset.name)
|
||||
# Render the template
|
||||
return trans.fill_template( "tracks/new_browser.mako", available_tracks=available_tracks, dbkey=dbkey, dbkey_set=dbkey_set, datasets=datasets )
|
||||
return trans.fill_template( "tracks/new_browser.mako", available_tracks=self.available_tracks, dbkey=dbkey, dbkey_set=dbkey_set, datasets=datasets )
|
||||
|
||||
@web.expose
|
||||
def browser(self, trans, id, chrom=""):
|
||||
@@ -118,13 +148,18 @@ class TracksController( BaseController ):
|
||||
hda_query = session.query( model.HistoryDatasetAssociation )
|
||||
for t in vis.latest_revision.config['tracks']:
|
||||
dataset_id = t['dataset_id']
|
||||
try:
|
||||
prefs = t['prefs']
|
||||
except KeyError:
|
||||
prefs = {}
|
||||
dataset = hda_query.get( dataset_id )
|
||||
track_type, indexer = dataset.datatype.get_track_type()
|
||||
tracks.append( {
|
||||
"type": track_type,
|
||||
"track_type": track_type,
|
||||
"indexer": indexer,
|
||||
"name": dataset.name,
|
||||
"dataset_id": dataset.id
|
||||
"dataset_id": dataset.id,
|
||||
"prefs": simplejson.dumps(prefs),
|
||||
} )
|
||||
dbkey = dataset.dbkey
|
||||
chrom_lengths = self._chroms( trans, dbkey )
|
||||
@@ -252,7 +287,40 @@ class TracksController( BaseController ):
|
||||
return new_dataset
|
||||
|
||||
@web.json
|
||||
def update_config( self, trans, **kwargs ):
|
||||
raise RuntimeError
|
||||
def save( self, trans, **kwargs ):
|
||||
decoded_id = trans.security.decode_id( kwargs['id'] )
|
||||
session = trans.sa_session
|
||||
vis = session.query( model.Visualization ).get( decoded_id )
|
||||
|
||||
decoded_payload = simplejson.loads( kwargs['payload'] )
|
||||
vis_rev = model.VisualizationRevision()
|
||||
vis_rev.visualization = vis
|
||||
vis_rev.title = vis.title
|
||||
tracks = []
|
||||
for track in decoded_payload:
|
||||
tracks.append( { "dataset_id": str(track['dataset_id']),
|
||||
"name": track['name'],
|
||||
"indexer": track['indexer'],
|
||||
"track_type": track['track_type'],
|
||||
"prefs": track['prefs']
|
||||
} )
|
||||
vis_rev.config = { "tracks": tracks }
|
||||
vis.latest_revision = vis_rev
|
||||
session.add( vis_rev )
|
||||
session.flush()
|
||||
|
||||
data_grid = DatasetSelectionGrid()
|
||||
|
||||
@web.expose
|
||||
@web.require_login( "see all available datasets" )
|
||||
def list_datasets( self, trans, **kwargs ):
|
||||
"""List all datasets that can be added as tracks"""
|
||||
|
||||
|
||||
# Render the list view
|
||||
# return trans.fill_template( 'tracks/add_tracks.mako', grid=data_grid( trans, status=status, message=message, **kwargs ) )
|
||||
return self.data_grid( trans, **kwargs )
|
||||
|
||||
#
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ log = logging.getLogger( __name__ )
|
||||
|
||||
class Grid( object ):
|
||||
"""
|
||||
Specifieds the content and format of a grid (data table).
|
||||
Specifies the content and format of a grid (data table).
|
||||
"""
|
||||
title = ""
|
||||
exposed = True
|
||||
@@ -157,10 +157,10 @@ class Grid( object ):
|
||||
if sort_key.startswith( "-" ):
|
||||
sort_key = sort_key[1:]
|
||||
sort_order = 'desc'
|
||||
query = query.order_by( self.model_class.table.c.get( sort_key ).desc() )
|
||||
query = query.order_by( func.lower( self.model_class.table.c.get( sort_key ) ).desc() )
|
||||
else:
|
||||
sort_order = 'asc'
|
||||
query = query.order_by( self.model_class.table.c.get( sort_key ).asc() )
|
||||
query = query.order_by( func.lower( self.model_class.table.c.get( sort_key ) ).asc() )
|
||||
extra_url_args['sort'] = encoded_sort_key
|
||||
|
||||
# There might be a current row
|
||||
@@ -230,7 +230,7 @@ class Grid( object ):
|
||||
else:
|
||||
new_kwargs[ 'id' ] = trans.security.encode_id( id )
|
||||
return url_for( **new_kwargs )
|
||||
|
||||
|
||||
async_request = ( ( self.use_async ) and ( 'async' in kwargs ) and ( kwargs['async'] in [ 'True', 'true'] ) )
|
||||
return trans.fill_template( iff( async_request, self.async_template, self.template),
|
||||
grid=self,
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+88
-62
@@ -94,7 +94,18 @@ $.extend( View.prototype, {
|
||||
this.tracks.push( track );
|
||||
if (track.init) { track.init(); }
|
||||
},
|
||||
redraw: function () {
|
||||
remove_track: function( track ) {
|
||||
delete this.tracks[track];
|
||||
},
|
||||
update_options: function() {
|
||||
for (var track_id in view.tracks) {
|
||||
var track = view.tracks[track_id];
|
||||
if (track.update_options) {
|
||||
track.update_options(track_id);
|
||||
}
|
||||
}
|
||||
},
|
||||
redraw: function() {
|
||||
var span = this.span / Math.pow(this.zoom_factor, this.zoom_level),
|
||||
low = this.center - (span / 2),
|
||||
high = low + span;
|
||||
@@ -252,23 +263,22 @@ $.extend( LabelTrack.prototype, Track.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
var LineTrack = function ( name, dataset_id, indexer, height, minval, maxval ) {
|
||||
var LineTrack = function ( name, dataset_id, indexer, prefs ) {
|
||||
this.track_type = "LineTrack";
|
||||
this.tile_cache = new Cache(CACHED_TILES_LINE);
|
||||
Track.call( this, name, $("#viewport") );
|
||||
TiledTrack.call( this );
|
||||
|
||||
this.indexer = indexer;
|
||||
this.height_px = (height ? height : 100);
|
||||
this.height_px = 100;
|
||||
this.container_div.addClass( "line-track" );
|
||||
this.dataset_id = dataset_id;
|
||||
this.data_queue = {};
|
||||
this.data_cache = new Cache(CACHED_DATA); // We need to cache some data because of
|
||||
// asynchronous calls
|
||||
if (minval !== undefined && maxval !== undefined) {
|
||||
this.min_value = minval;
|
||||
this.max_value = maxval;
|
||||
this.vertical_range = maxval - minval;
|
||||
}
|
||||
this.prefs = { 'min_value': undefined, 'max_value': undefined };
|
||||
if (prefs.min_value !== undefined) { this.prefs.min_value = prefs.min_value; }
|
||||
if (prefs.max_value !== undefined) { this.prefs.max_value = prefs.max_value; }
|
||||
};
|
||||
$.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
init: function() {
|
||||
@@ -293,19 +303,19 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
track.content_div.text("");
|
||||
track.content_div.css( "height", track.height_px + "px" );
|
||||
|
||||
if (track.min_value === undefined || track.max_value === undefined) {
|
||||
track.min_value = data.min;
|
||||
track.max_value = data.max;
|
||||
track.vertical_range = track.max_value - track.min_value;
|
||||
|
||||
if (track.prefs.min_value === undefined || track.prefs.max_value === undefined) {
|
||||
track.prefs.min_value = data.min;
|
||||
track.prefs.max_value = data.max;
|
||||
|
||||
// Update the config
|
||||
$('#track_' + track_id + '_minval').val(track.min_value);
|
||||
$('#track_' + track_id + '_maxval').val(track.max_value);
|
||||
$('#track_' + track_id + '_minval').val(track.prefs.min_value);
|
||||
$('#track_' + track_id + '_maxval').val(track.prefs.max_value);
|
||||
}
|
||||
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
|
||||
|
||||
// Draw y-axis labels
|
||||
var min_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_minval').text(track.min_value);
|
||||
var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.max_value);
|
||||
var min_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_minval').text(track.prefs.min_value);
|
||||
var max_label = $("<div></div>").addClass('yaxislabel').attr("id", 'linetrack_' + track_id + '_maxval').text(track.prefs.max_value);
|
||||
|
||||
max_label.css({ position: "relative", top: "25px" });
|
||||
max_label.prependTo(track.container_div);
|
||||
@@ -358,8 +368,13 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
|
||||
canvas.get(0).width = Math.ceil( tile_length * w_scale );
|
||||
canvas.get(0).height = this.height_px;
|
||||
var ctx = canvas.get(0).getContext("2d");
|
||||
var in_path = false;
|
||||
var ctx = canvas.get(0).getContext("2d"),
|
||||
in_path = false,
|
||||
min_value = this.prefs.min_value,
|
||||
max_value = this.prefs.max_value,
|
||||
vertical_range = this.vertical_range,
|
||||
height_px = this.height_px;
|
||||
|
||||
ctx.beginPath();
|
||||
for ( var i = 0; i < data.length - 1; i++ ) {
|
||||
var x = data[i][0] - tile_low;
|
||||
@@ -371,12 +386,12 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
// Translate
|
||||
x = x * w_scale;
|
||||
// console.log(y, this.min_value, this.vertical_range, (y - this.min_value) / this.vertical_range * this.height_px);
|
||||
if (y <= this.min_value) {
|
||||
y = this.min_value;
|
||||
} else if (y >= this.max_value) {
|
||||
y = this.max_value;
|
||||
if (y <= min_value) {
|
||||
y = min_value;
|
||||
} else if (y >= max_value) {
|
||||
y = max_value;
|
||||
}
|
||||
y = Math.round( this.height_px - (y - this.min_value) / this.vertical_range * this.height_px );
|
||||
y = Math.round( height_px - (y - min_value) / vertical_range * height_px );
|
||||
// console.log(canvas.get(0).height, canvas.get(0).width);
|
||||
if ( in_path ) {
|
||||
ctx.lineTo( x, y );
|
||||
@@ -395,33 +410,37 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
var minval = 'track_' + track_id + '_minval',
|
||||
maxval = 'track_' + track_id + '_maxval',
|
||||
min_label = $('<label></label>').attr("for", minval).text("Min value:"),
|
||||
min_input = $('<input></input>').attr("id", minval).val(this.min_value || ""),
|
||||
min_val = (this.prefs.min_value === undefined ? "" : this.prefs.min_value),
|
||||
min_input = $('<input></input>').attr("id", minval).val(min_val),
|
||||
max_label = $('<label></label>').attr("for", maxval).text("Max value:"),
|
||||
max_input = $('<input></input>').attr("id", maxval).val(this.max_value || "");
|
||||
max_val = (this.prefs.max_value === undefined ? "" : this.prefs.max_value),
|
||||
max_input = $('<input></input>').attr("id", maxval).val(max_val);
|
||||
|
||||
return container.append(min_label).append(min_input).append(max_label).append(max_input);
|
||||
}, update_options: function(track_id) {
|
||||
var min_value = $('#track_' + track_id + '_minval').val(),
|
||||
max_value = $('#track_' + track_id + '_maxval').val();
|
||||
if ( min_value !== this.min_value || max_value !== this.max_value) {
|
||||
this.min_value = parseFloat(min_value);
|
||||
this.max_value = parseFloat(max_value);
|
||||
this.vertical_range = this.max_value - this.min_value;
|
||||
$('#linetrack_' + track_id + '_minval').text(this.min_value);
|
||||
$('#linetrack_' + track_id + '_maxval').text(this.max_value);
|
||||
if ( min_value !== this.prefs.min_value || max_value !== this.prefs.max_value) {
|
||||
this.prefs.min_value = parseFloat(min_value);
|
||||
this.prefs.max_value = parseFloat(max_value);
|
||||
this.vertical_range = this.prefs.max_value - this.prefs.min_value;
|
||||
// Update the y-axis
|
||||
$('#linetrack_' + track_id + '_minval').text(this.prefs.min_value);
|
||||
$('#linetrack_' + track_id + '_maxval').text(this.prefs.max_value);
|
||||
this.tile_cache.clear();
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var FeatureTrack = function ( name, dataset_id, indexer, height ) {
|
||||
var FeatureTrack = function ( name, dataset_id, indexer, prefs ) {
|
||||
this.track_type = "FeatureTrack";
|
||||
this.tile_cache = new Cache(CACHED_TILES_FEATURE);
|
||||
Track.call( this, name, $("#viewport") );
|
||||
TiledTrack.call( this );
|
||||
|
||||
this.indexer = indexer;
|
||||
this.height_px = (height ? height : 100);
|
||||
this.height_px = 100;
|
||||
this.container_div.addClass( "feature-track" );
|
||||
this.dataset_id = dataset_id;
|
||||
this.zo_slots = {};
|
||||
@@ -429,14 +448,16 @@ var FeatureTrack = function ( name, dataset_id, indexer, height ) {
|
||||
this.showing_details = false;
|
||||
this.vertical_detail_px = 10;
|
||||
this.vertical_nodetail_px = 3;
|
||||
this.block_color = "black";
|
||||
this.label_color = "black";
|
||||
this.default_font = "9px Monaco, Lucida Console, monospace";
|
||||
this.left_offset = 200;
|
||||
this.inc_slots = {};
|
||||
this.data_queue = {};
|
||||
this.s_e_by_tile = {};
|
||||
this.data_cache = new Cache(20);
|
||||
this.prefs = { 'block_color': 'black', 'label_color': 'black' };
|
||||
if (prefs.block_color !== undefined) { this.prefs.block_color = prefs.block_color; }
|
||||
if (prefs.label_color !== undefined) { this.prefs.label_color = prefs.label_color; }
|
||||
|
||||
};
|
||||
$.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
init: function() {
|
||||
@@ -609,18 +630,23 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
|
||||
// console.log(tile_low, tile_high, tile_length, w_scale);
|
||||
var width = Math.ceil( tile_span * w_scale ),
|
||||
new_canvas = $("<canvas class='tile'></canvas>");
|
||||
new_canvas = $("<canvas class='tile'></canvas>"),
|
||||
label_color = this.prefs.label_color,
|
||||
block_color = this.prefs.block_color,
|
||||
left_offset = this.left_offset,
|
||||
showing_details = this.showing_details,
|
||||
y_scale = (this.showing_details ? this.vertical_detail_px : this.vertical_nodetail_px);
|
||||
|
||||
new_canvas.css({
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: ( tile_low - this.view.low ) * w_scale - this.left_offset
|
||||
left: ( tile_low - this.view.low ) * w_scale - left_offset
|
||||
});
|
||||
new_canvas.get(0).width = width + this.left_offset;
|
||||
new_canvas.get(0).width = width + left_offset;
|
||||
new_canvas.get(0).height = required_height;
|
||||
// console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
|
||||
var ctx = new_canvas.get(0).getContext("2d");
|
||||
ctx.fillStyle = this.block_color;
|
||||
ctx.fillStyle = this.prefs.block_color;
|
||||
ctx.font = this.default_font;
|
||||
ctx.textAlign = "right";
|
||||
|
||||
@@ -630,22 +656,22 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
if (feature.start <= tile_high && feature.end >= tile_low) {
|
||||
var f_start = Math.floor( Math.max(0, (feature.start - tile_low) * w_scale) ),
|
||||
f_end = Math.ceil( Math.min(width, (feature.end - tile_low) * w_scale) ),
|
||||
y_center = slots[feature.uid] * (this.showing_details ? this.vertical_detail_px : this.vertical_nodetail_px);
|
||||
y_center = slots[feature.uid] * y_scale;
|
||||
|
||||
var thickness, y_start, thick_start = null, thick_end = null;
|
||||
if (feature.thick_start && feature.thick_end) {
|
||||
thick_start = Math.floor( Math.max(0, (feature.thick_start - tile_low) * w_scale) );
|
||||
thick_end = Math.ceil( Math.min(width, (feature.thick_end - tile_low) * w_scale) );
|
||||
}
|
||||
if (!this.showing_details) {
|
||||
if (!showing_details) {
|
||||
// Non-detail levels
|
||||
ctx.fillRect(f_start + this.left_offset, y_center + 5, f_end - f_start, 1);
|
||||
ctx.fillRect(f_start + left_offset, y_center + 5, f_end - f_start, 1);
|
||||
} else {
|
||||
// Showing labels, blocks, details
|
||||
if (feature.start > tile_low) {
|
||||
ctx.fillStyle = this.label_color;
|
||||
ctx.fillText(feature.name, f_start - 1 + this.left_offset, y_center + 8);
|
||||
ctx.fillStyle = this.block_color;
|
||||
ctx.fillStyle = label_color;
|
||||
ctx.fillText(feature.name, f_start - 1 + left_offset, y_center + 8);
|
||||
ctx.fillStyle = block_color;
|
||||
}
|
||||
var blocks = feature.blocks;
|
||||
if (blocks) {
|
||||
@@ -656,8 +682,8 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
} else if (feature.strand == "-") {
|
||||
ctx.fillStyle = LEFT_STRAND;
|
||||
}
|
||||
ctx.fillRect(f_start + this.left_offset, y_center, f_end - f_start, 10);
|
||||
ctx.fillStyle = this.block_color;
|
||||
ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, 10);
|
||||
ctx.fillStyle = block_color;
|
||||
}
|
||||
|
||||
for (var k = 0, k_len = blocks.length; k < k_len; k++) {
|
||||
@@ -668,7 +694,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
// Draw the block
|
||||
thickness = 5;
|
||||
y_start = 3;
|
||||
ctx.fillRect(block_start + this.left_offset, y_center + y_start, block_end - block_start, thickness);
|
||||
ctx.fillRect(block_start + left_offset, y_center + y_start, block_end - block_start, thickness);
|
||||
|
||||
// Draw thick regions: check if block intersects with thick region
|
||||
if (thick_start !== undefined && !(block_start > thick_end || block_end < thick_start) ) {
|
||||
@@ -676,7 +702,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
y_start = 1;
|
||||
var block_thick_start = Math.max(block_start, thick_start),
|
||||
block_thick_end = Math.min(block_end, thick_end);
|
||||
ctx.fillRect(block_thick_start + this.left_offset, y_center + y_start, block_thick_end - block_thick_start, thickness);
|
||||
ctx.fillRect(block_thick_start + left_offset, y_center + y_start, block_thick_end - block_thick_start, thickness);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -684,15 +710,15 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
// If there are no blocks, we treat the feature as one big exon
|
||||
thickness = 9;
|
||||
y_start = 1;
|
||||
ctx.fillRect(f_start + this.left_offset, y_center + y_start, f_end - f_start, thickness);
|
||||
ctx.fillRect(f_start + left_offset, y_center + y_start, f_end - f_start, thickness);
|
||||
if ( feature.strand ) {
|
||||
if (feature.strand == "+") {
|
||||
ctx.fillStyle = RIGHT_STRAND_INV;
|
||||
} else if (feature.strand == "-") {
|
||||
ctx.fillStyle = LEFT_STRAND_INV;
|
||||
}
|
||||
ctx.fillRect(f_start + this.left_offset, y_center, f_end - f_start, 10);
|
||||
ctx.fillStyle = this.block_color;
|
||||
ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, 10);
|
||||
ctx.fillStyle = prefs.block_color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -707,29 +733,29 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
|
||||
var block_color = 'track_' + track_id + '_block_color',
|
||||
block_color_label = $('<label></label>').attr("for", block_color).text("Block color:"),
|
||||
block_color_input = $('<input></input>').attr("id", block_color).attr("name", block_color).val(this.block_color),
|
||||
block_color_input = $('<input></input>').attr("id", block_color).attr("name", block_color).val(this.prefs.block_color),
|
||||
label_color = 'track_' + track_id + '_label_color',
|
||||
label_color_label = $('<label></label>').attr("for", label_color).text("Label color:"),
|
||||
label_color_input = $('<input></input>').attr("id", label_color).attr("name", label_color).val(this.label_color);
|
||||
label_color_input = $('<input></input>').attr("id", label_color).attr("name", label_color).val(this.prefs.label_color);
|
||||
return container.append(block_color_label).append(block_color_input).append(label_color_label).append(label_color_input);
|
||||
}, update_options: function(track_id) {
|
||||
var block_color = $('#track_' + track_id + '_block_color').val(),
|
||||
label_color = $('#track_' + track_id + '_label_color').val();
|
||||
if (block_color !== this.block_color || label_color !== this.label_color) {
|
||||
this.block_color = block_color;
|
||||
this.label_color = label_color;
|
||||
if (block_color !== this.prefs.block_color || label_color !== this.prefs.label_color) {
|
||||
this.prefs.block_color = block_color;
|
||||
this.prefs.label_color = label_color;
|
||||
this.tile_cache.clear();
|
||||
this.draw();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var ReadTrack = function ( name, dataset_id, indexer, height ) {
|
||||
var ReadTrack = function ( name, dataset_id, indexer, prefs ) {
|
||||
this.track_type = "ReadTrack";
|
||||
this.tile_cache = new Cache(CACHED_TILES_FEATURE);
|
||||
Track.call( this, name, $("#viewport") );
|
||||
TiledTrack.call( this );
|
||||
FeatureTrack.call( this, name, dataset_id, indexer, height );
|
||||
this.default_font = "9px Monaco, Lucida Console, monospace";
|
||||
FeatureTrack.call( this, name, dataset_id, indexer, prefs );
|
||||
|
||||
};
|
||||
$.extend( ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
|
||||
@@ -760,7 +786,7 @@ $.extend( ReadTrack.prototype, TiledTrack.prototype, FeatureTrack.prototype, {
|
||||
new_canvas.get(0).height = required_height;
|
||||
// console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
|
||||
var ctx = new_canvas.get(0).getContext("2d");
|
||||
ctx.fillStyle = this.block_color;
|
||||
ctx.fillStyle = this.prefs.block_color;
|
||||
ctx.font = this.default_font;
|
||||
ctx.textAlign = "right";
|
||||
var px_per_char = ctx.measureText("A").width;
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
body, html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 0;
|
||||
padding: 0;
|
||||
font-family: verdana;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
background: #eeeeee;
|
||||
}
|
||||
|
||||
#content {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -24,10 +11,6 @@ body {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/*canvas{
|
||||
border-left: 1px solid green;
|
||||
border-right: 1px solid red; } /* debugging */
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
var grid = this;
|
||||
var checkboxes = $(this).find("input.grid-row-select-checkbox");
|
||||
var update = $(this).find( "span.grid-selected-count" );
|
||||
update.text("");
|
||||
$(checkboxes).each( function() {
|
||||
$(this).change( function() {
|
||||
var n = $(checkboxes).filter("[checked]").size();
|
||||
@@ -834,6 +835,7 @@
|
||||
<% num_rows_rendered = 1 %>
|
||||
%endif
|
||||
%for i, item in enumerate( query ):
|
||||
<% encoded_id = trans.security.encode_id( item.id ) %>
|
||||
<tr \
|
||||
%if current_item == item:
|
||||
class="current" \
|
||||
@@ -842,7 +844,7 @@
|
||||
## Item selection column
|
||||
%if show_item_checkboxes:
|
||||
<td style="width: 1.5em;">
|
||||
<input type="checkbox" name="id" value=${trans.security.encode_id( item.id )} class="grid-row-select-checkbox" />
|
||||
<input type="checkbox" id="${encoded_id}" name="id" value="${encoded_id}" class="grid-row-select-checkbox" />
|
||||
</td>
|
||||
%endif
|
||||
## Data columns
|
||||
@@ -875,12 +877,12 @@
|
||||
cls = "menubutton"
|
||||
if column.attach_popup and href:
|
||||
cls = "menubutton split"
|
||||
|
||||
|
||||
%>
|
||||
%if href:
|
||||
%if href:
|
||||
<td><div id="${id}" class="${cls}" style="float: left;"><a class="label" href="${href}">${v}</a></td>
|
||||
%else:
|
||||
<td><div id="${id}" class="${cls}">${v}</div></td>
|
||||
<td><div id="${id}" class="${cls}"><label for="${encoded_id}">${v}</label></div></td>
|
||||
%endif
|
||||
%endfor
|
||||
%endif
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
## Template generates a grid that enables user to add tracks
|
||||
<%namespace file="../grid_base.mako" import="*" />
|
||||
|
||||
${javascripts()}
|
||||
${stylesheets()}
|
||||
${render_grid_table( grid, show_item_checkboxes=True )}
|
||||
|
||||
## Initialize the grid.
|
||||
<script type="text/javascript">
|
||||
init_grid_elements();
|
||||
init_grid_controls();
|
||||
</script>
|
||||
@@ -78,16 +78,18 @@ ${h.css( "history" )}
|
||||
## <input name="title" id="title" value="${title}" />
|
||||
<div id="show-hide-move">
|
||||
<ul id="sortable-ul"></ul>
|
||||
## <input type="submit" id="update-config" value="Save settings" />
|
||||
<input type="button" id="refresh-button" value="Refresh" />
|
||||
</div>
|
||||
## <input type="submit" id="update-config" value="Save settings" />
|
||||
<input type="button" id="refresh-button" value="Refresh" />
|
||||
<input type="button" id="save-button" value="Save" />
|
||||
<input id="add-track" type="button" value="Add Track" />
|
||||
</form>
|
||||
|
||||
</%def>
|
||||
|
||||
<%def name="javascripts()">
|
||||
${parent.javascripts()}
|
||||
${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )}
|
||||
${h.js( "json2", "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.core", "ui.sortable" )}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -100,7 +102,9 @@ ${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.cor
|
||||
view.add_track( new LabelTrack( $("#nav-labeltrack" ) ) );
|
||||
|
||||
%for track in tracks:
|
||||
view.add_track( new ${track["type"]}( "${track['name']}", ${track['dataset_id']}, "${track['indexer']}" ) );
|
||||
view.add_track(
|
||||
new ${track["track_type"]}( "${track['name']}", ${track['dataset_id']}, "${track['indexer']}", ${track['prefs']} )
|
||||
);
|
||||
%endfor
|
||||
|
||||
$(document).bind( "redraw", function( e ) {
|
||||
@@ -164,12 +168,51 @@ ${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.cor
|
||||
});
|
||||
|
||||
$("#refresh-button").bind( "click", function(e) {
|
||||
for (var track_id in view.tracks) {
|
||||
var track = view.tracks[track_id];
|
||||
if (track.update_options) {
|
||||
track.update_options(track_id);
|
||||
view.update_options();
|
||||
});
|
||||
|
||||
// Use a popup grid to add more tracks
|
||||
$("#add-track").bind( "click", function(e) {
|
||||
$.ajax({
|
||||
url: "${h.url_for( action='list_datasets' )}",
|
||||
data: {},
|
||||
error: function() { alert( "Grid refresh failed" ) },
|
||||
success: function(table_html) {
|
||||
show_modal("Add Track — Select Dataset(s)", table_html, {
|
||||
"Insert": function() {
|
||||
hide_modal();
|
||||
},
|
||||
"Cancel": function() {
|
||||
hide_modal();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#save-button").bind("click", function(e) {
|
||||
view.update_options();
|
||||
var sorted = $("ul#sortable-ul").sortable('toArray');
|
||||
var payload = [];
|
||||
for (var i in sorted) {
|
||||
var track_id = parseInt(sorted[i].split("track_")[1]),
|
||||
track = view.tracks[track_id];
|
||||
|
||||
payload.push( {
|
||||
"track_type": track.track_type,
|
||||
"indexer": track.indexer,
|
||||
"name": track.name,
|
||||
"dataset_id": track.dataset_id,
|
||||
"prefs": track.prefs
|
||||
});
|
||||
}
|
||||
$.ajax({
|
||||
url: "${h.url_for( action='save' )}",
|
||||
data: {
|
||||
'id': '${id}',
|
||||
'payload': JSON.stringify(payload)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Execute this on page load
|
||||
@@ -195,12 +238,12 @@ ${h.js( "jquery", "jquery.event.drag", "jquery.mousewheel", "trackster", "ui.cor
|
||||
var track = view.tracks[track_id];
|
||||
if (!track.hidden) {
|
||||
var label = $('<label for="track_' + track_id + 'title">' + track.name + '</label>');
|
||||
var title = $('<div class="toolFormTitle"></div>');
|
||||
var title = $('<div class="historyItemTitle"></div>');
|
||||
var del_icon = $('<a style="display:block; float:right" href="#" class="icon-button delete" />');
|
||||
var body = $('<div class="toolFormBody"></div>');
|
||||
var body = $('<div class="historyItemBody"></div>');
|
||||
// var checkbox = $('<input type="checkbox" checked="checked"></input>').attr("id", "track_" + track_id + "title");
|
||||
var li = $('<li class="sortable"></li>').attr("id", "track_" + track_id);
|
||||
var div = $('<div class="toolForm"></div>');
|
||||
var div = $('<div class="historyItemContainer historyItem"></div>');
|
||||
del_icon.prependTo(title);
|
||||
label.appendTo(title);
|
||||
// checkbox.prependTo(title);
|
||||
|
||||
Reference in New Issue
Block a user