[VIVO-1249] Add capability maps for research areas (#35)
* Initial capability map implementation * Add autocomplete * Make headers update the info panel * Ajax retrieval of person details - reduce memory requirements and startup time * Remove old referer info * Handle missing labels. * Fix refresh button; add menu entry for new installations
This commit is contained in:
parent
1443ff6685
commit
ee7b974ac5
21 changed files with 3126 additions and 36 deletions
|
@ -0,0 +1,284 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.hp.hpl.jena.query.Dataset;
|
||||||
|
import com.hp.hpl.jena.query.QueryExecution;
|
||||||
|
import com.hp.hpl.jena.query.QueryExecutionFactory;
|
||||||
|
import com.hp.hpl.jena.query.QuerySolution;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.exceptions.MalformedQueryParametersException;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.ConceptLabelMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.ConceptPeopleMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.OrganizationPeopleMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.VisualizationRequestHandler;
|
||||||
|
import org.apache.axis.utils.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class CapabilityMapRequestHandler implements VisualizationRequestHandler {
|
||||||
|
@Override
|
||||||
|
public AuthorizationRequest getRequiredPrivileges() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseValues generateStandardVisualization(VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseValues generateVisualizationForShortURLRequests(Map<String, String> parameters, VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
return prepareMarkup(vitroRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object generateAjaxVisualization(VitroRequest vitroRequest, Log log, Dataset dataSource) throws MalformedQueryParametersException {
|
||||||
|
ConceptLabelMap conceptLabelMap = VisualizationCaches.conceptToLabel.get(vitroRequest.getRDFService());
|
||||||
|
ConceptPeopleMap conceptPeopleMap = VisualizationCaches.conceptToPeopleMap.get(vitroRequest.getRDFService());
|
||||||
|
OrganizationPeopleMap organizationPeopleMap = VisualizationCaches.organisationToPeopleMap.get(vitroRequest.getRDFService());
|
||||||
|
Map<String, String> organizationLabels = VisualizationCaches.organizationLabels.get(vitroRequest.getRDFService());
|
||||||
|
|
||||||
|
String data = vitroRequest.getParameter("data");
|
||||||
|
if (!StringUtils.isEmpty(data)) {
|
||||||
|
if ("concepts".equalsIgnoreCase(data)) {
|
||||||
|
Set<String> concepts = new HashSet<String>();
|
||||||
|
|
||||||
|
for (String conceptKey : conceptPeopleMap.conceptToPeople.keySet()) {
|
||||||
|
String label = conceptLabelMap.conceptToLabel.get(conceptKey);
|
||||||
|
if (!StringUtils.isEmpty(label)) {
|
||||||
|
concepts.add(conceptLabelMap.conceptToLabel.get(conceptKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
return gson.toJson(concepts);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
String personParam = vitroRequest.getParameter("person");
|
||||||
|
if (!StringUtils.isEmpty(personParam)) {
|
||||||
|
CapabilityMapResponse response = new CapabilityMapResponse();
|
||||||
|
CapabilityMapResult result = new CapabilityMapResult();
|
||||||
|
fillPersonDetails(vitroRequest.getRDFService(), personParam, result);
|
||||||
|
if (StringUtils.isEmpty(result.firstName) && StringUtils.isEmpty(result.lastName)) {
|
||||||
|
result.lastName = "Missing Name";
|
||||||
|
}
|
||||||
|
Set<String> concepts = conceptPeopleMap.personToConcepts.get(personParam);
|
||||||
|
if (concepts != null) {
|
||||||
|
result.subjectArea = concepts.toArray(new String[concepts.size()]);
|
||||||
|
}
|
||||||
|
Set<String> organizations = organizationPeopleMap.organizationToPeople.get(personParam);
|
||||||
|
if (organizations != null) {
|
||||||
|
for (String org : organizations) {
|
||||||
|
result.department = organizationLabels.get(org);
|
||||||
|
if (!StringUtils.isEmpty(result.department)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.results.add(result);
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
|
||||||
|
String callback = vitroRequest.getParameter("callback");
|
||||||
|
if (!StringUtils.isEmpty(callback)) {
|
||||||
|
return callback + "(" + gson.toJson(response) + ");";
|
||||||
|
}
|
||||||
|
return gson.toJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
String query = vitroRequest.getParameter("query");
|
||||||
|
if (!StringUtils.isEmpty(query)) {
|
||||||
|
CapabilityMapResponse response = new CapabilityMapResponse();
|
||||||
|
|
||||||
|
Set<String> matchedConcepts = conceptLabelMap.lowerLabelToConcepts.get(query.toLowerCase());
|
||||||
|
|
||||||
|
Set<String> people = new HashSet<String>();
|
||||||
|
if (matchedConcepts != null) {
|
||||||
|
for (String uri : matchedConcepts) {
|
||||||
|
Set<String> peopleSet = conceptPeopleMap.conceptToPeople.get(uri);
|
||||||
|
if (peopleSet != null) {
|
||||||
|
people.addAll(peopleSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> clusterConcepts = new HashSet<String>();
|
||||||
|
for (String person : people) {
|
||||||
|
if (conceptPeopleMap.personToConcepts.containsKey(person)) {
|
||||||
|
clusterConcepts.addAll(conceptPeopleMap.personToConcepts.get(person));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchedConcepts != null) {
|
||||||
|
clusterConcepts.removeAll(matchedConcepts);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> clusterLabels = new HashSet<String>();
|
||||||
|
for (String clusterConcept : clusterConcepts) {
|
||||||
|
String label = conceptLabelMap.conceptToLabel.get(clusterConcept);
|
||||||
|
if (!StringUtils.isEmpty(label)) {
|
||||||
|
clusterLabels.add(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] clusters = clusterLabels.toArray(new String[clusterLabels.size()]);
|
||||||
|
|
||||||
|
for (String person : people) {
|
||||||
|
CapabilityMapResult result = new CapabilityMapResult();
|
||||||
|
result.profileId = person;
|
||||||
|
result.query = query;
|
||||||
|
result.clusters = clusters;
|
||||||
|
response.results.add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gson gson = new Gson();
|
||||||
|
|
||||||
|
String callback = vitroRequest.getParameter("callback");
|
||||||
|
if (!StringUtils.isEmpty(callback)) {
|
||||||
|
return callback + "(" + gson.toJson(response) + ");";
|
||||||
|
}
|
||||||
|
return gson.toJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> generateDataVisualization(VitroRequest vitroRequest, Log log, Dataset dataset) throws MalformedQueryParametersException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues prepareMarkup(VitroRequest vreq) {
|
||||||
|
String standaloneTemplate = "capabilityMap.ftl";
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
body.put("title", "Capability Map");
|
||||||
|
body.put("vivoDefaultNamespace", vreq.getWebappDaoFactory().getDefaultNamespace());
|
||||||
|
return new TemplateResponseValues(standaloneTemplate, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillPersonDetails(final RDFService rdfService, final String personUri, final CapabilityMapResult result) {
|
||||||
|
try {
|
||||||
|
String construct = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"CONSTRUCT {\n" +
|
||||||
|
" <" + personUri + "> a foaf:Person .\n" +
|
||||||
|
" <" + personUri + "> foaf:lastName ?lastName .\n" +
|
||||||
|
" <" + personUri + "> foaf:firstName ?firstName .\n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:familyName ?familyName .\n" +
|
||||||
|
" ?contactName vcard:givenName ?givenName .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?contactTitleLabel .\n" +
|
||||||
|
" <" + personUri + "> public:thumbnailImage ?directDownloadUrl .\n" +
|
||||||
|
"} WHERE {\n" +
|
||||||
|
" { \n" +
|
||||||
|
" <" + personUri + "> foaf:lastName ?lastName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" <" + personUri + "> foaf:firstName ?firstName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:familyName ?familyName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:givenName ?givenName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?contactTitleLabel .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" <" + personUri + "> public:mainImage ?mainImage .\n" +
|
||||||
|
" ?mainImage public:thumbnailImage ?thumbnailImage .\n" +
|
||||||
|
" ?thumbnailImage public:downloadLocation ?downloadLocation .\n" +
|
||||||
|
" ?downloadLocation public:directDownloadUrl ?directDownloadUrl .\n" +
|
||||||
|
" } \n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
Model constructedModel = ModelFactory.createDefaultModel();
|
||||||
|
rdfService.sparqlConstructQuery(construct, constructedModel);
|
||||||
|
|
||||||
|
String nameQuery = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"SELECT ?familyName ?givenName ?lastName ?firstName ?title ?thumbnailUrl\n" +
|
||||||
|
"WHERE\n" +
|
||||||
|
"{\n" +
|
||||||
|
" <" + personUri + "> a foaf:Person .\n" + // ?person
|
||||||
|
" OPTIONAL {\n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" OPTIONAL { ?contactName vcard:familyName ?familyName . }\n" +
|
||||||
|
" OPTIONAL { ?contactName vcard:givenName ?givenName . }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" OPTIONAL {\n" +
|
||||||
|
" <" + personUri + "> obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?title .\n" +
|
||||||
|
" }\n" +
|
||||||
|
" OPTIONAL { <" + personUri + "> foaf:lastName ?lastName . }\n" +
|
||||||
|
" OPTIONAL { <" + personUri + "> foaf:firstName ?firstName . }\n" +
|
||||||
|
" OPTIONAL { <" + personUri + "> public:thumbnailImage ?thumbnailUrl . }\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
QueryExecution qe = QueryExecutionFactory.create(nameQuery, constructedModel);
|
||||||
|
|
||||||
|
try {
|
||||||
|
new ResultSetConsumer() {
|
||||||
|
@Override
|
||||||
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
|
result.profileId = personUri;
|
||||||
|
result.firstName = null;
|
||||||
|
result.lastName = null;
|
||||||
|
result.thumbNail = null;
|
||||||
|
result.preferredTitle = null;
|
||||||
|
|
||||||
|
Literal familyNameNode = qs.getLiteral("familyName");
|
||||||
|
if (familyNameNode != null) {
|
||||||
|
result.lastName = familyNameNode.getString();
|
||||||
|
} else {
|
||||||
|
Literal lastNameNode = qs.getLiteral("lastName");
|
||||||
|
result.lastName = lastNameNode == null ? null : lastNameNode.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal givenNameNode = qs.getLiteral("givenName");
|
||||||
|
if (givenNameNode != null) {
|
||||||
|
result.firstName = givenNameNode.getString();
|
||||||
|
} else {
|
||||||
|
Literal firstNameNode = qs.getLiteral("firstName");
|
||||||
|
result.firstName = firstNameNode == null ? null : firstNameNode.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal thumbnailUrlNode = qs.getLiteral("thumbnailUrl");
|
||||||
|
result.thumbNail = thumbnailUrlNode == null ? null : thumbnailUrlNode.getString();
|
||||||
|
|
||||||
|
Literal titleNode = qs.getLiteral("title");
|
||||||
|
result.preferredTitle = titleNode == null ? null : titleNode.getString();
|
||||||
|
}
|
||||||
|
}.processResultSet(qe.execSelect());
|
||||||
|
} finally {
|
||||||
|
qe.close();
|
||||||
|
}
|
||||||
|
} catch (RDFServiceException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CapabilityMapResponse {
|
||||||
|
List<CapabilityMapResult> results = new ArrayList<CapabilityMapResult>();
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
class CapabilityMapResult {
|
||||||
|
String[] clusters;
|
||||||
|
|
||||||
|
@SerializedName("md_1")
|
||||||
|
String profileId;
|
||||||
|
|
||||||
|
@SerializedName("md_2")
|
||||||
|
String description;
|
||||||
|
|
||||||
|
@SerializedName("md_3")
|
||||||
|
String thumbNail;
|
||||||
|
|
||||||
|
@SerializedName("md_4")
|
||||||
|
String department;
|
||||||
|
|
||||||
|
@SerializedName("md_5")
|
||||||
|
String overview;
|
||||||
|
|
||||||
|
@SerializedName("md_6")
|
||||||
|
String geographicFocus;
|
||||||
|
|
||||||
|
@SerializedName("md_7")
|
||||||
|
String geographicLocation;
|
||||||
|
|
||||||
|
@SerializedName("md_8")
|
||||||
|
String[] grants;
|
||||||
|
|
||||||
|
@SerializedName("md_A")
|
||||||
|
String firstName;
|
||||||
|
|
||||||
|
@SerializedName("md_B")
|
||||||
|
String lastName;
|
||||||
|
|
||||||
|
@SerializedName("md_F")
|
||||||
|
String fax;
|
||||||
|
|
||||||
|
@SerializedName("md_G")
|
||||||
|
String email;
|
||||||
|
|
||||||
|
@SerializedName("md_H")
|
||||||
|
String availableForSupervision;
|
||||||
|
|
||||||
|
@SerializedName("md_I")
|
||||||
|
String homepage;
|
||||||
|
|
||||||
|
@SerializedName("md_L")
|
||||||
|
String phoneNumber;
|
||||||
|
|
||||||
|
@SerializedName("md_U")
|
||||||
|
String[] publications;
|
||||||
|
|
||||||
|
@SerializedName("md_X")
|
||||||
|
String[] researchOverview;
|
||||||
|
|
||||||
|
@SerializedName("md_Y")
|
||||||
|
String[] subjectArea;
|
||||||
|
|
||||||
|
@SerializedName("md_Z")
|
||||||
|
String preferredTitle;
|
||||||
|
|
||||||
|
String query;
|
||||||
|
}
|
|
@ -39,11 +39,12 @@ public class QueryConstants {
|
||||||
put("wos", "http://vivo.mannlib.cornell.edu/ns/ThomsonWOS/0.1#");
|
put("wos", "http://vivo.mannlib.cornell.edu/ns/ThomsonWOS/0.1#");
|
||||||
put("core", "http://vivoweb.org/ontology/core#");
|
put("core", "http://vivoweb.org/ontology/core#");
|
||||||
put("vivo", "http://vivo.library.cornell.edu/ns/0.1#");
|
put("vivo", "http://vivo.library.cornell.edu/ns/0.1#");
|
||||||
put("j.1", "http://aims.fao.org/aos/geopolitical.owl#");
|
put("geo", "http://aims.fao.org/aos/geopolitical.owl#");
|
||||||
put("j.2", "http://vitro.mannlib.cornell.edu/ns/vitro/public#");
|
put("public", "http://vitro.mannlib.cornell.edu/ns/vitro/public#");
|
||||||
put("afn", "http://jena.hpl.hp.com/ARQ/function#");
|
put("afn", "http://jena.hpl.hp.com/ARQ/function#");
|
||||||
put("vivosocnet", "http://vivo.cns.iu.edu/ns/#");
|
put("vivosocnet", "http://vivo.cns.iu.edu/ns/#");
|
||||||
|
put("obo", "http://purl.obolibrary.org/obo/");
|
||||||
|
put("vcard", "http://www.w3.org/2006/vcard/ns#");
|
||||||
} };
|
} };
|
||||||
|
|
||||||
public static String getSparqlPrefixQuery() {
|
public static String getSparqlPrefixQuery() {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFServiceException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
|
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.OrganizationPeopleMap;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
||||||
import mapping.ScienceMapping;
|
import mapping.ScienceMapping;
|
||||||
|
@ -252,7 +253,7 @@ public class MapOfScienceVisualizationRequestHandler implements VisualizationReq
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
||||||
Map<String, Set<String>> organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
OrganizationPeopleMap organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
||||||
Map<String, Set<String>> personToPublicationMap = VisualizationCaches.personToPublication.get(rdfService).personToPublication;
|
Map<String, Set<String>> personToPublicationMap = VisualizationCaches.personToPublication.get(rdfService).personToPublication;
|
||||||
Map<String, String> publicationToJournalMap = VisualizationCaches.publicationToJournal.get(rdfService);
|
Map<String, String> publicationToJournalMap = VisualizationCaches.publicationToJournal.get(rdfService);
|
||||||
|
|
||||||
|
@ -267,7 +268,7 @@ public class MapOfScienceVisualizationRequestHandler implements VisualizationReq
|
||||||
orgPublicationsPeople,
|
orgPublicationsPeople,
|
||||||
subOrgPublicationsMap,
|
subOrgPublicationsMap,
|
||||||
subOrgMap,
|
subOrgMap,
|
||||||
organisationToPeopleMap,
|
organisationToPeopleMap.organizationToPeople,
|
||||||
personToPublicationMap
|
personToPublicationMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ConceptLabelMap {
|
||||||
|
public final Map<String, String> conceptToLabel = new HashMap<String, String>();
|
||||||
|
public final Map<String, Set<String>> lowerLabelToConcepts = new HashMap<String, Set<String>>();
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ConceptPeopleMap {
|
||||||
|
public final Map<String, Set<String>> conceptToPeople = new HashMap<String, Set<String>>();
|
||||||
|
public final Map<String, Set<String>> personToConcepts = new HashMap<String, Set<String>>();
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class OrganizationPeopleMap {
|
||||||
|
public final Map<String, Set<String>> organizationToPeople = new HashMap<String, Set<String>>();
|
||||||
|
public final Map<String, Set<String>> personToOrganizations = new HashMap<String, Set<String>>();
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.visualization.model;
|
||||||
|
|
||||||
|
public class Person {
|
||||||
|
public String uri;
|
||||||
|
public String preferredTitle;
|
||||||
|
public String firstName;
|
||||||
|
public String lastName;
|
||||||
|
public String thumbnailUrl;
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.OrganizationPeopleMap;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.CounterUtils;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.CounterUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
||||||
|
@ -152,7 +153,7 @@ public class TemporalGrantVisualizationRequestHandler implements
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
||||||
Map<String, Set<String>> organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
OrganizationPeopleMap organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
||||||
Map<String, String> orgMostSpecificLabelMap = VisualizationCaches.organizationToMostSpecificLabel.get(rdfService);
|
Map<String, String> orgMostSpecificLabelMap = VisualizationCaches.organizationToMostSpecificLabel.get(rdfService);
|
||||||
Map<String, String> personMostSpecificLabelMap = VisualizationCaches.personToMostSpecificLabel.get(rdfService);
|
Map<String, String> personMostSpecificLabelMap = VisualizationCaches.personToMostSpecificLabel.get(rdfService);
|
||||||
Map<String, Set<String>> personToGrantMap = VisualizationCaches.personToGrant.get(rdfService);
|
Map<String, Set<String>> personToGrantMap = VisualizationCaches.personToGrant.get(rdfService);
|
||||||
|
@ -169,7 +170,7 @@ public class TemporalGrantVisualizationRequestHandler implements
|
||||||
orgGrantsPeople,
|
orgGrantsPeople,
|
||||||
subOrgGrantsMap,
|
subOrgGrantsMap,
|
||||||
subOrgMap,
|
subOrgMap,
|
||||||
organisationToPeopleMap,
|
organisationToPeopleMap.organizationToPeople,
|
||||||
personToGrantMap
|
personToGrantMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.OrganizationPeopleMap;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.CounterUtils;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.CounterUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.OrgUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
import edu.cornell.mannlib.vitro.webapp.visualization.utilities.VisualizationCaches;
|
||||||
|
@ -91,7 +92,7 @@ public class TemporalPublicationVisualizationRequestHandler implements
|
||||||
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
Map<String, Set<String>> subOrgMap = VisualizationCaches.organizationSubOrgs.get(rdfService);
|
||||||
Map<String, String> orgMostSpecificLabelMap = VisualizationCaches.organizationToMostSpecificLabel.get(rdfService);
|
Map<String, String> orgMostSpecificLabelMap = VisualizationCaches.organizationToMostSpecificLabel.get(rdfService);
|
||||||
Map<String, String> personMostSpecificLabelMap = VisualizationCaches.personToMostSpecificLabel.get(rdfService);
|
Map<String, String> personMostSpecificLabelMap = VisualizationCaches.personToMostSpecificLabel.get(rdfService);
|
||||||
Map<String, Set<String>> organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
OrganizationPeopleMap organisationToPeopleMap = VisualizationCaches.organisationToPeopleMap.get(rdfService);
|
||||||
Map<String, Set<String>> personToPublicationMap = VisualizationCaches.personToPublication.get(rdfService).personToPublication;
|
Map<String, Set<String>> personToPublicationMap = VisualizationCaches.personToPublication.get(rdfService).personToPublication;
|
||||||
Map<String, String> publicationToYearMap = VisualizationCaches.publicationToYear.get(rdfService);
|
Map<String, String> publicationToYearMap = VisualizationCaches.publicationToYear.get(rdfService);
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ public class TemporalPublicationVisualizationRequestHandler implements
|
||||||
orgPublicationsPeople,
|
orgPublicationsPeople,
|
||||||
subOrgPublicationsMap,
|
subOrgPublicationsMap,
|
||||||
subOrgMap,
|
subOrgMap,
|
||||||
organisationToPeopleMap,
|
organisationToPeopleMap.organizationToPeople,
|
||||||
personToPublicationMap
|
personToPublicationMap
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,21 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.visualization.utilities;
|
package edu.cornell.mannlib.vitro.webapp.visualization.utilities;
|
||||||
|
|
||||||
|
import com.hp.hpl.jena.query.QueryExecution;
|
||||||
|
import com.hp.hpl.jena.query.QueryExecutionFactory;
|
||||||
import com.hp.hpl.jena.query.QuerySolution;
|
import com.hp.hpl.jena.query.QuerySolution;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Model;
|
||||||
|
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||||
import com.hp.hpl.jena.rdf.model.Resource;
|
import com.hp.hpl.jena.rdf.model.Resource;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.RDFService;
|
||||||
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
import edu.cornell.mannlib.vitro.webapp.rdfservice.ResultSetConsumer;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
|
import edu.cornell.mannlib.vitro.webapp.visualization.constants.QueryConstants;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.ConceptLabelMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.ConceptPeopleMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.OrganizationPeopleMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.visualization.model.Person;
|
||||||
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions;
|
import edu.cornell.mannlib.vitro.webapp.visualization.visutils.UtilityFunctions;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
|
@ -17,6 +27,11 @@ import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holder for the caches we are using in the visualizations
|
* Holder for the caches we are using in the visualizations
|
||||||
|
*
|
||||||
|
* String.intern() was a problem pre-Java 7, but has greater utility now.
|
||||||
|
* Please see the following guide for information on the implementation of String.intern()
|
||||||
|
*
|
||||||
|
* http://java-performance.info/string-intern-in-java-6-7-8/
|
||||||
*/
|
*/
|
||||||
final public class VisualizationCaches {
|
final public class VisualizationCaches {
|
||||||
// Affinity object to ensure that only one background thread can be running at once when updating the caches
|
// Affinity object to ensure that only one background thread can be running at once when updating the caches
|
||||||
|
@ -32,6 +47,8 @@ final public class VisualizationCaches {
|
||||||
* @param rdfService if not null, use this service in foreground, otherwise may use the background thread
|
* @param rdfService if not null, use this service in foreground, otherwise may use the background thread
|
||||||
*/
|
*/
|
||||||
public static void rebuildAll(RDFService rdfService) {
|
public static void rebuildAll(RDFService rdfService) {
|
||||||
|
conceptToLabel.build(rdfService);
|
||||||
|
conceptToPeopleMap.build(rdfService);
|
||||||
organizationLabels.build(rdfService);
|
organizationLabels.build(rdfService);
|
||||||
organizationSubOrgs.build(rdfService);
|
organizationSubOrgs.build(rdfService);
|
||||||
organizationToMostSpecificLabel.build(rdfService);
|
organizationToMostSpecificLabel.build(rdfService);
|
||||||
|
@ -43,9 +60,12 @@ final public class VisualizationCaches {
|
||||||
publicationToYear.build(rdfService);
|
publicationToYear.build(rdfService);
|
||||||
personToGrant.build(rdfService);
|
personToGrant.build(rdfService);
|
||||||
grantToYear.build(rdfService);
|
grantToYear.build(rdfService);
|
||||||
|
// people.build(rdfService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void buildMissing() {
|
public static void buildMissing() {
|
||||||
|
if (!conceptToLabel.isCached()) { conceptToLabel.build(null); }
|
||||||
|
if (!conceptToPeopleMap.isCached()) { conceptToPeopleMap.build(null); }
|
||||||
if (!organizationLabels.isCached()) { organizationLabels.build(null); }
|
if (!organizationLabels.isCached()) { organizationLabels.build(null); }
|
||||||
if (!organizationSubOrgs.isCached()) { organizationSubOrgs.build(null); }
|
if (!organizationSubOrgs.isCached()) { organizationSubOrgs.build(null); }
|
||||||
if (!organizationToMostSpecificLabel.isCached()) { organizationToMostSpecificLabel.build(null); }
|
if (!organizationToMostSpecificLabel.isCached()) { organizationToMostSpecificLabel.build(null); }
|
||||||
|
@ -57,6 +77,7 @@ final public class VisualizationCaches {
|
||||||
if (!publicationToYear.isCached()) { publicationToYear.build(null); }
|
if (!publicationToYear.isCached()) { publicationToYear.build(null); }
|
||||||
if (!personToGrant.isCached()) { personToGrant.build(null); }
|
if (!personToGrant.isCached()) { personToGrant.build(null); }
|
||||||
if (!grantToYear.isCached()) { grantToYear.build(null); }
|
if (!grantToYear.isCached()) { grantToYear.build(null); }
|
||||||
|
// if (!people.isCached()) { people.build(null); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,6 +92,139 @@ final public class VisualizationCaches {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of people
|
||||||
|
*/
|
||||||
|
public static final CachingRDFServiceExecutor<Map<String, Person>> people =
|
||||||
|
new CachingRDFServiceExecutor<>(
|
||||||
|
new CachingRDFServiceExecutor.RDFServiceCallable<Map<String, Person>>(visualizationAffinity) {
|
||||||
|
@Override
|
||||||
|
protected Map<String, Person> callWithService(RDFService rdfService) throws Exception {
|
||||||
|
final Map<String, Person> map = new HashMap<String, Person>();
|
||||||
|
|
||||||
|
String construct = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"CONSTRUCT {\n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person foaf:lastName ?lastName .\n" +
|
||||||
|
" ?person foaf:firstName ?firstName .\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:familyName ?familyName .\n" +
|
||||||
|
" ?contactName vcard:givenName ?givenName .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?contactTitleLabel .\n" +
|
||||||
|
" ?person public:thumbnailImage ?directDownloadUrl .\n" +
|
||||||
|
"} WHERE {\n" +
|
||||||
|
" { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person foaf:lastName ?lastName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person foaf:firstName ?firstName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:familyName ?familyName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" ?contactName vcard:givenName ?givenName .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?contactTitleLabel .\n" +
|
||||||
|
" } UNION { \n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person public:mainImage ?mainImage .\n" +
|
||||||
|
" ?mainImage public:thumbnailImage ?thumbnailImage .\n" +
|
||||||
|
" ?thumbnailImage public:downloadLocation ?downloadLocation .\n" +
|
||||||
|
" ?downloadLocation public:directDownloadUrl ?directDownloadUrl .\n" +
|
||||||
|
" } \n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
Model constructedModel = ModelFactory.createDefaultModel();
|
||||||
|
rdfService.sparqlConstructQuery(construct, constructedModel);
|
||||||
|
|
||||||
|
String nameQuery = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"SELECT ?person ?familyName ?givenName ?lastName ?firstName ?title ?thumbnailUrl\n" +
|
||||||
|
"WHERE\n" +
|
||||||
|
"{\n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" OPTIONAL {\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasName ?contactName .\n" +
|
||||||
|
" OPTIONAL { ?contactName vcard:familyName ?familyName . }\n" +
|
||||||
|
" OPTIONAL { ?contactName vcard:givenName ?givenName . }\n" +
|
||||||
|
" }\n" +
|
||||||
|
" OPTIONAL {\n" +
|
||||||
|
" ?person obo:ARG_2000028 ?contactInfo .\n" +
|
||||||
|
" ?contactInfo vcard:hasTitle ?contactTitle .\n" +
|
||||||
|
" ?contactTitle vcard:title ?title .\n" +
|
||||||
|
" }\n" +
|
||||||
|
" OPTIONAL { ?person foaf:lastName ?lastName . }\n" +
|
||||||
|
" OPTIONAL { ?person foaf:firstName ?firstName . }\n" +
|
||||||
|
" OPTIONAL { ?person public:thumbnailImage ?thumbnailUrl . }\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
QueryExecution qe = QueryExecutionFactory.create(nameQuery, constructedModel);
|
||||||
|
try {
|
||||||
|
new ResultSetConsumer() {
|
||||||
|
@Override
|
||||||
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
|
String personUri = qs.getResource("person").getURI();
|
||||||
|
String familyName = null;
|
||||||
|
String givenName = null;
|
||||||
|
String thumbnailUrl = null;
|
||||||
|
String title = null;
|
||||||
|
|
||||||
|
Literal familyNameNode = qs.getLiteral("familyName");
|
||||||
|
if (familyNameNode != null) {
|
||||||
|
familyName = familyNameNode.getString();
|
||||||
|
} else {
|
||||||
|
Literal lastNameNode = qs.getLiteral("lastName");
|
||||||
|
familyName = lastNameNode == null ? null : lastNameNode.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal givenNameNode = qs.getLiteral("givenName");
|
||||||
|
if (givenNameNode != null) {
|
||||||
|
givenName = givenNameNode.getString();
|
||||||
|
} else {
|
||||||
|
Literal firstNameNode = qs.getLiteral("firstName");
|
||||||
|
givenName = firstNameNode == null ? null : firstNameNode.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Literal thumbnailUrlNode = qs.getLiteral("thumbnailUrl");
|
||||||
|
thumbnailUrl = thumbnailUrlNode == null ? null : thumbnailUrlNode.getString();
|
||||||
|
|
||||||
|
Literal titleNode = qs.getLiteral("title");
|
||||||
|
title = titleNode == null ? null : titleNode.getString();
|
||||||
|
|
||||||
|
Person person = map.get(personUri);
|
||||||
|
if (person == null) {
|
||||||
|
person = new Person();
|
||||||
|
map.put(personUri.intern(), person);
|
||||||
|
}
|
||||||
|
|
||||||
|
person.firstName = givenName == null ? null : givenName.intern();
|
||||||
|
person.lastName = familyName == null ? null : familyName.intern();
|
||||||
|
person.preferredTitle = title == null ? null : title.intern();
|
||||||
|
person.thumbnailUrl = thumbnailUrl;
|
||||||
|
}
|
||||||
|
}.processResultSet(qe.execSelect());
|
||||||
|
} finally {
|
||||||
|
qe.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of organization labels (uri -> label)
|
* Cache of organization labels (uri -> label)
|
||||||
*/
|
*/
|
||||||
|
@ -95,7 +249,7 @@ final public class VisualizationCaches {
|
||||||
String org = qs.getResource("org").getURI();
|
String org = qs.getResource("org").getURI();
|
||||||
String orgLabel = qs.getLiteral("orgLabel").getString();
|
String orgLabel = qs.getLiteral("orgLabel").getString();
|
||||||
|
|
||||||
map.put(org, orgLabel);
|
map.put(org.intern(), orgLabel.intern());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -131,10 +285,10 @@ final public class VisualizationCaches {
|
||||||
Set<String> subOrgs = map.get(org);
|
Set<String> subOrgs = map.get(org);
|
||||||
if (subOrgs == null) {
|
if (subOrgs == null) {
|
||||||
subOrgs = new HashSet<String>();
|
subOrgs = new HashSet<String>();
|
||||||
subOrgs.add(subOrg);
|
subOrgs.add(subOrg.intern());
|
||||||
map.put(org, subOrgs);
|
map.put(org.intern(), subOrgs);
|
||||||
} else {
|
} else {
|
||||||
subOrgs.add(subOrg);
|
subOrgs.add(subOrg.intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -168,7 +322,7 @@ final public class VisualizationCaches {
|
||||||
protected void processQuerySolution(QuerySolution qs) {
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
String org = qs.getResource("org").getURI();
|
String org = qs.getResource("org").getURI();
|
||||||
String typeLabel = qs.getLiteral("typeLabel").getString();
|
String typeLabel = qs.getLiteral("typeLabel").getString();
|
||||||
map.put(org, String.valueOf(typeLabel));
|
map.put(org.intern(), typeLabel.intern());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -180,11 +334,11 @@ final public class VisualizationCaches {
|
||||||
/**
|
/**
|
||||||
* Map of people within an organisation (org uri -> list of person uri)
|
* Map of people within an organisation (org uri -> list of person uri)
|
||||||
*/
|
*/
|
||||||
public static final CachingRDFServiceExecutor<Map<String, Set<String>>> organisationToPeopleMap =
|
public static final CachingRDFServiceExecutor<OrganizationPeopleMap> organisationToPeopleMap =
|
||||||
new CachingRDFServiceExecutor<Map<String, Set<String>>>(
|
new CachingRDFServiceExecutor<OrganizationPeopleMap>(
|
||||||
new CachingRDFServiceExecutor.RDFServiceCallable<Map<String, Set<String>>>(visualizationAffinity) {
|
new CachingRDFServiceExecutor.RDFServiceCallable<OrganizationPeopleMap>(visualizationAffinity) {
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, Set<String>> callWithService(RDFService rdfService) throws Exception {
|
protected OrganizationPeopleMap callWithService(RDFService rdfService) throws Exception {
|
||||||
String query = QueryConstants.getSparqlPrefixQuery() +
|
String query = QueryConstants.getSparqlPrefixQuery() +
|
||||||
"SELECT ?organisation ?person\n" +
|
"SELECT ?organisation ?person\n" +
|
||||||
"WHERE\n" +
|
"WHERE\n" +
|
||||||
|
@ -196,22 +350,31 @@ final public class VisualizationCaches {
|
||||||
" ?person a foaf:Person .\n" +
|
" ?person a foaf:Person .\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
final Map<String, Set<String>> orgToPeopleMap = new HashMap<String, Set<String>>();
|
final OrganizationPeopleMap orgToPeopleMap = new OrganizationPeopleMap();
|
||||||
|
|
||||||
rdfService.sparqlSelectQuery(query, new ResultSetConsumer() {
|
rdfService.sparqlSelectQuery(query, new ResultSetConsumer() {
|
||||||
@Override
|
@Override
|
||||||
protected void processQuerySolution(QuerySolution qs) {
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
String org = qs.getResource("organisation").getURI();
|
String org = qs.getResource("organisation").getURI().intern();
|
||||||
String person = qs.getResource("person").getURI();
|
String person = qs.getResource("person").getURI().intern();
|
||||||
|
|
||||||
Set<String> people = orgToPeopleMap.get(org);
|
Set<String> people = orgToPeopleMap.organizationToPeople.get(org);
|
||||||
if (people == null) {
|
if (people == null) {
|
||||||
people = new HashSet<String>();
|
people = new HashSet<String>();
|
||||||
people.add(person);
|
people.add(person);
|
||||||
orgToPeopleMap.put(org, people);
|
orgToPeopleMap.organizationToPeople.put(org, people);
|
||||||
} else {
|
} else {
|
||||||
people.add(person);
|
people.add(person);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<String> organizations = orgToPeopleMap.personToOrganizations.get(org);
|
||||||
|
if (organizations == null) {
|
||||||
|
organizations = new HashSet<String>();
|
||||||
|
organizations.add(org);
|
||||||
|
orgToPeopleMap.organizationToPeople.put(person, organizations);
|
||||||
|
} else {
|
||||||
|
organizations.add(org);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -220,6 +383,103 @@ final public class VisualizationCaches {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concept to label
|
||||||
|
*/
|
||||||
|
public static final CachingRDFServiceExecutor<ConceptLabelMap> conceptToLabel =
|
||||||
|
new CachingRDFServiceExecutor<>(
|
||||||
|
new CachingRDFServiceExecutor.RDFServiceCallable<ConceptLabelMap>() {
|
||||||
|
@Override
|
||||||
|
protected ConceptLabelMap callWithService(RDFService rdfService) throws Exception {
|
||||||
|
String query = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"SELECT ?concept ?label\n" +
|
||||||
|
"WHERE\n" +
|
||||||
|
"{\n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person core:hasResearchArea ?concept .\n" +
|
||||||
|
" ?concept a skos:Concept .\n" +
|
||||||
|
" ?concept rdfs:label ?label .\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
// final Map<String, String> map = new HashMap<>();
|
||||||
|
final ConceptLabelMap map = new ConceptLabelMap();
|
||||||
|
|
||||||
|
rdfService.sparqlSelectQuery(query, new ResultSetConsumer() {
|
||||||
|
@Override
|
||||||
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
|
String conceptURI = qs.getResource("concept").getURI().intern();
|
||||||
|
String label = qs.getLiteral("label").getString().intern();
|
||||||
|
String labelLower = label.toLowerCase().intern();
|
||||||
|
|
||||||
|
map.conceptToLabel.put(conceptURI, label);
|
||||||
|
|
||||||
|
Set<String> conceptSet = map.lowerLabelToConcepts.get(labelLower);
|
||||||
|
if (conceptSet == null) {
|
||||||
|
conceptSet = new HashSet<String>();
|
||||||
|
conceptSet.add(conceptURI);
|
||||||
|
map.lowerLabelToConcepts.put(labelLower, conceptSet);
|
||||||
|
} else {
|
||||||
|
conceptSet.add(conceptURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of people associated with a concept
|
||||||
|
*/
|
||||||
|
public static final CachingRDFServiceExecutor<ConceptPeopleMap> conceptToPeopleMap =
|
||||||
|
new CachingRDFServiceExecutor<ConceptPeopleMap>(
|
||||||
|
new CachingRDFServiceExecutor.RDFServiceCallable<ConceptPeopleMap>(visualizationAffinity) {
|
||||||
|
@Override
|
||||||
|
protected ConceptPeopleMap callWithService(RDFService rdfService) throws Exception {
|
||||||
|
String query = QueryConstants.getSparqlPrefixQuery() +
|
||||||
|
"SELECT ?person ?concept\n" +
|
||||||
|
"WHERE\n" +
|
||||||
|
"{\n" +
|
||||||
|
" ?person a foaf:Person .\n" +
|
||||||
|
" ?person core:hasResearchArea ?concept .\n" +
|
||||||
|
" ?concept a skos:Concept .\n" +
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
final ConceptPeopleMap conceptPeopleMap = new ConceptPeopleMap();
|
||||||
|
|
||||||
|
rdfService.sparqlSelectQuery(query, new ResultSetConsumer() {
|
||||||
|
@Override
|
||||||
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
|
String concept = qs.getResource("concept").getURI().intern();
|
||||||
|
String person = qs.getResource("person").getURI().intern();
|
||||||
|
|
||||||
|
Set<String> people = conceptPeopleMap.conceptToPeople.get(concept);
|
||||||
|
if (people == null) {
|
||||||
|
people = new HashSet<String>();
|
||||||
|
people.add(person);
|
||||||
|
conceptPeopleMap.conceptToPeople.put(concept, people);
|
||||||
|
} else {
|
||||||
|
people.add(person);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> concepts = conceptPeopleMap.personToConcepts.get(person);
|
||||||
|
if (concepts == null) {
|
||||||
|
concepts = new HashSet<String>();
|
||||||
|
concepts.add(concept);
|
||||||
|
conceptPeopleMap.personToConcepts.put(person, concepts);
|
||||||
|
} else {
|
||||||
|
concepts.add(concept);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return conceptPeopleMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display labels for people (uri -> label)
|
* Display labels for people (uri -> label)
|
||||||
*/
|
*/
|
||||||
|
@ -244,7 +504,7 @@ final public class VisualizationCaches {
|
||||||
String person = qs.getResource("person").getURI();
|
String person = qs.getResource("person").getURI();
|
||||||
String personLabel = qs.getLiteral("personLabel").getString();
|
String personLabel = qs.getLiteral("personLabel").getString();
|
||||||
|
|
||||||
map.put(person, personLabel);
|
map.put(person.intern(), personLabel.intern());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -277,7 +537,7 @@ final public class VisualizationCaches {
|
||||||
protected void processQuerySolution(QuerySolution qs) {
|
protected void processQuerySolution(QuerySolution qs) {
|
||||||
String person = qs.getResource("person").getURI();
|
String person = qs.getResource("person").getURI();
|
||||||
String typeLabel = qs.getLiteral("typeLabel").getString();
|
String typeLabel = qs.getLiteral("typeLabel").getString();
|
||||||
map.put(person, String.valueOf(typeLabel));
|
map.put(person.intern(), String.valueOf(typeLabel).intern());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -317,7 +577,7 @@ final public class VisualizationCaches {
|
||||||
String personURI = person.getURI();
|
String personURI = person.getURI();
|
||||||
String documentURI = document.getURI();
|
String documentURI = document.getURI();
|
||||||
|
|
||||||
map.put(personURI, documentURI);
|
map.put(personURI.intern(), documentURI.intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -352,7 +612,7 @@ final public class VisualizationCaches {
|
||||||
String document = qs.getResource("document").getURI();
|
String document = qs.getResource("document").getURI();
|
||||||
String journalLabel = qs.getLiteral("journalLabel").getString();
|
String journalLabel = qs.getLiteral("journalLabel").getString();
|
||||||
|
|
||||||
map.put(document, journalLabel);
|
map.put(document.intern(), journalLabel.intern());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -390,7 +650,7 @@ final public class VisualizationCaches {
|
||||||
.getValidParsedDateTimeObject(pubDate);
|
.getValidParsedDateTimeObject(pubDate);
|
||||||
|
|
||||||
if (validParsedDateTimeObject != null) {
|
if (validParsedDateTimeObject != null) {
|
||||||
map.put(document, String.valueOf(validParsedDateTimeObject.getYear()));
|
map.put(document.intern(), String.valueOf(validParsedDateTimeObject.getYear()).intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,10 +694,10 @@ final public class VisualizationCaches {
|
||||||
Set<String> documents = map.get(personURI);
|
Set<String> documents = map.get(personURI);
|
||||||
if (documents == null) {
|
if (documents == null) {
|
||||||
documents = new HashSet<String>();
|
documents = new HashSet<String>();
|
||||||
documents.add(grant.getURI());
|
documents.add(grant.getURI().intern());
|
||||||
map.put(personURI, documents);
|
map.put(personURI.intern(), documents);
|
||||||
} else {
|
} else {
|
||||||
documents.add(grant.getURI());
|
documents.add(grant.getURI().intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,7 +738,7 @@ final public class VisualizationCaches {
|
||||||
.getValidParsedDateTimeObject(startDate);
|
.getValidParsedDateTimeObject(startDate);
|
||||||
|
|
||||||
if (validParsedDateTimeObject != null) {
|
if (validParsedDateTimeObject != null) {
|
||||||
map.put(grant, String.valueOf(validParsedDateTimeObject.getYear()));
|
map.put(grant.intern(), String.valueOf(validParsedDateTimeObject.getYear()).intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -520,7 +780,7 @@ final public class VisualizationCaches {
|
||||||
.getValidParsedDateTimeObject(startDate);
|
.getValidParsedDateTimeObject(startDate);
|
||||||
|
|
||||||
if (validParsedDateTimeObject != null) {
|
if (validParsedDateTimeObject != null) {
|
||||||
map.put(grant, String.valueOf(validParsedDateTimeObject.getYear()));
|
map.put(grant.intern(), String.valueOf(validParsedDateTimeObject.getYear()).intern());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ display:DefaultMenu
|
||||||
display:hasElement display:HomeMenuItem ;
|
display:hasElement display:HomeMenuItem ;
|
||||||
display:hasElement display:OrganizationsMenuItem ;
|
display:hasElement display:OrganizationsMenuItem ;
|
||||||
display:hasElement display:PeopleMenuItem ;
|
display:hasElement display:PeopleMenuItem ;
|
||||||
display:hasElement display:ResearchMenuItem .
|
display:hasElement display:ResearchMenuItem ;
|
||||||
|
display:hasElement display:CapabilityMapMenuItem .
|
||||||
|
|
||||||
#### Menu Items for Default Menu ####
|
#### Menu Items for Default Menu ####
|
||||||
|
|
||||||
|
@ -53,6 +54,12 @@ display:EventsMenuItem
|
||||||
display:linkText "Events";
|
display:linkText "Events";
|
||||||
display:toPage display:Events .
|
display:toPage display:Events .
|
||||||
|
|
||||||
|
display:CapabilityMapMenuItem
|
||||||
|
a display:NavigationElement ;
|
||||||
|
display:menuPosition 6;
|
||||||
|
display:linkText "Capability Map";
|
||||||
|
display:toPage display:CapabilityMap .
|
||||||
|
|
||||||
display:Home
|
display:Home
|
||||||
a display:HomePage ;
|
a display:HomePage ;
|
||||||
a display:Page ;
|
a display:Page ;
|
||||||
|
@ -93,7 +100,11 @@ display:Research
|
||||||
display:urlMapping "/research" ;
|
display:urlMapping "/research" ;
|
||||||
display:hasDataGetter display:researchDataGetter .
|
display:hasDataGetter display:researchDataGetter .
|
||||||
|
|
||||||
|
display:CapabilityMap
|
||||||
|
a display:Page ;
|
||||||
|
display:title "Capability Map" ;
|
||||||
|
display:urlMapping "/vis/capabilitymap" ;
|
||||||
|
display:hasDataGetter display:capabilityMapDataGetter .
|
||||||
|
|
||||||
#The data getter objects used above
|
#The data getter objects used above
|
||||||
display:peopleDataGetter
|
display:peopleDataGetter
|
||||||
|
@ -118,3 +129,8 @@ display:eventsDataGetter
|
||||||
|
|
||||||
display:homeDataGetter
|
display:homeDataGetter
|
||||||
a <java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.BrowseDataGetter> .
|
a <java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.BrowseDataGetter> .
|
||||||
|
|
||||||
|
display:capabilityMapDataGetter
|
||||||
|
a <java:edu.cornell.mannlib.vitro.webapp.utils.dataGetter.FixedHTMLDataGetter>;
|
||||||
|
display:htmlValue """Capability Map"""@en ;
|
||||||
|
display:saveToVar "capabilityMap" .
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
http://www.springframework.org/schema/context
|
http://www.springframework.org/schema/context
|
||||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||||
|
|
||||||
|
<bean id="capability_map"
|
||||||
|
class="edu.cornell.mannlib.vitro.webapp.visualization.capabilitymap.CapabilityMapRequestHandler" />
|
||||||
|
|
||||||
<bean id="person_pub_count"
|
<bean id="person_pub_count"
|
||||||
class="edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.PersonPublicationCountRequestHandler" />
|
class="edu.cornell.mannlib.vitro.webapp.visualization.personpubcount.PersonPublicationCountRequestHandler" />
|
||||||
|
@ -47,6 +49,10 @@
|
||||||
class="edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationInjector">
|
class="edu.cornell.mannlib.vitro.webapp.controller.visualization.VisualizationInjector">
|
||||||
<property name="visualizations">
|
<property name="visualizations">
|
||||||
<map>
|
<map>
|
||||||
|
<entry key="capabilitymap">
|
||||||
|
<ref bean="capability_map"></ref>
|
||||||
|
</entry>
|
||||||
|
|
||||||
<entry key="person_pub_count">
|
<entry key="person_pub_count">
|
||||||
<ref bean="person_pub_count"></ref>
|
<ref bean="person_pub_count"></ref>
|
||||||
</entry>
|
</entry>
|
||||||
|
|
355
webapp/src/main/webapp/css/visualization/capabilitymap/graph.css
Executable file
355
webapp/src/main/webapp/css/visualization/capabilitymap/graph.css
Executable file
|
@ -0,0 +1,355 @@
|
||||||
|
body {
|
||||||
|
background-position-y:60px;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
margin: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
color: red;
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
#queryform button, #queryform input[type=submit] {
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
-o-border-radius: 4px;
|
||||||
|
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
-webkit-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
-o-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
-webkit-text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
-moz-text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
-o-text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
background-color: #8BAB2E;
|
||||||
|
// background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#446791), to(#164682));
|
||||||
|
// background-image: -moz-linear-gradient(top, #446791, #164682);
|
||||||
|
width: auto;
|
||||||
|
padding: 9px 18px 8px;
|
||||||
|
// margin: 10px 10px 0 0;
|
||||||
|
color: #fff;
|
||||||
|
border: 0;
|
||||||
|
vertical-align: middle
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
width: 1200px;
|
||||||
|
max-width: 1200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contains all the graphics. */
|
||||||
|
#container {
|
||||||
|
/*width: 1200px;*/width:940px;
|
||||||
|
height: auto;
|
||||||
|
/* margin:0 auto; */
|
||||||
|
/*margin-left:-130px;*/
|
||||||
|
position:relative;
|
||||||
|
/*box-shadow:0px 0px 20px -6px #000000;*/
|
||||||
|
margin-top:15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-container,
|
||||||
|
#right-container,
|
||||||
|
#center-container {
|
||||||
|
height:600px;
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#log_printout {
|
||||||
|
display: block;
|
||||||
|
height: 330px;
|
||||||
|
overflow: scroll
|
||||||
|
}
|
||||||
|
|
||||||
|
#left-container, #right-container {
|
||||||
|
width: 300px;
|
||||||
|
color:#686c70;
|
||||||
|
text-align: left;
|
||||||
|
/*overflow: auto;*/
|
||||||
|
background-color:#fff;
|
||||||
|
background-repeat:no-repeat;
|
||||||
|
/*border-bottom:1px solid #ddd;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.result_body {
|
||||||
|
overflow:auto;
|
||||||
|
height:570px;
|
||||||
|
}
|
||||||
|
#left-container {
|
||||||
|
left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right-container {
|
||||||
|
right:0;
|
||||||
|
border-left:1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#right-container h4{
|
||||||
|
text-indent:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#center-container {
|
||||||
|
width: 900px;
|
||||||
|
background-color:#FFFFFF;
|
||||||
|
color:#ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result_section {
|
||||||
|
/* width: 100%;*/
|
||||||
|
font-size: 12px;
|
||||||
|
list-style:none;
|
||||||
|
margin:7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right:10px;
|
||||||
|
font-size:1.0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#infovis {
|
||||||
|
width:100%;
|
||||||
|
height:600px;
|
||||||
|
/*margin:auto;*/
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.close {
|
||||||
|
color:#FF5555;
|
||||||
|
cursor:pointer;
|
||||||
|
font-weight:bold;
|
||||||
|
margin-left:3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.name {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*TOOLTIPS*/
|
||||||
|
.tip {
|
||||||
|
color: #111;
|
||||||
|
width: 139px;
|
||||||
|
background-color: white;
|
||||||
|
border:1px solid #ccc;
|
||||||
|
-moz-box-shadow:#555 2px 2px 8px;
|
||||||
|
-webkit-box-shadow:#555 2px 2px 8px;
|
||||||
|
-o-box-shadow:#555 2px 2px 8px;
|
||||||
|
box-shadow:#555 2px 2px 8px;
|
||||||
|
opacity:0.9;
|
||||||
|
filter:alpha(opacity=90);
|
||||||
|
font-size:10px;
|
||||||
|
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
|
||||||
|
padding:7px;
|
||||||
|
text-align: left;
|
||||||
|
width:auto;
|
||||||
|
max-width:500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* LIST OF EXPERTS */
|
||||||
|
.field {
|
||||||
|
font-style: italic;
|
||||||
|
margin: .4ex 1ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#graphDetails {
|
||||||
|
margin-bottom:0px;
|
||||||
|
margin-top:5px;
|
||||||
|
}
|
||||||
|
input[disabled] {
|
||||||
|
opacity:0.5;
|
||||||
|
box-shadow:none;
|
||||||
|
}
|
||||||
|
#resetButton {
|
||||||
|
background-color: #933;
|
||||||
|
background-image: -webkit-gradient(linear,0 0,0 100%,from(#B55),to(#933));
|
||||||
|
background-image: -moz-linear-gradient(center top , #B55, #933);
|
||||||
|
}
|
||||||
|
#helptext {
|
||||||
|
width:630px;
|
||||||
|
/*padding:5px;*/
|
||||||
|
}
|
||||||
|
#center-container {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.bar {
|
||||||
|
height:15px;
|
||||||
|
display:block;
|
||||||
|
background-color:#EEE;
|
||||||
|
border:1px solid #CCC;
|
||||||
|
float:left;
|
||||||
|
margin-bottom:1px;
|
||||||
|
}
|
||||||
|
.barchart {
|
||||||
|
line-height:18px;
|
||||||
|
padding-top:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size:23px;
|
||||||
|
margin-top:0px;
|
||||||
|
padding-top:0px;
|
||||||
|
line-height:1.3em;
|
||||||
|
margin-bottom:20px;
|
||||||
|
}
|
||||||
|
.result_section h2 {
|
||||||
|
font-size:16px;
|
||||||
|
padding:10px 0px;
|
||||||
|
margin:0px;
|
||||||
|
}
|
||||||
|
.result_section ul li {
|
||||||
|
margin-top:3px;
|
||||||
|
}
|
||||||
|
li input[type=checkbox] {
|
||||||
|
vertical-align:middle;
|
||||||
|
}
|
||||||
|
.orange-square, .blue-circle {
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
height:15px;
|
||||||
|
width:15px;
|
||||||
|
margin-right:3px;
|
||||||
|
}
|
||||||
|
.orange-square {
|
||||||
|
background-color:#ffa500;
|
||||||
|
}
|
||||||
|
.blue-circle {
|
||||||
|
background-color:#23A4FF;
|
||||||
|
border-radius:7px;
|
||||||
|
}
|
||||||
|
ul.visible {
|
||||||
|
margin-bottom:1.3em;
|
||||||
|
margin-left:20px;
|
||||||
|
list-style-type:disc;
|
||||||
|
}
|
||||||
|
#cutofflabel {
|
||||||
|
display:inline-block;
|
||||||
|
width:0px;
|
||||||
|
overflow:visible;
|
||||||
|
position:relative;
|
||||||
|
left:10px;
|
||||||
|
top:2px;
|
||||||
|
foont-size: 14px;
|
||||||
|
}
|
||||||
|
#queryCutoff {
|
||||||
|
background:transparent;
|
||||||
|
text-align:right;
|
||||||
|
padding-left:40px;
|
||||||
|
}
|
||||||
|
#cutofflabel img {
|
||||||
|
vertical-align:middle;
|
||||||
|
position:relative;
|
||||||
|
top:-2px;
|
||||||
|
}
|
||||||
|
.progress, .progress div {
|
||||||
|
height:10px;
|
||||||
|
margin-bottom:-10px;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
.progress div {
|
||||||
|
background-color:#9999FF;
|
||||||
|
width:0%;
|
||||||
|
white-space:nowrap;
|
||||||
|
color:#FFF;
|
||||||
|
font-size:10px;
|
||||||
|
line-height:10px;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
background:#efefef;
|
||||||
|
}
|
||||||
|
.tabs {
|
||||||
|
width: auto;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
.tabs ul.titles li {
|
||||||
|
background: transparent;
|
||||||
|
/*padding-right: 1px;*/
|
||||||
|
line-height: normal;
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
.tabs ul {
|
||||||
|
padding-left:0px;
|
||||||
|
}
|
||||||
|
.tabs ul.titles {
|
||||||
|
list-style: none;
|
||||||
|
height:30px;
|
||||||
|
color: #5e6363;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.tabs ul.titles li a {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
outline: none;
|
||||||
|
display:block;
|
||||||
|
float:left;
|
||||||
|
// width:100px;
|
||||||
|
width:150px;
|
||||||
|
height:30px;
|
||||||
|
line-height:30px;
|
||||||
|
text-align:center;
|
||||||
|
color: #5e6363;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs ul.titles li a:hover {
|
||||||
|
background-color: #dddddd;
|
||||||
|
color: #002b44;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs ul.titles li.activeTab a,
|
||||||
|
.tabs ul.titles li.activeTab a:hover {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.smalllogo {
|
||||||
|
margin-left:-5px;
|
||||||
|
vertical-align:middle;
|
||||||
|
}
|
||||||
|
.advanced label, input {
|
||||||
|
display:inline;
|
||||||
|
}
|
||||||
|
.advanced input[type=text] {
|
||||||
|
width:50px;
|
||||||
|
}
|
||||||
|
.advanced {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.person_details {
|
||||||
|
margin-top:5px;
|
||||||
|
}
|
||||||
|
.person_details p {
|
||||||
|
margin-bottom:0px;
|
||||||
|
}
|
||||||
|
.person_details ul {
|
||||||
|
list-style:disc;
|
||||||
|
margin-left:20px;
|
||||||
|
}
|
||||||
|
.person_details li {
|
||||||
|
margin:0px;
|
||||||
|
margin-bottom:3px;
|
||||||
|
}
|
||||||
|
.ack {
|
||||||
|
padding-top:20px;
|
||||||
|
/*text-align:center;*/
|
||||||
|
color:#999;
|
||||||
|
margin:0px 20px;
|
||||||
|
/*font-size:8pt;*/
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
margin:0px 20px;
|
||||||
|
width:auto;
|
||||||
|
}
|
||||||
|
footer p.copyright {
|
||||||
|
margin-left:0px;
|
||||||
|
padding-left:0px;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
1128
webapp/src/main/webapp/js/visualization/capabilitymap/graph_new.js
Executable file
1128
webapp/src/main/webapp/js/visualization/capabilitymap/graph_new.js
Executable file
File diff suppressed because it is too large
Load diff
663
webapp/src/main/webapp/js/visualization/capabilitymap/jquery.color.js
Executable file
663
webapp/src/main/webapp/js/visualization/capabilitymap/jquery.color.js
Executable file
|
@ -0,0 +1,663 @@
|
||||||
|
/*!
|
||||||
|
* jQuery Color Animations v@VERSION
|
||||||
|
* https://github.com/jquery/jquery-color
|
||||||
|
*
|
||||||
|
* Copyright 2013 jQuery Foundation and other contributors
|
||||||
|
* Released under the MIT license.
|
||||||
|
* http://jquery.org/license
|
||||||
|
*
|
||||||
|
* Date: @DATE
|
||||||
|
*/
|
||||||
|
(function( jQuery, undefined ) {
|
||||||
|
|
||||||
|
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
|
||||||
|
|
||||||
|
// plusequals test for += 100 -= 100
|
||||||
|
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
|
||||||
|
// a set of RE's that can match strings and generate color tuples.
|
||||||
|
stringParsers = [{
|
||||||
|
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||||||
|
parse: function( execResult ) {
|
||||||
|
return [
|
||||||
|
execResult[ 1 ],
|
||||||
|
execResult[ 2 ],
|
||||||
|
execResult[ 3 ],
|
||||||
|
execResult[ 4 ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||||||
|
parse: function( execResult ) {
|
||||||
|
return [
|
||||||
|
execResult[ 1 ] * 2.55,
|
||||||
|
execResult[ 2 ] * 2.55,
|
||||||
|
execResult[ 3 ] * 2.55,
|
||||||
|
execResult[ 4 ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
// this regex ignores A-F because it's compared against an already lowercased string
|
||||||
|
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
|
||||||
|
parse: function( execResult ) {
|
||||||
|
return [
|
||||||
|
parseInt( execResult[ 1 ], 16 ),
|
||||||
|
parseInt( execResult[ 2 ], 16 ),
|
||||||
|
parseInt( execResult[ 3 ], 16 )
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
// this regex ignores A-F because it's compared against an already lowercased string
|
||||||
|
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
|
||||||
|
parse: function( execResult ) {
|
||||||
|
return [
|
||||||
|
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
|
||||||
|
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
|
||||||
|
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
|
||||||
|
space: "hsla",
|
||||||
|
parse: function( execResult ) {
|
||||||
|
return [
|
||||||
|
execResult[ 1 ],
|
||||||
|
execResult[ 2 ] / 100,
|
||||||
|
execResult[ 3 ] / 100,
|
||||||
|
execResult[ 4 ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
|
// jQuery.Color( )
|
||||||
|
color = jQuery.Color = function( color, green, blue, alpha ) {
|
||||||
|
return new jQuery.Color.fn.parse( color, green, blue, alpha );
|
||||||
|
},
|
||||||
|
spaces = {
|
||||||
|
rgba: {
|
||||||
|
props: {
|
||||||
|
red: {
|
||||||
|
idx: 0,
|
||||||
|
type: "byte"
|
||||||
|
},
|
||||||
|
green: {
|
||||||
|
idx: 1,
|
||||||
|
type: "byte"
|
||||||
|
},
|
||||||
|
blue: {
|
||||||
|
idx: 2,
|
||||||
|
type: "byte"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hsla: {
|
||||||
|
props: {
|
||||||
|
hue: {
|
||||||
|
idx: 0,
|
||||||
|
type: "degrees"
|
||||||
|
},
|
||||||
|
saturation: {
|
||||||
|
idx: 1,
|
||||||
|
type: "percent"
|
||||||
|
},
|
||||||
|
lightness: {
|
||||||
|
idx: 2,
|
||||||
|
type: "percent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
propTypes = {
|
||||||
|
"byte": {
|
||||||
|
floor: true,
|
||||||
|
max: 255
|
||||||
|
},
|
||||||
|
"percent": {
|
||||||
|
max: 1
|
||||||
|
},
|
||||||
|
"degrees": {
|
||||||
|
mod: 360,
|
||||||
|
floor: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
support = color.support = {},
|
||||||
|
|
||||||
|
// element for support tests
|
||||||
|
supportElem = jQuery( "<p>" )[ 0 ],
|
||||||
|
|
||||||
|
// colors = jQuery.Color.names
|
||||||
|
colors,
|
||||||
|
|
||||||
|
// local aliases of functions called often
|
||||||
|
each = jQuery.each;
|
||||||
|
|
||||||
|
// determine rgba support immediately
|
||||||
|
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
|
||||||
|
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
|
||||||
|
|
||||||
|
// define cache name and alpha properties
|
||||||
|
// for rgba and hsla spaces
|
||||||
|
each( spaces, function( spaceName, space ) {
|
||||||
|
space.cache = "_" + spaceName;
|
||||||
|
space.props.alpha = {
|
||||||
|
idx: 3,
|
||||||
|
type: "percent",
|
||||||
|
def: 1
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function clamp( value, prop, allowEmpty ) {
|
||||||
|
var type = propTypes[ prop.type ] || {};
|
||||||
|
|
||||||
|
if ( value == null ) {
|
||||||
|
return (allowEmpty || !prop.def) ? null : prop.def;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~~ is an short way of doing floor for positive numbers
|
||||||
|
value = type.floor ? ~~value : parseFloat( value );
|
||||||
|
|
||||||
|
// IE will pass in empty strings as value for alpha,
|
||||||
|
// which will hit this case
|
||||||
|
if ( isNaN( value ) ) {
|
||||||
|
return prop.def;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type.mod ) {
|
||||||
|
// we add mod before modding to make sure that negatives values
|
||||||
|
// get converted properly: -10 -> 350
|
||||||
|
return (value + type.mod) % type.mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for now all property types without mod have min and max
|
||||||
|
return 0 > value ? 0 : type.max < value ? type.max : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringParse( string ) {
|
||||||
|
var inst = color(),
|
||||||
|
rgba = inst._rgba = [];
|
||||||
|
|
||||||
|
string = string.toLowerCase();
|
||||||
|
|
||||||
|
each( stringParsers, function( i, parser ) {
|
||||||
|
var parsed,
|
||||||
|
match = parser.re.exec( string ),
|
||||||
|
values = match && parser.parse( match ),
|
||||||
|
spaceName = parser.space || "rgba";
|
||||||
|
|
||||||
|
if ( values ) {
|
||||||
|
parsed = inst[ spaceName ]( values );
|
||||||
|
|
||||||
|
// if this was an rgba parse the assignment might happen twice
|
||||||
|
// oh well....
|
||||||
|
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
|
||||||
|
rgba = inst._rgba = parsed._rgba;
|
||||||
|
|
||||||
|
// exit each( stringParsers ) here because we matched
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Found a stringParser that handled it
|
||||||
|
if ( rgba.length ) {
|
||||||
|
|
||||||
|
// if this came from a parsed string, force "transparent" when alpha is 0
|
||||||
|
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
|
||||||
|
if ( rgba.join() === "0,0,0,0" ) {
|
||||||
|
jQuery.extend( rgba, colors.transparent );
|
||||||
|
}
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
// named colors
|
||||||
|
return colors[ string ];
|
||||||
|
}
|
||||||
|
|
||||||
|
color.fn = jQuery.extend( color.prototype, {
|
||||||
|
parse: function( red, green, blue, alpha ) {
|
||||||
|
if ( red === undefined ) {
|
||||||
|
this._rgba = [ null, null, null, null ];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if ( red.jquery || red.nodeType ) {
|
||||||
|
red = jQuery( red ).css( green );
|
||||||
|
green = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inst = this,
|
||||||
|
type = jQuery.type( red ),
|
||||||
|
rgba = this._rgba = [];
|
||||||
|
|
||||||
|
// more than 1 argument specified - assume ( red, green, blue, alpha )
|
||||||
|
if ( green !== undefined ) {
|
||||||
|
red = [ red, green, blue, alpha ];
|
||||||
|
type = "array";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type === "string" ) {
|
||||||
|
return this.parse( stringParse( red ) || colors._default );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type === "array" ) {
|
||||||
|
each( spaces.rgba.props, function( key, prop ) {
|
||||||
|
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( type === "object" ) {
|
||||||
|
if ( red instanceof color ) {
|
||||||
|
each( spaces, function( spaceName, space ) {
|
||||||
|
if ( red[ space.cache ] ) {
|
||||||
|
inst[ space.cache ] = red[ space.cache ].slice();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
each( spaces, function( spaceName, space ) {
|
||||||
|
var cache = space.cache;
|
||||||
|
each( space.props, function( key, prop ) {
|
||||||
|
|
||||||
|
// if the cache doesn't exist, and we know how to convert
|
||||||
|
if ( !inst[ cache ] && space.to ) {
|
||||||
|
|
||||||
|
// if the value was null, we don't need to copy it
|
||||||
|
// if the key was alpha, we don't need to copy it either
|
||||||
|
if ( key === "alpha" || red[ key ] == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inst[ cache ] = space.to( inst._rgba );
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the only case where we allow nulls for ALL properties.
|
||||||
|
// call clamp with alwaysAllowEmpty
|
||||||
|
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
|
||||||
|
});
|
||||||
|
|
||||||
|
// everything defined but alpha?
|
||||||
|
if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
|
||||||
|
// use the default of 1
|
||||||
|
inst[ cache ][ 3 ] = 1;
|
||||||
|
if ( space.from ) {
|
||||||
|
inst._rgba = space.from( inst[ cache ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
is: function( compare ) {
|
||||||
|
var is = color( compare ),
|
||||||
|
same = true,
|
||||||
|
inst = this;
|
||||||
|
|
||||||
|
each( spaces, function( _, space ) {
|
||||||
|
var localCache,
|
||||||
|
isCache = is[ space.cache ];
|
||||||
|
if (isCache) {
|
||||||
|
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
|
||||||
|
each( space.props, function( _, prop ) {
|
||||||
|
if ( isCache[ prop.idx ] != null ) {
|
||||||
|
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
|
||||||
|
return same;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return same;
|
||||||
|
});
|
||||||
|
return same;
|
||||||
|
},
|
||||||
|
_space: function() {
|
||||||
|
var used = [],
|
||||||
|
inst = this;
|
||||||
|
each( spaces, function( spaceName, space ) {
|
||||||
|
if ( inst[ space.cache ] ) {
|
||||||
|
used.push( spaceName );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return used.pop();
|
||||||
|
},
|
||||||
|
transition: function( other, distance ) {
|
||||||
|
var end = color( other ),
|
||||||
|
spaceName = end._space(),
|
||||||
|
space = spaces[ spaceName ],
|
||||||
|
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
|
||||||
|
start = startColor[ space.cache ] || space.to( startColor._rgba ),
|
||||||
|
result = start.slice();
|
||||||
|
|
||||||
|
end = end[ space.cache ];
|
||||||
|
each( space.props, function( key, prop ) {
|
||||||
|
var index = prop.idx,
|
||||||
|
startValue = start[ index ],
|
||||||
|
endValue = end[ index ],
|
||||||
|
type = propTypes[ prop.type ] || {};
|
||||||
|
|
||||||
|
// if null, don't override start value
|
||||||
|
if ( endValue === null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if null - use end
|
||||||
|
if ( startValue === null ) {
|
||||||
|
result[ index ] = endValue;
|
||||||
|
} else {
|
||||||
|
if ( type.mod ) {
|
||||||
|
if ( endValue - startValue > type.mod / 2 ) {
|
||||||
|
startValue += type.mod;
|
||||||
|
} else if ( startValue - endValue > type.mod / 2 ) {
|
||||||
|
startValue -= type.mod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this[ spaceName ]( result );
|
||||||
|
},
|
||||||
|
blend: function( opaque ) {
|
||||||
|
// if we are already opaque - return ourself
|
||||||
|
if ( this._rgba[ 3 ] === 1 ) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rgb = this._rgba.slice(),
|
||||||
|
a = rgb.pop(),
|
||||||
|
blend = color( opaque )._rgba;
|
||||||
|
|
||||||
|
return color( jQuery.map( rgb, function( v, i ) {
|
||||||
|
return ( 1 - a ) * blend[ i ] + a * v;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
toRgbaString: function() {
|
||||||
|
var prefix = "rgba(",
|
||||||
|
rgba = jQuery.map( this._rgba, function( v, i ) {
|
||||||
|
return v == null ? ( i > 2 ? 1 : 0 ) : v;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( rgba[ 3 ] === 1 ) {
|
||||||
|
rgba.pop();
|
||||||
|
prefix = "rgb(";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix + rgba.join() + ")";
|
||||||
|
},
|
||||||
|
toHslaString: function() {
|
||||||
|
var prefix = "hsla(",
|
||||||
|
hsla = jQuery.map( this.hsla(), function( v, i ) {
|
||||||
|
if ( v == null ) {
|
||||||
|
v = i > 2 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// catch 1 and 2
|
||||||
|
if ( i && i < 3 ) {
|
||||||
|
v = Math.round( v * 100 ) + "%";
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( hsla[ 3 ] === 1 ) {
|
||||||
|
hsla.pop();
|
||||||
|
prefix = "hsl(";
|
||||||
|
}
|
||||||
|
return prefix + hsla.join() + ")";
|
||||||
|
},
|
||||||
|
toHexString: function( includeAlpha ) {
|
||||||
|
var rgba = this._rgba.slice(),
|
||||||
|
alpha = rgba.pop();
|
||||||
|
|
||||||
|
if ( includeAlpha ) {
|
||||||
|
rgba.push( ~~( alpha * 255 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return "#" + jQuery.map( rgba, function( v ) {
|
||||||
|
|
||||||
|
// default to 0 when nulls exist
|
||||||
|
v = ( v || 0 ).toString( 16 );
|
||||||
|
return v.length === 1 ? "0" + v : v;
|
||||||
|
}).join("");
|
||||||
|
},
|
||||||
|
toString: function() {
|
||||||
|
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
color.fn.parse.prototype = color.fn;
|
||||||
|
|
||||||
|
// hsla conversions adapted from:
|
||||||
|
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
|
||||||
|
|
||||||
|
function hue2rgb( p, q, h ) {
|
||||||
|
h = ( h + 1 ) % 1;
|
||||||
|
if ( h * 6 < 1 ) {
|
||||||
|
return p + (q - p) * h * 6;
|
||||||
|
}
|
||||||
|
if ( h * 2 < 1) {
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
if ( h * 3 < 2 ) {
|
||||||
|
return p + (q - p) * ((2/3) - h) * 6;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
spaces.hsla.to = function ( rgba ) {
|
||||||
|
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
|
||||||
|
return [ null, null, null, rgba[ 3 ] ];
|
||||||
|
}
|
||||||
|
var r = rgba[ 0 ] / 255,
|
||||||
|
g = rgba[ 1 ] / 255,
|
||||||
|
b = rgba[ 2 ] / 255,
|
||||||
|
a = rgba[ 3 ],
|
||||||
|
max = Math.max( r, g, b ),
|
||||||
|
min = Math.min( r, g, b ),
|
||||||
|
diff = max - min,
|
||||||
|
add = max + min,
|
||||||
|
l = add * 0.5,
|
||||||
|
h, s;
|
||||||
|
|
||||||
|
if ( min === max ) {
|
||||||
|
h = 0;
|
||||||
|
} else if ( r === max ) {
|
||||||
|
h = ( 60 * ( g - b ) / diff ) + 360;
|
||||||
|
} else if ( g === max ) {
|
||||||
|
h = ( 60 * ( b - r ) / diff ) + 120;
|
||||||
|
} else {
|
||||||
|
h = ( 60 * ( r - g ) / diff ) + 240;
|
||||||
|
}
|
||||||
|
|
||||||
|
// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
|
||||||
|
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
|
||||||
|
if ( diff === 0 ) {
|
||||||
|
s = 0;
|
||||||
|
} else if ( l <= 0.5 ) {
|
||||||
|
s = diff / add;
|
||||||
|
} else {
|
||||||
|
s = diff / ( 2 - add );
|
||||||
|
}
|
||||||
|
return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
|
||||||
|
};
|
||||||
|
|
||||||
|
spaces.hsla.from = function ( hsla ) {
|
||||||
|
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
|
||||||
|
return [ null, null, null, hsla[ 3 ] ];
|
||||||
|
}
|
||||||
|
var h = hsla[ 0 ] / 360,
|
||||||
|
s = hsla[ 1 ],
|
||||||
|
l = hsla[ 2 ],
|
||||||
|
a = hsla[ 3 ],
|
||||||
|
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
|
||||||
|
p = 2 * l - q;
|
||||||
|
|
||||||
|
return [
|
||||||
|
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
|
||||||
|
Math.round( hue2rgb( p, q, h ) * 255 ),
|
||||||
|
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
|
||||||
|
a
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
each( spaces, function( spaceName, space ) {
|
||||||
|
var props = space.props,
|
||||||
|
cache = space.cache,
|
||||||
|
to = space.to,
|
||||||
|
from = space.from;
|
||||||
|
|
||||||
|
// makes rgba() and hsla()
|
||||||
|
color.fn[ spaceName ] = function( value ) {
|
||||||
|
|
||||||
|
// generate a cache for this space if it doesn't exist
|
||||||
|
if ( to && !this[ cache ] ) {
|
||||||
|
this[ cache ] = to( this._rgba );
|
||||||
|
}
|
||||||
|
if ( value === undefined ) {
|
||||||
|
return this[ cache ].slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret,
|
||||||
|
type = jQuery.type( value ),
|
||||||
|
arr = ( type === "array" || type === "object" ) ? value : arguments,
|
||||||
|
local = this[ cache ].slice();
|
||||||
|
|
||||||
|
each( props, function( key, prop ) {
|
||||||
|
var val = arr[ type === "object" ? key : prop.idx ];
|
||||||
|
if ( val == null ) {
|
||||||
|
val = local[ prop.idx ];
|
||||||
|
}
|
||||||
|
local[ prop.idx ] = clamp( val, prop );
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( from ) {
|
||||||
|
ret = color( from( local ) );
|
||||||
|
ret[ cache ] = local;
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
return color( local );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// makes red() green() blue() alpha() hue() saturation() lightness()
|
||||||
|
each( props, function( key, prop ) {
|
||||||
|
// alpha is included in more than one space
|
||||||
|
if ( color.fn[ key ] ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
color.fn[ key ] = function( value ) {
|
||||||
|
var vtype = jQuery.type( value ),
|
||||||
|
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
|
||||||
|
local = this[ fn ](),
|
||||||
|
cur = local[ prop.idx ],
|
||||||
|
match;
|
||||||
|
|
||||||
|
if ( vtype === "undefined" ) {
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( vtype === "function" ) {
|
||||||
|
value = value.call( this, cur );
|
||||||
|
vtype = jQuery.type( value );
|
||||||
|
}
|
||||||
|
if ( value == null && prop.empty ) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if ( vtype === "string" ) {
|
||||||
|
match = rplusequals.exec( value );
|
||||||
|
if ( match ) {
|
||||||
|
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local[ prop.idx ] = value;
|
||||||
|
return this[ fn ]( local );
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// add cssHook and .fx.step function for each named hook.
|
||||||
|
// accept a space separated string of properties
|
||||||
|
color.hook = function( hook ) {
|
||||||
|
var hooks = hook.split( " " );
|
||||||
|
each( hooks, function( i, hook ) {
|
||||||
|
jQuery.cssHooks[ hook ] = {
|
||||||
|
set: function( elem, value ) {
|
||||||
|
var parsed, curElem,
|
||||||
|
backgroundColor = "";
|
||||||
|
|
||||||
|
if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
|
||||||
|
value = color( parsed || value );
|
||||||
|
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
|
||||||
|
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
|
||||||
|
while (
|
||||||
|
(backgroundColor === "" || backgroundColor === "transparent") &&
|
||||||
|
curElem && curElem.style
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
backgroundColor = jQuery.css( curElem, "backgroundColor" );
|
||||||
|
curElem = curElem.parentNode;
|
||||||
|
} catch ( e ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
|
||||||
|
backgroundColor :
|
||||||
|
"_default" );
|
||||||
|
}
|
||||||
|
|
||||||
|
value = value.toRgbaString();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
elem.style[ hook ] = value;
|
||||||
|
} catch( e ) {
|
||||||
|
// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
jQuery.fx.step[ hook ] = function( fx ) {
|
||||||
|
if ( !fx.colorInit ) {
|
||||||
|
fx.start = color( fx.elem, hook );
|
||||||
|
fx.end = color( fx.end );
|
||||||
|
fx.colorInit = true;
|
||||||
|
}
|
||||||
|
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
color.hook( stepHooks );
|
||||||
|
|
||||||
|
jQuery.cssHooks.borderColor = {
|
||||||
|
expand: function( value ) {
|
||||||
|
var expanded = {};
|
||||||
|
|
||||||
|
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
|
||||||
|
expanded[ "border" + part + "Color" ] = value;
|
||||||
|
});
|
||||||
|
return expanded;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic color names only.
|
||||||
|
// Usage of any of the other color names requires adding yourself or including
|
||||||
|
// jquery.color.svg-names.js.
|
||||||
|
colors = jQuery.Color.names = {
|
||||||
|
// 4.1. Basic color keywords
|
||||||
|
aqua: "#00ffff",
|
||||||
|
black: "#000000",
|
||||||
|
blue: "#0000ff",
|
||||||
|
fuchsia: "#ff00ff",
|
||||||
|
gray: "#808080",
|
||||||
|
green: "#008000",
|
||||||
|
lime: "#00ff00",
|
||||||
|
maroon: "#800000",
|
||||||
|
navy: "#000080",
|
||||||
|
olive: "#808000",
|
||||||
|
purple: "#800080",
|
||||||
|
red: "#ff0000",
|
||||||
|
silver: "#c0c0c0",
|
||||||
|
teal: "#008080",
|
||||||
|
white: "#ffffff",
|
||||||
|
yellow: "#ffff00",
|
||||||
|
|
||||||
|
// 4.2.3. "transparent" color keyword
|
||||||
|
transparent: [ null, null, null, 0 ],
|
||||||
|
|
||||||
|
_default: "#ffffff"
|
||||||
|
};
|
||||||
|
|
||||||
|
})( jQuery );
|
82
webapp/src/main/webapp/js/visualization/capabilitymap/jsr_class.js
Executable file
82
webapp/src/main/webapp/js/visualization/capabilitymap/jsr_class.js
Executable file
|
@ -0,0 +1,82 @@
|
||||||
|
// jsr_class.js
|
||||||
|
//
|
||||||
|
// JSONscriptRequest -- a simple class for making HTTP requests
|
||||||
|
// using dynamically generated script tags and JSON
|
||||||
|
//
|
||||||
|
// Author: Jason Levitt
|
||||||
|
// Date: December 7th, 2005
|
||||||
|
//
|
||||||
|
// A SECURITY WARNING FROM DOUGLAS CROCKFORD:
|
||||||
|
// "The dynamic <script> tag hack suffers from a problem. It allows a page
|
||||||
|
// to access data from any server in the web, which is really useful.
|
||||||
|
// Unfortunately, the data is returned in the form of a script. That script
|
||||||
|
// can deliver the data, but it runs with the same authority as scripts on
|
||||||
|
// the base page, so it is able to steal cookies or misuse the authorization
|
||||||
|
// of the user with the server. A rogue script can do destructive things to
|
||||||
|
// the relationship between the user and the base server."
|
||||||
|
//
|
||||||
|
// So, be extremely cautious in your use of this script.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Sample Usage:
|
||||||
|
//
|
||||||
|
// <script type="text/javascript" src="jsr_class.js"></script>
|
||||||
|
//
|
||||||
|
// function callbackfunc(jsonData) {
|
||||||
|
// alert('Latitude = ' + jsonData.ResultSet.Result[0].Latitude +
|
||||||
|
// ' Longitude = ' + jsonData.ResultSet.Result[0].Longitude);
|
||||||
|
// aObj.removeScriptTag();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// request = 'http://api.local.yahoo.com/MapsService/V1/geocode?appid=YahooDemo&
|
||||||
|
// output=json&callback=callbackfunc&location=78704';
|
||||||
|
// aObj = new JSONscriptRequest(request);
|
||||||
|
// aObj.buildScriptTag();
|
||||||
|
// aObj.addScriptTag();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor -- pass a REST request URL to the constructor
|
||||||
|
//
|
||||||
|
function JSONscriptRequest(fullUrl) {
|
||||||
|
// REST request path
|
||||||
|
this.fullUrl = fullUrl;
|
||||||
|
// Keep IE from caching requests
|
||||||
|
this.noCacheIE = '&noCacheIE=' + (new Date()).getTime();
|
||||||
|
// Get the DOM location to put the script tag
|
||||||
|
this.headLoc = document.getElementsByTagName("head").item(0);
|
||||||
|
// Generate a unique script tag id
|
||||||
|
this.scriptId = 'JscriptId' + JSONscriptRequest.scriptCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static script ID counter
|
||||||
|
JSONscriptRequest.scriptCounter = 1;
|
||||||
|
|
||||||
|
// buildScriptTag method
|
||||||
|
//
|
||||||
|
JSONscriptRequest.prototype.buildScriptTag = function () {
|
||||||
|
|
||||||
|
// Create the script tag
|
||||||
|
this.scriptObj = document.createElement("script");
|
||||||
|
|
||||||
|
// Add script object attributes
|
||||||
|
this.scriptObj.setAttribute("type", "text/javascript");
|
||||||
|
this.scriptObj.setAttribute("charset", "utf-8");
|
||||||
|
this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
|
||||||
|
this.scriptObj.setAttribute("id", this.scriptId);
|
||||||
|
};
|
||||||
|
|
||||||
|
// removeScriptTag method
|
||||||
|
//
|
||||||
|
JSONscriptRequest.prototype.removeScriptTag = function () {
|
||||||
|
// Destroy the script tag
|
||||||
|
this.headLoc.removeChild(this.scriptObj);
|
||||||
|
};
|
||||||
|
|
||||||
|
// addScriptTag method
|
||||||
|
//
|
||||||
|
JSONscriptRequest.prototype.addScriptTag = function () {
|
||||||
|
// Create the script tag
|
||||||
|
this.headLoc.appendChild(this.scriptObj);
|
||||||
|
};
|
|
@ -0,0 +1,167 @@
|
||||||
|
${scripts.add(
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/d3.min.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/visualization/capabilitymap/jquery.color.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/visualization/capabilitymap/jsr_class.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/visualization/capabilitymap/graph_new.js"></script>'
|
||||||
|
)}
|
||||||
|
|
||||||
|
${stylesheets.add(
|
||||||
|
'<link rel="stylesheet" href="${urls.base}/js/jquery-ui/css/smoothness/jquery-ui-1.8.9.custom.css" />',
|
||||||
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/templates/freemarker/edit/forms/css/autocomplete.css" />',
|
||||||
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/visualization/personlevel/page.css" />',
|
||||||
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/visualization/visualization.css" />',
|
||||||
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/visualization/capabilitymap/graph.css" />'
|
||||||
|
)}
|
||||||
|
|
||||||
|
<script language="JavaScript" type="text/javascript">
|
||||||
|
var contextPath = "${urls.base}";
|
||||||
|
$(document).ready(function() {
|
||||||
|
var loadedConcepts = $.ajax({
|
||||||
|
url: contextPath + "/visualizationAjax?vis=capabilitymap&data=concepts",
|
||||||
|
type: "GET",
|
||||||
|
async: false,
|
||||||
|
success: function(result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var conceptArray = $.parseJSON(loadedConcepts.responseText);
|
||||||
|
$("#query").autocomplete({
|
||||||
|
source: conceptArray
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="main" id="main-content" role="main">
|
||||||
|
<div class="col-8">
|
||||||
|
<h2>Capability Map</h2>
|
||||||
|
<p>Build a ‘first pass’ capability map by typing in a<!-- set of--> search term<!--s--> that could be said to represent a broad research capability.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="queryform">
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
<input name="query" id="query" size="34" value="" onfocus="" accesskey="q" onblur="" type="text" onkeydown="queryKeyDown(event);">
|
||||||
|
<label id="cutofflabel" for="queryCutoff">Cutoff:</label>
|
||||||
|
<input id="queryCutoff" name="queryCutoff" type="text" title="Cutoff" size="4" value="10">
|
||||||
|
<input type="submit" value="Search" id="add" type="button" onclick="addKwd();">
|
||||||
|
<input value="Search and Expand" type="submit" id="sExpand" onclick="expandLastQuery = 1; addKwd();">
|
||||||
|
<input value="Reset" id="resetButton" type="submit" onclick="reset()" disabled>
|
||||||
|
<!-- a style="display:inline-block; float:right; line-height:32px; height:32px; cursor:pointer" onclick="showhideadvanced(this)">Show advanced</a -->
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr style="clear:both;">
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<div id="helptext">
|
||||||
|
<p>
|
||||||
|
Welcome to the Capability Mapping tool.
|
||||||
|
This tool visualises how researchers relate to other
|
||||||
|
researchers via search terms.
|
||||||
|
</p>
|
||||||
|
<h3>Getting Started</h3>
|
||||||
|
<p>
|
||||||
|
Enter a research area into the search field above and press ‘Search’.
|
||||||
|
The resulting diagram displays the search term, rendered in orange,
|
||||||
|
connected to the blue group of researchers that are active in that area.
|
||||||
|
Enter another search term to see how researchers from both searches relate.
|
||||||
|
Keep adding search terms to build a capability map.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Tip: you can expand a broad search term into smaller concepts
|
||||||
|
by clicking ‘search and expand’.
|
||||||
|
</p>
|
||||||
|
<h3>Interacting with the visualisation</h3>
|
||||||
|
<p>
|
||||||
|
By clicking on any node in the visualisation,
|
||||||
|
additional information can be viewed in the
|
||||||
|
‘Info’ tab on the right-hand side.
|
||||||
|
For groups of people, the participants in the group
|
||||||
|
and their information can be viewed,
|
||||||
|
and individual researchers can be removed from the graph.
|
||||||
|
Selecting a search term will display all attached groups.
|
||||||
|
Under each group full information for each person is retrieved,
|
||||||
|
and the number of matching grants and publications
|
||||||
|
for each researcher within the mapped capabilities is shown.
|
||||||
|
Clicking on a researcher's name will lead to the original search
|
||||||
|
results.
|
||||||
|
</p>
|
||||||
|
<h4>Visual cues</h4>
|
||||||
|
<p>
|
||||||
|
To make the visualisation easier to read,
|
||||||
|
search terms and groups are scaled according
|
||||||
|
to the number of results returned.
|
||||||
|
Groups are also given different shades
|
||||||
|
according to the number of connected search terms.
|
||||||
|
The darker the shade, the more search terms a group is connected to.
|
||||||
|
</p>
|
||||||
|
<h3>Advanced features</h3>
|
||||||
|
<h4>Changing the cutoff value</h4>
|
||||||
|
<p>
|
||||||
|
The amount of researchers retrieved for each search term
|
||||||
|
for is limited by the cutoff value in the search form
|
||||||
|
(10 by default).
|
||||||
|
Increasing this cutoff will increase the likelihood
|
||||||
|
of an intersection between different search terms.
|
||||||
|
This will also increase the complexity of the graph,
|
||||||
|
however, and may make it difficult to identify patterns.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="center-container">
|
||||||
|
<div id="log"></div>
|
||||||
|
<div id="infovis"></div>
|
||||||
|
<div class="progress"><div id="progressbar"></div></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="right-container">
|
||||||
|
<div class="tabs">
|
||||||
|
<ul class="titles">
|
||||||
|
<li><a href="#demo">Search terms</a></li>
|
||||||
|
<li><a href="#logg">Info</a></li>
|
||||||
|
<!-- li><a href="#extractData">Data</a></li -->
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="result_body">
|
||||||
|
<div class="result_section" id="demo">
|
||||||
|
<h2>Current search terms</h2>
|
||||||
|
<ul id="log_printout">
|
||||||
|
<li>This panel displays a list of the search terms currently
|
||||||
|
on the graph. Search for something to begin.</li>
|
||||||
|
</ul>
|
||||||
|
<p style="position:absolute; bottom:10px">
|
||||||
|
<img src="${urls.base}/images/visualization/capabilitymap/key.png" alt="Key">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="result_section" id="logg">
|
||||||
|
<div id="inner-details">
|
||||||
|
<p>
|
||||||
|
This panel displays information about individual
|
||||||
|
search terms and groups. Click on a group to display
|
||||||
|
its information.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- div class="result_section" id="extractData">
|
||||||
|
<h2>Extract Data</h2>
|
||||||
|
<p>
|
||||||
|
Import:
|
||||||
|
<button disabled>SVG</button>
|
||||||
|
<button onclick="importGraphDetails();">JSON</button>
|
||||||
|
<br>
|
||||||
|
Export:
|
||||||
|
<button onclick="generateGraphSVG();">SVG</button>
|
||||||
|
<button onclick="download(g.export(), 'json')">JSON</button>
|
||||||
|
<button onclick="download(g.toDOT(), 'gv')">DOT</button>
|
||||||
|
<button onclick="generateGraphPersonList();">MRW</button>
|
||||||
|
</p>
|
||||||
|
<textarea id="graphDetails" style="width:99%; height:450px; border:1px solid #EEE; padding:0px;"></textarea>
|
||||||
|
</div -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue