Added Session Calendar to Server page (#115 100%)

This commit is contained in:
Rsl1122 2018-03-06 19:58:28 +02:00
parent e2d11e6dfe
commit 517ffa0bcf
9 changed files with 207 additions and 29 deletions

View File

@ -23,6 +23,7 @@ import com.djrapitops.plan.utilities.html.Html;
import com.djrapitops.plan.utilities.html.graphs.ActivityStackGraph; import com.djrapitops.plan.utilities.html.graphs.ActivityStackGraph;
import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph; import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph;
import com.djrapitops.plan.utilities.html.graphs.WorldMap; import com.djrapitops.plan.utilities.html.graphs.WorldMap;
import com.djrapitops.plan.utilities.html.graphs.calendar.ServerCalendar;
import com.djrapitops.plan.utilities.html.graphs.line.*; import com.djrapitops.plan.utilities.html.graphs.line.*;
import com.djrapitops.plan.utilities.html.graphs.pie.ActivityPie; import com.djrapitops.plan.utilities.html.graphs.pie.ActivityPie;
import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
@ -128,6 +129,11 @@ public class AnalysisData extends RawData {
geolocationsTab(geoLocations); geolocationsTab(geoLocations);
commandUsage(commandUsage); commandUsage(commandUsage);
List<Long> registered = profile.getPlayers().stream().map(PlayerProfile::getRegistered).collect(Collectors.toList());
ServerCalendar serverCalendar = new ServerCalendar(registered, sessions);
addValue("calendarSeries", serverCalendar.toCalendarSeries());
addValue("firstDay", 1);
addValue("ops", ops.size()); addValue("ops", ops.size());
addValue("playersTotal", playersTotal); addValue("playersTotal", playersTotal);

View File

@ -25,8 +25,8 @@ import com.djrapitops.plan.utilities.comparators.SessionStartComparator;
import com.djrapitops.plan.utilities.file.FileUtil; import com.djrapitops.plan.utilities.file.FileUtil;
import com.djrapitops.plan.utilities.html.HtmlStructure; import com.djrapitops.plan.utilities.html.HtmlStructure;
import com.djrapitops.plan.utilities.html.HtmlUtils; import com.djrapitops.plan.utilities.html.HtmlUtils;
import com.djrapitops.plan.utilities.html.graphs.PlayerCalendar;
import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph; import com.djrapitops.plan.utilities.html.graphs.PunchCardGraph;
import com.djrapitops.plan.utilities.html.graphs.calendar.PlayerCalendar;
import com.djrapitops.plan.utilities.html.graphs.pie.ServerPreferencePie; import com.djrapitops.plan.utilities.html.graphs.pie.ServerPreferencePie;
import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie; import com.djrapitops.plan.utilities.html.graphs.pie.WorldPie;
import com.djrapitops.plan.utilities.html.structure.ServerAccordion; import com.djrapitops.plan.utilities.html.structure.ServerAccordion;

View File

@ -138,7 +138,8 @@ public class HtmlExport extends SpecificExport {
"web/js/charts/serverPie.js", "web/js/charts/serverPie.js",
"web/js/charts/worldPie.js", "web/js/charts/worldPie.js",
"web/js/charts/healthGauge.js", "web/js/charts/healthGauge.js",
"web/js/charts/sessionCalendar.js" "web/js/charts/sessionCalendar.js",
"web/js/charts/onlineActivityCalendar.js"
}; };
copyFromJar(resources); copyFromJar(resources);

View File

@ -2,7 +2,7 @@
* Licence is provided in the jar as license.yml also here: * Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml * https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/ */
package com.djrapitops.plan.utilities.html.graphs; package com.djrapitops.plan.utilities.html.graphs.calendar;
import com.djrapitops.plan.data.container.PlayerKill; import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.data.container.Session; import com.djrapitops.plan.data.container.Session;

View File

@ -0,0 +1,109 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package com.djrapitops.plan.utilities.html.graphs.calendar;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.utilities.FormatUtils;
import java.util.*;
/**
* Utility for creating FullCalendar calendar event array on Player page.
*
* @author Rsl1122
*/
public class ServerCalendar {
private final List<Long> registerDates;
private final Map<UUID, List<Session>> sessions;
public ServerCalendar(List<Long> registerDates, Map<UUID, List<Session>> sessions) {
this.registerDates = registerDates;
this.sessions = sessions;
}
public String toCalendarSeries() {
StringBuilder series = new StringBuilder("[");
series.append("{title: 'badcode',start:0}");
appendSessionRelatedData(series);
appendRegistered(series);
return series.append("]").toString();
}
private void appendRegistered(StringBuilder series) {
Map<String, Integer> registeredByDay = getRegisteredByDay();
for (Map.Entry<String, Integer> entry : registeredByDay.entrySet()) {
String day = entry.getKey();
Integer newPlayers = entry.getValue();
series.append(",{title: 'New: ").append(newPlayers)
.append("',start:'").append(day)
.append("',color: '#8BC34A'")
.append("}");
}
}
private void appendSessionRelatedData(StringBuilder series) {
Map<String, Map<UUID, List<Session>>> sessionsByDay = getSessionsByDay();
for (Map.Entry<String, Map<UUID, List<Session>>> entry : sessionsByDay.entrySet()) {
String day = entry.getKey();
Map<UUID, List<Session>> sessionsPerUsers = entry.getValue();
long sessionCount = sessionsPerUsers.values().stream().mapToLong(Collection::size).sum();
long playtime = sessionsPerUsers.values().stream().flatMap(Collection::stream).mapToLong(Session::getLength).sum();
long uniquePlayers = sessionsPerUsers.size();
series.append(",{title: 'Playtime: ").append(FormatUtils.formatTimeAmount(playtime))
.append("',start:'").append(day)
.append("',color: '#4CAF50'")
.append("}");
series.append(",{title: 'Sessions: ").append(sessionCount)
.append("',start:'").append(day)
.append("',color: '#009688'")
.append("}");
series.append(",{title: 'Unique: ").append(uniquePlayers)
.append("',start:'").append(day)
.append("'}");
}
}
private Map<String, Map<UUID, List<Session>>> getSessionsByDay() {
Map<String, Map<UUID, List<Session>>> sessionsByDay = new HashMap<>();
for (Map.Entry<UUID, List<Session>> entry : sessions.entrySet()) {
UUID player = entry.getKey();
List<Session> sessions = entry.getValue();
for (Session session : sessions) {
String day = FormatUtils.formatTimeStampISO8601NoClock(session.getSessionStart());
Map<UUID, List<Session>> sessionsPerUserOfDay = sessionsByDay.getOrDefault(day, new HashMap<>());
List<Session> sessionsOfUser = sessionsPerUserOfDay.getOrDefault(player, new ArrayList<>());
sessionsOfUser.add(session);
sessionsPerUserOfDay.put(player, sessionsOfUser);
sessionsByDay.put(day, sessionsPerUserOfDay);
}
}
return sessionsByDay;
}
private Map<String, Integer> getRegisteredByDay() {
Map<String, Integer> RegisteredByDay = new HashMap<>();
for (Long registered : registerDates) {
String day = FormatUtils.formatTimeStampISO8601NoClock(registered);
int registeredPerDay = RegisteredByDay.getOrDefault(day, 0);
registeredPerDay += 1;
RegisteredByDay.put(day, registeredPerDay);
}
return RegisteredByDay;
}
}

View File

@ -0,0 +1,28 @@
function onlineActivityCalendar(id, events, firstDay) {
$(id).fullCalendar({
eventColor: '#2196F3',
firstDay: firstDay,
eventRender: function (eventObj, $el) {
$el.popover({
content: eventObj.title,
trigger: 'hover',
placement: 'top',
container: 'body'
});
},
events: events,
height: 'parent',
header: {
left: 'title',
center: '',
right: 'month prev,next'
}
});
setTimeout(function () {
$(id).fullCalendar('render')
}, 1000);
}

View File

@ -1,7 +1,7 @@
function sessionCalendar(id, events, firstDay) { function sessionCalendar(id, events, firstDay) {
$(id).fullCalendar({ $(id).fullCalendar({
eventColor: '#009688', eventColor: '#009688',
eventLimit: true, eventLimit: 4,
firstDay: firstDay, firstDay: firstDay,
eventRender: function (eventObj, $el) { eventRender: function (eventObj, $el) {
@ -20,7 +20,7 @@ function sessionCalendar(id, events, firstDay) {
header: { header: {
left: 'title', left: 'title',
center: '', center: '',
right: 'month agendaWeek agendaDay prev,next' right: 'month agendaWeek agendaDay today prev,next'
} }
}); });

View File

@ -708,10 +708,8 @@
color: '#222', color: '#222',
data: ${punchCardSeries} data: ${punchCardSeries}
}; };
var calendarSeries =; var calendarSeries = ${calendarSeries};
${calendarSeries} var firstDay = ${firstDay};
var firstDay =
${firstDay}
</script> </script>
<!-- Plan laod script --> <!-- Plan laod script -->

View File

@ -454,12 +454,10 @@
<div class="row clearfix"> <div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6"> <div class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
<div class="card"> <div class="card">
<div class="header"> <div class="body">
<!-- Nav tabs -->
<div class="row clearfix"> <div class="row clearfix">
<div class="col-xs-6 col-sm-6 col-lg-6"> <div class="col-xs-12 col-sm-12 col-lg-12">
<h2><i class="col-blue fa fa-area-chart"></i> Online Activity</h2>
</div>
<div class="col-xs-6 col-sm-6 col-lg-6">
<a href="javascript:void(0)" class="help material-icons pull-right" <a href="javascript:void(0)" class="help material-icons pull-right"
data-trigger="focus" data-toggle="popover" data-placement="left" data-trigger="focus" data-toggle="popover" data-placement="left"
data-container="body" data-html="true" data-container="body" data-html="true"
@ -467,33 +465,62 @@
data-content="Chart of Player Counts, recorded by TPS task. data-content="Chart of Player Counts, recorded by TPS task.
<br><br>TPS task starts 50 seconds after Plan enables and records Maximum player count for each minute." <br><br>TPS task starts 50 seconds after Plan enables and records Maximum player count for each minute."
>help_outline</a> >help_outline</a>
<ul class="nav nav-tabs tab-nav-right" role="tablist">
<li role="presentation" class="active"><a href="#playersOnline"
data-toggle="tab"><i
class="fa fa-area-chart"></i> ONLINE ACTIVITY</a></li>
<li role="presentation"><a href="#uniqueAndNew" data-toggle="tab"><i
class="fa fa-area-chart"></i> UNIQUE PLAYERS</a></li>
</ul>
</div> </div>
</div> </div>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade in active" id="playersOnline">
<div id="playerChartMonth" style="height: 500px;"
class="dashboard-flot-chart"></div>
</div>
<div role="tabpanel" class="tab-pane fade" id="uniqueAndNew">
<div id="uniqueChart" style="height: 500px;" class="dashboard-flot-chart"></div>
</div>
</div> </div>
<div class="body">
<div id="playerChartMonth" class="dashboard-flot-chart"></div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6"> <div class="col-xs-12 col-sm-12 col-md-6 col-lg-6">
<div class="card"> <div class="card">
<div class="header"> <div class="body">
<!-- Nav tabs -->
<div class="row clearfix"> <div class="row clearfix">
<div class="col-xs-6 col-sm-6 col-lg-6"> <div class="col-xs-12 col-sm-12 col-lg-12">
<h2><i class="col-black fa fa-braille"></i> Punchcard</h2>
</div>
<div class="col-xs-6 col-sm-6 col-lg-6">
<a href="javascript:void(0)" class="help material-icons pull-right" <a href="javascript:void(0)" class="help material-icons pull-right"
data-trigger="focus" data-toggle="popover" data-placement="left" data-trigger="focus" data-toggle="popover" data-placement="left"
data-container="body" data-html="true" data-container="body" data-html="true"
data-original-title="Player Join PunchCard" data-original-title="Calendar and Punchcard"
data-content="Chart displays the time and days players usually join the server.<br><br>Unlike Player page punchcard, only the last 30 days are included.<br><br><b>Relative Activity:</b> Size of a dot is relative to amount of sessions started in that hour." data-content="Chart displays the time and days players usually join the server.
<br><br>Unlike Player page punchcard, only the last 30 days are included.
<br><br><b>Relative Activity:</b> Size of a dot is relative to amount of sessions started in that hour."
>help_outline</a> >help_outline</a>
<ul class="nav nav-tabs tab-nav-right" role="tablist">
<li role="presentation" class="active"><a href="#calendarTab"
data-toggle="tab"><i
class="fa fa-calendar"></i> CALENDAR</a></li>
<li role="presentation"><a href="#punchCardTab" data-toggle="tab"><i
class="fa fa-braille"></i> PUNCHCARD</a></li>
</ul>
</div> </div>
</div> </div>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade in active" id="calendarTab">
<div id="calendar" style="height: 500px;" class="dashboard-flot-chart"></div>
</div>
<div role="tabpanel" class="tab-pane fade" id="punchCardTab">
<div id="punchCard" style="height: 500px;" class="dashboard-flot-chart"></div>
</div>
</div> </div>
<div class="body">
<div id="punchCard" class="dashboard-flot-chart"></div>
</div> </div>
</div> </div>
</div> </div>
@ -1086,6 +1113,11 @@
<!-- Header, Sidenav & Skin changer --> <!-- Header, Sidenav & Skin changer -->
<script src="js/admin.js"></script> <script src="js/admin.js"></script>
<!-- FullCalendar -->
<link rel='stylesheet' href='../plugins/fullcalendar/fullcalendar.min.css'/>
<script src='../plugins/momentjs/moment.js'></script>
<script src='../plugins/fullcalendar/fullcalendar.min.js'></script>
<!-- Plan Charts --> <!-- Plan Charts -->
<script src="js/charts/playerGraph.js"></script> <script src="js/charts/playerGraph.js"></script>
<script src="js/charts/punchCard.js"></script> <script src="js/charts/punchCard.js"></script>
@ -1098,6 +1130,7 @@
<script src="js/charts/resourceGraph.js"></script> <script src="js/charts/resourceGraph.js"></script>
<script src="js/charts/worldGraph.js"></script> <script src="js/charts/worldGraph.js"></script>
<script src="js/charts/worldMap.js"></script> <script src="js/charts/worldMap.js"></script>
<script src="js/charts/onlineActivityCalendar.js"></script>
<!-- Chart Data --> <!-- Chart Data -->
<script> <script>
@ -1125,7 +1158,8 @@
}, },
values: { values: {
tpsMed: ${tpsMedium}, tpsMed: ${tpsMedium},
tpsHigh: ${tpsHigh} tpsHigh: ${tpsHigh},
firstDay: ${firstDay}
}, },
data: { data: {
playersOnline: ${playersOnlineSeries}, playersOnline: ${playersOnlineSeries},
@ -1141,7 +1175,8 @@
punchCard: ${punchCardSeries}, punchCard: ${punchCardSeries},
activityStack: ${activityStackSeries}, activityStack: ${activityStackSeries},
activityStackCategories: ${activityStackCategories}, activityStackCategories: ${activityStackCategories},
healthIndex: ${healthIndex} healthIndex: ${healthIndex},
calendar: ${calendarSeries}
} }
}; };
@ -1326,6 +1361,7 @@
worldMap('worldMap', v.colors.geolocationsLow, v.colors.geolocationsHigh, series.geolocations); worldMap('worldMap', v.colors.geolocationsLow, v.colors.geolocationsHigh, series.geolocations);
punchCard('punchCard', series.punchCard); punchCard('punchCard', series.punchCard);
healthGauge('healthGauge', [v.data.healthIndex]); healthGauge('healthGauge', [v.data.healthIndex]);
onlineActivityCalendar('#calendar', v.data.calendar, v.values.firstDay);
${sessionTabGraphViewFunctions} ${sessionTabGraphViewFunctions}
/**/ /**/