NIHVIVO-592 Class group browse for home page. Still waiting on update to JSONServlet (NIHVIVO-1674) so classes in class group can be returned for AJAX requests. Introducing alternative bar graph in lieu of pie chart.

This commit is contained in:
nac26 2011-01-24 18:24:24 +00:00
parent 9f3a4343d2
commit 2be51ef25c
7 changed files with 795 additions and 28 deletions

View file

@ -0,0 +1,141 @@
/* $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();
// this.bindEventListeners();
},
// Add variables from menupage template
mergeFromTemplate: function() {
$.extend(this, browseData);
},
// Create references to frequently used elements for convenience
initObjects: function() {
this.vClassesInClassGroup = $('ul#classgroup-list');
this.browseClassGroupLinks = $('#browse-classgroups li a');
},
// Event listeners. Called on page load
bindEventListeners: function() {
// Listener for classGroup switching
this.browseClassGroupLinks.click(function() {
uri = $(this).attr("data-uri");
browseClassGroups.getVClasses(uri);
return false;
})
},
// Load classes and chart for default class group as defined by template
defaultClassGroup: function() {
if ( this.defaultBrowseClassGroupURI != "false" ) {
this.getVClasses(this.defaultBrowseClassGroupUri);
}
},
getVClasses: function(classgroupUri, alpha) {
url = this.dataServiceUrl + encodeURIComponent(classgroupUri);
if ( alpha && alpha != "all") {
url = url + '&alpha=' + alpha;
}
// First wipe currently displayed classes
this.vClassesInClassGroup.empty();
$.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;
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);
})
// set selected class group
browseClassGroups.selectedClassGroup(results.vclassGroup.URI);
});
},
selectedClassGroup: function(vclassUri) {
// 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');
// Add active class for requested vClass
$('#browse-childClasses li a[data-uri="'+ vclassUri +'"]').addClass('selected');
}
};
var graphClassGroups = {
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);
// 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
// "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
$('rect').click(function() {
var index = $('rect').index(this);
var uri = uris[index];
var link = browseClassGroups.baseUrl + '/individuallist?vclassId=' + encodeURIComponent(uri);
window.location = link;
})
// On hover
// 1. Change bar color
// 2. Reveal label
// 3. Highlight class name in main list
chart.hover(function() {
this.bar.attr({fill: "#ccc"});
$('rect').hover(function() {
var index = $('rect').index(this);
$('svg text').eq(index).show();
$('#classgroup-list 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');
})
});
}
};
$(document).ready(function() {
browseClassGroups.onLoad();
// browseClassGroups.defaultClassGroup();
graphClassGroups.barchart();
});

View file

@ -0,0 +1,405 @@
/*!
* 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.barchart = function (x, y, width, height, values, opts) {
opts = opts || {};
var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square",
gutter = parseFloat(opts.gutter || "20%"),
chart = this.set(),
bars = this.set(),
covers = this.set(),
covers2 = this.set(),
total = Math.max.apply(Math, values),
stacktotal = [],
paper = this,
multi = 0,
colors = opts.colors || this.g.colors,
singleColor = opts.singleColor,
len = values.length;
if (this.raphael.is(values[0], "array")) {
total = [];
multi = len;
len = 0;
for (var i = values.length; i--;) {
bars.push(this.set());
total.push(Math.max.apply(Math, values[i]));
len = Math.max(len, values[i].length);
}
if (opts.stacked) {
for (var i = len; i--;) {
var tot = 0;
for (var j = values.length; j--;) {
tot +=+ values[j][i] || 0;
}
stacktotal.push(tot);
}
}
for (var i = values.length; i--;) {
if (values[i].length < len) {
for (var j = len; j--;) {
values[i].push(0);
}
}
}
total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
}
total = (opts.to) || total;
var barwidth = width / (len * (100 + gutter) + gutter) * 100,
barhgutter = barwidth * gutter / 100,
barvgutter = opts.vgutter == null ? 20 : opts.vgutter,
stack = [],
X = x + barhgutter,
Y = (height - 2 * barvgutter) / total;
if (!opts.stretch) {
barhgutter = Math.round(barhgutter);
barwidth = Math.floor(barwidth);
}
!opts.stacked && (barwidth /= multi || 1);
for (var i = 0; i < len; i++) {
stack = [];
for (var j = 0; j < (multi || 1); j++) {
var h = Math.round((multi ? values[j][i] : values[i]) * Y),
top = y + height - barvgutter - h,
bar = this.g.finger(Math.round(X + barwidth / 2), top + h, barwidth, h, true, type).attr({stroke: "none", fill: singleColor ? singleColor : (colors[multi ? j : i]) });
if (multi) {
bars[j].push(bar);
} else {
bars.push(bar);
}
bar.y = top;
bar.x = Math.round(X + barwidth / 2);
bar.w = barwidth;
bar.h = h;
bar.value = multi ? values[j][i] : values[i];
if (!opts.stacked) {
X += barwidth;
} else {
stack.push(bar);
}
}
if (opts.stacked) {
var cvr;
covers2.push(cvr = this.rect(stack[0].x - stack[0].w / 2, y, barwidth, height).attr(this.g.shim));
cvr.bars = this.set();
var size = 0;
for (var s = stack.length; s--;) {
stack[s].toFront();
}
for (var s = 0, ss = stack.length; s < ss; s++) {
var bar = stack[s],
cover,
h = (size + bar.value) * Y,
path = this.g.finger(bar.x, y + height - barvgutter - !!size * .5, barwidth, h, true, type, 1);
cvr.bars.push(bar);
size && bar.attr({path: path});
bar.h = h;
bar.y = y + height - barvgutter - !!size * .5 - h;
covers.push(cover = this.rect(bar.x - bar.w / 2, bar.y, barwidth, bar.value * Y).attr(this.g.shim));
cover.bar = bar;
cover.value = bar.value;
size += bar.value;
}
X += barwidth;
}
X += barhgutter;
}
covers2.toFront();
X = x + barhgutter;
if (!opts.stacked) {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var cover;
covers.push(cover = this.rect(Math.round(X), y + barvgutter, barwidth, height - barvgutter).attr(this.g.shim));
cover.bar = multi ? bars[j][i] : bars[i];
cover.value = cover.bar.value;
X += barwidth;
}
X += barhgutter;
}
}
chart.label = function (labels, isBottom) {
labels = labels || [];
this.labels = paper.set();
var L, l = -Infinity;
if (opts.stacked) {
for (var i = 0; i < len; i++) {
var tot = 0;
for (var j = 0; j < (multi || 1); j++) {
tot += multi ? values[j][i] : values[i];
if (j == multi - 1) {
var label = paper.g.labelise(labels[i], tot, total);
L = paper.g.text(bars[0][i].x, y + height - barvgutter / 2, label).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if (bb.x - 7 < l) {
L.remove();
} else {
this.labels.push(L);
l = bb.x + bb.width;
}
}
}
}
} else {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total);
L = paper.g.text(bars[i * (multi || 1) + j].x, isBottom ? y + height - barvgutter / 2 : bars[i * (multi || 1) + j].y - 10, label).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if (bb.x - 7 < l) {
L.remove();
} else {
this.labels.push(L);
l = bb.x + bb.width;
}
}
}
}
return this;
};
chart.hover = function (fin, fout) {
covers2.hide();
covers.show();
fout = fout || function () {};
covers.mouseover(fin).mouseout(fout);
return this;
};
chart.hoverColumn = function (fin, fout) {
covers.hide();
covers2.show();
fout = fout || function () {};
covers2.mouseover(fin).mouseout(fout);
return this;
};
chart.click = function (f) {
covers2.hide();
covers.show();
covers.click(f);
return this;
};
chart.each = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers.length; i--;) {
f.call(covers[i]);
}
return this;
};
chart.eachColumn = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers2.length; i--;) {
f.call(covers2[i]);
}
return this;
};
chart.clickColumn = function (f) {
covers.hide();
covers2.show();
covers2.click(f);
return this;
};
chart.push(bars, covers, covers2);
chart.bars = bars;
chart.covers = covers;
return chart;
};
Raphael.fn.g.hbarchart = function (x, y, width, height, values, opts) {
opts = opts || {};
var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square",
gutter = parseFloat(opts.gutter || "20%"),
chart = this.set(),
bars = this.set(),
covers = this.set(),
covers2 = this.set(),
total = Math.max.apply(Math, values),
stacktotal = [],
paper = this,
multi = 0,
colors = opts.colors || this.g.colors,
singleColor = opts.singleColor,
len = values.length;
if (this.raphael.is(values[0], "array")) {
total = [];
multi = len;
len = 0;
for (var i = values.length; i--;) {
bars.push(this.set());
total.push(Math.max.apply(Math, values[i]));
len = Math.max(len, values[i].length);
}
if (opts.stacked) {
for (var i = len; i--;) {
var tot = 0;
for (var j = values.length; j--;) {
tot +=+ values[j][i] || 0;
}
stacktotal.push(tot);
}
}
for (var i = values.length; i--;) {
if (values[i].length < len) {
for (var j = len; j--;) {
values[i].push(0);
}
}
}
total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
}
total = (opts.to) || total;
var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100),
bargutter = Math.floor(barheight * gutter / 100),
stack = [],
Y = y + bargutter,
X = (width - 1) / total;
!opts.stacked && (barheight /= multi || 1);
for (var i = 0; i < len; i++) {
stack = [];
for (var j = 0; j < (multi || 1); j++) {
var val = multi ? values[j][i] : values[i],
bar = this.g.finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type).attr({stroke: "none", fill: singleColor ? singleColor : (colors[multi ? j : i])});
if (multi) {
bars[j].push(bar);
} else {
bars.push(bar);
}
bar.x = x + Math.round(val * X);
bar.y = Y + barheight / 2;
bar.w = Math.round(val * X);
bar.h = barheight;
bar.value = +val;
if (!opts.stacked) {
Y += barheight;
} else {
stack.push(bar);
}
}
if (opts.stacked) {
var cvr = this.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(this.g.shim);
covers2.push(cvr);
cvr.bars = this.set();
var size = 0;
for (var s = stack.length; s--;) {
stack[s].toFront();
}
for (var s = 0, ss = stack.length; s < ss; s++) {
var bar = stack[s],
cover,
val = Math.round((size + bar.value) * X),
path = this.g.finger(x, bar.y, val, barheight - 1, false, type, 1);
cvr.bars.push(bar);
size && bar.attr({path: path});
bar.w = val;
bar.x = x + val;
covers.push(cover = this.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(this.g.shim));
cover.bar = bar;
size += bar.value;
}
Y += barheight;
}
Y += bargutter;
}
covers2.toFront();
Y = y + bargutter;
if (!opts.stacked) {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var cover = this.rect(x, Y, width, barheight).attr(this.g.shim);
covers.push(cover);
cover.bar = multi ? bars[j][i] : bars[i];
cover.value = cover.bar.value;
Y += barheight;
}
Y += bargutter;
}
}
chart.label = function (labels, isInside) {
labels = labels || [];
this.labels = paper.set();
var L, l = -Infinity;
if (opts.stacked) {
for (var i = 0; i < len; i++) {
var tot = 0;
for (var j = 0; j < (multi || 1); j++) {
tot += multi ? values[j][i] : values[i];
if (j == multi - 1) {
var label = paper.g.labelise(labels[i], tot, total);
L = paper.g.text(0, bars[j][i].y, label).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if(isInside)
L.translate(x + bb.width / 2 + 2, bb.height / 4);
else
L.translate(x - bb.width / 2 - 2, bb.height / 4);
}
}
}
} else {
for (var i = 0; i < len; i++) {
for (var j = 0; j < (multi || 1); j++) {
var label = paper.g.labelise(labels[i], multi ? values[j][i] : values[i], total);
L = paper.g.text(0, bars[j][i].y, label).insertBefore(covers[i * (multi || 1) + j]);
var bb = L.getBBox();
if(isInside)
L.translate(x + bb.width / 2 + 2, bb.height / 4);
else
L.translate(x - bb.width / 2 - 2, bb.height / 4);
}
}
}
return this;
};
chart.hover = function (fin, fout) {
covers2.hide();
covers.show();
fout = fout || function () {};
covers.mouseover(fin).mouseout(fout);
return this;
};
chart.hoverColumn = function (fin, fout) {
covers.hide();
covers2.show();
fout = fout || function () {};
covers2.mouseover(fin).mouseout(fout);
return this;
};
chart.each = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers.length; i--;) {
f.call(covers[i]);
}
return this;
};
chart.eachColumn = function (f) {
if (!Raphael.is(f, "function")) {
return this;
}
for (var i = covers2.length; i--;) {
f.call(covers2[i]);
}
return this;
};
chart.click = function (f) {
covers2.hide();
covers.show();
covers.click(f);
return this;
};
chart.clickColumn = function (f) {
covers.hide();
covers2.show();
covers2.click(f);
return this;
};
chart.push(bars, covers, covers2);
chart.bars = bars;
chart.covers = covers;
return chart;
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long