Added geolocations to query results

This commit is contained in:
Risto Lahtela 2021-01-19 10:22:15 +02:00
parent 19dc55ad26
commit 8ee28e07dd
4 changed files with 95 additions and 12 deletions

View File

@ -36,6 +36,7 @@ import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityInde
import com.djrapitops.plan.storage.database.queries.filter.Filter;
import com.djrapitops.plan.storage.database.queries.filter.FilterQuery;
import com.djrapitops.plan.storage.database.queries.filter.QueryFilters;
import com.djrapitops.plan.storage.database.queries.objects.GeoInfoQueries;
import com.djrapitops.plan.storage.database.queries.objects.playertable.QueryTablePlayersQuery;
import com.djrapitops.plan.storage.json.JSONStorage;
import com.djrapitops.plan.utilities.java.Maps;
@ -146,12 +147,21 @@ public class QueryJSONResolver implements Resolver {
long before = dateFormat.parse(viewJSON.beforeDate + " " + viewJSON.beforeTime).getTime();
Database database = dbSystem.getDatabase();
return Maps.builder(String.class, Object.class)
.put("players", getPlayersTableData(playerUUIDs, after, before))
.put("activity", getActivityGraphData(playerUUIDs, after, before))
.put("geolocation", getGeolocationData(playerUUIDs))
.build();
}
private Map<String, Object> getGeolocationData(Set<UUID> playerUUIDs) {
Database database = dbSystem.getDatabase();
return graphJSONCreator.createGeolocationJSON(
database.query(GeoInfoQueries.networkGeolocationCounts(playerUUIDs))
);
}
private Map<String, Object> getActivityGraphData(Set<UUID> playerUUIDs, long after, long before) {
Database database = dbSystem.getDatabase();
Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD);
@ -164,8 +174,7 @@ public class QueryJSONResolver implements Resolver {
activityData.put(time, database.query(NetworkActivityIndexQueries.fetchActivityIndexGroupingsOn(time, threshold, playerUUIDs)));
}
Map<String, Object> activityGraphJSON = graphJSONCreator.createActivityGraphJSON(activityData);
return activityGraphJSON;
return graphJSONCreator.createActivityGraphJSON(activityData);
}
private Map<String, Object> getPlayersTableData(Set<UUID> playerUUIDs, long after, long before) {

View File

@ -23,6 +23,7 @@ import com.djrapitops.plan.storage.database.queries.QueryStatement;
import com.djrapitops.plan.storage.database.sql.tables.GeoInfoTable;
import com.djrapitops.plan.storage.database.sql.tables.UserInfoTable;
import com.djrapitops.plan.utilities.java.Lists;
import org.apache.commons.text.TextStringBuilder;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -157,6 +158,37 @@ public class GeoInfoQueries {
};
}
public static Query<Map<String, Integer>> networkGeolocationCounts(Collection<UUID> playerUUIDs) {
String subQuery1 = SELECT +
GeoInfoTable.USER_UUID + ", " +
GeoInfoTable.GEOLOCATION + ", " +
GeoInfoTable.LAST_USED +
FROM + GeoInfoTable.TABLE_NAME +
WHERE + GeoInfoTable.USER_UUID + " IN ('" +
new TextStringBuilder().appendWithSeparators(playerUUIDs, "','").build() + "')";
String subQuery2 = SELECT +
GeoInfoTable.USER_UUID + ", " +
"MAX(" + GeoInfoTable.LAST_USED + ") as m" +
FROM + GeoInfoTable.TABLE_NAME +
GROUP_BY + GeoInfoTable.USER_UUID;
String sql = SELECT + GeoInfoTable.GEOLOCATION + ", COUNT(1) as c FROM " +
"(" + subQuery1 + ") AS q1" +
INNER_JOIN + "(" + subQuery2 + ") AS q2 ON q1.uuid = q2.uuid" +
WHERE + GeoInfoTable.LAST_USED + "=m" +
GROUP_BY + GeoInfoTable.GEOLOCATION;
return new QueryAllStatement<Map<String, Integer>>(sql) {
@Override
public Map<String, Integer> processResults(ResultSet set) throws SQLException {
Map<String, Integer> geolocationCounts = new HashMap<>();
while (set.next()) {
geolocationCounts.put(set.getString(GeoInfoTable.GEOLOCATION), set.getInt("c"));
}
return geolocationCounts;
}
};
}
public static Query<Map<String, Integer>> serverGeolocationCounts(UUID serverUUID) {
String selectGeolocations = SELECT +
GeoInfoTable.USER_UUID + ", " +

View File

@ -313,6 +313,10 @@ function runQuery() {
data: json.data.players.data,
order: [[5, "desc"]]
});
const activityIndexHeader = document.querySelector("#DataTables_Table_0 thead th:nth-of-type(2)");
const lastSeenHeader = document.querySelector("#DataTables_Table_0 thead th:nth-of-type(6)");
activityIndexHeader.innerHTML += ` (${json.view.beforeDate})`
lastSeenHeader.innerHTML += ` (view)`
// Activity graphs
const activity_data = json.data.activity;
@ -320,13 +324,31 @@ function runQuery() {
name: 'Players', colorByPoint: true, data: activity_data.activity_pie_series
});
stackChart('activityStackGraph', activity_data.activity_labels, activity_data.activity_series, 'Players');
const activityIndexHeader = document.querySelector("#DataTables_Table_0 thead th:nth-of-type(2)");
const lastSeenHeader = document.querySelector("#DataTables_Table_0 thead th:nth-of-type(6)");
document.querySelector("#activity-date").innerHTML = json.view.beforeDate;
activityIndexHeader.innerHTML += ` (${json.view.beforeDate})`
lastSeenHeader.innerHTML += ` (view)`
// Geolocations
const geolocation_data = json.data.geolocation;
const geolocationSeries = {
name: 'Players',
type: 'map',
mapData: Highcharts.maps['custom/world'],
data: geolocation_data.geolocation_series,
joinBy: ['iso-a3', 'code']
};
const geolocationBarSeries = {
color: geolocation_data.colors.bars,
name: 'Players',
data: geolocation_data.geolocation_bar_series.map(function (bar) {
return bar.value
})
};
const geolocationBarCategories = geolocation_data.geolocation_bar_series.map(function (bar) {
return bar.label
});
worldMap('worldMap', geolocation_data.colors.low, geolocation_data.colors.high, geolocationSeries);
horizontalBarChart('countryBarChart', geolocationBarCategories, [geolocationBarSeries], 'Players');
});
}
@ -337,12 +359,12 @@ function renderDataResultScreen(resultCount, view) {
const beforeTime = filterView.beforeTime ? filterView.beforeTime : view.beforeTime;
document.querySelector('#content .tab').innerHTML =
`<div class="container-fluid mt-4">
<!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800"><i class="sidebar-toggler fa fa-fw fa-bars"></i>Plan &middot;
Query Results</h1>
<p class="mb-0 text-gray-800">(matched ${resultCount} players)</p>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-lg-12">
<div class="card shadow mb-4">
@ -361,6 +383,7 @@ function renderDataResultScreen(resultCount, view) {
</div>
</div>
</div>
<div class="row">
<div class="col-xl-8 col-lg-8 col-sm-12">
<div class="card shadow mb-4">
@ -372,7 +395,6 @@ function renderDataResultScreen(resultCount, view) {
<div class="chart-area" id="activityStackGraph"></div>
</div>
</div>
<div class="col-xl-4 col-lg-4 col-sm-12">
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
@ -384,5 +406,25 @@ function renderDataResultScreen(resultCount, view) {
</div>
</div>
</div>
<div class="row">
<div class="col-xl-12 col-lg-12 col-sm-12">
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
<h6 class="m-0 font-weight-bold col-black"><i
class="fas fa-fw fa-globe col-green"></i>
Geolocations</h6>
</div>
<div class="chart-area row" style="height: 100%;">
<div class="col-xs-12 col-sm-12 col-md-3 col-lg-3">
<div id="countryBarChart"></div>
</div>
<div class="col-xs-12 col-sm-12 col-md-9 col-lg-9">
<div id="worldMap"></div>
</div>
</div>
</div>
</div>
</div>
</div>`;
}

View File

@ -946,7 +946,7 @@
joinBy: ['iso-a3', 'code']
};
var geolocationBarSeries = {
color: '#4CAF50',
color: json.colors.bars,
name: 'Players',
data: json.geolocation_bar_series.map(function (bar) {
return bar.value
@ -955,7 +955,7 @@
var geolocationBarCategories = json.geolocation_bar_series.map(function (bar) {
return bar.label
});
worldMap('worldMap', v.colors.geolocationsLow, v.colors.geolocationsHigh, geolocationSeries);
worldMap('worldMap', json.colors.low, json.colors.high, geolocationSeries);
horizontalBarChart('countryBarChart', geolocationBarCategories, [geolocationBarSeries], 'Players');
} else if (error) {
$('#worldMap').text("Failed to load graph data: " + error);