// ==UserScript==
// @name Statistics
// @namespace http://tampermonkey.net/
// @version 4.0.0.1
// @description Shows EyeWire Statistics
// @author Krzysztof Kruk
// @match https://*.eyewire.org/*
// @exclude https://*.eyewire.org/1.0/*
// @downloadURL https://raw.githubusercontent.com/ChrisRaven/EyeWire-Statistics/master/statistics.user.js
// @connect ewstats.heliohost.us
// @require https://chrisraven.github.io/EyeWire-Statistics/jquery-jvectormap-2.0.3.min.js
// @require https://chrisraven.github.io/EyeWire-Statistics/jquery-jvectormap-world-mill.js
// @require https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js
// ==/UserScript==
/*jshint esversion: 6 */
/*globals $, Chart */
var LOCAL = false;
if (LOCAL) {
console.log('%c--== TURN OFF "LOCAL" BEFORE RELEASING!!! ==--', "color: red; font-style: italic; font-weight: bold;");
}
// source: https://eyewire.org/1.0/countries/
const countries = {"af":"Afghanistan","ax":"Aland Islands","al":"Albania","dz":"Algeria","as":"American Samoa","ad":"Andorra","ao":"Angola","ai":"Anguilla","aq":"Antarctica","ag":"Antigua and Barbuda","ar":"Argentina","am":"Armenia","aw":"Aruba","au":"Australia","at":"Austria","az":"Azerbaijan","bs":"Bahamas","bh":"Bahrain","bd":"Bangladesh","bb":"Barbados","by":"Belarus","be":"Belgium","bz":"Belize","bj":"Benin","bm":"Bermuda","bt":"Bhutan","bo":"Bolivia","bq":"Bonaire, Saint Eustatius and Saba","ba":"Bosnia and Herzegovina","bw":"Botswana","br":"Brazil","io":"British Indian Ocean Territory","bn":"Brunei Darussalam","bg":"Bulgaria","bf":"Burkina Faso","bi":"Burundi","kh":"Cambodia","cm":"Cameroon","ca":"Canada","cv":"Cape Verde","ky":"Cayman Islands","cf":"Central African Republic","td":"Chad","cl":"Chile","cn":"China","cx":"Christmas Island","cc":"Cocos (Keeling) Islands","co":"Colombia","km":"Comoros","cg":"Congo","cd":"Congo, The Democratic Republic of the","ck":"Cook Islands","cr":"Costa Rica","ci":"Cote D'Ivoire","hr":"Croatia","cu":"Cuba","cw":"Curacao","cy":"Cyprus","cz":"Czech Republic","dk":"Denmark","dj":"Djibouti","dm":"Dominica","do":"Dominican Republic","ec":"Ecuador","eg":"Egypt","sv":"El Salvador","gq":"Equatorial Guinea","er":"Eritrea","ee":"Estonia","et":"Ethiopia","eu":"Europe","hq":"EyeWire HQ","fk":"Falkland Islands (Malvinas)","fo":"Faroe Islands","fj":"Fiji","fi":"Finland","fr":"France","gf":"French Guiana","pf":"French Polynesia","tf":"French Southern Territories","ga":"Gabon","gm":"Gambia","ge":"Georgia","de":"Germany","gh":"Ghana","gi":"Gibraltar","gr":"Greece","gl":"Greenland","gd":"Grenada","gp":"Guadeloupe","gu":"Guam","gt":"Guatemala","gg":"Guernsey","gn":"Guinea","gw":"Guinea-Bissau","gy":"Guyana","ht":"Haiti","va":"Holy See (Vatican City State)","hn":"Honduras","hk":"Hong Kong","hu":"Hungary","is":"Iceland","in":"India","id":"Indonesia","ir":"Iran, Islamic Republic of","iq":"Iraq","ie":"Ireland","im":"Isle of Man","il":"Israel","it":"Italy","jm":"Jamaica","jp":"Japan","je":"Jersey","jo":"Jordan","kz":"Kazakhstan","ke":"Kenya","ki":"Kiribati","kp":"Korea, Democratic People's Republic of","kr":"Korea, Republic of","kw":"Kuwait","kg":"Kyrgyzstan","la":"Lao People's Democratic Republic","lv":"Latvia","lb":"Lebanon","ls":"Lesotho","lr":"Liberia","ly":"Libya","li":"Liechtenstein","lt":"Lithuania","lu":"Luxembourg","mo":"Macau","mk":"Macedonia","mg":"Madagascar","mw":"Malawi","my":"Malaysia","mv":"Maldives","ml":"Mali","mt":"Malta","mh":"Marshall Islands","mq":"Martinique","mr":"Mauritania","mu":"Mauritius","yt":"Mayotte","mx":"Mexico","fm":"Micronesia, Federated States of","md":"Moldova, Republic of","mc":"Monaco","mn":"Mongolia","me":"Montenegro","ms":"Montserrat","ma":"Morocco","mz":"Mozambique","mm":"Myanmar","na":"Namibia","nr":"Nauru","np":"Nepal","nl":"Netherlands","nc":"New Caledonia","nz":"New Zealand","ni":"Nicaragua","ne":"Niger","ng":"Nigeria","nu":"Niue","nf":"Norfolk Island","mp":"Northern Mariana Islands","no":"Norway","om":"Oman","pk":"Pakistan","pw":"Palau","ps":"Palestinian Territory","pa":"Panama","pg":"Papua New Guinea","py":"Paraguay","pe":"Peru","ph":"Philippines","pn":"Pitcairn Islands","pl":"Poland","pt":"Portugal","pr":"Puerto Rico","qa":"Qatar","re":"Reunion","ro":"Romania","ru":"Russian Federation","rw":"Rwanda","bl":"Saint Barthelemy","sh":"Saint Helena","kn":"Saint Kitts and Nevis","lc":"Saint Lucia","mf":"Saint Martin","pm":"Saint Pierre and Miquelon","vc":"Saint Vincent and the Grenadines","ws":"Samoa","sm":"San Marino","st":"Sao Tome and Principe","sa":"Saudi Arabia","sn":"Senegal","rs":"Serbia","sc":"Seychelles","sl":"Sierra Leone","sg":"Singapore","sx":"Sint Maarten (Dutch part)","sk":"Slovakia","si":"Slovenia","sb":"Solomon Islands","so":"Somalia","za":"South Africa","gs":"South Georgia and the South Sandwich Islands","ss":"South Sudan","es":"Spain","lk":"Sri Lanka","sd":"Sudan","sr":"Suriname","sj":"Svalbard and Jan Mayen","sz":"Swaziland","se":"Sweden","ch":"Switzerland","sy":"Syrian Arab Republic","tw":"Taiwan","tj":"Tajikistan","tz":"Tanzania, United Republic of","th":"Thailand","tl":"Timor-Leste","tg":"Togo","tk":"Tokelau","to":"Tonga","tt":"Trinidad and Tobago","tn":"Tunisia","tr":"Turkey","tm":"Turkmenistan","tc":"Turks and Caicos Islands","tv":"Tuvalu","ug":"Uganda","ua":"Ukraine","ae":"United Arab Emirates","gb":"United Kingdom","us":"United States","um":"United States Minor Outlying Islands","rd":"Unknown","uy":"Uruguay","uz":"Uzbekistan","vu":"Vanuatu","ve":"Venezuela","vn":"Vietnam","vg":"Virgin Islands, British","vi":"Virgin Islands, U.S.","wf":"Wallis and Futuna","eh":"Western Sahara","ye":"Yemen","zm":"Zambia","zw":"Zimbabwe"};
(function() {
'use strict';
'esversion: 6';
var K = {
gid: function (id) {
return document.getElementById(id);
},
qS: function (sel) {
return document.querySelector(sel);
},
qSa: function (sel) {
return document.querySelectorAll(sel);
},
addCSSFile: function (path) {
$("head").append('');
},
reduceArray: function (arr) {
var
total = 0, prop;
for (prop in arr) {
if (arr.hasOwnProperty(prop)) {
total += arr[prop];
}
}
return total;
},
hex: function (x) {
x = x.toString(16);
return (x.length == 1) ? '0' + x : x;
},
JSON_CORS: function (params) {
fetch(params.url, {
method: params.method,
// mode: 'cors'
})
.then(function (response) {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then(function (json) {
params.onload(json);
})
.catch(function (error) {
params.onerror(error);
});
},
date: {
dayLengthInMs: 1000 * 60 * 60 * 24,
// returns date in format of YYYY-MM-DD
ISO8601DateStr: function (date) {
return new Intl.DateTimeFormat('en-CA', {
year: 'numeric',
month: 'numeric',
day: 'numeric'
}).format(date);
},
// returns a string in format YYYY-MM-DD calculated basing on the user time
calculateHqDate: function () {
return new Intl.DateTimeFormat('en-CA', {
timeZone: 'America/New_York',
year: 'numeric',
month: 'numeric',
day: 'numeric'
}).format(Date.now());
},
getWeek: function (date) {
let firstDayOfTheYear = K.date.firstDayOfAYear(date.getFullYear());
let firstWednesday = 7 - firstDayOfTheYear - 3;
if (firstWednesday <= 0) {
firstWednesday += 7;
}
let startOfTheFirstWeek = firstWednesday - 3;
let startOfTheFirstWeekDate = new Date(date.getFullYear(), 0, startOfTheFirstWeek);
let currentWeek = Math.ceil(((date - startOfTheFirstWeekDate) / 86400000) / 7);
return currentWeek;
},
// source: https://stackoverflow.com/a/16353241
isLeapYear: function (year) {
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
},
firstDayOfAYear: function (year) {
// 0 = Sunday, 1 = Monday, etc.
return (new Date(year, 0, 1)).getDay();
},
numberOfWeeksInAYear: function (year) {
// assuming, that week belongs to the year, which contains the middle day
// of that week (which is Wednesday in case of Sun-Mon week)
let firstDay = K.date.firstDayOfAYear(year);
if (firstDay === 3 || K.date.isLeapYear(year) && (firstDay === 2 || firstDay === 4)) {
return 53;
}
return 52;
},
getLast: {
sevenDays: function (asDates = false) {
let result = [];
let currentHqDate = new Date(K.date.calculateHqDate());
let weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
let currentDayOfWeek = currentHqDate.getDay();
let weekLength = 7;
let cursor;
if (asDates) {
cursor = new Date();
cursor.setTime(currentHqDate.getTime() - weekLength * K.date.dayLengthInMs);
while (weekLength--) {
result.push(new Intl.DateTimeFormat('en-CA', {
year: 'numeric',
month: 'numeric',
day: 'numeric'
}).format(cursor));
cursor.setDate(cursor.getDate() + 1);
}
}
else {
cursor = currentDayOfWeek === 0 ? 6 : currentDayOfWeek - 1;
while (weekLength--) {
if (cursor >= 6) {
cursor -= 6;
}
else {
++cursor;
}
result.push(weekdays[cursor]);
}
}
return result;
},
tenWeeks: function (asDates = false) {
let result = [];
let currentHqDate = new Date(K.date.calculateHqDate());
let year = currentHqDate.getFullYear();
let currentWeek = K.date.getWeek(currentHqDate);
let periodLength = 10;
// -1 below, because we want the last day of the period to be the last completed week, not the current one,
// but +1, because we want to start at the first day of the period not from
// before the period started
let starter = currentWeek - periodLength - 1 + 1;
let cursor;
let numberOfWeeksInTheCurrentYear = K.date.numberOfWeeksInAYear(year);
let numberOfWeeksInThePreviousYear = K.date.numberOfWeeksInAYear(year - 1);
if (asDates) {
if (starter <= 0) {
year--;
starter += numberOfWeeksInThePreviousYear;
}
cursor = starter;
while (periodLength--) {
result.push(year + '-' + (cursor < 10 ? '0' : '') + cursor);
++cursor;
if (cursor >= 53) {
if (numberOfWeeksInTheCurrentYear === 52 || cursor === 54) {
cursor = 1;
year++;
}
}
}
}
else {
if (starter <= 0) {
starter += numberOfWeeksInThePreviousYear;
}
cursor = starter;
while (periodLength--) {
result.push(cursor);
++cursor;
if (cursor >= 53) {
if (numberOfWeeksInTheCurrentYear === 52 || cursor === 54) {
cursor = 1;
}
}
}
}
return result;
},
twelveMonths: function (asDates = false) {
let result = [];
let currentHqDate = new Date(K.date.calculateHqDate());
let months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
let currentMonth = currentHqDate.getMonth();
let year = currentHqDate.getFullYear();
let yearLength = 12;
let cursor = currentMonth;
// no matter what, if we substract 12 months from the current date, we'll be in the previous year
--year;
if (asDates) {
result.push(year + '-' + (cursor < 9 ? '0' : '') + (cursor + 1));
--yearLength;
while (yearLength--) {
if (cursor > 11) {
cursor = 0;
++year;
}
else {
++cursor;
}
result.push(year + '-' + (cursor < 9 ? '0' : '') + (cursor + 1));
}
}
else {
result.push(months[cursor]);
--yearLength;
while (yearLength--) {
if (cursor > 11) {
cursor = 0;
}
else {
++cursor;
}
result.push(months[cursor]);
}
}
return result;
}
},
daysInMonth: function (month, year) {
if (['April', 'June', 'September', 'November'].indexOf(month) !== -1) {
return 30;
}
if (month === 'February') {
return K.date.isLeapYear(year) ? 29 : 28;
}
return 31;
},
monthsFullNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
}
};
function StatsPanel() {
var
_this = this,
chart,
dataCurrentlyInUse;
this.map = null;
this.dataType = 'points';
this.timeRange = 'day';
(function addMenuItem() {
var
li, a, list;
li = document.createElement('li');
li.id = 'ewsLinkWrapper';
a = document.createElement('a');
a.id = 'ewsLink';
a.innerHTML = 'Stats';
li.appendChild(a);
list = K.gid('links').getElementsByTagName('ul')[0];
if (list) {
list.insertBefore(li, list.lastChild.previousSibling);
}
})();
// Stats dialog skeleton
$('body').append(
`
`
);
let s = {
day: {
year: K.gid('ewsTRSdayYear'),
month: K.gid('ewsTRSdayMonth'),
day: K.gid('ewsTRSdayDay')
},
week: {
year: K.gid('ewsTRSweekYear'),
week: K.gid('ewsTRSweekWeek')
},
month: {
year: K.gid('ewsTRSmonthYear'),
month: K.gid('ewsTRSmonthMonth')
},
customFrom: {
year: K.gid('ewsTRScustomFromYear'),
month: K.gid('ewsTRScustomFromMonth'),
day: K.gid('ewsTRScustomFromDay')
},
customTo: {
year: K.gid('ewsTRScustomToYear'),
month: K.gid('ewsTRScustomToMonth'),
day: K.gid('ewsTRScustomToDay')
}
};
$('#ewsCustomTimeRangeSelectionDialog')
.dialog({
resizable: false,
width: 400,
height: 'auto',
autoOpen: false,
modal: true,
title: 'Select time range',
dialogClass: 'ews-custom-time-range-selection-dialog',
open: function (evt) {
$('.ui-widget-overlay:last').click(function () {
$('.ews-custom-time-range-selection-dialog').find('.ui-dialog-content').dialog('close');
});
},
buttons: {
'Apply': function () {
let selection = document.querySelector('input[name="radioTimeRangeSelection"]:checked').value;
_this.customRangeType = selection;
switch (selection) {
case 'day':
_this.customDate =
s.day.year.value + '-' +
s.day.month.value + '-' +
s.day.day.value;
break;
case 'week':
_this.customDate =
s.week.year.value + '-' +
s.week.week.value;
break;
case 'month':
_this.customDate =
s.month.year.value + '-' +
s.month.month.value;
break;
case 'custom':
_this.customDate =
s.customFrom.year.value + '-' +
s.customFrom.month.value + '-' +
s.customFrom.day.value + '|' +
s.customTo.year.value + '-' +
s.customTo.month.value + '-' +
s.customTo.day.value;
break;
}
_this.getData();
$(this).dialog('close');
},
'Cancel': function () {
$(this).dialog('close');
}
}
})
.css('display', 'block');
function optionsYears(select) {
let str = '';
for (let i = 2012; i < 2100; i++) {
str += '