Support for HTML output together with a sample CSS style

sql-rework
Tomasz Goliński 2019-11-04 21:13:20 +01:00
rodzic 46a7321434
commit 91fc2ff7e4
4 zmienionych plików z 636 dodań i 25 usunięć

Wyświetl plik

@ -14,6 +14,10 @@ void Cache::show() const {
std::cout << '\t' << pos.lat << " " << pos.lon << "\t\t D/T: " << diff << '/' << terr << '\n';
}
std::string Cache::link() const {
return "http://coord.eu/" + code;
}
float Cache::distance() const {
return 2 * Earth_radius * asin(sqrt(pow(sin(degtorad((pos.lat - home.lat) / 2)), 2) + cos(degtorad(pos.lat)) * cos(degtorad(home.lat)) * pow(sin(degtorad((pos.lon - home.lon) / 2)), 2)));
}

Wyświetl plik

@ -54,6 +54,7 @@ public:
static Position home;
void show() const;
std::string link() const;
float distance() const;
};

517
geo.css 100644
Wyświetl plik

@ -0,0 +1,517 @@
@import url('https://fonts.googleapis.com/css?family=Lato|Special+Elite|Averia+Serif+Libre');
body {
padding: 0px;
margin: 0px;
background: white;
font-family: 'Lato', serif;
font-weight: normal;
font-size: 14px;
}
h1 {
text-align: center;
font-family: 'Averia Serif Libre', serif;
font-size: 34px;
font-weight: bold;
color: #BBB;
}
h2 {
text-align: center;
font-family: 'Special Elite', serif;
font-size: 26px;
font-weight: bold;
color: #48B;
}
table, dl, .histogram_others, .heatmap {
margin-left: auto;
margin-right: auto;
padding-bottom: 20px;
}
.heatmap {
display: block;
}
.dt_head {
font-weight: bold;
}
td {
width: 4em;
background: #CCC;
color: #000;
text-align: center;
}
td.dt_zero {
color: #888;
}
.bar {
font-size: .8em;
line-height: 1;
text-transform: uppercase;
width: 500px;
height: 40px;
margin-left: 200px;
background: repeating-linear-gradient(
to right,
#ddd,
#ddd 1px,
#fff 1px,
#fff 5%
);
}
.bar:after {
content: "";
display: block;
background-color: #48B;
width: 50px;
margin-bottom: 10px;
height: 90%;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.text {
/* font-weight: 600;*/
display: flex;
align-items: center;
height: 40px;
width: 200px;
background-color: white;
position: absolute;
left: 0;
justify-content: flex-end;
}
dl {
display: flex;
background-color: white;
flex-direction: column;
width: 100%;
max-width: 700px;
position: relative;
padding: 20px;
padding-top: 0;
}
.histogram_others {
width: 700px;
}
/*
dt {
align-self: flex-start;
width: 100%;
display: block;
text-align: center;
margin-bottom: 20px;
margin-left: 130px;
}
*/
.bar-1:after {
width: 1%;
}
.bar-2:after {
width: 2%;
}
.bar-3:after {
width: 3%;
}
.bar-4:after {
width: 4%;
}
.bar-5:after {
width: 5%;
}
.bar-6:after {
width: 6%;
}
.bar-7:after {
width: 7%;
}
.bar-8:after {
width: 8%;
}
.bar-9:after {
width: 9%;
}
.bar-10:after {
width: 10%;
}
.bar-11:after {
width: 11%;
}
.bar-12:after {
width: 12%;
}
.bar-13:after {
width: 13%;
}
.bar-14:after {
width: 14%;
}
.bar-15:after {
width: 15%;
}
.bar-16:after {
width: 16%;
}
.bar-17:after {
width: 17%;
}
.bar-18:after {
width: 18%;
}
.bar-19:after {
width: 19%;
}
.bar-20:after {
width: 20%;
}
.bar-21:after {
width: 21%;
}
.bar-22:after {
width: 22%;
}
.bar-23:after {
width: 23%;
}
.bar-24:after {
width: 24%;
}
.bar-25:after {
width: 25%;
}
.bar-26:after {
width: 26%;
}
.bar-27:after {
width: 27%;
}
.bar-28:after {
width: 28%;
}
.bar-29:after {
width: 29%;
}
.bar-30:after {
width: 30%;
}
.bar-31:after {
width: 31%;
}
.bar-32:after {
width: 32%;
}
.bar-33:after {
width: 33%;
}
.bar-34:after {
width: 34%;
}
.bar-35:after {
width: 35%;
}
.bar-36:after {
width: 36%;
}
.bar-37:after {
width: 37%;
}
.bar-38:after {
width: 38%;
}
.bar-39:after {
width: 39%;
}
.bar-40:after {
width: 40%;
}
.bar-41:after {
width: 41%;
}
.bar-42:after {
width: 42%;
}
.bar-43:after {
width: 43%;
}
.bar-44:after {
width: 44%;
}
.bar-45:after {
width: 45%;
}
.bar-46:after {
width: 46%;
}
.bar-47:after {
width: 47%;
}
.bar-48:after {
width: 48%;
}
.bar-49:after {
width: 49%;
}
.bar-50:after {
width: 50%;
}
.bar-51:after {
width: 51%;
}
.bar-52:after {
width: 52%;
}
.bar-53:after {
width: 53%;
}
.bar-54:after {
width: 54%;
}
.bar-55:after {
width: 55%;
}
.bar-56:after {
width: 56%;
}
.bar-57:after {
width: 57%;
}
.bar-58:after {
width: 58%;
}
.bar-59:after {
width: 59%;
}
.bar-60:after {
width: 60%;
}
.bar-61:after {
width: 61%;
}
.bar-62:after {
width: 62%;
}
.bar-63:after {
width: 63%;
}
.bar-64:after {
width: 64%;
}
.bar-65:after {
width: 65%;
}
.bar-66:after {
width: 66%;
}
.bar-67:after {
width: 67%;
}
.bar-68:after {
width: 68%;
}
.bar-69:after {
width: 69%;
}
.bar-70:after {
width: 70%;
}
.bar-71:after {
width: 71%;
}
.bar-72:after {
width: 72%;
}
.bar-73:after {
width: 73%;
}
.bar-74:after {
width: 74%;
}
.bar-75:after {
width: 75%;
}
.bar-76:after {
width: 76%;
}
.bar-77:after {
width: 77%;
}
.bar-78:after {
width: 78%;
}
.bar-79:after {
width: 79%;
}
.bar-80:after {
width: 80%;
}
.bar-81:after {
width: 81%;
}
.bar-82:after {
width: 82%;
}
.bar-83:after {
width: 83%;
}
.bar-84:after {
width: 84%;
}
.bar-85:after {
width: 85%;
}
.bar-86:after {
width: 86%;
}
.bar-87:after {
width: 87%;
}
.bar-88:after {
width: 88%;
}
.bar-89:after {
width: 89%;
}
.bar-90:after {
width: 90%;
}
.bar-91:after {
width: 91%;
}
.bar-92:after {
width: 92%;
}
.bar-93:after {
width: 93%;
}
.bar-94:after {
width: 94%;
}
.bar-95:after {
width: 95%;
}
.bar-96:after {
width: 96%;
}
.bar-97:after {
width: 97%;
}
.bar-98:after {
width: 98%;
}
.bar-99:after {
width: 99%;
}
.bar-100:after {
width: 100%;
}

Wyświetl plik

@ -11,7 +11,9 @@
#include <unistd.h>
#include <map>
void show_histogram(Caches* cc, std::string Cache::*ptr) {
const int HIST_MAX = 20;
void show_histogram(Caches* cc, std::string Cache::*ptr, std::string caption, bool html = 0) {
std::map<std::string, int> histogram;
std::vector<std::pair<std::string, int>> pairs;
for (auto el : *cc)
@ -20,8 +22,31 @@ void show_histogram(Caches* cc, std::string Cache::*ptr) {
pairs.push_back(el);
sort(pairs.begin(), pairs.end(), [=](std::pair<std::string, int>& a, std::pair<std::string, int>& b) { return a.second > b.second; });
for (auto own : pairs)
std::cout << own.first << ": " << own.second << '\n';
if (html) {
int max = pairs[0].second;
int i = 0;
std::cout << "<h2>" << caption << "</h2>\n";
std::cout << "<dl class=\"histogram\">\n";
for (auto own : pairs) {
if (i < HIST_MAX)
std::cout << "<dd class=\"bar bar-" << 100 * own.second / max << "\"><span class=\"text\">" << own.first << ": " << own.second << "</span></dd>\n";
else if (i == HIST_MAX) {
std::cout << "</dl>\n";
std::cout << "<div class=\"histogram_others\">Other: " << own.first;
}
if (i > HIST_MAX)
std::cout << ", " << own.first;
i++;
}
if (i < HIST_MAX)
std::cout << "</dl>\n";
else
std::cout << "</div>\n";
} else {
std::cout << caption << '\n';
for (auto own : pairs)
std::cout << own.first << ": " << own.second << '\n';
}
}
int main(int argc, char** argv) {
@ -31,6 +56,7 @@ int main(int argc, char** argv) {
bool show_dt = 0;
bool show_owners = 0;
bool show_types = 0;
bool show_html = 0;
std::string heat_file;
int heat_stamp_size = 15;
std::string heat_map = "Poland";
@ -46,7 +72,7 @@ int main(int argc, char** argv) {
#include "config_user.h"
int o;
while ((o = getopt(argc, argv, "qng:d:pu:MDOH:s:m:eLTYh?")) != -1)
while ((o = getopt(argc, argv, "qng:d:pu:MDOH:s:m:eLTYWh?")) != -1)
switch (o) {
case 'd':
try {
@ -87,6 +113,9 @@ int main(int argc, char** argv) {
case 'Y':
show_types = 1;
break;
case 'W':
show_html = 1;
break;
case 'H':
heat_file = optarg;
break;
@ -135,10 +164,19 @@ int main(int argc, char** argv) {
std::cout << "\t-T\tprint D/T matrix\n";
std::cout << "\t-O\tprint owner count for found caches\n";
std::cout << "\t-Y\tprint types count for found caches\n";
std::cout << "\t-W\toutput all data in HTML format\n";
std::cout << "\t-h\tdisplay this help screen\n";
std::exit(EXIT_FAILURE);
}
if (show_html) {
show_dist = 0;
show_list = 0;
show_dt = 0;
show_owners = 0;
show_types = 0;
}
Caches cc;
if (use_ocpl) {
@ -171,6 +209,18 @@ int main(int argc, char** argv) {
Debug(2) << "Caches read: " << cc.size() << '\n';
if (show_html) {
std::cout << "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n";
std::cout << "<html>\n";
std::cout << " <head>\n";
std::cout << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"utf-8\">\n";
std::cout << " <link rel=\"stylesheet\" type=\"text/css\" href=\"geo.css\">\n";
std::cout << " <title>Geocaching stats</title>\n";
std::cout << "</head>\n";
std::cout << "<body>\n";
std::cout << "<h1>Geocaching stats for user " << ocpl_user << "<br>Powered by <a href=\"https://gitlab.com/tomaszg/geostat\">GeoStat</a></h1>\n";
}
if (!heat_file.empty()) {
const Map* chosen_map;
if (maps.count(heat_map) > 0)
@ -181,22 +231,39 @@ int main(int argc, char** argv) {
}
Heat hmap(&cc, chosen_map);
hmap.generate(heat_file, heat_stamp_size, (heat_exp == 1 ? "exp" : "soft"));
if (show_html)
std::cout << "<img class=\"heatmap\" src=\"" << heat_file << "\" alt=\"heat map\">\n";
}
if (show_minmax) {
if (show_minmax || show_html) {
auto N = std::max_element(cc.begin(), cc.end(), CacheCmpNS);
auto S = std::min_element(cc.begin(), cc.end(), CacheCmpNS);
auto E = std::max_element(cc.begin(), cc.end(), CacheCmpEW);
auto W = std::min_element(cc.begin(), cc.end(), CacheCmpEW);
std::cout << "Most N:\n";
N->show();
std::cout << "Most S:\n";
S->show();
std::cout << "Most E:\n";
E->show();
std::cout << "Most W:\n";
W->show();
if (show_minmax) {
std::cout << "Most N:\n";
N->show();
std::cout << "Most S:\n";
S->show();
std::cout << "Most E:\n";
E->show();
std::cout << "Most W:\n";
W->show();
} else {
std::cout << "<h2>Geographically extreme caches</h2>\n";
std::cout << "<table class=\"minmax\">\n";
std::cout << "<tr>\n";
std::cout << " <td>North:</td><td><a href=\"" << N->link() << "\"</a>" << N->name << " (" << N->code << ")</a></td><td>" << N->pos.lat << "</td>\n";
std::cout << "</tr><tr>\n";
std::cout << " <td>South:</td><td><a href=\"" << S->link() << "\"</a>" << S->name << " (" << S->code << ")</a></td><td>" << S->pos.lat << "</td>\n";
std::cout << "</tr><tr>\n";
std::cout << " <td>East:</td> <td><a href=\"" << E->link() << "\"</a>" << E->name << " (" << E->code << ")</a></td><td>" << E->pos.lon << "</td>\n";
std::cout << "</tr><tr>\n";
std::cout << " <td>West:</td> <td><a href=\"" << W->link() << "\"</a>" << W->name << " (" << W->code << ")</a></td><td>" << W->pos.lon << "</td>\n";
std::cout << "</tr>\n";
std::cout << "</table>\n";
}
}
if (show_dist) {
@ -214,20 +281,14 @@ int main(int argc, char** argv) {
el.show();
}
if (show_owners) {
std::cout << "Owners:\n";
show_histogram(&cc, &Cache::owner);
if (show_owners || show_html) {
show_histogram(&cc, &Cache::owner, "Cache owners", show_html);
}
if (show_types) {
std::cout << "Types:\n";
show_histogram(&cc, &Cache::type);
std::cout << "\nServices:\n";
show_histogram(&cc, &Cache::origin);
std::cout << "\nRegions:\n";
show_histogram(&cc, &Cache::region);
if (show_types || show_html) {
show_histogram(&cc, &Cache::type, "Cache types", show_html);
if (!show_html) show_histogram(&cc, &Cache::origin, "Services", 0);
show_histogram(&cc, &Cache::region, "Regions", show_html);
}
if (show_dt) {
@ -248,4 +309,32 @@ int main(int argc, char** argv) {
std::cout << '\n';
}
}
if (show_html) {
short dt_table[11][11];
std::cout << "<h2>Difficulty / terrain matrix</h2>\n";
std::cout << "<table class=\"dt\">\n";
std::cout << "<tr class=\"dt_head\"><td></td>";
for (int j = 2; j <= 10; j++) { // print table terr headers
std::cout << "<td>" << j / 2.0 << "</td>";
}
std::cout << "</tr>\n";
for (int i = 2; i <= 10; i++) { // i -> diff in rows
std::cout << "<tr><td class=\"dt_head\">" << i / 2.0 << "</td> ";
for (int j = 2; j <= 10; j++) { // j -> terr in cols
dt_table[i][j] = std::count_if(cc.begin(), cc.end(), [i, j](Cache c) { return (c.diff == i / 2.0 && c.terr == j / 2.0); });
if (dt_table[i][j] == 0)
std::cout << "<td class=\"dt_zero\">" << dt_table[i][j] << "</td>";
else
std::cout << "<td>" << dt_table[i][j] << "</td>";
}
std::cout << "</tr>\n";
}
std::cout << "</table>\n";
}
if (show_html) {
std::cout << "</body>\n</html>\n";
}
}