Support discipline labels

Support display order for the Scimap circles
Support custom tooltip
Add % information on click action
Add info text
Add numerical information for mapped, total publications
Set default map view to 554 Sub-Discipline
Enable labels by default
This commit is contained in:
kongchinhua 2011-06-03 21:45:47 +00:00
parent 589a5cf09a
commit 815ef7f26e
32 changed files with 429 additions and 51 deletions

View file

@ -48,7 +48,7 @@ var SliderControlPanel = ControlPanel.extend({
},
initSlider: function() {
var me = this;
var label = $("<div />").width(20).css("font-size", "60%").css("float", "right").text("0");
var label = $("<div />").width(150).css("font-size", "75%").css("text-align", "center").text("");
var slider = $("<div />").width(150).css("font-size","60%");
slider.slider({
slide: function(event, ui) {
@ -61,8 +61,8 @@ var SliderControlPanel = ControlPanel.extend({
var div = me.getDiv();
div.css("margin-right", "10px");
div.append(slider);
div.append(label);
div.append(slider);
},
getValue: function () {
return this.sliderDiv.slider( "option", "value" );
@ -84,11 +84,8 @@ var SliderControlPanel = ControlPanel.extend({
this._setLabel(value);
},
_setLabel: function(value) {
if (value < 1) {
this.labelDiv.text("0");
} else {
this.labelDiv.text(value);
}
var labelText = "Top " + value + " disciplines shown"
this.labelDiv.text(labelText);
},
setChangeEventHandler: function(handlerFunc) {
this.sliderDiv.slider({
@ -96,3 +93,43 @@ var SliderControlPanel = ControlPanel.extend({
});
}
});
/**
* options
* map - Container map to be added
* click - Handler function for click event
* text - Description of the check Box
*/
var CheckBoxPanel = ControlPanel.extend({
init: function(options) {
this._super(options);
this.initCheckBox();
},
initCheckBox: function() {
var me = this;
var description
var text = me.options.text;
var checkBox = $('<input type="checkbox"><span style="font-size: 75%; vertical-align: text-top">'
+ text
+ '</span></input>'
);
me.checkBox = checkBox;
var div = me.getDiv();
div.css("margin-right", "10px");
div.append(checkBox);
me.checkBox.attr('checked', me.options.checked);
/* Init contents if it is given */
var click = me.options.click;
if (click) {
me.click(click);
}
},
click: function(handlerFunc) {
this.checkBox.click(handlerFunc);
},
isChecked: function() {
return this.checkBox.attr('checked');
}
});

View file

@ -5,10 +5,10 @@ var ScinodePolygon = CirclePolygon.extend({
this.hide();
},
setValue: function(value) {
this.options.value = value;
this.polygon.value = value;
},
getValue: function() {
return this.options.value;
return this.polygon.value;
},
setSize: function(size) {
this.setRadius(size);
@ -20,13 +20,16 @@ var ScinodePolygon = CirclePolygon.extend({
unfocus: function() {
this.setOptions({strokeWeight: 1.0});
},
setContent: function(content) {
this.polygon.content = content;
},
registerEvents : function() {
var me = this;
var polygon = me.polygon;
this._super();
this.registerEvent(addClickListener(polygon, function() {
INFO_WINDOW.setPosition(this.center);
var content = '<div style="font-size: 80%; padding: 5px; text-align: left;"><b>' + this.label +'</b><br />' + this.value + ' publications </div>';
var content = this.content;
INFO_WINDOW.setContent(content);
INFO_WINDOW.open(this.map);
}));

File diff suppressed because one or more lines are too long

View file

@ -214,18 +214,23 @@ var DataTableWidget = Class.extend({
me.widget.fnFilter("");
});
var totalPublications = me.pubsWithNoJournals + me.pubsWithInvalidJournals + me.pubsMapped;
$("#mapped-publications").text(addCommasToNumber(me.pubsMapped));
$("#percent-mapped-info").show();
$("#percent-mapped").text((100 * me.pubsMapped / (me.pubsWithNoJournals + me.pubsWithInvalidJournals + me.pubsMapped)).toFixed(2));
$("#percent-mapped").text((100 * me.pubsMapped / totalPublications).toFixed(2));
$("#total-publications").text(addCommasToNumber(totalPublications));
},
changeFilter: function(filterType) {
var me = this;
if (filterType === SCIMAP_TYPE.SUBDISCIPLINE) {
$("#science-areas-th").html("Sub-Disciplines");
me.widget.fnSettings()._iDisplayLength = 10;
if (me.widget) {
me.widget.fnSettings()._iDisplayLength = 10;
}
me.currentSelectedFilter = SCIMAP_TYPE.SUBDISCIPLINE;
$("a#csv").attr("href", entityMapOfScienceSubDisciplineCSVURL);
@ -233,12 +238,16 @@ var DataTableWidget = Class.extend({
$("#science-areas-th").html("Disciplines");
me.currentSelectedFilter = SCIMAP_TYPE.DISCIPLINE;
me.widget.fnSettings()._iDisplayLength = 13;
if (me.widget) {
me.widget.fnSettings()._iDisplayLength = 13;
}
$("a#csv").attr("href", entityMapOfScienceDisciplineCSVURL);
}
ACTIVE_DISCIPLINE_SUBDISCIPLINE_FILTER = me.currentSelectedFilter;
me.widget.fnDraw();
if (me.widget) {
me.widget.fnDraw();
}
}
});

View file

@ -45,7 +45,7 @@ function setupLoadingScreen() {
function initMap() {
var gMap = google.maps;
var centerLatLng = new google.maps.LatLng(50, 0);
var centerLatLng = new google.maps.LatLng(55, -10);
var mapOptions = {
center: centerLatLng,

View file

@ -0,0 +1,56 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
/**
* Marker Object for that hold external information - data. Please refer to the
* Google.map.MakerOptions for options' details
*/
var Marker = Class.extend({
init : function(options) {
this.options = $.extend({}, this.options, options);
this.marker = createGoogleMarker(this.options);
this.hide();
this.registerEvents();
},
options : {
value : 0,
map : null,
icon : null,
position : null,
content : null
},
addToMap : function() {
this.marker.setMap(this.options.map);
this.registerEvents();
},
removeFromMap : function() {
this.marker.setMap(null);
this.unregisterEvents();
},
show : function() {
this.marker.setVisible(true);
},
hide : function() {
this.marker.setVisible(false);
},
setIcon : function(icon) {
this.marker.setIcon(icon);
},
setZIndex: function(zIndex){
this.marker.setZIndex(zIndex);
},
setTitle : function(title) {
this.marker.title = title;
},
registerEvents : function() {
var handlers = new Array();
var marker = this.marker;
handlers.push(addClickListener(marker, function() {
updateIFrame(this.url);
}));
this.handlers = handlers;
},
unregisterEvents : function() {
removeListeners(this.handlers);
this.handlers = null;
}
});

View file

@ -4,10 +4,8 @@
* markers by grouping the markers by keys.
*/
var MarkerManager = Class.extend({
init: function(colorStrategy, sizeCoder) {
init: function() {
this.keyToMarker = {};
this.colorStrategy = colorStrategy;
this.sizeCoder = sizeCoder;
},
addMarker: function(key, marker) {
this.keyToMarker[key] = marker;
@ -22,6 +20,11 @@ var MarkerManager = Class.extend({
getMarker: function(key) {
return this.keyToMarker[key];
},
getMarkerArray: function() {
var array = [];
$.each(this.keyToMarker, function(i, e){ array.push(e); });
return array;
},
hasKey: function(key) {
return (this.keyToMarker.hasOwnProperty(key));
},
@ -36,7 +39,6 @@ var MarkerManager = Class.extend({
});
},
addMarkersToMap: function() {
// console.log(this.keyToMarker);
$.each(this.keyToMarker, function(i, marker) {
marker.addToMap();
});
@ -49,18 +51,46 @@ var MarkerManager = Class.extend({
});
/**
* Customized MarkerManager for Science map purpose. It is be an abstract class
* Customized Discipline labels MarkerManager for Science map purpose. It is an abstract class
*/
ScimapMarkerManager = MarkerManager.extend({
var DisciplineLabelsMarkerManager = MarkerManager.extend({
init: function(map) {
this._super();
this.map = map;
this.initMarkers(map);
},
initMarkers: function(map) {
me = this;
$.each(DISCIPLINES, function(id, discipline) {
var opts = {
map: map,
position: createNoWrapLatLng(discipline.labelLatitude, discipline.labelLongitude),
icon: getDisciplineLabelImageURL(id),
clickable: false
};
me.addMarker(id, new Marker(opts));
});
},
showMarkers: function() {
this._super();
}
});
/**
* Customized MarkerManager for Science map purpose. It is an abstract class
*/
var ScimapMarkerManager = MarkerManager.extend({
init: function(map, colorStrategy, sizeCoder) {
this._super();
this.colorStrategy = colorStrategy;
this.sizeCoder = sizeCoder;
this.map = map;
this.maxValue = 1;
this.layer = {};
},
setSizeCoder: function(sizeCoder) {
this.sizeCoder = sizeCoder;
this.maxValue = sizeCoder.getMaxValue();
},
createMarker: function(key, density) {
var me = this;
@ -89,11 +119,17 @@ ScimapMarkerManager = MarkerManager.extend({
}
},
display: function(numberOfMarkers) {
$.each(this.keyToMarker, function(i, marker) {
if (i <= numberOfMarkers) {
marker.show();
var markerArray = this.sortedMarkers;
if (!markerArray || !markerArray.length) {
markerArray = this.getMarkerArray();
}
$.each(markerArray, function() {
if (numberOfMarkers > 0) {
this.show();
numberOfMarkers--;
} else {
marker.hide();
this.hide();
}
});
},
@ -118,6 +154,12 @@ ScimapMarkerManager = MarkerManager.extend({
$.each(this.keyToMarker, function(i, marker) {
marker.unfocus();
});
},
sort: function() {
this.sortedMarkers = this.getMarkerArray();
this.sortedMarkers.sort(function(a, b) {
return b.getValue() -a.getValue();
});
}
});
@ -129,7 +171,16 @@ var DisciplineMarkerManager = ScimapMarkerManager.extend({
createMarker: function(subdisciplineKey, density) {
var me = this;
var key = SUBDISCIPLINES[subdisciplineKey].discipline;
return this._super(key, density);
var marker = this._super(key, density);
var poly = marker.polygon;
marker.setContent(
'<div style="font-size: 80%; padding: 5px; text-align: left;"><b>'
+ poly.label +'</b><br />'
+ addCommasToNumber(poly.value.toFixed(2)) + ' of pubs.<br />'
+ (poly.value * 100 / this.maxValue).toFixed(2) + '% of activity</div>'
);
return marker;
}
});
@ -137,5 +188,20 @@ var SubdisciplineMarkerManager = ScimapMarkerManager.extend({
init: function(map, colorStrategy, sizeCoder) {
this._super(map, colorStrategy, sizeCoder);
this.layer = SUBDISCIPLINES;
},
createMarker: function(subdisciplineKey, density) {
var marker = this._super(subdisciplineKey, density);
var disciplineId = SUBDISCIPLINES[subdisciplineKey].discipline;
var disciplineLabel = DISCIPLINES[disciplineId].label;
var poly = marker.polygon;
/* Override the getContent for Subdiscipline */
marker.setContent(
'<div style="font-size: 80%; padding: 5px; text-align: left;"><b>'
+ poly.label + '</b> in ' + disciplineLabel +'<br />'
+ addCommasToNumber(poly.value.toFixed(2)) + ' of pubs.<br />'
+ (poly.value * 100 / this.maxValue).toFixed(2) + '% of activity</div>'
);
return marker;
}
});

View file

@ -0,0 +1,16 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
// Adapted from http://www.mredkj.com/javascript/numberFormat.html
// format number to a better human readable text
function addCommasToNumber(nStr) {
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}

View file

@ -1,6 +1,6 @@
var INFO_WINDOW = createInfoWindow("", 300);
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
var INFO_WINDOW = createInfoWindow("", "300");
var Polygon = Class.extend({
init : function(options) {
this.options = $.extend({}, this.options, options);
@ -71,6 +71,8 @@ function degreeToRadians(degree) {
return degree * RADIAN_PER_DEGREE;
}
var TOOLTIP = new Tooltip({ attachedToMouse: true });
var CirclePolygon = Polygon.extend({
init : function(options) {
this.options = $.extend({}, this.options, options);
@ -91,7 +93,6 @@ var CirclePolygon = Polygon.extend({
this.initCirclePoints();
}
console.log(this.polygon.getPaths().getLength());
this._super();
},
isPointsCreated: function() {
@ -105,7 +106,6 @@ var CirclePolygon = Polygon.extend({
var me = this;
var map = me.options.map;
var latLngArray = new google.maps.MVCArray(); // Circle's LatLngs
//console.log(map.getProjection());
if (map && map.getProjection()) {
var projection = map.getProjection();
var centerPoint = projection.fromLatLngToPoint(me.options.center);
@ -132,8 +132,19 @@ var CirclePolygon = Polygon.extend({
},
registerEvents: function() {
var me = this;
var polygon = me.polygon;
this.registerEvent(addMapProjectionChangedListener(me.options.map, function() {
me.initCirclePoints();
}));
this.registerEvent(addMouseOverListener(polygon, function() {
TOOLTIP.setHtml("<b>" + this.label + "</b>");
TOOLTIP.show();
}));
this.registerEvent(addMouseOutListener(polygon, function() {
TOOLTIP.hide();
}));
}
});

View file

@ -1,22 +1,38 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
var DEFAULT_SLIDER_VALUE = 20;
var ScimapWidget = Class.extend({
init: function(map, sliderControl) {
this.activeManager = null;
this.isUnloaded = true;
this.map = map;
this.sliderControl = sliderControl;
this.initView();
var me = this;
me.activeManager = null;
me.isUnloaded = true;
me.map = map;
me.sliderControl = sliderControl;
me.labelsMarkerManager = new DisciplineLabelsMarkerManager(map);
me.disciplineLabelsControl = new CheckBoxPanel({
map: map,
checked: true,
text: "Show discipline labels",
click: function() {
if($(this).attr('checked')) {
me.labelsMarkerManager.showMarkers();
} else {
me.labelsMarkerManager.hideMarkers();
}
}
});
me.initView();
},
initView: function(){
var me = this;
/* Display labels if checked */
if (me.disciplineLabelsControl.isChecked()) {
me.labelsMarkerManager.showMarkers();
}
me.initMarkerManagers();
me.sliderControl.setChangeEventHandler(function(event, ui) {
me.updateDisplayedMarkers(ui.value);
});
me.show(SCIMAP_TYPE.DISCIPLINE);
me.show(SCIMAP_TYPE.SUBDISCIPLINE);
},
initMarkerManagers: function() {
if (this.keyToMarkerManagers == null) {
@ -49,6 +65,7 @@ var ScimapWidget = Class.extend({
me.pubsWithInvalidJournals = data.pubsWithInvalidJournals;
me.pubsMapped = data.pubsMapped;
this.isUnloaded = false;
$.each(this.keyToMarkerManagers, function(key, manager) {
// Need to create the AreaSizeCoding function
manager.setSizeCoder(new CircleSizeCoder({
@ -61,9 +78,10 @@ var ScimapWidget = Class.extend({
var marker = manager.createMarker(subdiscipline, density);
}); // end each subdisciplineActivity
manager.sort();
}); // end each markerManagers
me.updateMap();
this.isUnloaded = false;
},
mouseIn: function(key, childKey) {
var manager = this.getMarkerManager(key);
@ -118,6 +136,7 @@ var ScimapWidget = Class.extend({
cleanUp: function() {
if (this.activeManager) {
this.activeManager.removeMarkersFromMap();
INFO_WINDOW.close();
}
},
updateDisplayedMarkers: function(numberOfMarkers) {
@ -130,7 +149,7 @@ var ScimapWidget = Class.extend({
var slider = this.sliderControl;
slider.setMin(Math.min(1, length));
slider.setMax(length);
slider.setValue(Math.min(DEFAULT_SLIDER_VALUE, length));
slider.setValue(length);
}
},
changeFilter: function(filterType) {

View file

@ -57,7 +57,7 @@ var CircleSizeCoder = Class.extend({
},
options: {
minRadius: 0.8,
maxRadius: 100.0,//100.0,
maxRadius: 100.0,
scaler: new Scaler({})
},
getSize: function(value) {
@ -71,6 +71,9 @@ var CircleSizeCoder = Class.extend({
}
return radius;
},
getMaxValue: function() {
return this.options.scaler.options.maxValue;
}
});

View file

@ -0,0 +1,101 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
/**
* This tooltip source is modified based on the example of Google map V3. The demo html
* is at http://philmap.000space.com/gmap-api/poly-hov.html
*
* Modification:
* 1. Init container at constructor class
* 2. Add feature functions: setHtml, setWidth, setPosition
*/
var Tooltip = function(o) {
var me = this;
var id = 'tt';
var top = 3;
var left = 3;
var maxw = 300;
var speed = 10;
var fadeInTimer = 10;
var fadeOutTimer = 0;
var endalpha = 85;
var alpha = 0;
var preferredWidth;
var tt, t, c, b, h, w;
var opts = {};
var ie = document.all ? true : false;
opts = $.extend({}, opts, o);
tt = document.createElement('div');
tt.setAttribute('id', id);
t = document.createElement('div');
t.setAttribute('id', id + 'top');
c = document.createElement('div');
c.setAttribute('id', id + 'cont');
b = document.createElement('div');
b.setAttribute('id', id + 'bot');
tt.appendChild(t);
tt.appendChild(c);
tt.appendChild(b);
document.body.appendChild(tt);
tt.style.opacity = 0;
tt.style.filter = 'alpha(opacity=0)';
return {
show: function(){
document.onmousemove = this.pos;
var w = preferredWidth;
tt.style.display = 'block';
tt.style.width = w ? w + 'px' : 'auto';
if(!w && ie){
t.style.display = 'none';
b.style.display = 'none';
tt.style.width = tt.offsetWidth;
t.style.display = 'block';
b.style.display = 'block';
}
if(tt.offsetWidth > maxw) { tt.style.width = maxw + 'px' }
h = parseInt(tt.offsetHeight) + top;
clearInterval(tt.timer);
var me = this;
tt.timer = setInterval( function() { me.fade(1) }, fadeInTimer);
},
pos:function(e){
var u = ie ? event.clientY + document.documentElement.scrollTop : e.pageY;
var l = ie ? event.clientX + document.documentElement.scrollLeft : e.pageX;
tt.style.top = (u - h) + 'px';
tt.style.left = (l + left) + 'px';
},
fade:function(d){
var a = alpha;
if((a != endalpha && d == 1) || (a != 0 && d == -1)){
var i = speed;
if(endalpha - a < speed && d == 1){
i = endalpha - a;
}else if(alpha < speed && d == -1){
i = a;
}
alpha = a + (i * d);
tt.style.opacity = alpha * .01;
tt.style.filter = 'alpha(opacity=' + alpha + ')';
}else{
clearInterval(tt.timer);
if(d == -1){tt.style.display = 'none'}
}
},
hide:function(){
clearInterval(tt.timer);
var me = this;
tt.timer = setInterval( function(){ me.fade(-1) }, fadeOutTimer);
},
setHtml: function(v) {
c.innerHTML = v;
},
setWidth: function(w) {
preferredWidth = w;
},
setPosition: function(x, y) {
tt.style.top = x + 'px';
tt.style.left = y + 'px';
}
};
};

View file

@ -35,6 +35,9 @@ var EntityVisModeController = Class.extend({
$(this).addClass('active-filter');
}
});
/* Init default filter */
$("#" + dom.subdisciplinesFilterID).trigger('click');
},
initWidgets: function(map, sliderControl) {
var widgets = {};