forked from jumear/stirfry
-
Notifications
You must be signed in to change notification settings - Fork 0
/
iNat_id_summary_by_category.html
137 lines (127 loc) · 5.75 KB
/
iNat_id_summary_by_category.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
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="iNaturalist Identifications Summary by Category" />
<meta name="viewport" content="width=device-width, minimum-scale=0.6">
<title>iNaturalist Identifications Summary by Category</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; }
a { text-decoration:none; color:royalblue; }
a:hover { background:lightgray; }
tfoot tr { font-weight:600; background:black; color:white; }
</style>
</head>
<body>
<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') || 10;
//let p_page = winurlparams.get('page') || 1;
winurlparams.delete('per_page');
winurlparams.set('per_page',0); // set to 0 since we need only total record counts, not details.
winurlparams.delete('category');
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 fpct(d,p=1) {
x = d*100;
return x.toFixed(p);
};
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 fsettdvalue(rlabel,clabel,val) { document.getElementById(rlabel+'_'+clabel).innerHTML = val; };
function fgetcount(url) {
return fetch(url)
.then((response) => {
if (!response.ok) { throw new Error(response.status+': '+response.statusText); };
return response.json();
})
.then((data) => { return data.total_results; })
.catch((err) => { console.error(err); });
};
let apibase = 'https://api.inaturalist.org/v1/identifications';
let apiurl = apibase+((winurlparams!='')?('?'+winurlparams):'');
let apirefurl = 'https://api.inaturalist.org/v1/docs/#!/Identifications/get_identifications';
let apirefname = 'iNaturalist Identifications Search';
let apiref = furl(apirefurl,apirefname);
let pagetitle = document.title;
faddelem('h1',document.body,{innerText:pagetitle});
faddelem('p',document.body,{innerHTML:'This is the base query: '+furl(famp(apiurl))+'. (This page will accept most parameters from the '+apiref+' API endpoint.)'});
const cOther = 'Other';
const cTotal = 'Total';
let ary_category = [
{description:'Leading',param_value:'leading',fetch:true},
{description:'Improving',param_value:'improving',fetch:true},
{description:'Supporting',param_value:'supporting',fetch:true},
{description:'Maverick',param_value:'maverick',fetch:true},
{description:cOther,param_value:null,fetch:false},
{description:cTotal,param_value:null,fetch:true},
];
let table = faddelem('table',document.body,{id:'main'});
let thead = faddelem('thead',table);
let hrow = faddelem('tr',thead);
let labels = [
{innerText:'Category'},
{classList:'tar',innerText:'Count'},
{classList:'tar',innerText:'Percent'},
];
faddelems('th',hrow,labels);
let tbody = faddelem('tbody',table);
let tfoot = faddelem('tfoot',table);
let data = [];
for (let category of ary_category) {
let description = category.description;
let param_value = category.param_value;
let row = faddelem('tr',(description===cTotal)?tfoot:tbody);
let values = [
{innerText:description},
{classList:'tar',id:description+'_count'},
{classList:'tar',id:description+'_pct'},
];
faddelems('td',row,values);
if (category.fetch) {
if (param_value) { winurlparams.set('category',param_value); }
else { winurlparams.delete('category'); };
let prom0 = Promise.resolve(description);
let prom1 = fgetcount(apibase+'?'+winurlparams);
Promise.all([prom0,prom1]).then(results=>{
let cat = results[0];
let count = results[1] || 0;
fsettdvalue(cat,'count',fcomnum(count));
data.push({category:cat,count:count});
//if this is the last count to be returned, go on and calculate the "Other" category count, and then calculate percents for all categories
if (data.length===(ary_category.filter(v=>v.fetch).length)) {
let ttlcount = data.filter(d=>d.category===cTotal)[0].count;
let plug = data.filter(d=>d.category!==cTotal).reduce((cum,curr)=>cum-curr.count,ttlcount); // subtract non-total counts from total count
fsettdvalue(cOther,'count',fcomnum(plug));
data.push({category:cOther,count:plug});
for (p of data) {
p['pct'] = ttlcount?p.count/ttlcount:null;
fsettdvalue(p.category,'pct',ttlcount?fpct(p.count/ttlcount):'N/A');
};
};
});
};
};
</script>
</body>
</html>