analytics: Clean up graph styling.

This fixes a number of issues in the prototype /stats graphs, including:

* Adding a Total Users number to the Users graph.
* Changing the Messages sent over time graph so that the bot
trace is hidden by default.
* Fades out the last bars in the weekly view to represent unfinished
ata.
* Sets the default view to weekly only if the realm is > 12 weeks old.
* Gets rid of the tooltips and replaces them with hover text
for the Number of Users graph.
* Fixes a bug in the legend colors for the Messages Over Time
graph.
* It also adds the year to the hover text.
* Sets the pie chart colors and adds spaces between sectors.
* Changes the font to Humbug.
This commit is contained in:
Amy Liu
2017-02-01 16:07:41 -08:00
committed by Tim Abbott
parent 12e7be585d
commit 24f0716df3
3 changed files with 215 additions and 48 deletions

View File

@@ -24,14 +24,15 @@ function floor_to_local_week(date) {
return date_copy; return date_copy;
} }
function messages_sent_over_time_traces(dates, values, type, date_formatter) { function messages_sent_over_time_traces(dates, values, type,
date_formatter, human_colors, bot_colors) {
var text = dates.map(function (date) { var text = dates.map(function (date) {
return date_formatter(date); return date_formatter(date);
}); });
var common = { x: dates, type: type, hoverinfo: 'none', text: text, visible: true}; var common = { x: dates, type: type, hoverinfo: 'none', text: text};
return { return {
human: $.extend({ name: "Humans", y: values.human, marker: {color: '#1f77b4'}}, common), human: $.extend({ name: "Humans", y: values.human, marker: {color: human_colors}, visible: true}, common),
bot: $.extend({ name: "Bots", y: values.bot, marker: {color: '#ff7f00'}}, common), bot: $.extend({ name: "Bots", y: values.bot, marker: {color: bot_colors}, visible: 'legendonly'}, common),
}; };
} }
@@ -39,6 +40,7 @@ function format_date(date, include_hour) {
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var month_str = months[date.getMonth()]; var month_str = months[date.getMonth()];
var year = date.getFullYear();
var day = date.getDate(); var day = date.getDate();
if (include_hour) { if (include_hour) {
var hour = date.getHours(); var hour = date.getHours();
@@ -54,7 +56,7 @@ function format_date(date, include_hour) {
} }
return month_str + ' ' + day + ', ' + hour_str; return month_str + ' ' + day + ', ' + hour_str;
} }
return month_str + ' ' + day; return month_str + ' ' + day + ', ' + year;
} }
function messages_sent_over_time_rangeselector( function messages_sent_over_time_rangeselector(
@@ -108,6 +110,16 @@ function messages_sent_over_time_layout() {
x: 0.75, x: 0.75,
y: 1.12, y: 1.12,
orientation: 'h', orientation: 'h',
font: {
family: 'Humbug',
size: 14,
color: '#000000',
},
},
font: {
family: 'Humbug',
size: 14,
color: '#000000',
}, },
}; };
} }
@@ -117,11 +129,37 @@ function hover(id) {
myPlot.on('plotly_hover', function (data) { myPlot.on('plotly_hover', function (data) {
var date_text = data.points[0].data.text[data.points[0].pointNumber]; var date_text = data.points[0].data.text[data.points[0].pointNumber];
$('#hover_date').text(date_text); $('#hover_date').text(date_text);
var humans_visible = false;
var humans_trace_index = null;
var bots_visible = false;
var bots_trace_index = null;
for (var i = 0; i < data.points.length; i += 1) {
if (data.points[i].fullData.name === "Bots" && data.points[i].fullData.visible === true) {
bots_visible = true;
bots_trace_index = i;
} else if (data.points[i].fullData.name === "Humans" && data.points[i].fullData.visible === true) {
humans_visible = true;
humans_trace_index = i;
}
}
if (humans_visible) {
$('#hover_humans').show();
$('#hover_humans_value').show();
$('#hover_humans').text("Humans:"); $('#hover_humans').text("Humans:");
$('#hover_humans_value').text(data.points[0].y); $('#hover_humans_value').text(data.points[humans_trace_index].y);
} else {
$('#hover_humans').hide();
$('#hover_humans_value').hide();
}
if (bots_visible) {
$('#hover_bots').show();
$('#hover_bots_value').show();
$('#hover_bots').text("Bots:"); $('#hover_bots').text("Bots:");
$('#hover_bots_value').text(data.points[1].y); $('#hover_bots_value').text(data.points[bots_trace_index].y);
} else {
$('#hover_bots').hide();
$('#hover_bots_value').hide();
}
// var human_colors = data.points[0].data.x.map(function () { // var human_colors = data.points[0].data.x.map(function () {
// return '#1f77b4'; // return '#1f77b4';
// }); // });
@@ -146,6 +184,12 @@ function hover(id) {
// }); // });
} }
function fix_legend_colors() {
var legendBoxes = document.getElementById('id_messages_sent_over_time').getElementsByClassName("legendbar");
Plotly.d3.select(legendBoxes[0]).style("fill", "#1f77b4");
Plotly.d3.select(legendBoxes[1]).style("fill", "#ff7f00");
}
function populate_messages_sent_over_time(data) { function populate_messages_sent_over_time(data) {
if (data.end_times.length === 0) { if (data.end_times.length === 0) {
// TODO: do something nicer here // TODO: do something nicer here
@@ -198,21 +242,30 @@ function populate_messages_sent_over_time(data) {
var date_formatter = function (date) { var date_formatter = function (date) {
return format_date(date, true); return format_date(date, true);
}; };
var hourly_traces = messages_sent_over_time_traces(start_dates, data.realm, 'bar', date_formatter); var hourly_traces = messages_sent_over_time_traces(start_dates, data.realm, 'bar', date_formatter, '#1f77b4', '#ff7f00');
var info = aggregate_data('day'); var info = aggregate_data('day');
date_formatter = function (date) { date_formatter = function (date) {
return format_date(date, false); return format_date(date, false);
}; };
var daily_traces = messages_sent_over_time_traces(info.dates, info.values, 'bar', date_formatter); var daily_traces = messages_sent_over_time_traces(info.dates, info.values, 'bar', date_formatter, '#1f77b4', '#ff7f00');
info = aggregate_data('week'); info = aggregate_data('week');
date_formatter = function (date) { date_formatter = function (date) {
// return i18n.t("Week of __date__", {date: format_date(date, false)}); // return i18n.t("Week of __date__", {date: format_date(date, false)});
return "Week of " + format_date(date, false); return "Week of " + format_date(date, false);
}; };
var weekly_traces = messages_sent_over_time_traces(info.dates, info.values, 'bar', date_formatter); var human_colors = info.dates.map(function () {
return '#1f77b4';
});
var bot_colors = info.dates.map(function () {
return '#ff7f00';
});
human_colors[info.dates.length-1] = '#66b0e5';
bot_colors[info.dates.length-1] = '#ffa64d';
var weekly_traces = messages_sent_over_time_traces(info.dates, info.values, 'bar', date_formatter, human_colors, bot_colors);
var dates = data.end_times.map(function (timestamp) { var dates = data.end_times.map(function (timestamp) {
return new Date(timestamp*1000); return new Date(timestamp*1000);
}); });
@@ -220,7 +273,7 @@ function populate_messages_sent_over_time(data) {
date_formatter = function (date) { date_formatter = function (date) {
return format_date(date, true); return format_date(date, true);
}; };
var cumulative_traces = messages_sent_over_time_traces(dates, values, 'scatter', date_formatter); var cumulative_traces = messages_sent_over_time_traces(dates, values, 'scatter', date_formatter, '#1f77b4', '#ff7f00');
// Generate plot // Generate plot
var layout = messages_sent_over_time_layout(); var layout = messages_sent_over_time_layout();
@@ -228,9 +281,18 @@ function populate_messages_sent_over_time(data) {
0.68, -0.62, 10, 'Last 10 Days', 'day', 30, 'Last 30 Days', 'day'); 0.68, -0.62, 10, 'Last 10 Days', 'day', 30, 'Last 30 Days', 'day');
layout.xaxis.rangeselector = default_rangeselector; layout.xaxis.rangeselector = default_rangeselector;
if (info.dates.length < 12) {
Plotly.newPlot('id_messages_sent_over_time', Plotly.newPlot('id_messages_sent_over_time',
[daily_traces.human, daily_traces.bot], layout, {displayModeBar: false}); [daily_traces.human, daily_traces.bot], layout, {displayModeBar: false});
$('#daily_button').css('background', '#D8D8D8');
} else {
Plotly.newPlot('id_messages_sent_over_time',
[weekly_traces.human, weekly_traces.bot], layout, {displayModeBar: false});
$('#weekly_button').css('background', '#D8D8D8');
}
hover('id_messages_sent_over_time'); hover('id_messages_sent_over_time');
fix_legend_colors();
// Click handlers for aggregation buttons // Click handlers for aggregation buttons
var clicked_cumulative = false; var clicked_cumulative = false;
@@ -275,6 +337,13 @@ function populate_messages_sent_over_time(data) {
update_plot_on_aggregation_click(rangeselector, weekly_traces); update_plot_on_aggregation_click(rangeselector, weekly_traces);
$(this).css('background', '#D8D8D8'); $(this).css('background', '#D8D8D8');
clicked_cumulative = false; clicked_cumulative = false;
fix_legend_colors();
$('.legend').click(function () {
fix_legend_colors();
});
$('.rangeselector').click(function () {
fix_legend_colors();
});
}); });
$('#cumulative_button').click(function () { $('#cumulative_button').click(function () {
@@ -283,6 +352,14 @@ function populate_messages_sent_over_time(data) {
$(this).css('background', '#D8D8D8'); $(this).css('background', '#D8D8D8');
clicked_cumulative = true; clicked_cumulative = true;
}); });
$('.legend').click(function () {
fix_legend_colors();
});
$('.rangeselector').click(function () {
fix_legend_colors();
});
} }
function throw_error(msg) { function throw_error(msg) {
@@ -302,14 +379,25 @@ $.get({
}, },
}); });
function users_hover(id) {
var myPlot = document.getElementById(id);
myPlot.on('plotly_hover', function (data) {
var date_text = data.points[0].data.text[data.points[0].pointNumber];
$('#users_hover_date').text(date_text);
$('#users_hover_humans').text("Users:");
$('#users_hover_humans_value').text(data.points[0].y);
});
}
function populate_number_of_users(data) { function populate_number_of_users(data) {
var end_dates = data.end_times.map(function (timestamp) { var end_dates = data.end_times.map(function (timestamp) {
return new Date(timestamp*1000); return new Date(timestamp*1000);
}); });
var trace_humans = {x: end_dates, y: data.realm.human, type: 'bar', name: "Active users", var users_text = end_dates.map(function (date) {
hoverinfo: 'y', text: '', visible: true}; return format_date(date, false);
});
var trace_humans = {x: end_dates, y: data.realm.human, type: 'scatter', name: "Active users",
hoverinfo: 'none', text: users_text, visible: true};
var layout = { var layout = {
width: 750, width: 750,
height: 370, height: 370,
@@ -317,6 +405,7 @@ function populate_number_of_users(data) {
l: 40, r: 0, b: 100, t: 20, l: 40, r: 0, b: 100, t: 20,
}, },
xaxis: { xaxis: {
fixedrange: true,
rangeselector: { rangeselector: {
x: 0.808, x: 0.808,
y: -0.2, y: -0.2,
@@ -336,9 +425,18 @@ function populate_number_of_users(data) {
fixedrange: true, fixedrange: true,
rangemode: 'tozero', rangemode: 'tozero',
}, },
font: {
family: 'Humbug',
size: 14,
color: '#000000',
},
}; };
Plotly.newPlot('id_number_of_users', Plotly.newPlot('id_number_of_users',
[trace_humans], layout, {displayModeBar: false}); [trace_humans], layout, {displayModeBar: false});
users_hover('id_number_of_users');
var total_users = data.realm.human[data.realm.human.length - 1];
var total = document.getElementById('number_of_users_total');
total.innerHTML = total_users.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} }
$.get({ $.get({
@@ -359,12 +457,16 @@ function make_pie_trace(data, values, labels, text) {
labels: labels, labels: labels,
type: 'pie', type: 'pie',
direction: 'clockwise', direction: 'clockwise',
rotation: -180, rotation: -90,
sort: false, sort: false,
// textposition: textposition, // textposition: textposition,
textinfo: "text", textinfo: "text",
text: text, text: text,
hoverinfo: "label+text", hoverinfo: "label+text",
pull: 0.1,
marker: {
colors: ['#137061', '#0e836f', '#13a188', '#2bbba2', '#51d5be', '#7ce4d3'],
},
}]; }];
return trace; return trace;
} }
@@ -477,10 +579,15 @@ function populate_messages_sent_by_client(data) {
}, },
width: 450, width: 450,
height: 300, height: 300,
font: {
family: 'Humbug',
size: 14,
color: '#000000',
},
}; };
Plotly.newPlot('id_messages_sent_by_client', trace, layout, {displayModeBar: false}); Plotly.newPlot('id_messages_sent_by_client', trace, layout, {displayModeBar: false});
var total = document.getElementById('pie1_total'); var total = document.getElementById('pie_messages_sent_by_client_total');
total.innerHTML = "Total messages: " + total.innerHTML = "Total messages: " +
realm_total_cumulative.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); realm_total_cumulative.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -664,7 +771,7 @@ function populate_messages_sent_by_message_type(data) {
var trace = make_pie_trace(data, realm_values_cumulative, var trace = make_pie_trace(data, realm_values_cumulative,
realm_labels_cumulative, realm_text_cumulative); realm_labels_cumulative, realm_text_cumulative);
var total = document.getElementById('pie2_total'); var total = document.getElementById('pie_messages_sent_by_type_total');
total.innerHTML = "Total messages: " + total.innerHTML = "Total messages: " +
realm_total_cumulative.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); realm_total_cumulative.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -674,6 +781,11 @@ function populate_messages_sent_by_message_type(data) {
}, },
width: 465, width: 465,
height: 300, height: 300,
font: {
family: 'Humbug',
size: 14,
color: '#000000',
},
}; };
Plotly.newPlot('id_messages_sent_by_message_type', trace, layout, {displayModeBar: false}); Plotly.newPlot('id_messages_sent_by_message_type', trace, layout, {displayModeBar: false});

View File

@@ -4,18 +4,27 @@
max-width: none; max-width: none;
} }
body {
font-family: 'Humbug', 'Helvetica Neue', sans-serif !important;
}
p { p {
margin-bottom: 0px; margin-bottom: 0px;
} }
svg {
-webkit-font-smoothing: antialiased;
}
.alert { .alert {
display: none; display: none;
} }
.analytics-page-header { .analytics-page-header {
margin-top: 20px; margin-top: 30px;
margin-bottom: 50px; margin-bottom: 50px;
text-align: center; text-align: center;
font-size: 36px;
} }
.sidebar { .sidebar {
@@ -40,7 +49,7 @@ p {
.nav-link { .nav-link {
display: block; display: block;
font-size: 16px; font-size: 17px;
margin-left: 25px; margin-left: 25px;
} }
@@ -58,20 +67,16 @@ p {
.graph-title { .graph-title {
text-align: center; text-align: center;
font-size: 22px; font-size: 20px;
margin-bottom: 30px; margin-bottom: 30px;
} }
#button_label {
font-size: 12px;
}
#graph_container { #graph_container {
position: relative; position: relative;
} }
#button_label { #button_label {
font-size: 16px; font-size: 15px;
margin-left: 40px; margin-left: 40px;
margin-bottom: 0px; margin-bottom: 0px;
} }
@@ -101,7 +106,7 @@ p {
} }
.button { .button {
font-family: 'Humbug', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-family: 'Humbug', 'Helvetica Neue', sans-serif !important;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
outline: none; outline: none;
@@ -112,7 +117,7 @@ p {
} }
.pie-button { .pie-button {
font-family: 'Humbug', 'Helvetica Neue', Helvetica, Arial, sans-serif; font-family: 'Humbug', 'Helvetica Neue', sans-serif !important;
font-weight: inherit; font-weight: inherit;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
@@ -132,8 +137,7 @@ p {
#hourly_button { #hourly_button {
padding: 0px 5px 0px 5px; padding: 0px 5px 0px 5px;
font-size: 13.5px; font-size: 14px;
font-weight: 600px !important;
margin-left: 40px; margin-left: 40px;
margin-top: 0px; margin-top: 0px;
background: #F0F0F0; background: #F0F0F0;
@@ -141,21 +145,21 @@ p {
#daily_button { #daily_button {
padding: 0px 5px 0px 5px; padding: 0px 5px 0px 5px;
font-size: 13.5px; font-size: 14px;
margin-top: 0px; margin-top: 0px;
background: #D8D8D8; background: #F0F0F0;
} }
#weekly_button { #weekly_button {
padding: 0px 5px 0px 5px; padding: 0px 5px 0px 5px;
font-size: 13.5px; font-size: 14px;
margin-top: 0px; margin-top: 0px;
background: #F0F0F0; background: #F0F0F0;
} }
#cumulative_button { #cumulative_button {
padding: 0px 5px 0px 5px; padding: 0px 5px 0px 5px;
font-size: 13.5px; font-size: 14px;
margin-top: 0px; margin-top: 0px;
background: #F0F0F0; background: #F0F0F0;
} }
@@ -234,15 +238,57 @@ p {
} }
#pie_messages_sent_by_client_total { #pie_messages_sent_by_client_total {
font-size: 15px; font-size: 14px;
text-align: left; text-align: left;
margin: 0px 0px 10px 5px; margin: 0px 0px 5px 45px;
} }
#pie_messages_sent_by_type_total { #pie_messages_sent_by_type_total {
font-size: 15px; font-size: 14px;
text-align: left; text-align: left;
margin: 0px 0px 10px 50px; margin: 0px 0px 5px 53px;
}
#users_hover_info {
position: relative;
top: -65px;
height: 0;
width: 400px;
z-index: 1;
font-size: 14px;
margin-left: 20px;
}
#users_hover_date {
font-weight: 400;
margin-left: 18px;
}
#users_hover_humans {
font-weight: 400;
margin-left: 18px;
}
#users_total {
position: relative;
top: -65px;
height: 0;
width: 400px;
z-index: 1;
font-size: 13px;
margin-left: 320px;
}
#number_of_users {
font-weight: 400;
margin-left: 20px;
}
#number_of_users_total {
top: -65px;
font-size: 13px;
text-align: left;
margin: 0px 0px 8px 0px;
} }
@media (max-width: 1127px) { @media (max-width: 1127px) {

View File

@@ -8,7 +8,7 @@
<body> <body>
<div class="sidebar"> <div class="sidebar">
<nav class="nav"> <nav class="nav">
<p class="nav-subtitle">Messages</p> <p class="nav-subtitle">Messages Sent</p>
<a href="#messages_timescale_anchor" class="nav-link">Messages Sent Over Time</a> <a href="#messages_timescale_anchor" class="nav-link">Messages Sent Over Time</a>
<a href="#messages_by_client_anchor" class="nav-link">Messages Sent by Client</a> <a href="#messages_by_client_anchor" class="nav-link">Messages Sent by Client</a>
<a href="#messages_by_type_anchor" class="nav-link">Messages Sent by Recipient Type</a> <a href="#messages_by_type_anchor" class="nav-link">Messages Sent by Recipient Type</a>
@@ -45,7 +45,7 @@
<div id="pie_messages_sent_by_client"> <div id="pie_messages_sent_by_client">
<p class="graph-title" id="messages_by_client_anchor">Messages Sent by Client</p> <p class="graph-title" id="messages_by_client_anchor">Messages Sent by Client</p>
<div id="id_messages_sent_by_client"></div> <div id="id_messages_sent_by_client"></div>
<div id="pie1_total"> </div> <div id="pie_messages_sent_by_client_total"> </div>
<button class="pie-button" type="button" id='messages_by_client_user_button'> Me </button> <button class="pie-button" type="button" id='messages_by_client_user_button'> Me </button>
<button class="pie-button" type="button" id='messages_by_client_realm_button'> Everyone </button> <button class="pie-button" type="button" id='messages_by_client_realm_button'> Everyone </button>
<button class="pie-button" type="button" id='messages_by_client_ten_days_button'> Last 10 Days </button> <button class="pie-button" type="button" id='messages_by_client_ten_days_button'> Last 10 Days </button>
@@ -55,7 +55,7 @@
<div id="pie_messages_sent_by_type"> <div id="pie_messages_sent_by_type">
<p class="graph-title" id="messages_by_type_anchor">Messages Sent by Recipient Type</p> <p class="graph-title" id="messages_by_type_anchor">Messages Sent by Recipient Type</p>
<div id="id_messages_sent_by_message_type"></div> <div id="id_messages_sent_by_message_type"></div>
<div id="pie2_total"> </div> <div id="pie_messages_sent_by_type_total"> </div>
<button class="pie-button" type="button" id='messages_by_type_user_button'> Me </button> <button class="pie-button" type="button" id='messages_by_type_user_button'> Me </button>
<button class="pie-button" type="button" id='messages_by_type_realm_button'> Everyone </button> <button class="pie-button" type="button" id='messages_by_type_realm_button'> Everyone </button>
<button class="pie-button" type="button" id='messages_by_type_ten_days_button'> Last 10 Days </button> <button class="pie-button" type="button" id='messages_by_type_ten_days_button'> Last 10 Days </button>
@@ -67,6 +67,15 @@
<div class="center-block"> <div class="center-block">
<p class="graph-title" id="users_anchor">Number of Users</p> <p class="graph-title" id="users_anchor">Number of Users</p>
<div id="id_number_of_users"></div> <div id="id_number_of_users"></div>
<div id="users_hover_info">
<span id="users_hover_date"></span>
<span id="users_hover_humans"></span>
<span id="users_hover_humans_value"></span>
</div>
<div id="users_total">
<span id="number_of_users">Total Users:</span>
<span id="number_of_users_total"> </span>
</div>
</div> </div>
</div> </div>
</div> </div>