NIHVIVO-1073 Menu page refactoring. Removed temporary placeholder files and introduced pie charts on menu pages. UI team will compare with bar graphs on home page and determine whether we'll stick with one type over the other or throw them both into the mix.

This commit is contained in:
nac26 2011-01-28 18:25:21 +00:00
parent 81813bcb83
commit dd839ebd18
10 changed files with 322 additions and 8 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,021 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,95 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
var browseClassGroups = {
// Initial page setup
onLoad: function() {
this.mergeFromTemplate();
this.initObjects();
},
// Add variables from browse template
mergeFromTemplate: function() {
$.extend(this, browseData);
},
// Create references to frequently used elements for convenience
initObjects: function() {
this.browseClassLinks = $('#vgraph-classes li a');
},
// Retrieve classes
graphSetup: function() {
var values = [],
labels = [],
uris = [];
this.browseClassLinks.each(function() {
var count = $(this).children('span').text();
var count = parseInt(count.slice(1, -1), 10);
var percentage = parseInt(Math.round((count / browseClassGroups.classGroupIndividualCount) * 100), 10);
var name = $(this).text();
var countStart = name.lastIndexOf(' (');
var name = name.substring(0, countStart);
// alert(name +' | ' + count +' | '+ percentage);
if ( percentage > 0) {
values.push(percentage);
var name = name +' ('+ percentage +'%)';
labels.push(name);
uris.push($(this).attr("data-uri"));
}
});
// Send the parameters to build the pie chart
graphClasses.piechart(values, labels, uris);
}
};
var graphClasses = {
// Build the pie chart using gRaphael
piechart: function(values, labels, uris) {
// Clear the existing pie chart
$('#menupage-graph').empty();
// Create the canvas
var r = Raphael("menupage-graph", 500, 300);
// Setup the colors for the slices
// colors = ['#192933', '#26404E', '#294656', '#194c68', '#487A96', '#63A8CE', '#67AED6','#758A96', '#9DB9C9' ];
colors = ['#143D52', '#1F5C7A', '#297AA3', '#3399CC', '#5CADD6', '#85C2E0', '#ADD6EB', '#ADCBDD', '#D6EBF5', '#E9F1F5' ];
// Reverse colors to see how it looks with larger slices in lighter hues:
// colors = colors.reverse();
// Now draw the pie chart
var pie = r.g.piechart(150, 142, 100, values, {legend: labels, legendmark: "square", legendpos: "east", colors: colors});
pie.hover(function () {
this.sector.stop();
this.sector.scale(1.1, 1.1, this.cx, this.cy);
if (this.label) {
this.label[0].stop();
this.label[0].scale(1.5);
this.label[1].attr({"font-weight": 800});
}
}, function () {
this.sector.animate({scale: [1, 1, this.cx, this.cy]}, 500, "bounce");
if (this.label) {
this.label[0].animate({scale: 1}, 500, "bounce");
this.label[1].attr({"font-weight": 400});
}
});
// Can't reliably link the slices at the moment. Will come up with a solution if we end up sticking with the pie charts
// $('path').click(function() {
// var index = $('path').index(this);
// var uri = uris[index];
// // var link = browseClassGroups.baseUrl + '/individuallist?vclassId=' + encodeURIComponent(uri);
// window.location = "#browse-by";
// browseByVClass.getIndividuals(uri);
// return false;
// });
}
};
$(document).ready(function() {
browseClassGroups.onLoad();
browseClassGroups.graphSetup();
// graphClasses.piechart();
});

View file

@ -19,10 +19,8 @@ var browseByVClass = {
this.vgraphVClassLinks = $('#vgraph-classes li a');
this.browseVClasses = $('#browse-classes');
this.browseVClassLinks = $('#browse-classes li a');
this.selectedBrowseVClass = $('#browse-classes li a.selected');
this.alphaIndex = $('#alpha-browse-individuals');
this.alphaIndexLinks = $('#alpha-browse-individuals li a');
this.selectedAlphaIndex = $('#alpha-browse-individuals li a.selected');
this.paginationNav = $('nav.pagination');
this.paginationLinks = $('nav.pagination li a');
this.individualsInVClass = $('#individuals-in-class ul');
@ -56,9 +54,8 @@ var browseByVClass = {
this.paginationListener();
},
// Listener for page switching -- separate from the rest because it needs to be callable
paginationListener: function() {
// Listener for page switching
// separate from the rest because it needs to be callable
$('nav.pagination li a').click(function() {
uri = $('#browse-classes li a.selected').attr('data-uri');
alpha = $('#alpha-browse-individuals li a.selected').attr('data-alpha');
@ -75,6 +72,7 @@ var browseByVClass = {
}
},
// Where all the magic happens -- gonna fetch me some individuals
getIndividuals: function(vclassUri, alpha, page) {
url = this.dataServiceUrl + encodeURIComponent(vclassUri);
if ( alpha && alpha != "all") {
@ -149,22 +147,22 @@ var browseByVClass = {
browseByVClass.individualsInVClass.append(listItem);
})
// set selected class, alpha and page
// Set selected class, alpha and page
browseByVClass.selectedVClass(results.vclass.URI);
browseByVClass.selectedAlpha(alpha);
});
},
// Toggle the active class so it's clear which is selected
selectedVClass: function(vclassUri) {
// Remove active class on all vClasses
$('#browse-classes li a.selected').removeClass('selected');
// Can't figure out why using this.selectedBrowseVClass doesn't work here
// this.selectedBrowseVClass.removeClass('selected');
// Add active class for requested vClass
$('#browse-classes li a[data-uri="'+ vclassUri +'"]').addClass('selected');
},
// Toggle the active letter so it's clear which is selected
selectedAlpha: function(alpha) {
// if no alpha argument sent, assume all
if ( alpha == null ) {

View file

@ -0,0 +1,205 @@
/*
* g.Raphael 0.4.1 - Charting library, based on Raphaël
*
* Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*/
Raphael.fn.g.piechart = function (cx, cy, r, values, opts) {
opts = opts || {};
var paper = this,
sectors = [],
covers = this.set(),
chart = this.set(),
series = this.set(),
order = [],
len = values.length,
angle = 0,
total = 0,
others = 0,
cut = 9,
defcut = true;
chart.covers = covers;
if (len == 1) {
series.push(this.circle(cx, cy, r).attr({fill: this.g.colors[0], stroke: opts.stroke || "#fff", "stroke-width": opts.strokewidth == null ? 1 : opts.strokewidth}));
covers.push(this.circle(cx, cy, r).attr(this.g.shim));
total = values[0];
values[0] = {value: values[0], order: 0, valueOf: function () { return this.value; }};
series[0].middle = {x: cx, y: cy};
series[0].mangle = 180;
} else {
function sector(cx, cy, r, startAngle, endAngle, fill) {
var rad = Math.PI / 180,
x1 = cx + r * Math.cos(-startAngle * rad),
x2 = cx + r * Math.cos(-endAngle * rad),
xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad),
y1 = cy + r * Math.sin(-startAngle * rad),
y2 = cy + r * Math.sin(-endAngle * rad),
ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad),
res = ["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2, "z"];
res.middle = {x: xm, y: ym};
return res;
}
for (var i = 0; i < len; i++) {
total += values[i];
values[i] = {value: values[i], order: i, valueOf: function () { return this.value; }};
}
values.sort(function (a, b) {
return b.value - a.value;
});
for (i = 0; i < len; i++) {
if (defcut && values[i] * 360 / total <= 1.5) {
cut = i;
defcut = false;
}
if (i > cut) {
defcut = false;
values[cut].value += values[i];
values[cut].others = true;
others = values[cut].value;
}
}
len = Math.min(cut + 1, values.length);
others && values.splice(len) && (values[cut].others = true);
for (i = 0; i < len; i++) {
var mangle = angle - 360 * values[i] / total / 2;
if (!i) {
angle = 90 - mangle;
mangle = angle - 360 * values[i] / total / 2;
}
if (opts.init) {
var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(",");
}
var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
var p = this.path(opts.init ? ipath : path).attr({fill: opts.colors && opts.colors[i] || Raphael.getColor("#194c68") || "#666", stroke: opts.stroke || "#fff", "stroke-width": (opts.strokewidth == null ? 1 : opts.strokewidth), "stroke-linejoin": "round"});
p.value = values[i];
p.middle = path.middle;
p.mangle = mangle;
sectors.push(p);
series.push(p);
opts.init && p.animate({path: path.join(",")}, (+opts.init - 1) || 1000, ">");
}
for (i = 0; i < len; i++) {
p = paper.path(sectors[i].attr("path")).attr(this.g.shim);
opts.href && opts.href[i] && p.attr({href: opts.href[i]});
p.attr = function () {};
covers.push(p);
series.push(p);
}
}
chart.hover = function (fin, fout) {
fout = fout || function () {};
var that = this;
for (var i = 0; i < len; i++) {
(function (sector, cover, j) {
var o = {
sector: sector,
cover: cover,
cx: cx,
cy: cy,
mx: sector.middle.x,
my: sector.middle.y,
mangle: sector.mangle,
r: r,
value: values[j],
total: total,
label: that.labels && that.labels[j]
};
cover.mouseover(function () {
fin.call(o);
}).mouseout(function () {
fout.call(o);
});
})(series[i], covers[i], i);
}
return this;
};
// x: where label could be put
// y: where label could be put
// value: value to show
// total: total number to count %
chart.each = function (f) {
var that = this;
for (var i = 0; i < len; i++) {
(function (sector, cover, j) {
var o = {
sector: sector,
cover: cover,
cx: cx,
cy: cy,
x: sector.middle.x,
y: sector.middle.y,
mangle: sector.mangle,
r: r,
value: values[j],
total: total,
label: that.labels && that.labels[j]
};
f.call(o);
})(series[i], covers[i], i);
}
return this;
};
chart.click = function (f) {
var that = this;
for (var i = 0; i < len; i++) {
(function (sector, cover, j) {
var o = {
sector: sector,
cover: cover,
cx: cx,
cy: cy,
mx: sector.middle.x,
my: sector.middle.y,
mangle: sector.mangle,
r: r,
value: values[j],
total: total,
label: that.labels && that.labels[j]
};
cover.click(function () { f.call(o); });
})(series[i], covers[i], i);
}
return this;
};
chart.inject = function (element) {
element.insertBefore(covers[0]);
};
var legend = function (labels, otherslabel, mark, dir) {
var x = cx + r + r / 5,
y = cy,
h = y + 10;
labels = labels || [];
dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east";
mark = paper.g.markers[mark && mark.toLowerCase()] || "disc";
chart.labels = paper.set();
for (var i = 0; i < len; i++) {
var clr = series[i].attr("fill"),
j = values[i].order,
txt;
values[i].others && (labels[j] = otherslabel || "Others");
labels[j] = paper.g.labelise(labels[j], values[i], total);
chart.labels.push(paper.set());
chart.labels[i].push(paper.g[mark](x + 5, h, 5).attr({fill: clr, stroke: "none"}));
chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(paper.g.txtattr).attr({fill: opts.legendcolor || "#000", "text-anchor": "start"}));
covers[i].label = chart.labels[i];
h += txt.getBBox().height * 1.2;
}
var bb = chart.labels.getBBox(),
tr = {
east: [0, -bb.height / 2],
west: [-bb.width - 2 * r - 20, -bb.height / 2],
north: [-r - bb.width / 2, -r - bb.height - 10],
south: [-r - bb.width / 2, r + 10]
}[dir];
chart.labels.translate.apply(chart.labels, tr);
chart.push(chart.labels);
};
if (opts.legend) {
legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
}
chart.push(series, covers);
chart.series = series;
chart.covers = covers;
return chart;
};

View file

@ -21,12 +21,22 @@ template variable with the domain name for an AJAX request with visualizations.
</#if>
</#list>
<#-- classGroupIndividualCount is assigned in menupage-vClassesInClassGroup.ftl -->
<script type="text/javascript">
var menupageData = {
baseUrl: '${domainName + urls.base}',
dataServiceUrl: '${domainName + urls.base}/dataservice?getLuceneIndividualsByVClass=1&vclassId=',
defaultBrowseVClassUri: '${firstNonEmptyVClass}'
};
var browseData = {
classGroupUri: '${classGroupUri!}',
classGroupIndividualCount: '${classGroupIndividualCount!}'
};
</script>
${scripts.add("/js/menupage/browseByVClass.js")}
<#-- Script to enable browsing individuals within a class -->
${scripts.add("/js/menupage/browseByVClass.js")}
<#-- Scripts required to create the visual graphs -->
${scripts.add("/js/raphael/raphael.js", "/js/raphael/g.raphael.js", "/js/raphael/g.pie.js", "/js/browseClassGroupsPie.js")}

View file

@ -7,6 +7,12 @@
<#list vClassGroup as vClass>
<#-- Only display vClasses with individuals -->
<#if (vClass.entityCount > 0)>
<#-- Calculate the individual count for the group since it's not currently provided to menu page templates -->
<#if !classGroupIndividualCount??>
<#assign classGroupIndividualCount = vClass.entityCount />
<#else>
<#assign classGroupIndividualCount = classGroupIndividualCount + vClass.entityCount />
</#if>
<li role="listitem"><a href="#browse-by" title="Browse all individuals in this class" data-uri="${vClass.URI}">${vClass.name} <span class="count-classes">(${vClass.entityCount})</span></a></li>
</#if>
</#list>