morpheus.HeatMapToolBar = function (controller) { this.controller = controller; this.rowSearchResultModelIndices = []; this.columnSearchResultModelIndices = []; var _this = this; var $el = $('
' + '
' + '
' + '
'); var searchHtml = []; var $search = $(''); $search.on('submit', function (e) { e.preventDefault(); }); // search rows if (controller.options.toolbar.searchRows) { searchHtml.push('
'); searchHtml.push('
'); searchHtml.push('
'); searchHtml .push(''); searchHtml.push(''); searchHtml.push('
'); // input-group-btn searchHtml .push(''); searchHtml.push('
'); searchHtml.push('
'); searchHtml.push('
'); searchHtml.push(''); searchHtml .push(''); searchHtml .push(''); searchHtml .push(''); searchHtml .push(''); searchHtml.push(''); searchHtml.push('
'); } if (controller.options.toolbar.searchColumns) { searchHtml .push('
'); // spacer // search columns searchHtml.push('
'); searchHtml.push('
'); // group searchHtml.push('
'); searchHtml .push(''); searchHtml .push(''); searchHtml.push('
'); // input-group-btn searchHtml .push('
'); searchHtml.push('
'); searchHtml.push(''); searchHtml.push('
'); searchHtml .push(''); searchHtml.push(''); searchHtml .push(''); searchHtml .push(''); searchHtml .push(''); searchHtml.push(''); searchHtml.push('
'); } // search values searchHtml .push('
'); searchHtml .push('
Values
'); searchHtml.push('
'); searchHtml.push('
'); searchHtml .push('
'); searchHtml.push('
'); // row dendrogram searchHtml .push(''); // column dendrogram searchHtml .push(''); // dimensions searchHtml.push('
'); searchHtml .push('
'); searchHtml .push('
'); searchHtml.push('
'); searchHtml.push('
'); $(searchHtml.join('')).appendTo($search); if (!controller.options.toolbar.searchValues) { $search.find('[data-name=searchValuesDiv]').css('display', 'none'); } var $buttons = $search.find('[data-name=buttons]'); var $tools = $('
'); $tools.on('submit', function (e) { e.preventDefault(); }); var toolbarHtml = []; // zoom if (controller.options.toolbar.zoom) { toolbarHtml .push(''); toolbarHtml .push(''); toolbarHtml .push(''); toolbarHtml .push(''); } toolbarHtml.push('
'); if (controller.options.toolbar.sort) { toolbarHtml .push(''); } if (controller.options.toolbar.options) { toolbarHtml .push(''); } toolbarHtml.push('
'); if (controller.options.toolbar.saveImage) { toolbarHtml .push(''); } if (controller.options.toolbar.saveDataset) { toolbarHtml .push(''); } if (controller.options.toolbar.openFile) { toolbarHtml .push(''); } toolbarHtml.push('
'); if (controller.options.toolbar.filter) { toolbarHtml .push(''); } if (typeof Plotly !== 'undefined') { toolbarHtml .push(''); } var tools = [{ tool: new morpheus.HClusterTool() }, { tool: new morpheus.MarkerSelection() }, { tool: new morpheus.NearestNeighbors() }, { tool: new morpheus.NewHeatMapTool(), }, null, { tool: new morpheus.AdjustDataTool() }, { tool: new morpheus.CollapseDatasetTool() }, { tool: new morpheus.CreateAnnotation() }, { tool: new morpheus.SimilarityMatrixTool() }, { tool: new morpheus.TransposeTool() }, { tool: new morpheus.WordCloudTool() }]; // DevAPI, { this.getToolByName = function (name) { for (var i = 0; i < tools.length; i++) { if (tools[i] && tools[i].tool.toString && tools[i].tool.toString() === name) { return tools[i].tool; } } throw name + ' not found'; }; if (controller.options.toolbar.tools) { toolbarHtml.push('
'); toolbarHtml .push(''); toolbarHtml.push('
'); } toolbarHtml.push('
'); // legend if (controller.options.toolbar.colorKey) { toolbarHtml.push('
'); toolbarHtml .push(''); toolbarHtml.push(''); toolbarHtml.push('
'); } toolbarHtml.push('
'); toolbarHtml.push(''); $buttons.on('click', '[name=pca]', function () { console.log("test button clicked"); new morpheus.PcaPlotTool({project : controller.getProject()}); }); var $lineOneColumn = $el.find('[data-name=lineOneColumn]'); $search.appendTo($lineOneColumn); var $toolbarForm = $(toolbarHtml.join('')); $toolbarForm.appendTo($buttons); if (controller.options.$help) { controller.options.$help.appendTo($buttons); } $('
').appendTo($el.find('[data-name=lineTwoColumn]')); // $hide.appendTo($el.find('[data-name=toggleEl]')); $el.prependTo(controller.$content); var $tools = $el.find('[data-name=tools]'); this.$tip = $el.find('[data-name=tip]'); $tools.on('click', 'li > a', function (e) { e.preventDefault(); var index = parseInt($(this).attr('data-name')); if (tools[index].tool) { morpheus.HeatMap.showTool(tools[index].tool, controller); } else { tools[index].action(); } }); this.defaultRowMatchMode = 'contains'; this.defaultColumnMatchMode = 'contains'; var $rowSearchOptions = $el.find('[data-name=rowSearchOptions]'); $rowSearchOptions.on('click', 'li > a', function (e) { e.preventDefault(); _this.defaultRowMatchMode = $(this).attr('data-name'); $rowSearchOptions.find('li').removeClass('active'); $(this).parent('li').addClass('active'); _this.search(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'rowSearchMatchMode' }); }); var $columnSearchOptions = $el.find('[data-name=columnSearchOptions]'); $columnSearchOptions.on('click', 'li > a', function (e) { e.preventDefault(); _this.defaultColumnMatchMode = $(this).attr('data-name'); $columnSearchOptions.find('li').removeClass('active'); $(this).parent('li').addClass('active'); _this.search(false); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'columnSearchMatchMode' }); }); var filterModal = []; var filterLabelId = _.uniqueId('morpheus'); filterModal .push(''); var $filterModal = $(filterModal.join('')); $filterModal.on('mousewheel', function (e) { e.stopPropagation(); }); var $filter = $('
'); $filter.appendTo($filterModal.find('.modal-body')); $filterModal.appendTo($el); var filterHtml = []; filterHtml .push('
'); filterHtml .push('
'); var $filterChooser = $(filterHtml.join('')); $filterChooser.appendTo($filter); var columnFilterUI = new morpheus.FilterUI(controller.getProject(), true); var rowFilterUI = new morpheus.FilterUI(controller.getProject(), false); controller.getProject().getRowFilter().on('focus', function (e) { $filterChooser.find('[value=rows]').prop('checked', true); columnFilterUI.$div.hide(); rowFilterUI.$div.show(); $filterModal.modal('show'); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'rowFilter' }); }); controller.getProject().getColumnFilter().on('focus', function (e) { $filterChooser.find('[value=columns]').prop('checked', true); columnFilterUI.$div.show(); rowFilterUI.$div.hide(); $filterModal.modal('show'); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'columnFilter' }); }); rowFilterUI.$div.appendTo($filter); columnFilterUI.$div.appendTo($filter); columnFilterUI.$div.css('display', 'none'); var $filterRadio = $filterChooser.find('[name=rowsOrColumns]'); $filterRadio.on('change', function (e) { var val = $filterRadio.filter(':checked').val(); if (val === 'columns') { columnFilterUI.$div.show(); rowFilterUI.$div.hide(); } else { columnFilterUI.$div.hide(); rowFilterUI.$div.show(); } e.preventDefault(); }); $el.find('[name=filterButton]').on('click', function () { $filterModal.modal('show'); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'filter' }); }); $el.find('[data-toggle="tooltip"]').tooltip({ placement: 'bottom', container: 'body', trigger: 'hover' }).on('click', function () { $(this).tooltip('hide'); }); var $key = $el.find('[data-name=key]'); var $keyContent = $el.find('[data-name=keyContent]'); $key.dropdown().parent().on('show.bs.dropdown', function () { new morpheus.HeatMapColorSchemeLegend(controller, $keyContent); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'colorKey' }); }); $el.find('[name=openFile]').on('click', function () { morpheus.HeatMap.showTool(new morpheus.OpenFileTool({ customUrls: controller._customUrls }), controller); }); $el.find('[name=saveImage]').on('click', function () { morpheus.HeatMap.showTool(new morpheus.SaveImageTool(), controller); }); $el.find('[name=saveDataset]').on('click', function () { morpheus.HeatMap.showTool(new morpheus.SaveDatasetTool(), controller); }); $el.find('[name=chart]').on( 'click', function () { new morpheus.ChartTool({ project: controller.getProject(), getVisibleTrackNames: _.bind( controller.getVisibleTrackNames, controller) }); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'chart' }); }); var _this = this; $el .find('[name=tutorial]') .on( 'click', function () { window .open('http://www.broadinstitute.org/cancer/software/morpheus/tutorial.html'); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'tutorial' }); }); this.$previousColumnMatch = $el.find('[name=previousColumnMatch]'); this.$nextColumnMatch = $el.find('[name=nextColumnMatch]'); this.$previousRowMatch = $el.find('[name=previousRowMatch]'); this.$nextRowMatch = $el.find('[name=nextRowMatch]'); this.$dimensionsLabel = $el.find('[data-name=dim]'); this.$columnTextField = $el.find('[name=searchColumns]'); this.$valueTextField = $el.find('[name=searchValues]'); this.$selectionLabel = $el.find('[data-name=selection]'); this.$rowTextField = $el.find('[name=searchRows]'); this.$columnMatchesToTop = $el.find('[name=columnMatchesToTop]'); this.$rowMatchesToTop = $el.find('[name=rowMatchesToTop]'); this.$rowSearchDiv = $el.find('[data-name=rowSearchDiv]'); this.$columnSearchDiv = $el.find('[data-name=columnSearchDiv]'); this.$searchRowDendrogramWrapper = $el .find('[data-name=searchRowDendrogramWrapper]'); this.$searchRowDendrogram = $el.find('[name=searchRowDendrogram]'); this.$searchResultsRowDendrogram = $el .find('[data-name=searchResultsRowDendrogram]'); this.$searchColumnDendrogramWrapper = $el .find('[data-name=searchColumnDendrogramWrapper]'); this.$searchColumnDendrogram = $el.find('[name=searchColumnDendrogram]'); this.$searchResultsColumnDendrogram = $el .find('[data-name=searchResultsColumnDendrogram]'); controller.on('dendrogramAnnotated', function (e) { (e.isColumns ? _this.$searchColumnDendrogramWrapper : _this.$searchRowDendrogramWrapper).show(); }); controller.on('dendrogramChanged', function (e) { (e.isColumns ? _this.$searchColumnDendrogramWrapper : _this.$searchRowDendrogramWrapper).hide(); }); var project = controller.getProject(); morpheus.Util.autosuggest({ $el: this.$rowTextField, filter: function (terms, cb) { var indices = []; var meta = project.getSortedFilteredDataset().getRowMetadata(); controller.getVisibleTrackNames(false).forEach(function (name) { indices.push(morpheus.MetadataUtil.indexOf(meta, name)); }); meta = new morpheus.MetadataModelColumnView(meta, indices); morpheus.MetadataUtil.autocomplete(meta)(terms, cb); }, select: function () { _this.search(true); } }); this.$rowTextField.on('keyup', _.debounce(function (e) { if (e.which === 13) { e.preventDefault(); } _this.search(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'searchRows' }); }, 500)); morpheus.Util.autosuggest({ $el: this.$columnTextField, filter: function (terms, cb) { var indices = []; var meta = project.getSortedFilteredDataset().getColumnMetadata(); controller.getVisibleTrackNames(true).forEach(function (name) { indices.push(morpheus.MetadataUtil.indexOf(meta, name)); }); meta = new morpheus.MetadataModelColumnView(meta, indices); morpheus.MetadataUtil.autocomplete(meta)(terms, cb); }, select: function () { _this.search(false); } }); this.$columnTextField.on('keyup', _.debounce(function (e) { if (e.which === 13) { e.preventDefault(); } _this.search(false); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'searchColumns' }); }, 500)); // TODO combine search with autocomplete this.$searchRowDendrogram.on('keyup', _.debounce(function (e) { if (e.which === 13) { // _this.$searchRowDendrogram.autocomplete('close'); e.preventDefault(); } _this.searchDendrogram(false); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'searchRowDendrogram' }); }, 500)); this.$searchColumnDendrogram.on('keyup', _.debounce(function (e) { if (e.which === 13) { // _this.$searchColumnDendrogram.autocomplete('close'); e.preventDefault(); } _this.searchDendrogram(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'searchColumnDendrogram' }); }, 500)); function searchValues() { var $searchResultsLabel = _this.$el.find('[data-name=searchResultsValues]'); var text = $.trim(_this.$valueTextField.val()); if (text === '') { $searchResultsLabel.html(''); project.getElementSelectionModel().setViewIndices(null); } else { var viewIndices = new morpheus.Set(); morpheus.DatasetUtil.searchValues(project .getSortedFilteredDataset(), text, function (value, i, j) { viewIndices.add(new morpheus.Identifier([i, j])); }); project.getElementSelectionModel().setViewIndices(viewIndices); $searchResultsLabel.html(viewIndices.size() + ' match' + (viewIndices.size() === 1 ? '' : 'es')); } } morpheus.Util.autosuggest({ $el: this.$valueTextField, filter: function (terms, cb) { morpheus.DatasetUtil.autocompleteValues( project.getSortedFilteredDataset())(terms, cb); }, select: function () { searchValues(); } }); this.$valueTextField.on('keyup', _.debounce(function (e) { if (e.which === 13) { _this.$valueTextField.autocomplete('close'); e.preventDefault(); } searchValues(); }, 500)); $toolbarForm.on('submit', function (e) { e.preventDefault(); }); $buttons.on('click', '[name=in]', function (e) { e.preventDefault(); controller.zoom(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'zoomIn' }); }); $buttons.on('click', '[name=out]', function (e) { e.preventDefault(); controller.zoom(false); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'zoomOut' }); }); $buttons.on('click', '[name=options]', function (e) { e.preventDefault(); controller.showOptions(); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'options' }); }); $buttons.on('click', '[name=sort]', function (e) { e.preventDefault(); new morpheus.SortDialog(project); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'sort' }); }); $buttons.on('click', '[name=fit]', function (e) { e.preventDefault(); controller.fitToWindow(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'fit' }); }); $buttons.on('click', '[name=resetZoom]', function (e) { e.preventDefault(); controller.resetZoom(); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'resetZoom' }); }); this.toggleMenu = function () { if ($lineOneColumn.css('display') === 'none') { $lineOneColumn.css('display', ''); _this.$rowTextField.focus(); } else { $lineOneColumn.css('display', 'none'); $(_this.controller.heatmap.canvas).focus(); } }; this.$el = $el; var updateFilterStatus = function () { if (controller.getProject().getRowFilter().isEnabled() || controller.getProject().getColumnFilter().isEnabled()) { _this.$el.find('[name=filterButton]').addClass('btn-primary'); } else { _this.$el.find('[name=filterButton]').removeClass('btn-primary'); } }; updateFilterStatus(); this.$columnMatchesToTop .on( 'click', function (e) { e.preventDefault(); var $this = $(this); $this.toggleClass('btn-primary'); _this.setSelectionOnTop({ isColumns: true, isOnTop: $this.hasClass('btn-primary'), updateButtonStatus: false }); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'columnMatchesToTop' }); }); this.$rowMatchesToTop .on( 'click', function (e) { e.preventDefault(); var $this = $(this); $this.toggleClass('btn-primary'); _this.setSelectionOnTop({ isColumns: false, isOnTop: $this.hasClass('btn-primary'), updateButtonStatus: false }); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'rowMatchesToTop' }); }); project.on('rowSortOrderChanged.morpheus', function (e) { if (_this.searching) { return; } _this._updateSearchIndices(false); _this.$rowMatchesToTop.removeClass('btn-primary'); }); project.on('columnSortOrderChanged.morpheus', function (e) { if (_this.searching) { return; } _this._updateSearchIndices(true); _this.$columnMatchesToTop.removeClass('btn-primary'); }); controller.getProject().on('rowFilterChanged.morpheus', function (e) { _this.search(true); updateFilterStatus(); }); controller.getProject().on('columnFilterChanged.morpheus', function (e) { _this.search(false); updateFilterStatus(); }); controller.getProject().on('datasetChanged.morpheus', function () { _this.search(true); _this.search(false); updateFilterStatus(); }); controller.getProject().getRowSelectionModel().on( 'selectionChanged.morpheus', function () { _this.updateSelectionLabel(); }); controller.getProject().getColumnSelectionModel().on( 'selectionChanged.morpheus', function () { _this.updateSelectionLabel(); }); this.rowSearchResultViewIndicesSorted = null; this.currentRowSearchIndex = 0; this.columnSearchResultViewIndicesSorted = null; this.currentColumnSearchIndex = -1; this.$previousColumnMatch .on( 'click', function () { _this.currentColumnSearchIndex--; if (_this.currentColumnSearchIndex < 0) { _this.currentColumnSearchIndex = _this.columnSearchResultViewIndicesSorted.length - 1; } controller .scrollLeft(controller .getHeatMapElementComponent() .getColumnPositions() .getPosition( _this.columnSearchResultViewIndicesSorted[_this.currentColumnSearchIndex])); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'previousColumnMatch' }); }); this.$previousRowMatch .on( 'click', function () { _this.currentRowSearchIndex--; if (_this.currentRowSearchIndex < 0) { _this.currentRowSearchIndex = _this.rowSearchResultViewIndicesSorted.length - 1; } controller .scrollTop(controller .getHeatMapElementComponent() .getRowPositions() .getPosition( _this.rowSearchResultViewIndicesSorted[_this.currentRowSearchIndex])); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'previousRowMatch' }); }); this.$nextColumnMatch.on('click', function () { _this.next(true); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'nextColumnMatch' }); }); this.$nextRowMatch.on('click', function () { _this.next(false); morpheus.Util.trackEvent({ eventCategory: 'ToolBar', eventAction: 'nextRowMatch' }); }); this.updateDimensionsLabel(); this.updateSelectionLabel(); }; morpheus.HeatMapToolBar.HIGHLIGHT_SEARCH_MODE = 0; morpheus.HeatMapToolBar.FILTER_SEARCH_MODE = 1; morpheus.HeatMapToolBar.MATCHES_TO_TOP_SEARCH_MODE = 2; morpheus.HeatMapToolBar.SELECT_MATCHES_SEARCH_MODE = 3; morpheus.HeatMapToolBar.prototype = { quickColumnFilter: false, searching: false, rowSearchMode: morpheus.HeatMapToolBar.SELECT_MATCHES_SEARCH_MODE, columnSearchMode: morpheus.HeatMapToolBar.SELECT_MATCHES_SEARCH_MODE, _updateSearchIndices: function (isColumns) { var project = this.controller.getProject(); if (isColumns) { var viewIndices = []; var modelIndices = this.columnSearchResultModelIndices; for (var i = 0, length = modelIndices.length; i < length; i++) { var index = project .convertModelColumnIndexToView(modelIndices[i]); if (index !== -1) { viewIndices.push(index); } } viewIndices.sort(function (a, b) { return a < b ? -1 : 1; }); this.columnSearchResultViewIndicesSorted = viewIndices; this.currentColumnSearchIndex = -1; } else { var viewIndices = []; var modelIndices = this.rowSearchResultModelIndices; for (var i = 0, length = modelIndices.length; i < length; i++) { var index = project.convertModelRowIndexToView(modelIndices[i]); if (index !== -1) { viewIndices.push(index); } } viewIndices.sort(function (a, b) { return a < b ? -1 : 1; }); this.rowSearchResultViewIndicesSorted = viewIndices; this.currentRowSearchIndex = -1; } }, next: function (isColumns) { var controller = this.controller; if (isColumns) { this.currentColumnSearchIndex++; if (this.currentColumnSearchIndex >= this.columnSearchResultViewIndicesSorted.length) { this.currentColumnSearchIndex = 0; } controller .scrollLeft(controller .getHeatMapElementComponent() .getColumnPositions() .getPosition( this.columnSearchResultViewIndicesSorted[this.currentColumnSearchIndex])); } else { this.currentRowSearchIndex++; if (this.currentRowSearchIndex >= this.rowSearchResultViewIndicesSorted.length) { this.currentRowSearchIndex = 0; } controller .scrollTop(controller .getHeatMapElementComponent() .getRowPositions() .getPosition( this.rowSearchResultViewIndicesSorted[this.currentRowSearchIndex])); } }, setSearchText: function (options) { var $tf = options.isColumns ? this.$columnTextField : this.$rowTextField; var existing = options.append ? $.trim($tf.val()) : ''; if (existing !== '') { existing += ' '; } if (options.onTop) { options.isColumns ? this.$columnMatchesToTop .addClass('btn-primary') : this.$rowMatchesToTop .addClass('btn-primary'); } $tf.val(existing + options.text); this.search(!options.isColumns); if (options.scrollTo) { this.next(options.isColumns); // click next } }, updateDimensionsLabel: function () { var p = this.controller.getProject(); var d = p.getFullDataset(); var f = p.getSortedFilteredDataset(); var text = 'showing ' + morpheus.Util.intFormat(f.getRowCount()) + '/' + morpheus.Util.intFormat(d.getRowCount()) + ' rows, ' + morpheus.Util.intFormat(f.getColumnCount()) + '/' + morpheus.Util.intFormat(d.getColumnCount()) + ' columns'; this.$dimensionsLabel.html(text); }, updateSelectionLabel: function () { var nc = this.controller.getProject().getColumnSelectionModel().count(); var nr = this.controller.getProject().getRowSelectionModel().count(); var text = []; text.push(morpheus.Util.intFormat(nr) + ' row'); if (nr !== 1) { text.push('s'); } text.push(', '); text.push(morpheus.Util.intFormat(nc) + ' column'); if (nc !== 1) { text.push('s'); } text.push(' selected'); this.$selectionLabel.html(text.join('')); }, searchDendrogram: function (isColumns) { var text = $.trim(isColumns ? this.$searchColumnDendrogram.val() : this.$searchRowDendrogram.val()); var dendrogram = isColumns ? this.controller.columnDendrogram : this.controller.rowDendrogram; var $searchResults = isColumns ? this.$searchResultsColumnDendrogram : this.$searchResultsRowDendrogram; var matches = morpheus.AbstractDendrogram.search( dendrogram.tree.rootNode, text); if (matches === -1) { $searchResults.html(''); } else { $searchResults.html(matches + ' match' + (matches === 1 ? '' : 'es')); } if (matches <= 0) { var positions = isColumns ? this.controller .getHeatMapElementComponent().getColumnPositions() : this.controller.getHeatMapElementComponent() .getRowPositions(); positions.setSquishedIndices(null); if (isColumns) { this.controller.getProject().setGroupColumns([], true); } else { this.controller.getProject().setGroupRows([], true); } positions.setSize(isColumns ? this.controller.getFitColumnSize() : this.controller.getFitRowSize()); } else { morpheus.AbstractDendrogram.squishNonSearchedNodes(this.controller, isColumns); } this.controller.updateDataset(); // need to update spaces for group // by this.controller.revalidate(); }, search: function (isRows) { this.searching = true; var isMatchesOnTop = isRows ? this.$rowMatchesToTop .hasClass('btn-primary') : this.$columnMatchesToTop .hasClass('btn-primary'); var controller = this.controller; var project = controller.getProject(); var sortKeys = isRows ? project.getRowSortKeys() : project .getColumnSortKeys(); var keyIndex = -1; for (var i = 0; i < sortKeys.length; i++) { if (sortKeys[i].toString() === 'matches on top') { keyIndex = i; break; } } if (keyIndex !== -1) { sortKeys.splice(keyIndex, 1); } var dataset = project.getSortedFilteredDataset(); var $searchResultsLabel = this.$el.find('[data-name=searchResults' + (isRows ? 'Rows' : 'Columns') + ']'); var searchText = !isRows ? $.trim(this.$columnTextField.val()) : $ .trim(this.$rowTextField.val()); var metadata = isRows ? dataset.getRowMetadata() : dataset .getColumnMetadata(); var visibleIndices = []; controller.getVisibleTrackNames(!isRows).forEach(function (name) { visibleIndices.push(morpheus.MetadataUtil.indexOf(metadata, name)); }); metadata = new morpheus.MetadataModelColumnView(metadata, visibleIndices); var searchResultViewIndices = morpheus.MetadataUtil.search({ model: metadata, text: searchText, isColumns: !isRows, defaultMatchMode: isRows ? this.defaultRowMatchMode : this.defaultColumnMatchMode }); if (searchText === '') { $searchResultsLabel.html(''); if (isRows) { this.$rowSearchDiv.hide(); } else { this.$columnSearchDiv.hide(); } } else { $searchResultsLabel.html(searchResultViewIndices.length + ' match' + (searchResultViewIndices.length === 1 ? '' : 'es')); if (isRows) { this.$rowSearchDiv.show(); } else { this.$columnSearchDiv.show(); } } var searchResultsModelIndices = []; if (searchResultViewIndices != null) { for (var i = 0, length = searchResultViewIndices.length; i < length; i++) { var viewIndex = searchResultViewIndices[i]; searchResultsModelIndices.push(isRows ? project .convertViewRowIndexToModel(viewIndex) : project .convertViewColumnIndexToModel(viewIndex)); } } if (searchResultViewIndices !== null && isMatchesOnTop) { var key = new morpheus.MatchesOnTopSortKey(project, searchResultsModelIndices, 'matches on top'); sortKeys = sortKeys.filter(function (key) { return !(key instanceof morpheus.MatchesOnTopSortKey); }); searchResultViewIndices = key.indices; // matching indices // are now on top // add to beginning of sort keys sortKeys.splice(0, 0, key); if (isRows) { project.setRowSortKeys(sortKeys, false); } else { project.setColumnSortKeys(sortKeys, false); } } var searchResultsViewIndicesSet = new morpheus.Set(); if (searchResultViewIndices != null) { for (var i = 0, length = searchResultViewIndices.length; i < length; i++) { var viewIndex = searchResultViewIndices[i]; searchResultsViewIndicesSet.add(viewIndex); } } if (searchResultViewIndices == null) { searchResultViewIndices = []; } if (isRows) { this.rowSearchResultModelIndices = searchResultsModelIndices; this.rowSearchResultViewIndicesSorted = searchResultViewIndices .sort(function (a, b) { return a < b ? -1 : 1; }); this.currentRowSearchIndex = -1; } else { this.columnSearchResultModelIndices = searchResultsModelIndices; this.columnSearchResultViewIndicesSorted = searchResultViewIndices .sort(function (a, b) { return a < b ? -1 : 1; }); this.currentColumnSearchIndex = -1; } // update selection (!isRows ? project.getColumnSelectionModel() : project .getRowSelectionModel()).setViewIndices( searchResultsViewIndicesSet, true); if (isMatchesOnTop) { // resort if (isRows) { project.setRowSortKeys(morpheus.SortKey.keepExistingSortKeys( sortKeys, project.getRowSortKeys()), true); } else { project.setColumnSortKeys(morpheus.SortKey .keepExistingSortKeys(sortKeys, project .getColumnSortKeys()), true); } } this.updateDimensionsLabel(); this.updateSelectionLabel(); this.searching = false; }, isSelectionOnTop: function (isColumns) { var $btn = isColumns ? this.$columnMatchesToTop : this.$rowMatchesToTop; return $btn.hasClass('btn-primary'); }, setSelectionOnTop: function (options) { if (options.updateButtonStatus) { var $btn = options.isColumns ? this.$columnMatchesToTop : this.$rowMatchesToTop; if (options.isOnTop) { $btn.addClass('btn-primary'); } else { $btn.removeClass('btn-primary'); } } var project = this.controller.getProject(); var sortKeys = options.isColumns ? project.getColumnSortKeys() : project.getRowSortKeys(); // clear existing sort keys except dendrogram sortKeys = sortKeys .filter(function (key) { return (key instanceof morpheus.SpecifiedModelSortOrder && key.name === 'dendrogram'); }); if (options.isOnTop) { // bring to top var key = new morpheus.MatchesOnTopSortKey(project, options.isColumns ? this.columnSearchResultModelIndices : this.rowSearchResultModelIndices, 'matches on top'); sortKeys.splice(0, 0, key); if (options.isColumns) { this.controller.scrollLeft(0); } else { this.controller.scrollTop(0); } } this.searching = true; if (options.isColumns) { project.setColumnSortKeys(sortKeys, true); } else { project.setRowSortKeys(sortKeys, true); } this._updateSearchIndices(options.isColumns); this.searching = false; } };