/*global define */
define(['jquery', 'underscore', 'backbone', 'd3', 'LineChart', 'BarChart', 'DonutChart', 'CircleBadge',
'collections/Citations', 'models/MetricsModel', 'models/Stats', 'MetricsChart', 'views/CitationListView',
'text!templates/metricModalTemplate.html', 'text!templates/profile.html',
'text!templates/alert.html', 'text!templates/loading.html', 'text!templates/loading-metrics.html', ],
function($, _, Backbone, d3, LineChart, BarChart, DonutChart, CircleBadge, Citations, MetricsModel,
StatsModel, MetricsChart, CitationList, MetricModalTemplate, profileTemplate, AlertTemplate,
LoadingTemplate, MetricsLoadingTemplate) {
'use strict';
var StatsView = Backbone.View.extend(
/** @lends StatsView.prototype */{
el: '#Content',
model: null,
hideUpdatesChart: false,
/*
* Flag to indicate whether the statsview is a node summary view
* @type {boolean}
*/
nodeSummaryView: false,
/**
* Whether or not to show the graph that indicated the assessment score for all metadata in the query.
* @type {boolean}
*/
hideMetadataAssessment: false,
subviews: [],
template: _.template(profileTemplate),
metricTemplate: _.template(MetricModalTemplate),
alertTemplate: _.template(AlertTemplate),
loadingTemplate: _.template(LoadingTemplate),
metricsLoadingTemplate: _.template(MetricsLoadingTemplate),
initialize: function(options){
if(!options) options = {};
this.title = (typeof options.title === "undefined") ? "Summary of Holdings" : options.title;
this.description = (typeof options.description === "undefined") ?
"A summary of all datasets in our catalog." : options.description;
this.metricsModel = (typeof options.metricsModel === undefined) ? undefined : options.metricsModel;
this.userType = (typeof options.userType === undefined) ? undefined : options.userType;
this.userId = (typeof options.userId === undefined) ? undefined : options.userId;
this.userLabel = (typeof options.userLabel === undefined) ? undefined : options.userLabel;
if(typeof options.el === "undefined")
this.el = options.el;
this.hideUpdatesChart = (options.hideUpdatesChart === true)? true : false;
this.hideMetadataAssessment = (typeof options.hideMetadataAssessment === "undefined") ? true : options.hideMetadataAssessment;
this.hideCitationsChart = (typeof options.hideCitationsChart === "undefined") ? true : options.hideCitationsChart;
this.hideDownloadsChart = (typeof options.hideDownloadsChart === "undefined") ? true : options.hideDownloadsChart;
this.hideViewsChart = (typeof options.hideViewsChart === "undefined") ? true : options.hideViewsChart;
this.model = options.model || null;
},
render: function (options) {
//The Node info needs to be fetched first since a lot of this code requires info about MNs
if( !MetacatUI.nodeModel.get("checked") && !MetacatUI.nodeModel.get("error") ){
this.listenToOnce( MetacatUI.nodeModel, "change:checked error", function(){
//Remove listeners and render the view, even if there was an error fetching the NodeModel
this.stopListening(MetacatUI.nodeModel);
this.render(options);
});
this.$el.html(this.loadingTemplate);
return;
}
if ( !options )
options = {};
var view = this,
userIsCN = false,
nodeId,
isHostedRepo = false;
// Check if the node is a coordinating node
this.userIsCN = userIsCN;
if( this.userType !== undefined && this.userLabel !== undefined) {
if (this.userType === "repository") {
userIsCN = MetacatUI.nodeModel.isCN(this.userId);
if (userIsCN && typeof isCN !== 'undefined')
this.userIsCN = true;
}
}
if ( options.nodeSummaryView ) {
this.nodeSummaryView = true;
nodeId = MetacatUI.appModel.get("nodeId");
userIsCN = MetacatUI.nodeModel.isCN(nodeId);
//Save whether this profile is for a CN
if (userIsCN && typeof userIsCN !== 'undefined'){
this.userIsCN = true;
}
//Figure out if this profile is for a hosted repo
else if( nodeId ){
isHostedRepo = _.contains(MetacatUI.appModel.get("dataoneHostedRepos"), nodeId);
}
// Disable the metrics if the nodeId is not available or if it is not a DataONE Hosted Repo
if (!this.userIsCN && (nodeId === "undefined" || nodeId === null || !isHostedRepo) ) {
this.hideCitationsChart = true;
this.hideDownloadsChart = true;
this.hideViewsChart = true;
this.hideMetadataAssessment = true;
}
else{
// Overwrite the metrics display flags as set in the AppModel
this.hideMetadataAssessment = MetacatUI.appModel.get("hideSummaryMetadataAssessment");
this.hideCitationsChart = MetacatUI.appModel.get("hideSummaryCitationsChart");
this.hideDownloadsChart = MetacatUI.appModel.get("hideSummaryDownloadsChart");
this.hideViewsChart = MetacatUI.appModel.get("hideSummaryViewsChart");
}
}
if ( !this.hideCitationsChart || !this.hideDownloadsChart || !this.hideViewsChart ) {
if ( typeof this.metricsModel === "undefined" ) {
// Create a list with the repository ID
var pid_list = new Array();
pid_list.push(nodeId);
// Create a new object of the metrics model
var metricsModel = new MetricsModel({
pid_list: pid_list,
type: this.userType
});
metricsModel.fetch();
this.metricsModel = metricsModel;
}
}
if( !this.model ){
this.model = new StatsModel({
hideMetadataAssessment: this.hideMetadataAssessment,
mdqImageId: nodeId
});
}
//Clear the page
this.$el.html("");
//Only trigger the functions that draw SVG charts if d3 loaded correctly
if(d3){
//Draw a chart that shows the temporal coverage of all datasets in this collection
this.listenTo(this.model, 'change:temporalCoverage', this.drawCoverageChart);
//Draw charts that plot the latest updates of metadata and data files
this.listenTo(this.model, "change:dataUpdateDates", this.drawDataUpdatesChart);
this.listenTo(this.model, "change:metadataUpdateDates", this.drawMetadataUpdatesChart);
//Render the total file size of all contents in this collection
this.listenTo(this.model, "change:totalSize", this.displayTotalSize);
//Render the total number of datasets in this collection
this.listenTo(this.model, 'change:metadataCount', this.displayTotalCount);
// Display replicas only for member nodes
if (this.userType === "repository" && !this.userIsCN)
this.listenTo(this.model, "change:totalReplicas", this.displayTotalReplicas);
//Draw charts that show the breakdown of format IDs for metadata and data files
this.listenTo(this.model, 'change:dataFormatIDs', this.drawDataCountChart);
this.listenTo(this.model, 'change:metadataFormatIDs', this.drawMetadataCountChart);
}
//When the last coverage endDate is found, draw a title for the temporal coverage chart
this.listenTo(this.model, 'change:lastEndDate', this.drawCoverageChartTitle);
//When the total count is updated, check if there if the count is 0, so we can show there is no "activity" for this collection
this.listenTo(this.model, "change:totalCount", this.showNoActivity);
// set the header type
MetacatUI.appModel.set('headerType', 'default');
// Loading template for the FAIR chart
var fairLoadingHtml = this.metricsLoadingTemplate({
message: "Running an assessment report...",
character: "none",
type: "FAIR"
});
// Loading template for the citations section
var citationsLoadingHtml = this.metricsLoadingTemplate({
message: "Scouring our records for publications that cited these datasets...",
character: "none",
type: "citations"
});
// Loading template for the downloads bar chart
var downloadsLoadingHtml = this.metricsLoadingTemplate({
message: "Crunching some numbers...",
character: "developer",
type: "barchart"
});
// Loading template for the views bar chart
var viewsLoadingHtml = this.metricsLoadingTemplate({
message: "Just doing a few more calculations...",
character: "statistician",
type: "barchart"
});
//Insert the template
this.$el.html(this.template({
query: this.model.get('query'),
title: this.title,
description: this.description,
userType: this.userType,
userIsCN: this.userIsCN,
fairLoadingHtml: fairLoadingHtml,
citationsLoadingHtml: citationsLoadingHtml,
downloadsLoadingHtml: downloadsLoadingHtml,
viewsLoadingHtml: viewsLoadingHtml,
hideUpdatesChart: this.hideUpdatesChart,
hideCitationsChart: this.hideCitationsChart,
hideDownloadsChart: this.hideDownloadsChart,
hideViewsChart: this.hideViewsChart,
hideMetadataAssessment: this.hideMetadataAssessment
}));
// Insert the metadata assessment chart
var view = this;
if( this.hideMetadataAssessment !== true ){
this.listenTo(this.model, "change:mdqScoresImage", this.drawMetadataAssessment);
this.listenTo(this.model, "change:mdqScoresError", function () {
view.renderMetadataAssessmentError();
});
}
//Insert the loading template into the space where the charts will go
if(d3){
this.$(".chart").html(this.loadingTemplate);
this.$(".show-loading").html(this.loadingTemplate);
}
//If SVG isn't supported, insert an info warning
else{
this.$el.prepend(this.alertTemplate({
classes: "alert-info",
msg: "Please upgrade your browser or use a different browser to view graphs of these statistics.",
email: false
}));
}
this.$el.data("view", this);
if (this.userType == "portal" || this.userType === "repository") {
if ( !this.hideCitationsChart || !this.hideDownloadsChart || !this.hideViewsChart ) {
if (this.metricsModel.get("totalViews") !== null) {
this.renderMetrics();
}
else{
// render metrics on fetch success.
this.listenTo(view.metricsModel, "sync" , this.renderMetrics);
// in case when there is an error for the fetch call.
this.listenTo(view.metricsModel, "error", this.renderUsageMetricsError);
var view = this;
setTimeout(function(){
if( view.$('.views-metrics, .downloads-metrics, #user-citations').find(".metric-chart-loading").length ){
view.renderUsageMetricsError();
view.stopListening(view.metricsModel, "error", view.renderUsageMetricsError);
}
}, 6000);
}
}
}
//Start retrieving data from Solr
this.model.getAll();
// Only gather replication stats if the view is a repository view
if (this.userType === "repository") {
if (this.userLabel !== undefined)
{
var identifier = MetacatUI.appSearchModel.escapeSpecialChar(encodeURIComponent(this.userId));
this.model.getTotalReplicas(identifier);
}
else if (this.nodeSummaryView) {
var nodeId = MetacatUI.appModel.get("nodeId");
var identifier = MetacatUI.appSearchModel.escapeSpecialChar(encodeURIComponent(nodeId));
this.model.getTotalReplicas(identifier);
}
}
return this;
},
/**
* drawMetadataAssessment - Insert the metadata assessment image into the view
*/
drawMetadataAssessment: function(){
try {
var scoresImage = this.model.get("mdqScoresImage");
if( scoresImage ){
// Replace the preloader figure with the assessment chart
this.$("#metadata-assessment-graphic").html(scoresImage);
}
// If there was no image received from the MDQ scores service,
// then show a warning message
else {
this.renderMetadataAssessmentError();
}
} catch (e) {
// If there's an error inserting the image, log an error message
console.log("Error displaying the metadata assessment figure. Error message: " + e);
this.renderMetadataAssessmentError();
}
},
renderMetrics: function(){
if(!this.hideCitationsChart)
this.renderCitationMetric();
if(!this.hideDownloadsChart)
this.renderDownloadMetric();
if(!this.hideViewsChart)
this.renderViewMetric();
},
renderCitationMetric: function() {
var citationSectionEl = this.$('#user-citations');
var citationEl = this.$('.citations-metrics-list');
var citationCountEl = this.$('.citation-count');
var metricName = "Citations";
var metricCount = this.metricsModel.get("totalCitations");
citationCountEl.text(MetacatUI.appView.numberAbbreviator(metricCount,1));
// Displaying Citations
var resultDetails = this.metricsModel.get("resultDetails");
// Creating a new collection object
// Parsing result-details with citation dictionary format
var resultDetailsCitationCollection = new Array();
for (var key in resultDetails["citations"]) {
resultDetailsCitationCollection.push(resultDetails["citations"][key]);
}
var citationCollection = new Citations(resultDetailsCitationCollection, {parse:true});
this.citationCollection = citationCollection;
// Checking if there are any citations available for the List display.
if(this.metricsModel.get("totalCitations") == 0) {
var citationList = new CitationList();
// reattaching the citations at the bottom when the counts are 0.
var detachCitationEl = this.$(citationSectionEl).detach();
this.$('.charts-container').append(detachCitationEl);
}
else {
var citationList = new CitationList({citations: this.citationCollection});
}
this.citationList = citationList;
citationEl.html(this.citationList.render().$el.html());
},
renderDownloadMetric: function() {
var downloadEl = this.$('.downloads-metrics > .metric-chart');
var metricName = "Downloads";
var metricCount = this.metricsModel.get("totalDownloads");
var downloadCountEl = this.$('.download-count');
downloadCountEl.text(MetacatUI.appView.numberAbbreviator(metricCount,1));
var metricChartView = this.createMetricsChart(metricName);
downloadEl.html(metricChartView.el);
metricChartView.render();
},
renderViewMetric: function() {
var viewEl = this.$('.views-metrics > .metric-chart');
var metricName = "Views";
var metricCount = this.metricsModel.get("totalViews");
var viewCountEl = this.$('.view-count');
viewCountEl.text(MetacatUI.appView.numberAbbreviator(metricCount,1));
var metricChartView = this.createMetricsChart(metricName);
viewEl.html(metricChartView.el);
metricChartView.render();
},
// Currently only being used for portals and profile views
createMetricsChart: function(metricName){
var metricNameLemma = metricName.toLowerCase()
var metricMonths = this.metricsModel.get("months");
var metricCount = this.metricsModel.get(metricNameLemma);
var chartEl = document.getElementById('user-'+metricNameLemma+'-chart' );
var viewType = this.userType;
// Draw a metric chart
var modalMetricChart = new MetricsChart({
id: metricNameLemma + "-chart",
metricCount: metricCount,
metricMonths: metricMonths,
type: viewType,
metricName: metricName,
});
this.subviews.push(modalMetricChart);
return modalMetricChart;
},
drawDataCountChart: function(){
var dataCount = this.model.get('dataCount');
var data = this.model.get('dataFormatIDs');
if(dataCount){
var svgClass = "data";
}
else if(!this.model.get('dataCount') && this.model.get('metadataCount')){ //Are we drawing a blank chart (i.e. 0 data objects found)?
var svgClass = "data default";
}
else if(!this.model.get('metadataCount') && !this.model.get('dataCount'))
var svgClass = "data no-activity";
//If d3 isn't supported in this browser or didn't load correctly, insert a text title instead
if(!d3){
this.$('.format-charts-data').html("<h2 class='" + svgClass + " fallback'>" + MetacatUI.appView.commaSeparateNumber(dataCount) + " data files</h2>");
return;
}
//Draw a donut chart
var donut = new DonutChart({
id: "data-chart",
data: data,
total: this.model.get('dataCount'),
titleText: "data files",
titleCount: dataCount,
svgClass: svgClass,
countClass: "data",
height: 300,
width: 380,
formatLabel: function(name){
//If this is the application/vnd.ms-excel formatID - let's just display "MS Excel"
if((name !== undefined) && (name.indexOf("ms-excel") > -1)) name = "MS Excel";
else if((name != undefined) && (name == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) name= "MS Excel OpenXML"
else if((name != undefined) && (name == "application/vnd.openxmlformats-officedocument.wordprocessingml.document")) name= "MS Word OpenXML"
//Application/octet-stream - shorten it
else if((name !== undefined) && (name == "application/octet-stream")) name = "Application file";
if(name === undefined) name = "";
return name;
}
});
this.$('.format-charts-data').html(donut.render().el);
},
drawMetadataCountChart: function(){
var metadataCount = this.model.get("metadataCount");
var data = this.model.get('metadataFormatIDs');
if(metadataCount){
var svgClass = "metadata";
}
else if(!this.model.get('metadataCount') && this.model.get('dataCount')){ //Are we drawing a blank chart (i.e. 0 data objects found)?
var svgClass = "metadata default";
}
else if(!this.model.get('metadataCount') && !this.model.get('dataCount'))
var svgClass = "metadata no-activity";
//If d3 isn't supported in this browser or didn't load correctly, insert a text title instead
if(!d3){
this.$('.format-charts-metadata').html("<h2 class='" + svgClass + " fallback'>" + MetacatUI.appView.commaSeparateNumber(metadataCount) + " metadata files</h2>");
return;
}
//Draw a donut chart
var donut = new DonutChart({
id: "metadata-chart",
data: data,
total: this.model.get('metadataCount'),
titleText: "metadata files",
titleCount: metadataCount,
svgClass: svgClass,
countClass: "metadata",
height: 300,
width: 380,
formatLabel: function(name){
if((name !== undefined) && ((name.indexOf("//ecoinformatics.org") > -1) || (name.indexOf("//eml.ecoinformatics.org") > -1))){
//EML - extract the version only
if((name.substring(0,4) == "eml:") || (name.substring(0,6) == "https:")) name = name.substr(name.lastIndexOf("/")+1).toUpperCase().replace('-', ' ');
//EML modules
if((name.indexOf("-//ecoinformatics.org//eml-") > -1) || (name.indexOf("-//eml.ecoinformatics.org//eml-") > -1)) name = "EML " + name.substring(name.indexOf("//eml-")+6, name.lastIndexOf("-")) + " " + name.substr(name.lastIndexOf("-")+1, 5);
}
//Dryad - shorten it
else if((name !== undefined) && (name == "http://datadryad.org/profile/v3.1")) name = "Dryad 3.1";
//FGDC - just display "FGDC {year}"
else if((name !== undefined) && (name.indexOf("FGDC") > -1)) name = "FGDC " + name.substring(name.length-4);
//Onedcx v1.0
else if((name !== undefined) && (name == "http://ns.dataone.org/metadata/schema/onedcx/v1.0")) name = "Onedcx v1.0";
//GMD-NOAA
else if((name !== undefined) && (name == "http://www.isotc211.org/2005/gmd-noaa")) name = "GMD-NOAA";
//GMD-PANGAEA
else if((name !== undefined) && (name == "http://www.isotc211.org/2005/gmd-pangaea")) name = "GMD-PANGAEA";
if(name === undefined) name = "";
return name;
}
});
this.$('.format-charts-metadata').html(donut.render().el);
},
//drawUploadChart will get the upload stats from the stats model and draw a time series cumulative chart
drawUploadChart: function(){
//Get the width of the chart by using the parent container width
var parentEl = this.$('.upload-chart');
var width = parentEl.width() || null;
//If there was no first upload, draw a blank chart and exit
if( (!this.model.get("metadataUploads") || !this.model.get("metadataUploads").length) && (!this.model.get("dataUploads") || !this.model.get("dataUploads").length) ){
var lineChartView = new LineChart(
{ id: "upload-chart",
yLabel: "files uploaded",
frequency: 0,
width: width
});
this.$('.upload-chart').html(lineChartView.render().el);
return;
}
//Set the frequency of our points
var frequency = 12;
//Check which line we should draw first since the scale will be based off the first line
if(this.model.get("metadataUploads") > this.model.get("dataUploads") ){
//If there isn't a lot of point to graph, draw points more frequently on the line
if(this.model.get("metadataUploadDates").length < 40) frequency = 1;
//Create the line chart and draw the metadata line
var lineChartView = new LineChart(
{ data: this.model.get('metadataUploadDates'),
formatFromSolrFacets: true,
cumulative: true,
id: "upload-chart",
className: "metadata",
yLabel: "files uploaded",
labelValue: "Metadata: ",
width: width,
labelDate: "M-y"
});
this.$('.upload-chart').html(lineChartView.render().el);
//Only draw the data file line if there was at least one uploaded
if(this.model.get("dataUploads")){
//Add a line to our chart for data uploads
lineChartView.className = "data";
lineChartView.labelValue ="Data: ";
lineChartView.addLine(this.model.get('dataUploadDates'));
}
}
else{
var lineChartView = new LineChart(
{ data: this.model.get('dataUploadDates'),
formatFromSolrFacets: true,
cumulative: true,
id: "upload-chart",
className: "data",
yLabel: "files uploaded",
labelValue: "Data: ",
width: width,
labelDate: "M-y"
});
this.$('.upload-chart').html(lineChartView.render().el);
//If no metadata files were uploaded, we don't want to draw the data file line
if(this.model.get("metadataUploads")){
//Add a line to our chart for metadata uploads
lineChartView.className = "metadata";
lineChartView.labelValue = "Metadata: ";
lineChartView.addLine(this.model.get('metadataUploadDates'));
}
}
},
//drawUploadTitle will draw a circle badge title for the uploads time series chart
drawUploadTitle: function(){
//If d3 isn't supported in this browser or didn't load correctly, insert a text title instead
if(!d3){
this.$('#uploads-title').html("<h2 class='packages fallback'>" + MetacatUI.appView.commaSeparateNumber(this.model.get('totalCount')) + "</h2>");
return;
}
if(!this.model.get('dataUploads') && !this.model.get('metadataUploads')){
//Draw the upload chart title
var uploadChartTitle = new CircleBadge({
id: "upload-chart-title",
className: "no-activity",
globalR: 60,
data: [{ count: 0, label: "uploads" }]
});
this.$('#uploads-title').prepend(uploadChartTitle.render().el);
return;
}
//Get information for our upload chart title
var titleChartData = [],
metadataUploads = this.model.get("metadataUploads"),
dataUploads = this.model.get("dataUploads"),
metadataClass = "metadata",
dataClass = "data";
if(metadataUploads == 0) metadataClass = "default";
if(dataUploads == 0) dataClass = "default";
var titleChartData = [
{count: this.model.get("metadataUploads"), label: "metadata", className: metadataClass},
{count: this.model.get("dataUploads"), label: "data", className: dataClass}
];
//Draw the upload chart title
var uploadChartTitle = new CircleBadge({
id: "upload-chart-title",
data: titleChartData,
className: "chart-title",
useGlobalR: true,
globalR: 60
});
this.$('#uploads-title').prepend(uploadChartTitle.render().el);
},
/*
* displayTotalCount - renders a simple count of total metadata files/datasets
*/
displayTotalCount: function(){
var className = "quick-stats-count";
if( !this.model.get("metadataCount") && !this.model.get("dataCount") )
className += " no-activity";
var countEl = $(document.createElement("p"))
.addClass(className)
.text(MetacatUI.appView.commaSeparateNumber(this.model.get("metadataCount")));
var titleEl = $(document.createElement("p"))
.addClass("chart-title")
.text("datasets");
this.$('#total-datasets').html(countEl);
this.$('#total-datasets').append(titleEl);
},
/*
* displayTotalSize renders a count of the total file size of
* all current metadata and data files
*/
displayTotalSize: function(){
var className = "quick-stats-count";
var count = "";
if( !this.model.get("totalSize") ){
count = "0 bytes";
className += " no-activity";
}
else{
count = this.bytesToSize( this.model.get("totalSize") );
}
var countEl = $(document.createElement("p"))
.addClass(className)
.text(count);
var titleEl = $(document.createElement("p"))
.addClass("chart-title")
.text("of content");
this.$('#total-size').html(countEl);
this.$('#total-size').append(titleEl);
},
/**
* Draws both the metadata and data update date charts.
* Note that this function may be deprecated in the future.
* Views should directly call drawMetadataUpdatesChart() or drawDataUpdatesChart() directly,
* since metadata and data dates are fetched via separate AJAX calls.
*/
drawUpdatesChart: function(){
//Draw the metadata and data updates charts
this.drawMetadataUpdatesChart();
this.drawDataUpdatesChart();
},
/**
* Draws a line chart representing the latest metadata updates over time
*/
drawMetadataUpdatesChart: function(){
//Set some configurations for the LineChart
var chartClasses = "data",
data;
//If the number of metadata objects in this data collection is 0, then set the data for the LineChart to null.
// And add a "no-activity" class to the chart.
if( !this.model.get("metadataUpdateDates") || !this.model.get("metadataUpdateDates").length ){
data = null;
chartClasses += " no-activity";
}
else{
//Use the metadata update dates for the LineChart
data = this.model.get('metadataUpdateDates');
}
//Create the line chart for metadata updates
var metadataLineChart = new LineChart({
data: data,
formatFromSolrFacets: true,
cumulative: false,
id: "updates-chart",
className: chartClasses,
yLabel: "metadata files updated",
width: this.$('.metadata-updates-chart').width(),
labelDate: "M-y"
});
//Render the LineChart and insert it into the container element
this.$('.metadata-updates-chart').html(metadataLineChart.render().el);
},
/**
* Draws a line chart representing the latest metadata updates over time
*/
drawDataUpdatesChart: function(){
//Set some configurations for the LineChart
var chartClasses = "data",
view = this,
data;
//Use the data update dates for the LineChart
if(this.model.get("dataCount")){
data = this.model.get('dataUpdateDates');
}
else{
//If the number of data objects in this data collection is 0, then set the data for the LineChart to null.
// And add a "no-activity" class to the chart.
data = null;
chartClasses += " no-activity";
}
//Create the line chart for data updates
var dataLineChart = new LineChart({
data: data,
formatFromSolrFacets: true,
cumulative: false,
id: "updates-chart",
className: chartClasses,
yLabel: "data files updated",
width: this.$('.data-updates-chart').width(),
labelDate: "M-y"
});
//Render the LineChart and insert it into the container element
this.$('.data-updates-chart').html(dataLineChart.render().el);
// redraw the charts to avoid overlap at different widths
$(window).on("resize", function(){
if(!view.hideUpdatesChart)
view.drawUpdatesChart();
});
},
//Draw a bar chart for the temporal coverage
drawCoverageChart: function(e, data){
//Get the width of the chart by using the parent container width
var parentEl = this.$('.temporal-coverage-chart');
if (this.userType == "repository") {
parentEl.addClass("repository-portal-view");
}
var width = parentEl.width() || null;
// If results were found but none have temporal coverage, draw a default chart
if(!this.model.get('temporalCoverage')){
parentEl.html("<p class='subtle center'>There are no metadata documents that describe temporal coverage.</p>");
return;
}
var options = {
data: data,
formatFromSolrFacets: true,
id: "temporal-coverage-chart",
yLabel: "data packages",
yFormat: d3.format(",d"),
barClass: "packages",
roundedRect: true,
roundedRadius: 3,
barLabelClass: "packages",
width: width
};
var barChart = new BarChart(options);
parentEl.html(barChart.render().el);
},
drawCoverageChartTitle: function(){
if((!this.model.get('firstBeginDate')) || (!this.model.get('lastEndDate')) || !this.model.get("temporalCoverage") ) return;
//Create the range query
var yearRange = this.model.get('firstBeginDate').getUTCFullYear() + " - " + this.model.get('lastEndDate').getUTCFullYear();
//Find the year range element
this.$('#data-coverage-year-range').text(yearRange);
},
/*
* Shows that this person/group/node has no activity
*/
showNoActivity: function(){
if( this.model.get("metadataCount") === 0 && this.model.get("dataCount") === 0 ){
this.$(".show-loading .loading").remove();
this.$(".stripe").addClass("no-activity");
this.$(".metric-chart-loading svg animate").remove();
$.each($(".metric-chart-loading .message"), function(i,messageEl){
$(messageEl).html("No metrics to show")
});
}
},
/**
* Convert number of bytes into human readable format
*
* @param integer bytes Number of bytes to convert
* @param integer precision Number of digits after the decimal separator
* @return string
*/
bytesToSize: function(bytes, precision){
var kilobyte = 1024;
var megabyte = kilobyte * 1024;
var gigabyte = megabyte * 1024;
var terabyte = gigabyte * 1024;
if(typeof bytes === "undefined") var bytes = this.get("size");
if ((bytes >= 0) && (bytes < kilobyte)) {
return bytes + ' B';
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
return (bytes / kilobyte).toFixed(precision) + ' KB';
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
return (bytes / megabyte).toFixed(precision) + ' MB';
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
return (bytes / gigabyte).toFixed(precision) + ' GB';
} else if (bytes >= terabyte) {
return (bytes / terabyte).toFixed(precision) + ' TB';
} else {
return bytes + ' B';
}
},
renderUsageMetricsError: function() {
var message = "<p class='check-back-message'><strong>This might take some time. Check back in 24 hours to see these results.</strong></p>";
$.each($('.views-metrics, .downloads-metrics, #user-citations'), function(i,metricEl){
$(metricEl).find(".check-back-message").remove();
$(metricEl).find(".message").append(message);
});
},
/**
* renderMetadataAssessmentError - update the metadata assessment
* pre-loading figure to indicate to the user that the assessment is not
* available at the moment.
*/
renderMetadataAssessmentError: function(){
try {
$("#metadata-assessment-graphic .message").append("<br><strong>This might take some time. Check back in 24 hours to see these results.</strong>")
} catch (e) {
console.log("Error showing the metadata assessment error message in the metrics. " + e);
}
},
/*
* getReplicas gets the number of replicas in this member node
*/
displayTotalReplicas: function(){
var view = this;
var className = "quick-stats-count";
var count;
if( this.model.get("totalReplicas") > 0 ){
count = MetacatUI.appView.commaSeparateNumber(view.model.get("totalReplicas"));
var countEl = $(document.createElement("p"))
.addClass(className)
.text(count);
var titleEl = $(document.createElement("p"))
.addClass("chart-title")
.text("replicas");
// display the totals
this.$('#total-replicas').html(countEl);
this.$('#total-replicas').append(titleEl);
}
else{
// hide the replicas container if the replica count is 0.
this.$('#replicas-container').hide()
}
},
onClose: function () {
//Clear the template
this.$el.html("");
//Stop listening to changes in the model
this.stopListening(this.model);
//Stop listening to resize
$(window).off("resize");
//Reset the stats model
this.model = null;
}
});
return StatsView;
});