2d091022fd185c7273ef37c9721415e3706e294e kate Fri Feb 17 22:09:17 2012 -0800 1. Add crosshair hover effect on matrix. Break out functions for readability (thanks to Teresa for code review). diff --git src/hg/js/encodeDataMatrix.js src/hg/js/encodeDataMatrix.js index 1540d69..6107bdb 100644 --- src/hg/js/encodeDataMatrix.js +++ src/hg/js/encodeDataMatrix.js @@ -9,143 +9,190 @@ $(function () { var requests = [ // requests to server API encodeProject.serverRequests.experiment, encodeProject.serverRequests.dataType, encodeProject.serverRequests.cellType, encodeProject.serverRequests.expId ]; var dataTypeLabelHash = {}, dataTypeTermHash = {}, cellTypeHash = {}; var dataType, cellType; var organism, assembly, server, header; var karyotype; var spinner; + function rowAddCells(row, dataGroups, matrix, cellType) { + // populate a row in the matrix with cells for data groups and data types + + $.each(dataGroups, function (i, group) { + // skip group header + td = $('<td></td>'); + td.addClass('matrixCell'); + row.append(td); + $.each(group.dataTypes, function (i, dataTypeLabel) { + dataType = dataTypeLabelHash[dataTypeLabel].term; + // prune out datatypes with no experiments + if (dataTypeLabelHash[dataTypeLabel].count === undefined) { + return true; + } + td = $('<td></td>'); + td.addClass('matrixCell'); + row.append(td); + if (cellType === null) { + return true; + } + if (!matrix[cellType][dataType]) { + td.addClass('todoExperiment'); + return true; + } + // fill in count, mouseover and selection by click + td.addClass('experiment'); + td.text(matrix[cellType][dataType]); + td.data({ + 'dataType' : dataType, + 'cellType' : cellType + }); + td.mouseover(function() { + $(this).attr('title', 'Click to select: ' + + dataTypeTermHash[$(this).data().dataType].label + + ' ' + ' in ' + + $(this).data().cellType +' cells'); + }); + td.click(function() { + // TODO: base on preview ? + var url = encodeProject.getSearchUrl(assembly); + // TODO: encapsulate var names + url += + ('&hgt_mdbVar1=dataType&hgt_mdbVal1=' + $(this).data().dataType + + '&hgt_mdbVar2=cell&hgt_mdbVal2=' + $(this).data().cellType + + '&hgt_mdbVar3=view&hgt_mdbVal3=Any'); + window.open(url, "searchWindow"); + }); + }); + }); + } + + function addFloatingHeader(table) { + // add callback for floating table header feature + + table.floatHeader({ + cbFadeIn: function (header) { + // hide axis labels -- a bit tricky to do so + // as special handling needed for X axis label + $(".floatHeader #headerLabelRow").remove(); + $(".floatHeader #cellHeaderLabel").html(''); + $(".floatHeader #searchTypePanel").remove(); + + // Note: user-defined callback requires + // default actions from floatHeader plugin + // implementation (stop+fadeIn) + header.stop(true, true); + header.fadeIn(100); + } + }); + } + function tableOut(matrix, cellTiers, dataGroups) { // create table with rows for each cell types and columns for each data type - var table, tableHeader, row, td; + var table, thead, tableHeader, row, td; // fill in column headers from dataTypes returned by server tableHeader = $('#columnHeaders'); + table = $('#matrixTable'); + thead = $('thead'); + // 1st column is row headers + thead.before('<colgroup></colgroup>'); $.each(dataGroups, function (i, group) { tableHeader.append('<th class="groupType"><div class="verticalText">' + group.label + '</div></th>'); + // add colgroup element to support cross-hair hover effect + thead.before('<colgroup></colgroup>'); $.each(group.dataTypes, function (i, dataTypeLabel) { dataType = dataTypeLabelHash[dataTypeLabel].term; if (dataTypeLabelHash[dataTypeLabel].count !== undefined) { // prune out datatypes with no experiments tableHeader.append('<th class="elementType" title="' + dataTypeLabelHash[dataTypeLabel].description + '"><div class="verticalText">' + dataTypeLabel + '</div></th>'); + // add colgroup element to support cross-hair hover effect + thead.before('<colgroup class="dataTypeCol"></colgroup>'); } }); }); // fill in matrix -- // add rows with cell type labels (column 1) and cells for experiments - table = $('#matrixTable'); - // add sections for each Tier of cell type $.each(cellTiers, function (i, tier) { //skip bogus 4th tier (not my property ?) if (tier === undefined) { return true; } - table.append($('<tr class="matrix"><th class="groupType">' + - "Tier " + tier.term + '</th></td></tr>')); + row = $('<tr class="matrix"><th class="groupType">' + + "Tier " + tier.term + '</th></td></tr>'); + rowAddCells(row, dataGroups, matrix, null); + table.append(row); + $.each(tier.cellTypes, function (i, cellType) { if (!cellType) { return true; } if (!matrix[cellType]) { return true; } karyotype = cellTypeHash[cellType].karyotype; // TODO: recognize cancer* // NOTE: coupled to CSS if (karyotype !== 'cancer' && karyotype !== 'normal') { karyotype = 'unknown'; } row = $('<tr><th class="elementType" title="' + cellTypeHash[cellType].description + - '"><a href="/cgi-bin/hgEncodeVocab?ra=encode/cv.ra&term=' + cellType - + '">' + cellType + '</a><span title="karyotype: ' + karyotype + + '"><a href="/cgi-bin/hgEncodeVocab?ra=encode/cv.ra&term=' + cellType + + '">' + cellType + '</a><span title="karyotype: ' + karyotype + '" class="' + karyotype + '">•</span></th>'); - $.each(dataGroups, function (i, group) { - // skip group header - row.append('<td></td>'); - $.each(group.dataTypes, function (i, dataTypeLabel) { - dataType = dataTypeLabelHash[dataTypeLabel].term; - // prune out datatypes with no experiments - if (dataTypeLabelHash[dataTypeLabel].count === undefined) { - return true; - } - td = $('<td></td>'); - td.addClass('matrixCell'); - if (matrix[cellType][dataType]) { - // fill in count, mouseover and selection by click - td.addClass('experiment'); - td.text(matrix[cellType][dataType]); - td.data({ - 'dataType' : dataType, - 'cellType' : cellType - }); - td.mouseover(function() { - $(this).attr('title', 'Click to select: ' + - dataTypeTermHash[$(this).data().dataType].label + - ' ' + ' in ' + - $(this).data().cellType +' cells'); - }); - td.click(function() { - // TODO: base on preview ? - var url = encodeProject.getSearchUrl(assembly); + rowAddCells(row, dataGroups, matrix, cellType); - // TODO: encapsulate var names - url += - ('&hgt_mdbVar1=dataType&hgt_mdbVal1=' + $(this).data().dataType + - '&hgt_mdbVar2=cell&hgt_mdbVal2=' + $(this).data().cellType + - '&hgt_mdbVar3=view&hgt_mdbVal3=Any'); - // TODO: open search window - //window.open(url, "searchWindow"); - window.location = url; - }); - } - row.append(td); - }); - table.append(row); - }); table.append(row); }); }); $("body").append(table); - // callback for floating table header feature - table.floatHeader({ - cbFadeIn: function (header) { - // hide axis labels -- a bit tricky to do so - // as special handling needed for X axis label - $(".floatHeader #headerLabelRow").remove(); - $(".floatHeader #cellHeaderLabel").html(''); - $(".floatHeader #searchTypePanel").remove(); + addFloatingHeader(table); - // Note: user-defined callback requires - // default actions from floatHeader plugin - // implementation (stop+fadeIn) - header.stop(true, true); - header.fadeIn(100); + // column and row hover (cross-hair effect) + // thanks to Chris Coyier, css-tricks.com + // NOTE: acts on colgroups declared at start of table + $("#matrixTable, #matrixTableFloatHeaderClone").delegate('.matrixCell, .elementType','mouseover mouseleave', function(e) { + if (!$(this).hasClass('experiment') && !$(this).hasClass('todoExperiment') && + !$(this).hasClass('elementType') && !$(this).hasClass('groupType')) { + return; + } + if (e.type == 'mouseover') { + // refrain from highlighting header row + if (!$(this).parent().is("#columnHeaders")) { + $(this).parent().addClass("crossHair"); + } + col = $("colGroup").eq($(this).index()); + if (col.hasClass("dataTypeCol")) { + col.addClass("crossHair"); + } + } else { + $(this).parent().removeClass("crossHair"); + $("colGroup").eq($(this).index()).removeClass("crossHair"); } }); } function handleServerData(responses) { // main actions, called when loading data from server is complete var experiments = responses[0], dataTypes = responses[1], cellTypes = responses[2], expIds = responses[3]; var dataGroups, cellTiers, expIdHash, header; var matrix = {}; hideLoadingImage(spinner); $('#matrixTable').show(); // set up structures for data types and their groups