[2.9.0-DEV] Added demographics tab to analysis page, Bugfixes

Fix #53
Fix #54
This commit is contained in:
Rsl1122 2017-03-18 22:40:14 +02:00
parent 8522e2fb05
commit 43a693403d
11 changed files with 173 additions and 37 deletions

View File

@ -74,7 +74,7 @@ public enum Phrase {
ERROR_NO_DATA_VIEW(ChatColor.YELLOW + "Webserver disabled but Alternative IP/PlanLite not used, no way to view data!"),
ERROR_WEBSERVER_OFF_ANALYSIS(ChatColor.YELLOW + "" + PREFIX + "This command can be only used if the webserver is running on this server."),
ERROR_WEBSERVER_OFF_INSPECT(ChatColor.YELLOW + "" + PREFIX + "This command can be only used if webserver/planlite is enabled on this server."),
ERROR_LOGGED("Caugth "+REPLACE0+". It has been logged to the Errors.txt"),
ERROR_LOGGED("Caught "+REPLACE0+". It has been logged to the Errors.txt"),
ERROR_SESSIONDATA_INITIALIZATION("Player's session was initialized in a wrong way! (" + REPLACE0 + ")"),
//
CMD_FOOTER(COLOR_TER.color() + "" + ARROWS_RIGHT),

View File

@ -1,19 +1,10 @@
package main.java.com.djrapitops.plan.command.commands.manage;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.CommandType;
import main.java.com.djrapitops.plan.command.SubCommand;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.database.databases.SQLiteDB;
import main.java.com.djrapitops.plan.utilities.ManageUtils;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;

View File

@ -10,21 +10,16 @@ import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.CommandType;
import main.java.com.djrapitops.plan.command.SubCommand;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor;
import main.java.com.djrapitops.plan.data.cache.DataCacheHandler;
import main.java.com.djrapitops.plan.data.importing.Importer;
import main.java.com.djrapitops.plan.data.importing.OnTimeImporter;
import main.java.com.djrapitops.plan.utilities.ManageUtils;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import static org.bukkit.Bukkit.getOfflinePlayer;
import static org.bukkit.Bukkit.getOfflinePlayer;
/**
*

View File

@ -1,18 +1,12 @@
package main.java.com.djrapitops.plan.command.commands.manage;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import main.java.com.djrapitops.plan.Phrase;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.command.CommandType;
import main.java.com.djrapitops.plan.command.SubCommand;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.cache.DBCallableProcessor;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.utilities.ManageUtils;
import org.bukkit.command.Command;

View File

@ -44,6 +44,10 @@ public class AnalysisData {
private long totaldeaths;
private long sessionAverage;
private String geomapCountries;
private String geomapZ;
private String geomapCodes;
/**
* Class constructor.
@ -55,11 +59,38 @@ public class AnalysisData {
commandUseTableHtml = Html.ERROR_NOT_SET+"";
top20ActivePlayers = Html.ERROR_NOT_SET+"";
recentPlayers = Html.ERROR_NOT_SET+"";
geomapCountries = Html.ERROR_NOT_SET+"";
geomapZ = Html.ERROR_NOT_SET+"";
geomapCodes = Html.ERROR_NOT_SET+"";
playersDataArray = new String[]{"[0]","[\"No data\"]","[0]","[\"No data\"]","[0]","[\"No data\"]"};
}
// Getters and setters v---------------------------------v
public String getGeomapCountries() {
return geomapCountries;
}
public void setGeomapCountries(String geomapCountries) {
this.geomapCountries = geomapCountries;
}
public String getGeomapZ() {
return geomapZ;
}
public void setGeomapZ(String geomapZ) {
this.geomapZ = geomapZ;
}
public String getGeomapCodes() {
return geomapCodes;
}
public void setGeomapCodes(String geomapCodes) {
this.geomapCodes = geomapCodes;
}
/**
*
* @return

View File

@ -29,6 +29,8 @@ public class RawAnalysisData {
private HashMap<String, Long> playtimes;
private List<SessionData> sessiondata;
private HashMap<String, Integer> commandUse;
private HashMap<String, Integer> geolocations;
private HashMap<String, String> geocodes;
private List<Long> registered;
/**
@ -51,11 +53,42 @@ public class RawAnalysisData {
ages = new ArrayList<>();
latestLogins = new HashMap<>();
playtimes = new HashMap<>();
sessiondata = new ArrayList<>();
sessiondata = new ArrayList<>();
commandUse = new HashMap<>();
geolocations = new HashMap<>();
geocodes = new HashMap<>();
registered = new ArrayList<>();
}
public void addGeoloc(String country) {
if (geolocations.get(country) == null) {
return;
}
geolocations.put(country, geolocations.get(country) + 1);
}
public void fillGeolocations() {
String[] countries = new String[]{"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas, The", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burma", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic of the", "Congo, Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Curacao", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Islas Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "Gabon", "Gambia, The", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea-Bissau", "Guinea", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, North", "Korea, South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia, Federated States of", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Namibia", "Nepal", "Netherlands", "New Caledonia", "New Zealand", "Nicaragua", "Nigeria", "Niger", "Niue", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia", "Saint Martin", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands", "West Bank", "Yemen", "Zambia", "Zimbabwe"};
String[] codes = new String[]{"AFG","ALB","DZA","ASM","AND","AGO","AIA","ATG","ARG","ARM","ABW","AUS","AUT","AZE","BHM","BHR","BGD","BRB","BLR","BEL","BLZ","BEN","BMU","BTN","BOL","BIH","BWA","BRA","VGB","BRN","BGR","BFA","MMR","BDI","CPV","KHM","CMR","CAN","CYM","CAF","TCD","CHL","CHN","COL","COM","COD","COG","COK","CRI","CIV","HRV","CUB","CUW","CYP","CZE","DNK","DJI","DMA","DOM","ECU","EGY","SLV","GNQ","ERI","EST","ETH","FLK","FRO","FJI","FIN","FRA","PYF","GAB","GMB","GEO","DEU","GHA","GIB","GRC","GRL","GRD","GUM","GTM","GGY","GNB","GIN","GUY","HTI","HND","HKG","HUN","ISL","IND","IDN","IRN","IRQ","IRL","IMN","ISR","ITA","JAM","JPN","JEY","JOR","KAZ","KEN","KIR","KOR","PRK","KSV","KWT","KGZ","LAO","LVA","LBN","LSO","LBR","LBY","LIE","LTU","LUX","MAC","MKD","MDG","MWI","MYS","MDV","MLI","MLT","MHL","MRT","MUS","MEX","FSM","MDA","MCO","MNG","MNE","MAR","MOZ","NAM","NPL","NLD","NCL","NZL","NIC","NGA","NER","NIU","MNP","NOR","OMN","PAK","PLW","PAN","PNG","PRY","PER","PHL","POL","PRT","PRI","QAT","ROU","RUS","RWA","KNA","LCA","MAF","SPM","VCT","WSM","SMR","STP","SAU","SEN","SRB","SYC","SLE","SGP","SXM","SVK","SVN","SLB","SOM","ZAF","SSD","ESP","LKA","SDN","SUR","SWZ","SWE","CHE","SYR","TWN","TJK","TZA","THA","TLS","TGO","TON","TTO","TUN","TUR","TKM","TUV","UGA","UKR","ARE","GBR","USA","URY","UZB","VUT","VEN","VNM","VGB","WBG","YEM","ZMB","ZWE"};
for (int i = 0; i < countries.length; i++) {
String country = countries[i];
if (geolocations.get(country) == null) {
geolocations.put(country, 0);
}
if (geocodes.get(country) == null) {
geocodes.put(country, codes[i]);
}
}
}
public HashMap<String, Integer> getGeolocations() {
return geolocations;
}
public HashMap<String, String> getGeocodes() {
return geocodes;
}
/**
*
* @param gmZero

View File

@ -47,7 +47,7 @@ public class Response {
String[] requestArgs = request.getUri().split("/");
boolean forbidden = false;
String securityCode = "";
if (requestArgs.length < 2) {
if (requestArgs.length <= 2) {
forbidden = true;
} else {
securityCode = requestArgs[1];
@ -81,7 +81,7 @@ public class Response {
if (requestHandler.checkIfCached(uuid)) {
try {
String dataHtml = requestHandler.getInspectHtml(uuid);
String htmlDef = "HTTP/1.1 OK\r\n"
String htmlDef = "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "Content-Length: " + dataHtml.length() + "\r\n"
+ "\r\n";
@ -101,7 +101,7 @@ public class Response {
} else if (command.equals("server")) {
if (requestHandler.checkIfAnalysisIsCached()) {
String analysisHtml = requestHandler.getAnalysisHtml();
String htmlDef = "HTTP/1.1 OK\r\n"
String htmlDef = "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "Content-Length: " + analysisHtml.length() + "\r\n"
+ "\r\n";

View File

@ -92,7 +92,8 @@ public class Analysis {
/**
* Caches analyzed data of db to the provided cache analysisCache.
*
* @param analysisCache Cache that will contain AnalysisData result of this method.
* @param analysisCache Cache that will contain AnalysisData result of this
* method.
* @param db Database which data will be analyzed.
* @return Whether or not analysis was successful.
*/
@ -132,6 +133,7 @@ public class Analysis {
log(Phrase.ANALYSIS_BEGIN_ANALYSIS + "");
AnalysisData analysisData = new AnalysisData();
analysisData.setSortablePlayersTable(AnalysisUtils.createSortablePlayersTable(rawData));
sorted.fillGeolocations();
// Fill Dataset with userdata.
rawData.parallelStream().forEach((uData) -> {
try {
@ -176,12 +178,14 @@ public class Analysis {
sorted.addTotalDeaths(uData.getDeaths());
sorted.getSessiondata().addAll(uData.getSessions());
sorted.getRegistered().add(uData.getRegistered());
sorted.addGeoloc(uData.getDemData().getGeoLocation());
uData.stopAccessing();
} catch (NullPointerException e) {
plugin.logError(Phrase.DATA_CORRUPTION_WARN.parse(uData.getUuid() + ""));
plugin.toLog(this.getClass().getName(), e);
}
});
});
createCloroplethMap(analysisData, sorted.getGeolocations(), sorted.getGeocodes());
// Analyze & Save RawAnalysisData to AnalysisData
createPlayerActivityGraphs(analysisData, sorted.getSessiondata(), sorted.getRegistered());
analysisData.setRecentPlayers(RecentPlayersButtonsCreator.createRecentLoginsButtons(sorted.getLatestLogins(), 20));
@ -276,4 +280,26 @@ public class Analysis {
plugin.log(msg);
}
}
private void createCloroplethMap(AnalysisData aData, HashMap<String, Integer> geolocations, HashMap<String, String> geocodes) {
String locations = "[";
String z = "[";
String text = "[";
for (String c : geolocations.keySet()) {
locations += "\""+c+"\"" + ",";
z += geolocations.get(c) + ",";
String code = geocodes.get(c);
if (code != null) {
text += "\""+code+"\"" + ",";
} else {
text += "\"UNK\",";
}
}
locations += "]";
z += "]";
text += "]";
aData.setGeomapCountries(locations.replace(",]", "]"));
aData.setGeomapZ(z.replace(",]", "]"));
aData.setGeomapCodes(text.replace(",]", "]"));
}
}

View File

@ -2,17 +2,14 @@ package main.java.com.djrapitops.plan.utilities;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.SessionData;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.ui.Html;
import main.java.com.djrapitops.plan.ui.tables.SortableCommandUseTableCreator;
import main.java.com.djrapitops.plan.ui.tables.SortablePlayersTableCreator;
import main.java.com.djrapitops.plan.utilities.comparators.MapComparator;
/**
*

View File

@ -99,6 +99,9 @@ public class PlaceholderUtils {
+ "\",\"#" + Settings.HCOLOR_GMP_2 + "\",\"#" + Settings.HCOLOR_GMP_3 + "\"");
replaceMap.putAll(plugin.getHookHandler().getAdditionalAnalysisReplaceRules());
replaceMap.put("%sessionaverage%", FormatUtils.formatTimeAmount(data.getSessionAverage() + ""));
replaceMap.put("%geomapcountries%", data.getGeomapCountries());
replaceMap.put("%geomapz%", data.getGeomapZ());
replaceMap.put("%geomapcodes%", data.getGeomapCodes());
return replaceMap;
}

View File

@ -7,6 +7,7 @@
<meta name="author" content="Rsl1122">
<link rel="icon" href="https://puu.sh/tK0KL/6aa2ba141b.ico" type="image/x-icon" />
<script src="https://use.fontawesome.com/df48eb908b.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<style>
* {
box-sizing: border-box;
@ -89,13 +90,13 @@
content: " \25B4\25BE"
}
#wrapper {
width: 400%;
width: 500%;
transform: translate3d(0, 0, 0);
transition: transform .5s ease-in-out;
}
.content {
float: left;
width: 25%;
width: 20%;
height: 100%;
white-space: normal;
background-repeat: no-repeat;
@ -201,9 +202,10 @@
<div id="navLinks">
<ul>
<li class="itemLinks" data-pos="0px"><i class="fa fa-info-circle" aria-hidden="true"></i> Information</li>
<li class="itemLinks" data-pos="-25%"><i class="fa fa-bar-chart" aria-hidden="true"></i> Online Activity</li>
<li class="itemLinks" data-pos="-50%"><i class="fa fa-list-alt" aria-hidden="true"></i> Playerlist</li>
<li class="itemLinks" data-pos="-75%"><i class="fa fa-terminal" aria-hidden="true"></i> Command usage</li>
<li class="itemLinks" data-pos="-20%"><i class="fa fa-bar-chart" aria-hidden="true"></i> Online Activity</li>
<li class="itemLinks" data-pos="-40%"><i class="fa fa-list-alt" aria-hidden="true"></i> Playerlist</li>
<li class="itemLinks" data-pos="-60%"><i class="fa fa-terminal" aria-hidden="true"></i> Command usage</li>
<li class="itemLinks" data-pos="-80%"><i class="fa fa-globe" aria-hidden="true"></i> Demographics</li>
</ul>
</div>
<div id="contentContainer">
@ -526,8 +528,31 @@
</tbody>
</table>
</div>
</div>
</div></div>
<div class="content">
<div class="headerbox">
<div class="header-icon">
<div class="header-label"><i class="fa fa-globe" aria-hidden="true"></i><span class="header-text"> Demographics</span></div>
</div>
<div class="infobox" style="float: right;">
<div class="info-icon">
<i class="fa fa-globe" aria-hidden="true"></i>
</div>
<div class="info-text">
<div class="info-number">
0
</div>
<div class="info-label">
Temp
</div>
</div>
</div>
</div>
<div class="column" style="width:50%;">
<div style="width:100%;"><div id="cloropleth"></div></div>
</div>
</div>
</div> <!--wrapper-->
</div></div> <!--contentcontainer, clearfix-->
</body>
<script src="http://www.kryogenix.org/code/browser/sorttable/sorttable.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
@ -707,6 +732,47 @@
}
});
</script>
<script>
CLOROPLETH = document.getElementById('cloropleth');
var data = [{
type: 'choropleth',
locationmode: "country names",
locations: %geomapcountries%,
z: %geomapz%,
text: %geomapcodes%,
colorscale: [
[0,'rgb(38, 127, 0)'],[1,'rgb(220, 220, 220)']],
autocolorscale: false,
reversescale: true,
marker: {
line: {
color: 'rgb(100,100,100)',
width: 0.5
}
},
tick0: 0,
zmin: 0,
dtick: 1000,
colorbar: {
autotic: false,
tickprefix: '',
title: 'Players'
}
}];
var layout = {
title: 'Geographic locations',
autosize: true,
geo:{
showframe: false,
showcoastlines: false,
projection:{
type: 'mercator'
}
}
};
Plotly.plot(CLOROPLETH, data, layout, {showLink: false});
</script>
<script>
// Script for the page navigation buttons
var links = document.querySelectorAll(".itemLinks");