NIHVIVO-592 Improvements to class group browse and bar graphs on home page.

This commit is contained in:
nac26 2011-01-28 18:21:17 +00:00
parent 6b6bd1194a
commit 81813bcb83
4 changed files with 114 additions and 84 deletions

View file

@ -64,18 +64,18 @@ ul#browse-classgroups .count-classes {
background: #fff;
min-height: 230px;
}
ul#classgroup-list {
ul#classes-in-classgroup {
float: left;
width: 90%;
padding: 0 10px 15px 22px;
margin-top: 20px;
margin-bottom: 10px;
}
ul#classgroup-list.vis {
ul#classes-in-classgroup.vis {
width: 44%;
border-right: 1px solid #DDE5E4;
}
ul#classgroup-list li {
ul#classes-in-classgroup li {
display: block;
float: left;
width: 100%;
@ -84,17 +84,17 @@ ul#classgroup-list li {
height: 35px;
line-height: 35px;
}
ul#classgroup-list li:last-child {
ul#classes-in-classgroup li:last-child {
border-bottom: none
}
ul#classgroup-list a {
ul#classes-in-classgroup a {
display: block;
padding-left: 15px;
height: 35px;
color: #5e6363;
text-decoration: none;
}
ul#classgroup-list .count-individuals {
ul#classes-in-classgroup .count-individuals {
font-size: 12px;
}
/* VISUALIZATION ------> */

View file

@ -5,17 +5,17 @@ var browseClassGroups = {
onLoad: function() {
this.mergeFromTemplate();
this.initObjects();
// this.bindEventListeners();
this.bindEventListeners();
},
// Add variables from menupage template
// Add variables from browse template
mergeFromTemplate: function() {
$.extend(this, browseData);
},
// Create references to frequently used elements for convenience
initObjects: function() {
this.vClassesInClassGroup = $('ul#classgroup-list');
this.vClassesInClassGroup = $('ul#classes-in-classgroup');
this.browseClassGroupLinks = $('#browse-classgroups li a');
},
@ -26,6 +26,25 @@ var browseClassGroups = {
uri = $(this).attr("data-uri");
browseClassGroups.getVClasses(uri);
return false;
});
// Call the bar chart highlighter listener
this.chartHighlighterListener();
},
// Listener for bar chart highlighting -- separate from the rest because it needs to be callable
chartHighlighterListener: function() {
// This essentially replicates the native Raphael hover behavior (see chart.hover below)
// but allows us to trigger it via jQuery from the list of classes adjacent to the chart
$('ul#classes-in-classgroup li a').hover(function() {
var classIndex = $('ul#classes-in-classgroup li a').index(this);
$('#visual-graph svg path').eq(classIndex).attr('fill', '#ccc');
$('#visual-graph svg text').eq(classIndex).toggle();
return false;
}, function() {
var classIndex = $('ul#classes-in-classgroup li a').index(this);
$('#visual-graph svg path').eq(classIndex).attr('fill', '#999');
$('#visual-graph svg text').eq(classIndex).toggle();
})
},
@ -36,6 +55,7 @@ var browseClassGroups = {
}
},
// Where all the magic happens -- gonna fetch me some classes
getVClasses: function(classgroupUri, alpha) {
url = this.dataServiceUrl + encodeURIComponent(classgroupUri);
if ( alpha && alpha != "all") {
@ -45,72 +65,92 @@ var browseClassGroups = {
// First wipe currently displayed classes
this.vClassesInClassGroup.empty();
var values = [],
labels = [],
uris = [];
$.getJSON(url, function(results) {
$.each(results.vClasses, function(i, item) {
name = results.vClasses[i].name;
uri = results.vClasses[i].URI;
indivCount = results.vClasses[i].individualCount;
$.each(results.classes, function(i, item) {
name = results.classes[i].name;
uri = results.classes[i].URI;
indivCount = results.classes[i].entityCount;
indexUrl = browseClassGroups.baseUrl + '/individuallist?vclassId=' + encodeURIComponent(uri);
// Build the content of each list item, piecing together each component
listItem = '<li role="listitem">';
listItem += '<a href="'+ indexUrl +'" title="View all '+ name +'content">'+ name +'</a>';
// Include the moniker only if it's not empty and not equal to the VClass name
listItem += ' <span class="count-individuals">(${indivCount})</span>'
listItem += '</li>';
browseClassGroups.vClassesInClassGroup.append(listItem);
// Only add to the arrays and render classes when they aren't empty
if ( indivCount > 0 ) {
values.push(parseInt(indivCount, 10));
labels.push(name + ' (' + parseInt(indivCount, 10) +')');
uris.push(uri);
// Build the content of each list item, piecing together each component
listItem = '<li role="listitem">';
listItem += '<a href="'+ indexUrl +'" title="Browse all '+ name +' content">'+ name;
listItem += ' <span class="count-individuals">('+ indivCount +')</span></a>';
listItem += '</li>';
browseClassGroups.vClassesInClassGroup.append(listItem);
}
})
// set selected class group
browseClassGroups.selectedClassGroup(results.vclassGroup.URI);
// Set selected class group
browseClassGroups.selectedClassGroup(results.classGroupUri);
// Update the graph
graphClassGroups.barchart(values, labels, uris);
// Call the bar highlighter listener
browseClassGroups.chartHighlighterListener();
});
},
selectedClassGroup: function(vclassUri) {
// Toggle the active class group so it's clear which is selected
selectedClassGroup: function(classGroupUri) {
// Remove active class on all vClasses
$('#browse-childClasses li a.selected').removeClass('selected');
// Can't figure out why using this.selectedBrowseVClass doesn't work here
// this.selectedBrowseVClass.removeClass('selected');
$('#browse-classgroups li a.selected').removeClass('selected');
// Add active class for requested vClass
$('#browse-childClasses li a[data-uri="'+ vclassUri +'"]').addClass('selected');
$('#browse-classgroups li a[data-uri="'+ classGroupUri +'"]').addClass('selected');
}
};
var graphClassGroups = {
// Build the bar chart using gRaphael
barchart: function(values, labels, uris) {
// Clear the existing bar chart
$('#visual-graph').empty();
barchart: function() {
var values = [],
labels = [];
uris = [];
$("tr").each(function() {
values.push(parseInt($("td", this).text(), 10));
labels.push($("th", this).text());
uris.push($("th", this).attr("data-uri"));
});
var height = values.length * 37;
// Create the canvas
var r = Raphael("pieViz", 300, height + 10);
var r = Raphael("visual-graph", 300, height + 10);
// Hide the table containing the data to be graphed
$('table.graph-data').addClass('hidden');
var chart = r.g.hbarchart(0, 16, 300, height, [values], {type:"soft", singleColor:"#999"});
// Add the class names as labels and then hide them
chart.label(labels, true);
// getting a JS error in the console when trying to add the class
// Getting a JS error in the console when trying to add the class
// "setting a property that has only a getter"
// $('svg text').addClass('hidden');
// so using .hide() instead
$('svg text').hide();
// Was unable to append <a> within <svg> -- was always hidden and couldn't get it to display
// So using jQuery click to add links
// so using jQuery click to add links
$('rect').click(function() {
var index = $('rect').index(this);
var uri = uris[index];
var link = browseClassGroups.baseUrl + '/individuallist?vclassId=' + encodeURIComponent(uri);
window.location = link;
})
});
// Add title attributes to each <rect> in the bar chart
$('rect').each(function() {
var index = $('rect').index(this);
var label = labels[index];
var countStart = label.lastIndexOf(' (');
var label = label.substring(0, countStart);
var title = 'View all '+ label +' content';
// Add a title attribute
$(this).attr('title', title);
});
// On hover
// 1. Change bar color
@ -121,14 +161,14 @@ var graphClassGroups = {
$('rect').hover(function() {
var index = $('rect').index(this);
$('svg text').eq(index).show();
$('#classgroup-list li a').eq(index).addClass('selected');
$('#classes-in-classgroup li a').eq(index).addClass('selected');
})
}, function() {
this.bar.attr({fill: "#999"});
$('rect').hover(function() {
var index = $('rect').index(this);
$('svg text').eq(index).hide();
$('#classgroup-list li a').eq(index).removeClass('selected');
$('#classes-in-classgroup li a').eq(index).removeClass('selected');
})
});
}
@ -136,6 +176,5 @@ var graphClassGroups = {
$(document).ready(function() {
browseClassGroups.onLoad();
// browseClassGroups.defaultClassGroup();
graphClassGroups.barchart();
browseClassGroups.defaultClassGroup();
});

View file

@ -28,7 +28,7 @@ ${stylesheets.add("/css/browseClassGroups.css")}
<#elseif classGroup.uri == group.uri>
<#assign activeGroup = selected />
</#if>
<li role="listitem"><a data-uri="${group.uri}" ${activeGroup}href="${urls.base}/${currentPage}?classgroupUri=${group.uri?url}#browse">${group.publicName?capitalize} <span class="count-classes">(${group.individualCount})</span></a></li>
<li role="listitem"><a data-uri="${group.uri}" ${activeGroup}href="${urls.base}/${currentPage}?classgroupUri=${group.uri?url}#browse" title="Browse ${group.publicName?capitalize}">${group.publicName?capitalize} <span class="count-classes">(${group.individualCount})</span></a></li>
</#if>
</#list>
</#assign>
@ -43,11 +43,11 @@ ${stylesheets.add("/css/browseClassGroups.css")}
</ul>
<#-- If requesting the home page without any additional URL parameters, select the first populated class group-->
<#assign defaultSelectedClassGroup = firstPopulatedClassGroup! />
<#assign defaultSelectedClassGroup = firstPopulatedClassGroup />
<section id="browse-classes" role="navigation">
<nav>
<ul id="classgroup-list" class="vis" role="list">
<ul id="classes-in-classgroup" class="vis" role="list">
<#if classes??>
<#-- We don't need to send parameters because the data we need is delivered as template variables -->
<@classesInClassgroup />
@ -66,6 +66,24 @@ ${stylesheets.add("/css/browseClassGroups.css")}
</#if>
</section> <!-- #browse-classes -->
</section> <!-- #browse -->
<#----------------------------------------------------------------------------------
requestedPage is currently provided by FreemarkerHttpServlet. Should this be moved
to PageController? Maybe we should have Java provide the domain name directly
instead of the full URL of the requested page? Chintan was also asking for a
template variable with the domain name for an AJAX request with visualizations.
------------------------------------------------------------------------------------>
<#assign domainName = requestedPage?substring(0, requestedPage?index_of("/", 7)) />
<script type="text/javascript">
var browseData = {
baseUrl: '${domainName + urls.base}',
dataServiceUrl: '${domainName + urls.base}/dataservice?getVClassesForVClassGroup=1&classgroupUri=',
defaultBrowseClassGroupUri: '${firstPopulatedClassGroup.uri!}'
};
</script>
${scripts.add("/js/browseClassGroups.js")}
<#else>
<#-- Would be nice to update classgroups-checkForData.ftl with macro so it could be used here as well -->
<#-- <#include "classgroups-checkForData.ftl"> -->
@ -75,37 +93,21 @@ ${stylesheets.add("/css/browseClassGroups.css")}
<p>Please <a href="${urls.login}" title="log in to manage this site">log in</a> to manage content.</p>
</#if>
</#if>
<#----------------------------------------------------------------------------------
requestedPage is currently provided by FreemarkerHttpServlet. Should this be moved
to PageController? Maybe we should have Java provide the domain name directly
instead of the full URL of the requested page? Chintan was also asking for a
template variable with the domain name for an AJAX request with visualizations.
------------------------------------------------------------------------------------>
<#assign domainName = requestedPage?substring(0, requestedPage?index_of("/", 7)) />
<script type="text/javascript">
var browseData = {
baseUrl: '${domainName + urls.base}',
dataServiceUrl: '${domainName + urls.base}/dataservice?getLuceneIndividualsByVClass=1&vclassId=',
defaultBrowseClassGroupUri: '${firstPopulatedClassGroup.uri}'
};
</script>
${scripts.add("/js/browseClassGroups.js")}
</#macro>
<#macro classesInClassgroup classes=classes classGroup=classGroup>
<#list classes as class>
<#if (class.individualCount > 0)>
<li role="listitem"><a href="${urls.base}/individuallist?vclassId=${class.uri?url}">${class.name} <span class="count-individuals"> (${class.individualCount})</span></a></li>
<li role="listitem"><a href="${urls.base}/individuallist?vclassId=${class.uri?url}" title="Browse all ${class.name} content">${class.name} <span class="count-individuals"> (${class.individualCount})</span></a></li>
</#if>
</#list>
</#macro>
<#macro pieChart classes=classes classGroup=classGroup>
<section id="visual-graph" role="region">
<table>
<table class="graph-data">
<#list classes?sort_by("individualCount") as class>
<#assign countPercentage = (class.individualCount / classGroup.individualCount) * 100 />
<#if (class.individualCount > 0 && countPercentage?round > 0)>
@ -123,22 +125,11 @@ ${stylesheets.add("/css/browseClassGroups.css")}
${scripts.add("/themes/wilma/js/jquery_plugins/raphael/raphael.js", "/themes/wilma/js/jquery_plugins/raphael/pie.js")}
</#macro>
<#macro visualGraph classes=classes classGroup=classGroup>
<section id="visual-graph" class="barchart" role="region">
<table class="graph-data">
<#list classes as class>
<#if (class.individualCount > 0)>
<tr>
<th data-uri="${class.uri}">${class.name} (${class.individualCount})</th>
<td>${class.individualCount}</td>
</tr>
</#if>
</#list>
</table>
<section id="pieViz" role="region"></section>
<#-- Will be populated dynamically via AJAX request -->
</section>
<#-- ${scripts.add("/themes/wilma/js/jquery_plugins/raphael/raphael.js", "/themes/wilma/js/jquery_plugins/raphael/pie.js")} -->
${scripts.add("/js/raphael/raphael.js", "/js/raphael/g.raphael.js", "/js/raphael/g.bar.js")}
</#macro>

View file

@ -32,7 +32,7 @@
<section id="browse-classes" role="navigation">
<nav>
<ul id="classgroup-list" role="list">
<ul id="classes-in-classgroup" role="list">
<#list classes as class>
<#if (class.individualCount > 0)>
<li role="listitem"><a href="${urls.base}/${currentPage}?classgroupUri=${classGroup.uri?url}&vclassUri=${class.uri?url}">${class.name} <span class="count-individuals"> (${class.individualCount})</span></a></li>