diff --git a/static/scripts/trackster.js b/static/scripts/trackster.js index 35d04679728..f1c2f361ada 100644 --- a/static/scripts/trackster.js +++ b/static/scripts/trackster.js @@ -464,7 +464,7 @@ extend(ReferenceTrackDataManager.prototype, DataManager.prototype, Cache.prototy /** * View object manages complete viz view, including tracks and user interactions. */ -var View = function( container, title, vis_id, dbkey, callback ) { +var View = function(container, title, vis_id, dbkey, callback) { this.container = container; this.chrom = null; this.vis_id = vis_id; @@ -826,6 +826,7 @@ extend( View.prototype, { sortable( track.container_div, '.draghandle' ); this.track_id_counter += 1; this.num_tracks += 1; + this.has_changes = true; this.update_intro_div(); }, add_label_track: function (label_track) { @@ -993,9 +994,9 @@ extend( View.prototype, { view.overview_track.set_is_overview(false); } view.overview_track = track; - view.has_changes = true; track.set_is_overview(true); }); + view.has_changes = true; }, /** Close and reset overview. */ reset_overview: function() { diff --git a/static/scripts/trackster_ui.js b/static/scripts/trackster_ui.js new file mode 100644 index 00000000000..c456d366946 --- /dev/null +++ b/static/scripts/trackster_ui.js @@ -0,0 +1,118 @@ +/************************************************************************ + * Functions used for creating and managing the Trackster user interface. + ************************************************************************/ + +/** + * Add bookmark. + */ +var add_bookmark = function(position, annotation) { + var + bookmarks_container = $("#bookmarks-container"), + new_bookmark = $("
").addClass("bookmark").appendTo(bookmarks_container), + delete_icon_container = $("").addClass("delete-icon-container").appendTo(new_bookmark).click(function (){ + // Remove bookmark. + new_bookmark.slideUp("fast"); + new_bookmark.remove(); + view.has_changes = true; + return false; + }), + delete_icon = $("").addClass("icon-button delete").appendTo(delete_icon_container), + position_div = $("").addClass("position").appendTo(new_bookmark), + position_link = $("").text(position).appendTo(position_div).click(function() { + view.go_to(position); + return false; + }); + annotation_div = get_editable_text_elt(annotation, true).addClass("annotation").appendTo(new_bookmark); + + view.has_changes = true; + return new_bookmark; +}; + +/** + * Types of tracks that can be added to a view. + */ +var addable_track_types = { "LineTrack": LineTrack, "FeatureTrack": FeatureTrack, "ReadTrack": ReadTrack }; + +/** + * Decode a track from a dictionary. + */ +var track_from_dict = function(track_dict) { + return new addable_track_types[track_dict.track_type]( + track_dict.name, view, track_dict.hda_ldda, track_dict.dataset_id, + track_dict.prefs, track_dict.filters, track_dict.tool + /* TODO: ( track_dict.is_child ? parent_track : undefined */ ); +}; + +/** + * Create a complete Trackster visualization. Returns view. + */ +var create_visualization = function(parent_elt, title, id, dbkey, callback, tracks_config, bookmarks_config) { + + // Create view. + view = new View(parent_elt, title, id, dbkey, callback); + view.editor = true; + + // Add tracks to view. + if (tracks_config) { + var track_config, track, parent_track, parent_obj; + for (var i = 0; i < tracks_config.length; i++) { + track_config = tracks_config[i]; + // TODO: set parent for child track: + track = track_from_dict(track_config); + parent_obj = view; + if (track_config.is_child) { + parent_obj = parent_track; + } + else { + // New parent track is this track. + parent_track = track; + } + parent_obj.add_track(track); + } + } + + // Load bookmarks. + if (bookmarks_config) { + var bookmark; + for (var i = 0; i < bookmarks_config.length; i++) { + bookmark = bookmarks_config[i]; + add_bookmark(bookmark['position'], bookmark['annotation']); + } + } + + // View has no changes as of yet. + view.has_changes = false; + + return view; +}; + +/** + * Set up keyboard navigation for a visualization. + */ +var init_keyboard_nav = function(view) { + // Keyboard navigation. Scroll ~7% of height when scrolling up/down. + $(document).keydown(function(e) { + // Do not navigate if arrow keys used in input element. + if ($(e.srcElement).is(':input')) { + return; + } + + // Key codes: left == 37, up == 38, right == 39, down == 40 + switch(e.which) { + case 37: + view.move_fraction(0.25); + break + case 38: + var change = Math.round(view.viewport_container.height()/15.0); + view.viewport_container.scrollTo('-=' + change + 'px'); + break; + case 39: + view.move_fraction(-0.25); + break; + case 40: + var change = Math.round(view.viewport_container.height()/15.0); + view.viewport_container.scrollTo('+=' + change + 'px'); + break; + } + }); +}; diff --git a/templates/tracks/browser.mako b/templates/tracks/browser.mako index 9e788cb1afc..5354b5a9d62 100644 --- a/templates/tracks/browser.mako +++ b/templates/tracks/browser.mako @@ -42,7 +42,7 @@ ${parent.javascripts()} -${h.js( "galaxy.base", "galaxy.panels", "json2", "jquery", "jstorage", "jquery.event.drag", "jquery.mousewheel", "jquery.autocomplete", "trackster", "jquery.ui.sortable.slider", "jquery.scrollTo", "farbtastic" )} +${h.js( "galaxy.base", "galaxy.panels", "json2", "jquery", "jstorage", "jquery.event.drag", "jquery.mousewheel", "jquery.autocomplete", "trackster", "trackster_ui", "jquery.ui.sortable.slider", "jquery.scrollTo", "farbtastic" )} - ${h.js( "jquery.event.drag", "jquery.autocomplete", "jquery.mousewheel", "jquery.autocomplete", "trackster", "jquery.ui.sortable.slider", "jquery.scrollTo", "farbtastic" )} + ${h.js( "jquery.event.drag", "jquery.autocomplete", "jquery.mousewheel", "jquery.autocomplete", "trackster", "trackster_ui", "jquery.ui.sortable.slider", "jquery.scrollTo", "farbtastic" )} %def> <%def name="stylesheets()"> @@ -86,64 +86,19 @@ $("#right-border").click(function() { view.resize_window(); }); } - // Create view and add tracks. + // Create visualization. var callback; %if 'viewport' in config: var callback = function() { view.change_chrom( '${config['viewport']['chrom']}', ${config['viewport']['start']}, ${config['viewport']['end']} ); } %endif - view = new View(container_element, "${config.get('title') | h}", "${config.get('vis_id')}", "${config.get('dbkey')}", callback); - ## A little ugly and redundant, but it gets the job done moving the config from python to JS: - var tracks_config = JSON.parse('${ h.to_json_string( config.get('tracks') ) }'); - var track_config, track, parent_track, parent_obj; - for (var i = 0; i < tracks_config.length; i++) { - track_config = tracks_config[i]; - track = new addable_track_types[track_config["track_type"]]( - track_config['name'], - view, - track_config['hda_ldda'], - track_config['dataset_id'], - track_config['prefs'], - track_config['filters'], - track_config['tool'], - (track_config.is_child ? parent_track : undefined)); - parent_obj = view; - if (track_config.is_child) { - parent_obj = parent_track; - } - else { - // New parent track is this track. - parent_track = track; - } - parent_obj.add_track(track); - } + view = create_visualization( container_element, "${config.get('title') | h}", + "${config.get('vis_id')}", "${config.get('dbkey')}", callback, + JSON.parse('${ h.to_json_string( config.get('tracks') ) }'), + JSON.parse('${ h.to_json_string( config.get('bookmarks') ) }') + ); - // - // Keyboard navigation. Scroll ~7% of height when scrolling up/down. - // - $(document).keydown(function(e) { - // Do not navigate if arrow keys used in input element. - if ($(e.srcElement).is(':input')) { - return; - } - - // Key codes: left == 37, up == 38, right == 39, down == 40 - switch(e.which) { - case 37: - view.move_fraction(0.25); - break - case 38: - var change = Math.round(view.viewport_container.height()/15.0); - view.viewport_container.scrollTo('-=' + change + 'px'); - break; - case 39: - view.move_fraction(-0.25); - break; - case 40: - var change = Math.round(view.viewport_container.height()/15.0); - view.viewport_container.scrollTo('+=' + change + 'px'); - break; - } - }); + // Set up keyboard navigation. + init_keyboard_nav(view); });