forked from jumear/stirfry
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iNat_identifier_stats.html
145 lines (140 loc) · 7.82 KB
/
iNat_identifier_stats.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="iNaturalist Identifier Stats" />
<meta name="viewport" content="width=device-width, minimum-scale=0.6">
<title>iNaturalist Identifier Stats</title>
<style>
html,body { font:14px Sans-Serif; }
#main { width:100%; }
table, thead, tbody, tr, td, th { margin:0; padding:4px; border-width:1px 0px;border-style:solid; border-color:lightgray; border-spacing:0; border-collapse:collapse; }
th { position:-webkit-sticky /*Safari*/; position:sticky; top:0; font-weight:600; background:forestgreen; color:white; text-align:left; vertical-align:bottom; }
tr { background:whitesmoke; }
tr:nth-child(even) { background-color:white; }
.tar { text-align:right; }
.icon { height:48px; width:48px; border-radius:50%; }
.photo { height:64px; width:64px; }
img { margin:0; padding:0; border:0; }
a { text-decoration:none; color:royalblue; }
a:hover { background:lightgray; }
</style>
</head>
<body>
<form action="javascript:fgetuser()">
<input type='text' id="input_user" placeholder='Input a User ID here' />
<input type='submit' value='Get Identifier Stats' />
</form>
<hr />
<script>
let winurlstr = window.location.href;
let winurlsearchstr = window.location.search;
let winurlexsearchstr = winurlstr.replace(winurlsearchstr,'');
let winurlparams = new URLSearchParams(winurlsearchstr.substring(1));
//let p_per_page = winurlparams.get('per_page') || 200;
//let p_page = winurlparams.get('page') || 1;
let input_user = document.getElementById('input_user');
let p_user_id = winurlparams.get('user_id');
if (p_user_id) {
input_user.value = p_user_id;
fresults();
}
else {
faddelem('p',document.body,{innerText:'Input a valid User Login or ID, and click the button to retrieve identifier stats. Alternatively, you may select a user by adding user_id as a query parameter in the URL. Note that user logins input into the text input field on the page will be automatically translated to lowercase. In the rare cases of users with mixed-case logins, those can be searched by querying for user_id=[Login] in the URL or by searching using a numeric ID.'});
};
function furl(url,txt=url) { return '<a href="'+url+'">'+txt+'</a>'; };
function famp(str) { return str.replace(/&/g,'&'); };
function fcomnum(n) { return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g,',') };
function faddelem(etype,eparent=null,eattributes={}) {
let eobj = document.createElement(etype);
for (let [key,value] of Object.entries(eattributes)) {
if ( typeof value === 'object' && value !== null ) {
for (let [subkey,subvalue] of Object.entries(value)) { eobj[key][subkey] = subvalue; };
}
else { eobj[key] = value; };
};
if (eparent) { eparent.appendChild(eobj); };
return eobj;
};
function faddelems(etype,eparent=null,eattributes=[]) { for (let e of eattributes) { faddelem(etype,eparent,e); }; };
function faddtr(tparent,td=[]) {
let row = faddelem('tr',tparent);
faddelems('td',row,td);
};
function fISOdate(s) {
let d = s.split(/\D+/);
let o = (s.search('[\+]')>=0)?-1:1;
return new Date(Date.UTC(d[0], d[1]-1 /*months:0-11*/, d[2], d[3], d[4], d[5]) + ((d[6]||0)*3600000*o) + ((d[7]||0)*60000*o) ); // iNat dates don't come with milliseconds
};
function fparamdate(n) {
d = new Date(n);
function fpad(num) { return num.toString().padStart(2,'0') };
return fpad(d.getFullYear())+'-'+fpad(d.getMonth()+1)+'-'+fpad(d.getDate())+'T'+fpad(d.getHours())+':'+fpad(d.getMinutes())+':'+fpad(d.getSeconds());
};
function ffetch(url) {
return fetch(url)
.then((response) => {
if (!response.ok) { throw new Error(response.status+': '+response.statusText); };
return response.json();
})
.catch((err) => { console.error(err); });
};
function fgetuser() {
if (input_user.value.length === 0) { document.location.href=winurlexsearchstr }
else {
winurlparams.set('user_id',input_user.value.toLowerCase());
input_user.value = p_user_id;
document.location.href=winurlexsearchstr+'?'+winurlparams;
};
};
function fresults() {
let div_main = document.getElementById('main');
if (div_main) { div_main.remove(); }
div_main = faddelem('div',document.body,{id:'main'});
let user_id = input_user.value
let urlsumbycat = 'iNat_id_summary_by_category.html';
let urlsumbyic = 'iNat_id_counts_by_iconic_taxa.html';
let urlids = 'iNatAPIv1_identifications.html'
let apibase = 'https://api.inaturalist.org/v1/';
let date_curr = new Date();
let prom_user = ffetch(apibase + 'users/' + user_id);
let prom_id_all = ffetch(apibase + 'identifications?per_page=0&only_id=true&user_id=' + user_id);
let prom_id_others = ffetch(apibase + 'identifications?per_page=0&only_id=true&own_observation=false&user_id=' + user_id);
let prom_id_last = ffetch(apibase + 'identifications?per_page=1&only_id=false¤t=any&is_change=false&user_id=' + user_id);
//let prom_id_t24hrs = ffetch(apibase + 'identifications?per_page=0&only_id=true&is_change=false&user_id=' + user_id +'&d1=' + fparamdate(date_curr-(1000*60*60*24)));
Promise.all([prom_user,prom_id_all,prom_id_others,prom_id_last/*,prom_id_t24hrs*/])
.then(req=>{
if (!req[0]) {
faddelem('p',div_main,{innerText:'No data found. Input a valid User Login or ID and try again.'});
return false;
}
else {
let user = req[0].results[0];
let id_all = req[1].total_results || user.identifications_count || 0 ;
let id_others = req[2].total_results || user.identifications_count || 0 ;
let date_last_id = (req[3].results && req[3].results[0]) ? fISOdate(req[3].results[0].created_at) : 'N/A';
let diff_last_id = (date_curr-date_last_id) / 1000 / 60 / 60 / 24;
//let id_t24hrs = req[4].total_results;
let date_join = fISOdate(user.created_at);
let diff_days = (date_curr-date_join) / 1000 / 60 / 60 / 24;
if (user.icon_url) { faddelem('img',div_main,{src:user.icon_url}); };
let table = faddelem('table',div_main);
let tbody = faddelem('tbody',table);
faddtr(tbody,[{innerText:'User Login:'},{innerHTML:furl('https://www.inaturalist.org/people/'+user.login,user.login)}]);
faddtr(tbody,[{innerText:'User ID:'},{innerText:user.id}]);
if (user.name) { faddtr(tbody,[{innerText:'User Name:'},{innerText:user.name}]); };
faddtr(tbody,[{innerText:'Current Date:'},{innerText:date_curr.toString()}]);
faddtr(tbody,[{innerText:'Date of Last ID:'},{innerText:date_last_id.toString()}]);
faddtr(tbody,[{innerText:'Days Since Last ID:'},{innerText:diff_last_id?fcomnum(diff_last_id.toFixed(2)):'N/A'}]);
faddtr(tbody,[{innerText:'Date Joined:'},{innerText:date_join.toString()}]);
faddtr(tbody,[{innerText:'Days Since Joining:'},{innerText:fcomnum(diff_days.toFixed(2))}]);
faddtr(tbody,[{innerText:'IDs (all):'},{innerHTML:fcomnum(id_all)+' ( view: '+furl(urlids+'?per_page=100&user_id='+user.id,'detail')+' | '+furl(urlsumbycat+'?user_id='+user.id,'by category')+' | '+furl(urlsumbyic+'?user_id='+user.id,'by iconic taxa')+' )'}]);
faddtr(tbody,[{innerText:'IDs (for others):'},{innerHTML:fcomnum(id_others)+' ( view: '+furl(urlids+'?per_page=100&own_observation=false&user_id='+user.id,'detail')+' | '+furl(urlsumbycat+'?own_observation=false&user_id='+user.id,'by category')+' | '+furl(urlsumbyic+'?own_observation=false&user_id='+user.id,'by iconic taxa')+' )'}]);
faddtr(tbody,[{innerText:'IDs (for others) per day:'},{innerText:fcomnum((id_others/diff_days).toFixed(2))}]);
//faddtr(tbody,[{innerText:'IDs (all) last 24hrs:'},{innerHTML:fcomnum(id_t24hrs)}]);
};
});
};
</script>
</body>
</html>