Merge branch 'task/stats-player-detail' of hardi/opt-cc into master
commit
2fedfe35e0
|
@ -9,6 +9,7 @@ module.exports = {
|
||||||
command: rootRoute + '/cmd',
|
command: rootRoute + '/cmd',
|
||||||
decorations: rootRoute + '/decorations',
|
decorations: rootRoute + '/decorations',
|
||||||
overview: rootRoute + '/overview',
|
overview: rootRoute + '/overview',
|
||||||
|
players: rootRoute + '/players',
|
||||||
ranks: rootRoute + '/ranks',
|
ranks: rootRoute + '/ranks',
|
||||||
request: rootRoute + '/request',
|
request: rootRoute + '/request',
|
||||||
signatures: '/signatures',
|
signatures: '/signatures',
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"cors": "^2.8.3",
|
"cors": "^2.8.3",
|
||||||
"cron": "^1.2.1",
|
"cron": "^1.2.1",
|
||||||
"debug": "~2.2.0",
|
"debug": "~2.2.0",
|
||||||
"express": "~4.13.1",
|
"express": "^4.16.1",
|
||||||
"imagemin": "^5.2.2",
|
"imagemin": "^5.2.2",
|
||||||
"imagemin-pngquant": "^5.0.0",
|
"imagemin-pngquant": "^5.0.0",
|
||||||
"jimp": "^0.2.27",
|
"jimp": "^0.2.27",
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// modules
|
||||||
|
const express = require('express');
|
||||||
|
const logger = require('debug')('cc:wars');
|
||||||
|
|
||||||
|
// HTTP status codes by name
|
||||||
|
const codes = require('./http-codes');
|
||||||
|
|
||||||
|
const routerHandling = require('../middleware/router-handling');
|
||||||
|
|
||||||
|
// Mongoose Model using mongoDB
|
||||||
|
const CampaignModel = require('../models/campaign');
|
||||||
|
const PlayerModel = require('../models/player');
|
||||||
|
const WarModel = require('../models/war');
|
||||||
|
|
||||||
|
const campaignPlayer = express.Router();
|
||||||
|
|
||||||
|
// routes **********************
|
||||||
|
campaignPlayer.route('/:campaignId/:playerName')
|
||||||
|
.get((req, res, next) => {
|
||||||
|
CampaignModel.findById(req.params.campaignId, (err, campaign) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
WarModel.find({campaign: req.params.campaignId}, '_id', (err, wars) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
const warIds = wars.map((obj) => {
|
||||||
|
return obj._id;
|
||||||
|
});
|
||||||
|
PlayerModel.find({name: req.params.playerName, warId: {"$in": warIds}})
|
||||||
|
.populate('warId')
|
||||||
|
.exec((err, items) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
if (!items || items.length === 0) {
|
||||||
|
const err = new Error('unknown player name');
|
||||||
|
err.status = codes.notfound;
|
||||||
|
return next(err)
|
||||||
|
}
|
||||||
|
res.locals.items = {
|
||||||
|
name: req.params.playerName,
|
||||||
|
campaign: campaign,
|
||||||
|
players: items
|
||||||
|
};
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
.all(
|
||||||
|
routerHandling.httpMethodNotAllowed
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
campaignPlayer.use(routerHandling.emptyResponse);
|
||||||
|
|
||||||
|
module.exports = campaignPlayer;
|
|
@ -30,6 +30,7 @@ const rankRouter = require('./routes/ranks');
|
||||||
const decorationRouter = require('./routes/decorations');
|
const decorationRouter = require('./routes/decorations');
|
||||||
const awardingRouter = require('./routes/awardings');
|
const awardingRouter = require('./routes/awardings');
|
||||||
const requestRouter = require('./routes/request');
|
const requestRouter = require('./routes/request');
|
||||||
|
const playerRouter = require('./routes/players');
|
||||||
const signatureRouter = require('./routes/signatures');
|
const signatureRouter = require('./routes/signatures');
|
||||||
const commandRouter = require('./routes/command');
|
const commandRouter = require('./routes/command');
|
||||||
const campaignRouter = require('./routes/campaigns');
|
const campaignRouter = require('./routes/campaigns');
|
||||||
|
@ -80,6 +81,7 @@ app.use(urls.decorations, decorationRouter);
|
||||||
app.use(urls.request, requestRouter);
|
app.use(urls.request, requestRouter);
|
||||||
app.use(urls.awards, awardingRouter);
|
app.use(urls.awards, awardingRouter);
|
||||||
app.use(urls.wars, warRouter);
|
app.use(urls.wars, warRouter);
|
||||||
|
app.use(urls.players, playerRouter);
|
||||||
app.use(urls.campaigns,campaignRouter);
|
app.use(urls.campaigns,campaignRouter);
|
||||||
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
|
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
|
||||||
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
|
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "opt-cc",
|
"name": "opt-cc",
|
||||||
"version": "1.4.4",
|
"version": "1.5.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -11,6 +11,7 @@ export class AppConfig {
|
||||||
public readonly apiSquadPath = this.apiUrl + '/squads/';
|
public readonly apiSquadPath = this.apiUrl + '/squads/';
|
||||||
public readonly apiUserPath = this.apiUrl + '/users/';
|
public readonly apiUserPath = this.apiUrl + '/users/';
|
||||||
public readonly apiOverviewPath = this.apiUrl + '/overview';
|
public readonly apiOverviewPath = this.apiUrl + '/overview';
|
||||||
|
public readonly apiPlayersPath = this.apiUrl + '/players';
|
||||||
public readonly apiRequestAwardPath = this.apiUrl + '/request/award';
|
public readonly apiRequestAwardPath = this.apiUrl + '/request/award';
|
||||||
public readonly apiPromotionPath = this.apiUrl + '/request/promotion';
|
public readonly apiPromotionPath = this.apiUrl + '/request/promotion';
|
||||||
public readonly apiWarPath = this.apiUrl + '/wars';
|
public readonly apiWarPath = this.apiUrl + '/wars';
|
||||||
|
|
|
@ -29,6 +29,12 @@ export interface Player {
|
||||||
flagTouch?: number;
|
flagTouch?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CampaignPlayer {
|
||||||
|
name?: string;
|
||||||
|
campaign?: Campaign;
|
||||||
|
players?: Player[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface Campaign {
|
export interface Campaign {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {AppConfig} from "../../app.config";
|
||||||
|
import {HttpClient} from "../http-client";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PlayerService {
|
||||||
|
|
||||||
|
constructor(private http: HttpClient,
|
||||||
|
private config: AppConfig) {
|
||||||
|
}
|
||||||
|
|
||||||
|
getCampaignPlayer(campaignId: string, playerName: string) {
|
||||||
|
return this.http.get(this.config.apiPlayersPath + '/' + campaignId + '/' + playerName)
|
||||||
|
.map(res => res.json())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
.overview {
|
||||||
|
position: fixed;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
border-left: thin solid lightgrey;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 80%;
|
||||||
|
padding-left: 20px;
|
||||||
|
padding-right: 5%;
|
||||||
|
padding-top: 70px;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-back {
|
||||||
|
clear: both;
|
||||||
|
float: left;
|
||||||
|
width: 120px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sum-container {
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
clear: left;
|
||||||
|
padding: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gauge-container {
|
||||||
|
padding: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sum-bar-container {
|
||||||
|
width: 70%;
|
||||||
|
height: 400px;
|
||||||
|
margin: auto;
|
||||||
|
padding-left: 4%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.charts-parent {
|
||||||
|
clear: left;
|
||||||
|
padding-top: 50px;
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
width: 42%;
|
||||||
|
min-width: 500px;
|
||||||
|
height: 300px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 2%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
<div class="overview fade-in" xmlns="http://www.w3.org/1999/html">
|
||||||
|
|
||||||
|
<h2 class="pull-left">Spielerstatistik - {{campaignPlayer.name}}</h2>
|
||||||
|
<h2 class="pull-right">{{campaignPlayer.campaign.title}} Kampagne</h2>
|
||||||
|
|
||||||
|
<span class="btn btn-default btn-back" (click)="navigateBack()">< Zurück</span>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="sum-container">
|
||||||
|
<div class="gauge-container pull-left">
|
||||||
|
<ngx-charts-linear-gauge
|
||||||
|
[view]="[200, 100]"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[value]="kdRatio"
|
||||||
|
[previousValue]="1"
|
||||||
|
[max]="maxKd"
|
||||||
|
[min]="0"
|
||||||
|
[units]="'Kill/Death'">
|
||||||
|
</ngx-charts-linear-gauge>
|
||||||
|
<span style="height: 150px; display: block;"></span>
|
||||||
|
<ngx-charts-linear-gauge
|
||||||
|
[view]="[200, 100]"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[value]="respawnDeathRatio"
|
||||||
|
[previousValue]="0.5"
|
||||||
|
[max]="maxRespawnDeathRatio"
|
||||||
|
[min]="0"
|
||||||
|
[units]="'Respawn/Death'">
|
||||||
|
</ngx-charts-linear-gauge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sum-bar-container pull-left">
|
||||||
|
<ngx-charts-bar-horizontal
|
||||||
|
[scheme]="colorSchemeBar"
|
||||||
|
[results]="sumData"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel">
|
||||||
|
</ngx-charts-bar-horizontal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="charts-parent">
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="killData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="killRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisKill"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="friendlyFireData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="friendlyFireRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisFriendlyFire"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="deathData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="deathRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisDeath"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="respawnData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="respawnRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisRespawn"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="reviveData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="reviveRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisRevive"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chart-container">
|
||||||
|
<ngx-charts-line-chart
|
||||||
|
[results]="captureData"
|
||||||
|
[showRefLines]="showRefLines"
|
||||||
|
[showRefLabels]="showRefLabels"
|
||||||
|
[referenceLines]="captureRefLines"
|
||||||
|
[scheme]="colorScheme"
|
||||||
|
[gradient]="gradient"
|
||||||
|
[xAxis]="xAxis"
|
||||||
|
[yAxis]="yAxis"
|
||||||
|
[legend]="legend"
|
||||||
|
[showXAxisLabel]="showXAxisLabel"
|
||||||
|
[showYAxisLabel]="showYAxisLabel"
|
||||||
|
[yAxisLabel]="yAxisCapture"
|
||||||
|
[autoScale]="autoscale"
|
||||||
|
[timeline]="timeline"
|
||||||
|
[roundDomains]="roundDomains">
|
||||||
|
</ngx-charts-line-chart>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
|
@ -0,0 +1,178 @@
|
||||||
|
import {Component} from "@angular/core";
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
import {CampaignPlayer} from "../../models/model-interfaces";
|
||||||
|
import {PlayerService} from "../../services/player-service/player.service";
|
||||||
|
import {ChartUtils} from "../../utils/chart-utils";
|
||||||
|
import {Location} from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'campaign-player-detail',
|
||||||
|
templateUrl: './campaign-player-detail.component.html',
|
||||||
|
styleUrls: ['./campaign-player-detail.component.css', '../../style/list-entry.css']
|
||||||
|
})
|
||||||
|
export class CampaignPlayerDetailComponent {
|
||||||
|
|
||||||
|
campaignPlayer: CampaignPlayer = {campaign: {}, players: []};
|
||||||
|
|
||||||
|
sumData: any[] = [];
|
||||||
|
killData: any[] = [];
|
||||||
|
friendlyFireData: any[] = [];
|
||||||
|
deathData: any[] = [];
|
||||||
|
respawnData: any[] = [];
|
||||||
|
reviveData: any[] = [];
|
||||||
|
captureData: any[] = [];
|
||||||
|
|
||||||
|
yAxisKill = 'Kills';
|
||||||
|
yAxisFriendlyFire = 'FriendlyFire';
|
||||||
|
yAxisDeath = 'Tode';
|
||||||
|
yAxisRespawn = 'Respawn';
|
||||||
|
yAxisRevive = 'Revive';
|
||||||
|
yAxisCapture = 'Eroberungen';
|
||||||
|
avgLabel = 'Durchschnitt';
|
||||||
|
|
||||||
|
colorScheme = {
|
||||||
|
domain: ['#00ce12']
|
||||||
|
};
|
||||||
|
colorSchemeBar = {
|
||||||
|
domain: [
|
||||||
|
'#2d5a00', '#455600', '#00561f', '#3f3b00', '#003c19', '#083c00'
|
||||||
|
]
|
||||||
|
};
|
||||||
|
showRefLines = true;
|
||||||
|
showRefLabels = true;
|
||||||
|
killRefLines = [];
|
||||||
|
deathRefLines = [];
|
||||||
|
captureRefLines = [];
|
||||||
|
friendlyFireRefLines = [];
|
||||||
|
reviveRefLines = [];
|
||||||
|
respawnRefLines = [];
|
||||||
|
|
||||||
|
gradient = false;
|
||||||
|
xAxis = true;
|
||||||
|
yAxis = true;
|
||||||
|
legend = false;
|
||||||
|
showXAxisLabel = true;
|
||||||
|
showYAxisLabel = true;
|
||||||
|
autoscale = false;
|
||||||
|
timeline = false;
|
||||||
|
roundDomains = true;
|
||||||
|
|
||||||
|
totalKills;
|
||||||
|
totalFriendlyFire;
|
||||||
|
totalDeath;
|
||||||
|
totalRespawn;
|
||||||
|
totalRevive;
|
||||||
|
totalCapture;
|
||||||
|
|
||||||
|
kdRatio = 0;
|
||||||
|
maxKd = 1.7;
|
||||||
|
|
||||||
|
respawnDeathRatio = 0;
|
||||||
|
maxRespawnDeathRatio = 1;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute,
|
||||||
|
private location: Location,
|
||||||
|
private playerService: PlayerService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.route.params
|
||||||
|
.map(params => [params['id'], params['playerName']])
|
||||||
|
.flatMap(id => this.playerService.getCampaignPlayer(id[0], encodeURIComponent(id[1])))
|
||||||
|
.subscribe(campaignPlayer => {
|
||||||
|
this.campaignPlayer = campaignPlayer;
|
||||||
|
this.killData = this.assignData(this.yAxisKill, "kill");
|
||||||
|
this.friendlyFireData = this.assignData(this.yAxisFriendlyFire, "friendlyFire");
|
||||||
|
this.deathData = this.assignData(this.yAxisDeath, "death");
|
||||||
|
this.respawnData = this.assignData(this.yAxisRespawn, "respawn");
|
||||||
|
this.reviveData = this.assignData(this.yAxisRevive, "revive");
|
||||||
|
this.captureData = this.assignData(this.yAxisCapture, "flagTouch");
|
||||||
|
|
||||||
|
this.kdRatio = parseFloat((this.totalKills / this.totalDeath).toFixed(2));
|
||||||
|
if (this.kdRatio > 1) this.maxKd = this.kdRatio * 1.7;
|
||||||
|
|
||||||
|
this.respawnDeathRatio = parseFloat((this.totalRespawn / this.totalDeath).toFixed(2));
|
||||||
|
|
||||||
|
this.sumData = [
|
||||||
|
{
|
||||||
|
name: this.yAxisKill,
|
||||||
|
value: this.totalKills
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.yAxisFriendlyFire,
|
||||||
|
value: this.totalFriendlyFire
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.yAxisDeath,
|
||||||
|
value: this.totalDeath
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.yAxisRespawn,
|
||||||
|
value: this.totalRespawn
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.yAxisRevive,
|
||||||
|
value: this.totalRevive
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: this.yAxisCapture,
|
||||||
|
value: this.totalCapture
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
Object.assign(this, [this.sumData, this.killData, this.friendlyFireData, this.deathData, this.respawnData, this.reviveData, this.captureData]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private assignData(label, field) {
|
||||||
|
let killObj = {
|
||||||
|
name: label,
|
||||||
|
series: []
|
||||||
|
};
|
||||||
|
const playerLength = this.campaignPlayer.players.length;
|
||||||
|
let total = 0;
|
||||||
|
for (let i = 0; i < playerLength; i++) {
|
||||||
|
const warDateString = ChartUtils.getShortDateString(this.campaignPlayer.players[i].warId.date);
|
||||||
|
const warKills = this.campaignPlayer.players[i][field];
|
||||||
|
killObj.series.push({
|
||||||
|
name: warDateString,
|
||||||
|
value: warKills
|
||||||
|
});
|
||||||
|
total += warKills;
|
||||||
|
}
|
||||||
|
switch (field) {
|
||||||
|
case 'kill':
|
||||||
|
this.killRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalKills = total;
|
||||||
|
break;
|
||||||
|
case 'friendlyFire':
|
||||||
|
this.friendlyFireRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalFriendlyFire = total;
|
||||||
|
break;
|
||||||
|
case 'death':
|
||||||
|
this.deathRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalDeath = total;
|
||||||
|
break;
|
||||||
|
case 'respawn':
|
||||||
|
this.respawnRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalRespawn = total;
|
||||||
|
break;
|
||||||
|
case 'revive':
|
||||||
|
this.reviveRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalRevive = total;
|
||||||
|
break;
|
||||||
|
case 'flagTouch':
|
||||||
|
this.captureRefLines.push({value: total / playerLength, name: this.avgLabel});
|
||||||
|
this.totalCapture = total;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return [killObj];
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateBack() {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,9 +10,7 @@
|
||||||
(click)="goToSlide(1)">Spielerzahlen
|
(click)="goToSlide(1)">Spielerzahlen
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<carousel class="fade-in" [(activeSlide)]="activeSlideIndex">
|
||||||
|
|
||||||
<carousel [(activeSlide)]="activeSlideIndex">
|
|
||||||
<slide *ngIf="id != 'all'">
|
<slide *ngIf="id != 'all'">
|
||||||
<div class="slide-chart-container">
|
<div class="slide-chart-container">
|
||||||
<h3>Gesamtpunktzahl</h3>
|
<h3>Gesamtpunktzahl</h3>
|
||||||
|
|
|
@ -2,12 +2,13 @@ import {Component} from "@angular/core";
|
||||||
import {ActivatedRoute} from "@angular/router";
|
import {ActivatedRoute} from "@angular/router";
|
||||||
import {CarouselConfig} from "ngx-bootstrap";
|
import {CarouselConfig} from "ngx-bootstrap";
|
||||||
import {CampaignService} from "../../services/campaign-service/campaign.service";
|
import {CampaignService} from "../../services/campaign-service/campaign.service";
|
||||||
|
import {ChartUtils} from "../../utils/chart-utils";
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stats-overview',
|
selector: 'stats-overview',
|
||||||
templateUrl: './stats-overview.component.html',
|
templateUrl: './stats-overview.component.html',
|
||||||
styleUrls: ['./stats-overview.component.css'],
|
styleUrls: ['./stats-overview.component.css', '../../style/list-entry.css'],
|
||||||
inputs: ['campaigns'],
|
inputs: ['campaigns'],
|
||||||
providers: [{provide: CarouselConfig, useValue: {interval: false}}]
|
providers: [{provide: CarouselConfig, useValue: {interval: false}}]
|
||||||
})
|
})
|
||||||
|
@ -94,11 +95,7 @@ export class StatisticOverviewComponent {
|
||||||
|
|
||||||
for (let i = wars.length - 1; i >= 0; i--) {
|
for (let i = wars.length - 1; i >= 0; i--) {
|
||||||
let j = wars.length - i - 1;
|
let j = wars.length - i - 1;
|
||||||
// const warDateString = new Date(wars[i].date); TODO: use ngx-chart timeline
|
const warDateString = ChartUtils.getShortDateString(wars[i].date);
|
||||||
const isoDate = wars[i].date.slice(0, 10);
|
|
||||||
const dayDate = parseInt(isoDate.slice(8, 10)) + 1;
|
|
||||||
const warDateString = (dayDate < 10 ? "0" + dayDate : dayDate) + '.'
|
|
||||||
+ isoDate.slice(5, 7) + '.' + isoDate.slice(2, 4);
|
|
||||||
|
|
||||||
pointsObj[0].series.push({
|
pointsObj[0].series.push({
|
||||||
name: warDateString,
|
name: warDateString,
|
||||||
|
|
|
@ -3,16 +3,17 @@ import {CommonModule} from "@angular/common";
|
||||||
import {SharedModule} from "../shared.module";
|
import {SharedModule} from "../shared.module";
|
||||||
import {statsRouterModule, statsRoutingComponents} from "./stats.routing";
|
import {statsRouterModule, statsRoutingComponents} from "./stats.routing";
|
||||||
import {WarService} from "../services/war-service/war.service";
|
import {WarService} from "../services/war-service/war.service";
|
||||||
import {LineChartModule, PieChartModule} from "@swimlane/ngx-charts";
|
import {NgxChartsModule} from "@swimlane/ngx-charts";
|
||||||
import {AccordionModule, CarouselModule} from "ngx-bootstrap";
|
import {AccordionModule, CarouselModule} from "ngx-bootstrap";
|
||||||
import {CampaignService} from "../services/campaign-service/campaign.service";
|
import {CampaignService} from "../services/campaign-service/campaign.service";
|
||||||
import {NgxDatatableModule} from "@swimlane/ngx-datatable";
|
import {NgxDatatableModule} from "@swimlane/ngx-datatable";
|
||||||
|
import {PlayerService} from "../services/player-service/player.service";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: statsRoutingComponents,
|
declarations: statsRoutingComponents,
|
||||||
imports: [CommonModule, SharedModule, statsRouterModule, LineChartModule, PieChartModule,
|
imports: [CommonModule, SharedModule, statsRouterModule, NgxChartsModule,
|
||||||
AccordionModule.forRoot(), CarouselModule.forRoot(), NgxDatatableModule],
|
AccordionModule.forRoot(), CarouselModule.forRoot(), NgxDatatableModule],
|
||||||
providers: [WarService, CampaignService]
|
providers: [WarService, CampaignService, PlayerService]
|
||||||
})
|
})
|
||||||
export class StatsModule {
|
export class StatsModule {
|
||||||
static routes = statsRouterModule;
|
static routes = statsRouterModule;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {StatisticOverviewComponent} from "./overview/stats-overview.component";
|
||||||
import {WarItemComponent} from "./war-list/war-item.component";
|
import {WarItemComponent} from "./war-list/war-item.component";
|
||||||
import {ModuleWithProviders} from "@angular/core";
|
import {ModuleWithProviders} from "@angular/core";
|
||||||
import {CampaignSubmitComponent} from "./campaign-submit/campaign-submit.component";
|
import {CampaignSubmitComponent} from "./campaign-submit/campaign-submit.component";
|
||||||
|
import {CampaignPlayerDetailComponent} from "./campaign-player-detail/campaign-player-detail.component";
|
||||||
|
|
||||||
|
|
||||||
export const statsRoutes: Routes = [{
|
export const statsRoutes: Routes = [{
|
||||||
|
@ -37,10 +38,15 @@ export const statsRoutes: Routes = [{
|
||||||
path: 'war/:id',
|
path: 'war/:id',
|
||||||
component: WarDetailComponent,
|
component: WarDetailComponent,
|
||||||
outlet: 'right'
|
outlet: 'right'
|
||||||
}];
|
},
|
||||||
|
{
|
||||||
|
path: 'campaign-player/:id/:playerName',
|
||||||
|
component: CampaignPlayerDetailComponent,
|
||||||
|
outlet: 'right'
|
||||||
|
},];
|
||||||
|
|
||||||
export const statsRouterModule: ModuleWithProviders = RouterModule.forChild(statsRoutes);
|
export const statsRouterModule: ModuleWithProviders = RouterModule.forChild(statsRoutes);
|
||||||
|
|
||||||
export const statsRoutingComponents = [StatisticComponent, StatisticOverviewComponent, CampaignSubmitComponent,
|
export const statsRoutingComponents = [StatisticComponent, StatisticOverviewComponent, CampaignSubmitComponent,
|
||||||
WarListComponent, WarSubmitComponent, WarDetailComponent, WarItemComponent];
|
WarListComponent, WarSubmitComponent, WarDetailComponent, CampaignPlayerDetailComponent, WarItemComponent];
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
:host /deep/ .datatable-body-row {
|
:host /deep/ .datatable-body-row {
|
||||||
color: #222222;
|
color: #222222;
|
||||||
border-bottom: 1px solid grey;
|
border-bottom: 1px solid grey;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host /deep/ .datatable-body-row:hover {
|
:host /deep/ .datatable-body-row:hover {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="overview" xmlns="http://www.w3.org/1999/html">
|
<div class="overview fade-in" xmlns="http://www.w3.org/1999/html">
|
||||||
|
|
||||||
<div style="min-height: 263px;">
|
<div style="min-height: 263px;">
|
||||||
<h2>{{war.title}} - vom {{war.date | date: 'dd.MM.yyyy'}}</h2>
|
<h2>{{war.title}} - vom {{war.date | date: 'dd.MM.yyyy'}}</h2>
|
||||||
|
@ -57,10 +57,13 @@
|
||||||
[messages]="{emptyMessage: 'Loading...'}"
|
[messages]="{emptyMessage: 'Loading...'}"
|
||||||
[headerHeight]="cellHeight"
|
[headerHeight]="cellHeight"
|
||||||
[rowHeight]="cellHeight"
|
[rowHeight]="cellHeight"
|
||||||
[cssClasses]='customClasses'>
|
[cssClasses]='customClasses'
|
||||||
|
[selectionType]="'single'"
|
||||||
|
(select)="selectPlayerDetail($event)">
|
||||||
<ngx-datatable-column name="Spieler" prop="name" [width]="210" style="padding-left:10px">
|
<ngx-datatable-column name="Spieler" prop="name" [width]="210" style="padding-left:10px">
|
||||||
<ng-template ngx-datatable-cell-template let-row="row" let-value="value">
|
<ng-template ngx-datatable-cell-template let-row="row" let-value="value">
|
||||||
<span class="player-name" [ngClass]="row['fraction'] === 'BLUFOR' ? 'text-blufor' : 'text-opfor'">
|
<span class="player-name"
|
||||||
|
[ngClass]="row['fraction'] === 'BLUFOR' ? 'text-blufor' : 'text-opfor'">
|
||||||
{{value}}
|
{{value}}
|
||||||
</span>
|
</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Component} from "@angular/core";
|
import {Component} from "@angular/core";
|
||||||
import {ActivatedRoute} from "@angular/router";
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
import {WarService} from "../../services/war-service/war.service";
|
import {WarService} from "../../services/war-service/war.service";
|
||||||
import {War} from "../../models/model-interfaces";
|
import {War} from "../../models/model-interfaces";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {War} from "../../models/model-interfaces";
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'war-detail',
|
selector: 'war-detail',
|
||||||
templateUrl: './war-detail.component.html',
|
templateUrl: './war-detail.component.html',
|
||||||
styleUrls: ['./war-detail.component.css']
|
styleUrls: ['./war-detail.component.css', '../../style/list-entry.css']
|
||||||
})
|
})
|
||||||
export class WarDetailComponent {
|
export class WarDetailComponent {
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ export class WarDetailComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
constructor(private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
private warService: WarService) {
|
private warService: WarService) {
|
||||||
Object.assign(this, this.playerChart)
|
Object.assign(this, this.playerChart)
|
||||||
}
|
}
|
||||||
|
@ -64,4 +65,11 @@ export class WarDetailComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectPlayerDetail(player) {
|
||||||
|
if (player && player.selected && player.selected.length > 0) {
|
||||||
|
this.router.navigate(['../../campaign-player/' + this.war.campaign + '/' + player.selected[0].name],
|
||||||
|
{relativeTo: this.route});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
export class ChartUtils {
|
||||||
|
|
||||||
|
public static getShortDateString(date) : string {
|
||||||
|
const isoDate = date.slice(0, 10);
|
||||||
|
const dayDate = parseInt(isoDate.slice(8, 10)) + 1;
|
||||||
|
return (dayDate < 10 ? "0" + dayDate : dayDate) + '.'
|
||||||
|
+ isoDate.slice(5, 7) + '.' + isoDate.slice(2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue