mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2024-11-04 01:39:35 +01:00
Fix webserver being unable to respond due to open socket -> endless inputstream.
(Introduced in 7e03c1dcc0
)
Fix #179
Attempts to use scatter graph for inspect page, code still needs refining.
This commit is contained in:
parent
7a4edcac03
commit
3769c303fb
@ -1,47 +1,29 @@
|
||||
package main.java.com.djrapitops.plan.ui.html.graphs;
|
||||
|
||||
import main.java.com.djrapitops.plan.Plan;
|
||||
import main.java.com.djrapitops.plan.Settings;
|
||||
import main.java.com.djrapitops.plan.data.SessionData;
|
||||
import main.java.com.djrapitops.plan.data.TPS;
|
||||
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.MiscUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.analysis.MathUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.analysis.Point;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rsl1122
|
||||
*/
|
||||
public class PlayerActivityGraphCreator {
|
||||
|
||||
@Deprecated
|
||||
public static String[] generateArray(List<TPS> tpsData, long scale) {
|
||||
long now = MiscUtils.getTime();
|
||||
List<TPS> filtered = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).collect(Collectors.toList());
|
||||
String players = filtered.stream().map(TPS::getPlayers).collect(Collectors.toList()).toString();
|
||||
String dates = filtered.stream().map(TPS::getDate).collect(Collectors.toList()).toString();
|
||||
return new String[]{players, dates};
|
||||
}
|
||||
|
||||
public static String buildScatterDataString(List<TPS> tpsData, long scale) {
|
||||
long now = MiscUtils.getTime();
|
||||
List<Point> points = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).map(tps -> new Point(tps.getDate(), tps.getPlayers())).collect(Collectors.toList());
|
||||
List<Point> points = tpsData.stream()
|
||||
.filter(tps -> tps.getDate() >= now - scale)
|
||||
.map(tps -> new Point(tps.getDate(), tps.getPlayers()))
|
||||
.collect(Collectors.toList());
|
||||
return ScatterGraphCreator.scatterGraph(points, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sessionData
|
||||
* @param scale
|
||||
* @return
|
||||
*/
|
||||
public static String[] generateDataArray(List<SessionData> sessionData, long scale) {
|
||||
public static String buildScatterDataStringSessions(List<SessionData> sessionData, long scale) {
|
||||
long now = MiscUtils.getTime();
|
||||
long nowMinusScale = now - scale;
|
||||
List<List<Long>> s = filterAndTransformSessions(sessionData, nowMinusScale);
|
||||
@ -53,52 +35,26 @@ public class PlayerActivityGraphCreator {
|
||||
sessionStarts.add(nowMinusScale);
|
||||
}
|
||||
|
||||
Map<Long, Integer> change = transformIntoChangeMap(sessionStarts, sessionEnds);
|
||||
|
||||
long lastPValue = 0;
|
||||
long lastSavedPValue = -1;
|
||||
long lastSaveIndex = 0;
|
||||
List<Long> playersOnline = new ArrayList<>();
|
||||
List<String> labels = new ArrayList<>();
|
||||
for (long i = nowMinusScale / 1000; i <= now / 1000; i += 1) {
|
||||
long index = i * 1000;
|
||||
boolean contains = change.containsKey(index);
|
||||
boolean isBelowMinimumScaleThreshold = index - lastSaveIndex > (scale / (long) 75);
|
||||
if (!(contains || isBelowMinimumScaleThreshold)) {
|
||||
continue;
|
||||
}
|
||||
if (contains) {
|
||||
lastPValue += change.get(index);
|
||||
}
|
||||
if (isBelowMinimumScaleThreshold || lastSavedPValue != lastPValue) {
|
||||
lastSaveIndex = index;
|
||||
labels.add("\"" + FormatUtils.formatTimeStamp(index) + "\"");
|
||||
lastSavedPValue = lastPValue;
|
||||
playersOnline.add(lastPValue);
|
||||
}
|
||||
}
|
||||
if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) {
|
||||
long average = MathUtils.averageLong(playersOnline.stream());
|
||||
double standardDeviation = getStandardDeviation(playersOnline, average);
|
||||
if (standardDeviation > 3.5) {
|
||||
for (int i = 0; i < playersOnline.size(); i++) {
|
||||
long value = playersOnline.get(i);
|
||||
if (value - average > 3 * standardDeviation) {
|
||||
playersOnline.set(i, (long) Plan.getInstance().getVariable().getMaxPlayers() + 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new String[]{playersOnline.toString(), labels.toString()};
|
||||
Map<Long, Integer> changeMap = transformIntoChangeMap(sessionStarts, sessionEnds);
|
||||
List<Point> points = getPointsFromChangeMap(changeMap);
|
||||
return ScatterGraphCreator.scatterGraph(points, false);
|
||||
}
|
||||
|
||||
private static double getStandardDeviation(List<Long> players, long avg) {
|
||||
List<Double> valueMinusAvg = players.stream()
|
||||
.map(p -> Math.pow(Math.abs(p - avg), 2))
|
||||
.collect(Collectors.toList());
|
||||
int size = valueMinusAvg.size();
|
||||
double sum = MathUtils.sumDouble(valueMinusAvg.stream().map(p -> (Serializable) p));
|
||||
return Math.sqrt(sum / size);
|
||||
private static List<Point> getPointsFromChangeMap(Map<Long, Integer> changeMap) {
|
||||
List<Point> points = new ArrayList<>();
|
||||
int lastIndex = -1;
|
||||
for (Long key : changeMap.keySet()) {
|
||||
long date = key;
|
||||
int change = changeMap.get(key);
|
||||
if (change != 0) {
|
||||
int previousValue = 0;
|
||||
if (lastIndex >= 0) {
|
||||
previousValue = (int) points.get(lastIndex).getY();
|
||||
}
|
||||
points.add(new Point(date, previousValue+change));
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
private static Map<Long, Integer> transformIntoChangeMap(List<Long> sessionStarts, List<Long> sessionEnds) {
|
||||
@ -121,20 +77,15 @@ public class PlayerActivityGraphCreator {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param values
|
||||
* @param lookFor
|
||||
* @return
|
||||
*/
|
||||
public static long getCount(List<Long> values, long lookFor) {
|
||||
return Collections.frequency(values, lookFor);
|
||||
// values.stream()
|
||||
// .filter((start) -> (start == lookFor))
|
||||
// .count();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sessionData
|
||||
* @param nowMinusScale
|
||||
* @return
|
||||
@ -162,7 +113,6 @@ public class PlayerActivityGraphCreator {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ms
|
||||
* @return
|
||||
*/
|
||||
|
@ -1,14 +1,13 @@
|
||||
package main.java.com.djrapitops.plan.ui.html.graphs;
|
||||
|
||||
import main.java.com.djrapitops.plan.data.TPS;
|
||||
import main.java.com.djrapitops.plan.utilities.FormatUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.MiscUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.analysis.Point;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import main.java.com.djrapitops.plan.Log;
|
||||
import main.java.com.djrapitops.plan.data.TPS;
|
||||
import main.java.com.djrapitops.plan.utilities.Benchmark;
|
||||
import main.java.com.djrapitops.plan.utilities.MiscUtils;
|
||||
import main.java.com.djrapitops.plan.utilities.analysis.Point;
|
||||
import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -17,22 +16,12 @@ import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator;
|
||||
*/
|
||||
public class TPSGraphCreator {
|
||||
|
||||
public static String[] generateDataArray(List<TPS> tpsData, long scale) {
|
||||
Benchmark.start("TPSGraph: generate array");
|
||||
long now = MiscUtils.getTime();
|
||||
List<TPS> filtered = filterTPS(tpsData, now - scale);
|
||||
Log.debug("TPSGraph, filtered: " + filtered.size());
|
||||
filtered.sort(new TPSComparator());
|
||||
List<Long> dates = filtered.stream().map(TPS::getDate).collect(Collectors.toList());
|
||||
List<Double> tps = filtered.stream().map(TPS::getTps).collect(Collectors.toList());
|
||||
List<Integer> players = filtered.stream().map(TPS::getPlayers).collect(Collectors.toList());
|
||||
Benchmark.stop("TPSGraph: generate array");
|
||||
return new String[]{dates.toString(), tps.toString(), players.toString()};
|
||||
}
|
||||
|
||||
public static String buildScatterDataStringTPS(List<TPS> tpsData, long scale) {
|
||||
long now = MiscUtils.getTime();
|
||||
List<Point> points = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).map(tps -> new Point(tps.getDate(), tps.getTps())).collect(Collectors.toList());
|
||||
List<Point> points = tpsData.stream()
|
||||
.filter(tps -> tps.getDate() >= now - scale)
|
||||
.map(tps -> new Point(tps.getDate(), Double.parseDouble(FormatUtils.cutDecimals(tps.getTps()).replace(",", "."))))
|
||||
.collect(Collectors.toList());
|
||||
return ScatterGraphCreator.scatterGraph(points, true);
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,12 @@ import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a HTTP Request.
|
||||
*
|
||||
* <p>
|
||||
* Request is read from the given InputStream.
|
||||
*
|
||||
* <p>
|
||||
* Closing the Request closes the InputStream. (Closing Socket InputStream
|
||||
* closes the socket.)
|
||||
*
|
||||
* <p>
|
||||
* Request Strings should not be logged because they may contain base64 encoded
|
||||
* user:password Authorization combinations.
|
||||
*
|
||||
@ -40,11 +40,11 @@ public class Request implements Closeable {
|
||||
|
||||
/**
|
||||
* Reads the information in the Request and parses required information.
|
||||
*
|
||||
* <p>
|
||||
* Parses Request (GET, POST etc.)
|
||||
*
|
||||
* <p>
|
||||
* Parses Target (/home/etc)
|
||||
*
|
||||
* <p>
|
||||
* Parses Authorization (Authorization header).
|
||||
*
|
||||
* @throws java.io.IOException if InputStream can not be read.
|
||||
@ -53,8 +53,11 @@ public class Request implements Closeable {
|
||||
StringBuilder headerB = new StringBuilder();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(input));
|
||||
close = in;
|
||||
String line;
|
||||
while ((line = in.readLine()) != null) {
|
||||
while (true) {
|
||||
String line = in.readLine();
|
||||
if (line == null || line.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
headerB.append(line);
|
||||
headerB.append(":::");
|
||||
}
|
||||
@ -126,7 +129,7 @@ public class Request implements Closeable {
|
||||
|
||||
/**
|
||||
* Closes the Request.
|
||||
*
|
||||
* <p>
|
||||
* Closes the InputStream.
|
||||
*
|
||||
* @throws IOException if the stream can not be closed.
|
||||
|
@ -92,8 +92,8 @@ public class WebSocketServer {
|
||||
response.sendStaticResource();
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
} finally {
|
||||
Benchmark.stop("Webserver Response");
|
||||
MiscUtils.close(input, request, output, socket);
|
||||
Benchmark.stop("Webserver Response");
|
||||
}
|
||||
}
|
||||
this.cancel();
|
||||
|
@ -37,6 +37,7 @@ public abstract class Response {
|
||||
+ content;
|
||||
// Log.debug("Response: " + response); // Responses should not be logged, html content large.
|
||||
output.write(response.getBytes());
|
||||
output.flush();
|
||||
}
|
||||
|
||||
public void setHeader(String header) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package main.java.com.djrapitops.plan.utilities;
|
||||
|
||||
import com.djrapitops.plugin.api.TimeAmount;
|
||||
import main.java.com.djrapitops.plan.Plan;
|
||||
import main.java.com.djrapitops.plan.Settings;
|
||||
import main.java.com.djrapitops.plan.data.AnalysisData;
|
||||
@ -106,10 +107,9 @@ public class PlaceholderUtils {
|
||||
Plan plugin = Plan.getInstance();
|
||||
replaceMap.put("%version%", plugin.getDescription().getVersion());
|
||||
replaceMap.put("%planlite%", "");
|
||||
String[] playersDataArray = PlayerActivityGraphCreator.generateDataArray(data.getSessions(), (long) 604800 * 1000);
|
||||
replaceMap.put("%graphmaxplayers%", 2 + "");
|
||||
replaceMap.put("%dataweek%", playersDataArray[0]);
|
||||
replaceMap.put("%labelsweek%", playersDataArray[1]);
|
||||
String scatterGraphData = PlayerActivityGraphCreator.buildScatterDataStringSessions(data.getSessions(), TimeAmount.WEEK.ms());
|
||||
replaceMap.put("%dataweek%", scatterGraphData);
|
||||
replaceMap.put("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL + "");
|
||||
replaceMap.put("%playersgraphfill%", Settings.HCOLOR_ACT_ONL_FILL + "");
|
||||
replaceMap.put("%datapunchcard%", PunchCardGraphCreator.generateDataArray(data.getSessions()));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Plan | Inspect %name%</title>
|
||||
<meta name="description" content="Player Analysis window">
|
||||
<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>
|
||||
<style>
|
||||
<title>Plan | Inspect %name%</title>
|
||||
<meta name="description" content="Player Analysis window">
|
||||
<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>
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
@ -314,240 +314,252 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div class="header-content">
|
||||
<img style="float: right; padding: 5px" src="https://puu.sh/tJZUb/c2e0ab220f.png" alt="Player Analytics | Analysis">
|
||||
<p style="float: right; text-align: right;">Player Analytics v.%version%</p>
|
||||
<h1><span id="navbutton" onclick="openNav()">☰ </span>%servername% | Inspect Player %name%%op%</h1>
|
||||
</div>
|
||||
<div class="header-content">
|
||||
<img style="float: right; padding: 5px" src="https://puu.sh/tJZUb/c2e0ab220f.png"
|
||||
alt="Player Analytics | Analysis">
|
||||
<p style="float: right; text-align: right;">Player Analytics v.%version%</p>
|
||||
<h1><span id="navbutton" onclick="openNav()">☰ </span>%servername% | Inspect Player %name%%op%</h1>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content" class="content">
|
||||
<div id="sidenav" class="sidenav">
|
||||
<p>Last Refresh: <br><span id="divTime">%refresh%</span> ago</p>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-info-circle" aria-hidden="true"></i> Information
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i> Sessions
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-cubes" aria-hidden="true"></i> Plugins
|
||||
</a>
|
||||
</div>
|
||||
<div id="limiter" class="main-limiter">
|
||||
<div id="main" class="main-wrapper">
|
||||
<div class="tab">
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-info-circle" aria-hidden="true"></i><span class="header-text"> Information</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%registered%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Registered
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img style="float: right; padding: 5px" alt="%name%" src="https://cravatar.eu/head/%name%/128.png">
|
||||
<p><i class="fa fa-user" aria-hidden="true"></i> %active% %isonline%%banned%<br/>
|
||||
<i class="fa fa-address-card-o" aria-hidden="true"></i> Nicknames: %nicknames%<br/>
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i> Playtime: %playtime%<br/>
|
||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i> Login times: %logintimes%<br/>
|
||||
<i class="fa fa-gavel" aria-hidden="true"></i> Times kicked: %timeskicked%<br/>
|
||||
<i class="fa fa-crosshairs" aria-hidden="true"></i> Player kills: %playerkills% | <i class="fa fa-crosshairs" aria-hidden="true"></i> Mob kills: %mobkills% | <i class="fa fa-meh-o" aria-hidden="true"></i> Deaths: %deaths%<br/>
|
||||
<br/>
|
||||
<i class="fa fa-globe" aria-hidden="true"></i> Geolocation: %geoloc%<br/>
|
||||
<i class="fa fa-tag" aria-hidden="true"></i> UUID: %uuid%<br/>
|
||||
<i class="fa fa-globe" aria-hidden="true"></i> Has Connected from ips: %ips%</p>
|
||||
</div>
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon" style="width: 50%">
|
||||
<div class="header-label"><i class="fa fa-pie-chart" aria-hidden="true"></i><span class="header-text"> Gamemode Usage</span></div>
|
||||
</div>
|
||||
<div class="infobox" >
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%gmtotal%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Total
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-area">
|
||||
<div class="infobox" style="float: left; background-color: #%gm0col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-fire" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm0%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Survival
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm1col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-cube" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm1%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Creative
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm2col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-chevron-right" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm2%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Adventure
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm3col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-binoculars" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm3%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Spectator
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="gmPie" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Player Activity: 7d</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-calendar-check-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%lastseen%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Last seen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-crosshairs" aria-hidden="true"></i><span class="header-text"> Last 10 Kills</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-crosshairs" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%playerkills%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Player Kills
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
%killstable%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon" style="width: 50%">
|
||||
<div class="header-label"><i class="fa fa-braille" aria-hidden="true"></i><span class="header-text"> PunchCard</span></div>
|
||||
</div>
|
||||
<div class="infobox" >
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%logintimes%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Login Times
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span class="header-text"> Length Distribution</span></div>
|
||||
</div>
|
||||
<div class="infobox">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%sessionaverage%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Average Length
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
<p>If the graph contains more sessions than login times, likely cause is use of /reload (Restarts sessions).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" style="display: block;">
|
||||
%plugins%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
<div id="sidenav" class="sidenav">
|
||||
<p>Last Refresh: <br><span id="divTime">%refresh%</span> ago</p>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-info-circle" aria-hidden="true"></i> Information
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-calendar" aria-hidden="true"></i> Sessions
|
||||
</a>
|
||||
<a href="javascript:void(0)" class="nav-button">
|
||||
<i class="fa fa-cubes" aria-hidden="true"></i> Plugins
|
||||
</a>
|
||||
</div>
|
||||
<div id="limiter" class="main-limiter">
|
||||
<div id="main" class="main-wrapper">
|
||||
<div class="tab">
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-info-circle" aria-hidden="true"></i><span
|
||||
class="header-text"> Information</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-user-plus" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%registered%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Registered
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img style="float: right; padding: 5px" alt="%name%"
|
||||
src="https://cravatar.eu/head/%name%/128.png">
|
||||
<p><i class="fa fa-user" aria-hidden="true"></i> %active% %isonline%%banned%<br/>
|
||||
<i class="fa fa-address-card-o" aria-hidden="true"></i> Nicknames: %nicknames%<br/>
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i> Playtime: %playtime%<br/>
|
||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i> Login times: %logintimes%<br/>
|
||||
<i class="fa fa-gavel" aria-hidden="true"></i> Times kicked: %timeskicked%<br/>
|
||||
<i class="fa fa-crosshairs" aria-hidden="true"></i> Player kills: %playerkills% | <i
|
||||
class="fa fa-crosshairs" aria-hidden="true"></i> Mob kills: %mobkills% | <i
|
||||
class="fa fa-meh-o" aria-hidden="true"></i> Deaths: %deaths%<br/>
|
||||
<br/>
|
||||
<i class="fa fa-globe" aria-hidden="true"></i> Geolocation: %geoloc%<br/>
|
||||
<i class="fa fa-tag" aria-hidden="true"></i> UUID: %uuid%<br/>
|
||||
<i class="fa fa-globe" aria-hidden="true"></i> Has Connected from ips: %ips%</p>
|
||||
</div>
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon" style="width: 50%">
|
||||
<div class="header-label"><i class="fa fa-pie-chart" aria-hidden="true"></i><span
|
||||
class="header-text"> Gamemode Usage</span></div>
|
||||
</div>
|
||||
<div class="infobox">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%gmtotal%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Total
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-area">
|
||||
<div class="infobox" style="float: left; background-color: #%gm0col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-fire" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm0%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Survival
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm1col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-cube" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm1%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Creative
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm2col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-chevron-right" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm2%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Adventure
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="infobox" style="float: left; background-color: #%gm3col%; width: 45%;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-binoculars" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text">
|
||||
<div class="info-number">
|
||||
%gm3%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Spectator
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="gmPie" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span
|
||||
class="header-text"> Player Activity: 7d</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-calendar-check-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%lastseen%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Last seen
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="playerChartWeek" width="1000" height="350" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-crosshairs" aria-hidden="true"></i><span
|
||||
class="header-text"> Last 10 Kills</span></div>
|
||||
</div>
|
||||
<div class="infobox" style="float: right;">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-crosshairs" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%playerkills%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Player Kills
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
%killstable%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab">
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon" style="width: 50%">
|
||||
<div class="header-label"><i class="fa fa-braille" aria-hidden="true"></i><span
|
||||
class="header-text"> PunchCard</span></div>
|
||||
</div>
|
||||
<div class="infobox">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-calendar-plus-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%logintimes%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Login Times
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="punchcard" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="about box column">
|
||||
<div class="headerbox">
|
||||
<div class="header-icon">
|
||||
<div class="header-label"><i class="fa fa-bar-chart" aria-hidden="true"></i><span
|
||||
class="header-text"> Length Distribution</span></div>
|
||||
</div>
|
||||
<div class="infobox">
|
||||
<div class="info-icon">
|
||||
<i class="fa fa-clock-o" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="info-text" style="width: 70%;">
|
||||
<div class="info-number">
|
||||
%sessionaverage%
|
||||
</div>
|
||||
<div class="info-label">
|
||||
Average Length
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="sessiondistribution" width="1000" height="600" style="width: 95%;"></canvas>
|
||||
<p>If the graph contains more sessions than login times, likely cause is use of /reload
|
||||
(Restarts sessions).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab" style="display: block;">
|
||||
%plugins%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var serverTime = new Date(%currenttime%);
|
||||
var now = new Date();
|
||||
var timediff = serverTime.getTime()-now.getTime();
|
||||
@ -639,11 +651,12 @@
|
||||
document.getElementById('divTime').innerHTML = out;
|
||||
setTimeout('countUpTimer()', 1000);
|
||||
}
|
||||
</script>
|
||||
<script src="https://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>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
<script src="https://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>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.js"></script>
|
||||
<script>
|
||||
function hour(i) {
|
||||
switch (i) {
|
||||
case 25:
|
||||
@ -702,7 +715,6 @@
|
||||
});
|
||||
var ctxweek = document.getElementById("playerChartWeek");
|
||||
var dataweek = {
|
||||
labels: %labelsweek% ,
|
||||
datasets: [{
|
||||
label: "Online",
|
||||
fill: true,
|
||||
@ -726,14 +738,24 @@
|
||||
data: %dataweek% ,
|
||||
}]};
|
||||
var playersChartWeek = new Chart(ctxweek, {
|
||||
type: 'line',
|
||||
data: dataweek,
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
display: true,
|
||||
ticks: {
|
||||
callback: function(value, index, values) {
|
||||
type: 'scatter',
|
||||
data: dataweek,
|
||||
options: {
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItems, data) {
|
||||
var newDate = new Date();
|
||||
newDate.setTime(tooltipItems.xLabel);
|
||||
dateString = newDate.toUTCString();
|
||||
return dateString +': '+ tooltipItems.yLabel+ ' Players';
|
||||
}
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
yAxes: [{
|
||||
display: true,
|
||||
ticks: {
|
||||
callback: function(value, index, values) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return '0';
|
||||
@ -743,16 +765,16 @@
|
||||
return '';
|
||||
};
|
||||
},
|
||||
suggestedMax: 2,
|
||||
suggestedMin: 0
|
||||
suggestedMax: %graphmaxplayers%
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
type: 'linear',
|
||||
display: false
|
||||
}]
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
display: false
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
var ctxpunch = document.getElementById("punchcard");
|
||||
var datapunch = {
|
||||
datasets: [
|
||||
@ -877,6 +899,8 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,15 +1,17 @@
|
||||
package test.java.main.java.com.djrapitops.plan.ui.graphs;
|
||||
|
||||
import main.java.com.djrapitops.plan.data.SessionData;
|
||||
import main.java.com.djrapitops.plan.ui.html.graphs.PlayerActivityGraphCreator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import main.java.com.djrapitops.plan.data.SessionData;
|
||||
import main.java.com.djrapitops.plan.ui.html.graphs.PlayerActivityGraphCreator;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -30,18 +32,6 @@ public class PlayerActivityGraphCreatorTest {
|
||||
public PlayerActivityGraphCreatorTest() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Useless test")
|
||||
public void testGenerateDataArray() {
|
||||
List<SessionData> sessionData = createRandomSessionDataList();
|
||||
long scale = 2592000L * 1000L;
|
||||
String result = PlayerActivityGraphCreator.generateDataArray(sessionData, scale)[1];
|
||||
assertTrue("0", 0 < result.length());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
|
Loading…
Reference in New Issue
Block a user