Release v1.9.6 (#61)

release/v1.9.7 v1.9.6
hardi 2019-10-11 20:25:07 +02:00 committed by Gogs
parent 12ca58d43e
commit 7851e64fd5
18 changed files with 348 additions and 150 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "opt-cc", "name": "opt-cc",
"version": "1.9.5", "version": "1.9.6",
"author": "Florian Hartwich <hardi@noarch.de>", "author": "Florian Hartwich <hardi@noarch.de>",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@ -26,92 +26,100 @@ campaignPlayer.route('/ranking/:campaignId')
const warIds = wars.map((obj) => { const warIds = wars.map((obj) => {
return obj._id; return obj._id;
}); });
PlayerModel.find({warId: {'$in': warIds}}, (err, items) => { WarModel.findOne({campaign: req.params.campaignId}, {}, {sort: {'date': -1}}, (err, latestWar) => {
if (err) return next(err); PlayerModel.find({warId: {'$in': warIds}}, (err, items) => {
if (!items || items.length === 0) { if (err) return next(err);
const err = new Error('No players for given campaignId'); if (!items || items.length === 0) {
err.status = codes.notfound; const err = new Error('No players for given campaignId');
return next(err); err.status = codes.notfound;
} return next(err);
const rankingItems = [];
// check only first player to have valid steamUUID - then decide if tracked by name or by ID
const usesUUID = isSteamUUID(items[0].steamUUID);
new Set(items.map(usesUUID ? (x) => x.steamUUID : (x) => x.name))
.forEach((player) => {
const playerInstances = items.filter(
usesUUID ? (p) => p.steamUUID === player : (p) => p.name === player);
const resItem = {
name: usesUUID ? playerInstances[playerInstances.length - 1].name : player,
kill: 0,
vehicleLight: 0,
vehicleHeavy: 0,
vehicleAir: 0,
death: 0,
friendlyFire: 0,
revive: 0,
respawn: 0,
flagTouch: 0,
travelDistance: 0,
driverDistance: 0,
};
for (let i = 0; i < playerInstances.length; i++) {
const player = playerInstances[i];
resItem.kill += player.kill;
resItem.death += player.death;
resItem.friendlyFire += player.friendlyFire;
resItem.vehicleLight += player.vehicleLight;
resItem.vehicleHeavy += player.vehicleHeavy;
resItem.vehicleAir += player.vehicleAir;
resItem.revive += player.revive;
resItem.respawn += player.respawn;
resItem.flagTouch += player.flagTouch;
if (player.travelDistance) {
resItem.travelDistance += Math.round(player.travelDistance / 1000); // meters -> km
}
if (player.driverDistance) {
resItem.driverDistance += Math.round(player.driverDistance / 1000); // meters -> km
}
}
resItem.warCount = playerInstances.length;
resItem.fraction = playerInstances[playerInstances.length - 1].fraction;
rankingItems.push(resItem);
});
const getSortedField = (fieldName) => {
let num = 1;
const filteredSortResult = rankingItems.map((item) => {
return {
name: item.name,
fraction: item.fraction,
[fieldName]: item[fieldName],
};
})
.sort((a, b) => b[fieldName] - a[fieldName]);
const res = JSON.parse(JSON.stringify(filteredSortResult));
for (const entity of res) {
entity.num = num++;
} }
return res;
};
res.locals.items = { const rankingItems = [];
kill: getSortedField('kill'),
death: getSortedField('death'), // check only first player to have valid steamUUID - then decide if tracked by name or by ID
friendlyFire: getSortedField('friendlyFire'), const usesUUID = isSteamUUID(items[0].steamUUID);
vehicleLight: getSortedField('vehicleLight'),
vehicleHeavy: getSortedField('vehicleHeavy'), new Set(items.map(usesUUID ? (x) => x.steamUUID : (x) => x.name))
vehicleAir: getSortedField('vehicleAir'), .forEach((player) => {
revive: getSortedField('revive'), const playerInstances = items.filter(
respawn: getSortedField('respawn'), usesUUID ? (p) => p.steamUUID === player : (p) => p.name === player);
flagTouch: getSortedField('flagTouch'), const resItem = {
travelDistance: getSortedField('travelDistance'), name: usesUUID ? playerInstances[playerInstances.length - 1].name : player,
driverDistance: getSortedField('driverDistance'), kill: 0,
warCount: getSortedField('warCount'), vehicleLight: 0,
}; vehicleHeavy: 0,
next(); vehicleAir: 0,
death: 0,
friendlyFire: 0,
revive: 0,
respawn: 0,
flagTouch: 0,
travelDistance: 0,
driverDistance: 0,
};
for (let i = 0; i < playerInstances.length; i++) {
const player = playerInstances[i];
resItem.kill += player.kill;
resItem.death += player.death;
resItem.friendlyFire += player.friendlyFire;
resItem.vehicleLight += player.vehicleLight;
resItem.vehicleHeavy += player.vehicleHeavy;
resItem.vehicleAir += player.vehicleAir;
resItem.revive += player.revive;
resItem.respawn += player.respawn;
resItem.flagTouch += player.flagTouch;
if (player.travelDistance) {
resItem.travelDistance += Math.round(player.travelDistance / 1000); // meters -> km
}
if (player.driverDistance) {
resItem.driverDistance += Math.round(player.driverDistance / 1000); // meters -> km
}
}
resItem.warCount = playerInstances.length;
const latestPlayerFraction = playerInstances[playerInstances.length - 1].fraction;
resItem.fraction =
(latestPlayerFraction === 'OPFOR') ?
latestWar.fractionMappingOpfor :
latestWar.fractionMappingBlufor;
rankingItems.push(resItem);
});
const getSortedField = (fieldName) => {
let num = 1;
const filteredSortResult = rankingItems.map((item) => {
return {
name: item.name,
fraction: item.fraction,
[fieldName]: item[fieldName],
};
})
.sort((a, b) => b[fieldName] - a[fieldName]);
const res = JSON.parse(JSON.stringify(filteredSortResult));
for (const entity of res) {
entity.num = num++;
}
return res;
};
res.locals.items = {
kill: getSortedField('kill'),
death: getSortedField('death'),
friendlyFire: getSortedField('friendlyFire'),
vehicleLight: getSortedField('vehicleLight'),
vehicleHeavy: getSortedField('vehicleHeavy'),
vehicleAir: getSortedField('vehicleAir'),
revive: getSortedField('revive'),
respawn: getSortedField('respawn'),
flagTouch: getSortedField('flagTouch'),
travelDistance: getSortedField('travelDistance'),
driverDistance: getSortedField('driverDistance'),
warCount: getSortedField('warCount'),
};
next();
});
}); });
}); });
}) })

View File

@ -19,8 +19,8 @@
[(ngModel)]="decoration.fraction"> [(ngModel)]="decoration.fraction">
<option value="{{fraction.ARF}}">{{fraction.ARF}}</option> <option value="{{fraction.ARF}}">{{fraction.ARF}}</option>
<option value="{{fraction.SWORD}}">{{fraction.SWORD}}</option> <option value="{{fraction.SWORD}}">{{fraction.SWORD}}</option>
<option value="{{fraction.OPFOR}}">{{fraction.OPFOR}}</option> <option value="OPFOR">{{fraction.OPFOR}}</option>
<option value="{{fraction.BLUFOR}}">{{fraction.BLUFOR}}</option> <option value="BLUFOR">{{fraction.BLUFOR}}</option>
<option value="GLOBAL">{{'decorations.submit.field.fraction.global' | translate}}</option> <option value="GLOBAL">{{'decorations.submit.field.fraction.global' | translate}}</option>
</select> </select>
<show-error displayName="{{'decorations.submit.field.fraction' | translate}}" controlPath="fraction"></show-error> <show-error displayName="{{'decorations.submit.field.fraction' | translate}}" controlPath="fraction"></show-error>

View File

@ -1,4 +1,5 @@
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {Fraction} from '../utils/fraction.enum';
export interface AppUser { export interface AppUser {
_id?: string; _id?: string;
@ -59,6 +60,8 @@ export interface War {
endDate?: string; endDate?: string;
ptBlufor?: number; ptBlufor?: number;
ptOpfor?: number; ptOpfor?: number;
fractionMappingBlufor?: Fraction.SWORD | Fraction.ARF | 'BLUFOR' | 'OPFOR';
fractionMappingOpfor?: Fraction.SWORD | Fraction.ARF | 'BLUFOR' | 'OPFOR';
playersBlufor?: number; playersBlufor?: number;
playersOpfor?: number; playersOpfor?: number;
budgetBlufor?: number; budgetBlufor?: number;

View File

@ -28,7 +28,7 @@
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>{{'stats.highscore.header.name' | translate}}</th> <th mat-header-cell *matHeaderCellDef>{{'stats.highscore.header.name' | translate}}</th>
<td mat-cell *matCellDef="let element" <td mat-cell *matCellDef="let element"
[style.color]="element['fraction'] === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR"> [style.color]="fractionHelpers.getFractionColor(element['fraction'])">
{{element.name}} {{element.name}}
</td> </td>
</ng-container> </ng-container>

View File

@ -1,11 +1,11 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {PlayerService} from '../../../services/logs/player.service'; import {PlayerService} from '../../../services/logs/player.service';
import {Fraction} from '../../../utils/fraction.enum';
import {FormControl} from '@angular/forms'; import {FormControl} from '@angular/forms';
import {Observable} from 'rxjs/Observable'; import {Observable} from 'rxjs/Observable';
import {Player} from '../../../models/model-interfaces'; import {Player} from '../../../models/model-interfaces';
import {PlayerUtils} from '../../../utils/player-utils'; import {PlayerUtils} from '../../../utils/player-utils';
import {FractionHelpers} from '../../../utils/global.helpers';
@Component({ @Component({
@ -25,7 +25,7 @@ export class StatisticHighScoreComponent implements OnInit {
playerAttributeDisplayNames = PlayerUtils.attributeDisplayNames.slice(2, PlayerUtils.attributeDisplayNames.length); playerAttributeDisplayNames = PlayerUtils.attributeDisplayNames.slice(2, PlayerUtils.attributeDisplayNames.length);
readonly fraction = Fraction; readonly fractionHelpers = FractionHelpers;
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private playerService: PlayerService) { private playerService: PlayerService) {

View File

@ -4,6 +4,8 @@ import {CampaignService} from '../../../services/logs/campaign.service';
import {ChartUtils} from '../../../utils/chart-utils'; import {ChartUtils} from '../../../utils/chart-utils';
import {Fraction} from '../../../utils/fraction.enum'; import {Fraction} from '../../../utils/fraction.enum';
import {WarService} from '../../../services/logs/war.service'; import {WarService} from '../../../services/logs/war.service';
import {FractionHelpers} from '../../../utils/global.helpers';
import {War} from '../../../models/model-interfaces';
@Component({ @Component({
@ -22,9 +24,7 @@ export class StatisticOverviewComponent implements OnInit {
playerData: any[] = []; playerData: any[] = [];
currentData: any[] = []; currentData: any[] = [];
colorScheme = { colorScheme;
domain: [Fraction.COLOR_BLUFOR, Fraction.COLOR_OPFOR]
};
gradient = false; gradient = false;
xAxis = true; xAxis = true;
yAxis = true; yAxis = true;
@ -81,44 +81,71 @@ export class StatisticOverviewComponent implements OnInit {
} }
} }
initChart(wars: any[]) { initChart(wars: War[]) {
const pointsObj = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); const fractions: string[] = [];
const pointsSumObj = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.colorScheme = {
const playersObj = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); domain: []
};
if (wars.find(war => war.fractionMappingBlufor === 'BLUFOR' || war.fractionMappingOpfor === 'BLUFOR')) {
fractions.push(Fraction.BLUFOR);
this.colorScheme.domain.push(FractionHelpers.getFractionColor('BLUFOR'));
}
if (wars.find(war => war.fractionMappingBlufor === 'OPFOR' || war.fractionMappingOpfor === 'OPFOR')) {
fractions.push(Fraction.OPFOR);
this.colorScheme.domain.push(FractionHelpers.getFractionColor('OPFOR'));
}
if (wars.find(war => war.fractionMappingBlufor === Fraction.ARF || war.fractionMappingOpfor === Fraction.ARF)) {
fractions.push(Fraction.ARF);
this.colorScheme.domain.push(FractionHelpers.getFractionColor(Fraction.ARF));
}
if (wars.find(war => war.fractionMappingBlufor === Fraction.SWORD || war.fractionMappingOpfor === Fraction.SWORD)) {
fractions.push(Fraction.SWORD);
this.colorScheme.domain.push(FractionHelpers.getFractionColor(Fraction.SWORD));
}
const pointsObj = ChartUtils.getMultiDataArray(...fractions);
const pointsSumObj = ChartUtils.getMultiDataArray(...fractions);
const playersObj = ChartUtils.getMultiDataArray(...fractions);
for (let i = wars.length - 1; i >= 0; i--) { for (let i = wars.length - 1; i >= 0; i--) {
const war = wars[i]; const war = wars[i];
if (!war) { if (!war) {
continue; continue;
} }
const bluforIndex = fractions.findIndex(fraction =>
fraction === FractionHelpers.getFractionName(war, 'BLUFOR'));
const opforIndex = fractions.findIndex(
fraction => fraction === FractionHelpers.getFractionName(war, 'OPFOR'));
const j = wars.length - i - 1; const j = wars.length - i - 1;
const warDate = (this.id === 'all') ? new Date(war.date) : ChartUtils.getShortDateString(war.date); const warDate = (this.id === 'all') ? new Date(war.date) : ChartUtils.getShortDateString(war.date);
pointsObj[bluforIndex].series.push({
pointsObj[0].series.push({
name: warDate, name: warDate,
value: war.ptBlufor value: war.ptBlufor
}); });
pointsObj[1].series.push({ pointsObj[opforIndex].series.push({
name: warDate, name: warDate,
value: war.ptOpfor value: war.ptOpfor
}); });
pointsSumObj[0].series.push({ pointsSumObj[bluforIndex].series.push({
name: warDate, name: warDate,
value: pointsSumObj[0].series[j - 1] ? value: pointsSumObj[bluforIndex].series[j - 1] ?
pointsSumObj[0].series[j - 1].value + war.ptBlufor : pointsSumObj[bluforIndex].series[j - 1].value + war.ptBlufor :
war.ptBlufor war.ptBlufor
}); });
pointsSumObj[1].series.push({ pointsSumObj[opforIndex].series.push({
name: warDate, name: warDate,
value: pointsSumObj[1].series[j - 1] value: pointsSumObj[opforIndex].series[j - 1]
? pointsSumObj[1].series[j - 1].value + war.ptOpfor : ? pointsSumObj[opforIndex].series[j - 1].value + war.ptOpfor :
war.ptOpfor war.ptOpfor
}); });
playersObj[0].series.push({ playersObj[bluforIndex].series.push({
name: warDate, name: warDate,
value: war.playersBlufor value: war.playersBlufor
}); });
playersObj[1].series.push({ playersObj[opforIndex].series.push({
name: warDate, name: warDate,
value: war.playersOpfor value: war.playersOpfor
}); });

View File

@ -1,8 +1,8 @@
import {Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; import {Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core';
import {ChartUtils} from '../../../utils/chart-utils'; import {ChartUtils} from '../../../utils/chart-utils';
import {Fraction} from '../../../utils/fraction.enum';
import {War} from '../../../models/model-interfaces'; import {War} from '../../../models/model-interfaces';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {FractionHelpers} from '../../../utils/global.helpers';
@Component({ @Component({
@ -12,8 +12,6 @@ import {TranslateService} from '@ngx-translate/core';
}) })
export class FractionStatsComponent implements OnInit, OnChanges { export class FractionStatsComponent implements OnInit, OnChanges {
readonly fraction = Fraction;
@ViewChild('overview') private overviewContainer: ElementRef; @ViewChild('overview') private overviewContainer: ElementRef;
@Input() war: War; @Input() war: War;
@ -41,10 +39,9 @@ export class FractionStatsComponent implements OnInit, OnChanges {
tmpStabilizeData; tmpStabilizeData;
tmpPlayerCountData; tmpPlayerCountData;
colorScheme = { colorScheme;
domain: [Fraction.COLOR_BLUFOR, Fraction.COLOR_OPFOR, Fraction.COLOR_BLUFOR_LIGHT, Fraction.COLOR_OPFOR_LIGHT, fractionNameBlufor;
Fraction.COLOR_BLUFOR_DARK, Fraction.COLOR_OPFOR_DARK, Fraction.COLOR_BLUFOR_GREY, Fraction.COLOR_OPFOR_GREY] fractionNameOpfor;
};
labels; labels;
labelsKeys; labelsKeys;
@ -77,6 +74,21 @@ export class FractionStatsComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (changes.war || changes.logData) { if (changes.war || changes.logData) {
this.fractionNameBlufor = FractionHelpers.getFractionName(this.war, 'BLUFOR');
this.fractionNameOpfor = FractionHelpers.getFractionName(this.war, 'OPFOR');
this.colorScheme = {
domain: [
FractionHelpers.getFractionColor('BLUFOR', this.war),
FractionHelpers.getFractionColor('OPFOR', this.war),
FractionHelpers.getFractionColor('BLUFOR', this.war, 'LIGHT'),
FractionHelpers.getFractionColor('OPFOR', this.war, 'LIGHT'),
FractionHelpers.getFractionColor('BLUFOR', this.war, 'DARK'),
FractionHelpers.getFractionColor('OPFOR', this.war, 'DARK'),
FractionHelpers.getFractionColor('BLUFOR', this.war, 'GREY'),
FractionHelpers.getFractionColor('OPFOR', this.war, 'GREY'),
]
};
this.initialized = { this.initialized = {
budget: false, budget: false,
kill: false, kill: false,
@ -433,7 +445,7 @@ export class FractionStatsComponent implements OnInit, OnChanges {
name: t, name: t,
series: [ series: [
{ {
name: Fraction.BLUFOR, name: this.fractionNameBlufor,
value: flagStatusMap.blufor[lastExistingIdx] ? 1 : 0 value: flagStatusMap.blufor[lastExistingIdx] ? 1 : 0
} }
] ]
@ -442,7 +454,7 @@ export class FractionStatsComponent implements OnInit, OnChanges {
name: t, name: t,
series: [ series: [
{ {
name: Fraction.OPFOR, name: this.fractionNameOpfor,
value: flagStatusMap.opfor[lastExistingIdx] ? -1 : 0 value: flagStatusMap.opfor[lastExistingIdx] ? -1 : 0
} }
] ]
@ -453,17 +465,17 @@ export class FractionStatsComponent implements OnInit, OnChanges {
} }
initializeTempCollections() { initializeTempCollections() {
this.tmpPointData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpPointData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpBudgetData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpBudgetData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpKillData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpKillData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpFrienlyFireData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpFrienlyFireData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpVehicleData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR, this.tmpVehicleData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor,
Fraction.BLUFOR.concat(' Leicht'), Fraction.OPFOR.concat(' Leicht'), Fraction.BLUFOR.concat(' Schwer'), this.fractionNameBlufor.concat(' Leicht'), this.fractionNameOpfor.concat(' Leicht'), this.fractionNameBlufor.concat(' Schwer'),
Fraction.OPFOR.concat(' Schwer'), Fraction.BLUFOR.concat(' Luft'), Fraction.OPFOR.concat(' Luft')); this.fractionNameOpfor.concat(' Schwer'), this.fractionNameBlufor.concat(' Luft'), this.fractionNameOpfor.concat(' Luft'));
this.tmpTransportData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpTransportData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpReviveData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpReviveData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpStabilizeData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpStabilizeData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
this.tmpPlayerCountData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR); this.tmpPlayerCountData = ChartUtils.getMultiDataArray(this.fractionNameBlufor, this.fractionNameOpfor);
[this.tmpKillData, this.tmpFrienlyFireData, this.tmpVehicleData, this.tmpReviveData, this.tmpStabilizeData, [this.tmpKillData, this.tmpFrienlyFireData, this.tmpVehicleData, this.tmpReviveData, this.tmpStabilizeData,
this.tmpTransportData].forEach(tmp => { this.tmpTransportData].forEach(tmp => {
@ -509,10 +521,10 @@ export class FractionStatsComponent implements OnInit, OnChanges {
axisFormatY(val) { axisFormatY(val) {
if (val === 1) { if (val === 1) {
return Fraction.BLUFOR; return this.fractionNameBlufor;
} }
if (val === -1) { if (val === -1) {
return Fraction.OPFOR; return this.fractionNameOpfor;
} }
return ''; return '';
} }

View File

@ -8,7 +8,7 @@
<mat-header-cell *matHeaderCellDef <mat-header-cell *matHeaderCellDef
mat-sort-header="{{tableHead[0].prop}}">{{tableHead[0].head | translate}}</mat-header-cell> mat-sort-header="{{tableHead[0].prop}}">{{tableHead[0].head | translate}}</mat-header-cell>
<mat-cell *matCellDef="let element" <mat-cell *matCellDef="let element"
[style.color]="element['fraction'] === 'BLUFOR' ? fraction.COLOR_BLUFOR : fraction.COLOR_OPFOR"> [style.color]="fractionHelpers.getFractionColor(element['fraction'],war)">
{{element.name}} {{element.name}}
</mat-cell> </mat-cell>
</ng-container> </ng-container>
@ -16,7 +16,7 @@
<ng-container matColumnDef="{{tableHead[1].prop}}"> <ng-container matColumnDef="{{tableHead[1].prop}}">
<mat-header-cell *matHeaderCellDef <mat-header-cell *matHeaderCellDef
mat-sort-header="{{tableHead[1].prop}}">{{tableHead[1].head | translate}}</mat-header-cell> mat-sort-header="{{tableHead[1].prop}}">{{tableHead[1].head | translate}}</mat-header-cell>
<mat-cell *matCellDef="let element">{{element.fraction === 'BLUFOR' ? fraction.BLUFOR : fraction.OPFOR}}</mat-cell> <mat-cell *matCellDef="let element">{{fractionHelpers.getFractionName(war, element.fraction)}}</mat-cell>
</ng-container> </ng-container>
<ng-container *ngFor="let column of tableHead.slice(2, tableHead.length)" matColumnDef="{{column.prop}}"> <ng-container *ngFor="let column of tableHead.slice(2, tableHead.length)" matColumnDef="{{column.prop}}">

View File

@ -6,6 +6,7 @@ import {saveAs} from 'file-saver/FileSaver';
import {MatSort} from '@angular/material'; import {MatSort} from '@angular/material';
import {SortUtils} from '../../../utils/sort-utils'; import {SortUtils} from '../../../utils/sort-utils';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {FractionHelpers} from '../../../utils/global.helpers';
@Component({ @Component({
selector: 'cc-scoreboard', selector: 'cc-scoreboard',
@ -16,6 +17,8 @@ export class ScoreboardComponent implements OnChanges {
readonly fraction = Fraction; readonly fraction = Fraction;
readonly fractionHelpers = FractionHelpers;
@Input() war: War; @Input() war: War;
@Input() fractionFilterSelected: string; @Input() fractionFilterSelected: string;

View File

@ -2,20 +2,28 @@
<div class="war-header-container"> <div class="war-header-container">
<div class="pull-left head-field"> <div class="pull-left head-field">
<h4>{{'stats.scoreboard.standings' | translate}}</h4> <h4>{{'stats.scoreboard.standings' | translate}}</h4>
<span [style.color]="fraction.COLOR_BLUFOR" <span [style.color]="fractionHelpers.getFractionColor('BLUFOR',war)"
style="font-weight: bold; margin-right: 10px">{{fraction.BLUFOR}} {{war.ptBlufor}}</span> style="font-weight: bold; margin-right: 10px">
{{fractionHelpers.getFractionName(war, 'BLUFOR')}} {{war.ptBlufor}}
</span>
<span style="font-size: x-large">|</span> <span style="font-size: x-large">|</span>
<span [style.color]="fraction.COLOR_OPFOR" <span [style.color]="fractionHelpers.getFractionColor('OPFOR',war)"
style="font-weight: bold; margin-left: 10px;">{{war.ptOpfor}} {{fraction.OPFOR}}</span> style="font-weight: bold; margin-left: 10px;">
{{war.ptOpfor}} {{fractionHelpers.getFractionName(war, 'OPFOR')}}
</span>
</div> </div>
<div class="pull-left head-field" style="margin-top:0" *ngIf="isSmallLayout"> <div class="pull-left head-field" style="margin-top:0" *ngIf="isSmallLayout">
<h4>{{'stats.scoreboard.participants' | translate}}</h4> <h4>{{'stats.scoreboard.participants' | translate}}</h4>
<span [style.color]="fraction.COLOR_BLUFOR" <span [style.color]="fractionHelpers.getFractionColor('BLUFOR',war)"
style="font-weight: bold; margin-right: 10px">{{fraction.BLUFOR}} {{war.playersBlufor}}</span> style="font-weight: bold; margin-right: 10px">
{{fractionHelpers.getFractionName(war, 'BLUFOR')}} {{war.playersBlufor}}
</span>
<span style="font-size: 13px;font-weight: bold;">vs</span> <span style="font-size: 13px;font-weight: bold;">vs</span>
<span [style.color]="fraction.COLOR_OPFOR" <span [style.color]="fractionHelpers.getFractionColor('OPFOR',war)"
style="font-weight: bold; margin-left: 10px;">{{war.playersOpfor}} {{fraction.OPFOR}}</span> style="font-weight: bold; margin-left: 10px;">
{{war.playersOpfor}} {{fractionHelpers.getFractionName(war, 'OPFOR')}}
</span>
</div> </div>
<div class="pull-left head-field-pie-chart" *ngIf="!isSmallLayout"> <div class="pull-left head-field-pie-chart" *ngIf="!isSmallLayout">

View File

@ -8,6 +8,7 @@ import {LogsService} from '../../../services/logs/logs.service';
import {ScoreboardComponent} from '../scoreboard/scoreboard.component'; import {ScoreboardComponent} from '../scoreboard/scoreboard.component';
import {BaseConfig} from '../../../app.config'; import {BaseConfig} from '../../../app.config';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {FractionHelpers} from '../../../utils/global.helpers';
@Component({ @Component({
@ -19,6 +20,8 @@ export class WarHeaderComponent implements OnInit {
readonly fraction = Fraction; readonly fraction = Fraction;
readonly fractionHelpers = FractionHelpers;
war: War; war: War;
@ViewChild('scoreboard') scoreBoardComponent: ScoreboardComponent; @ViewChild('scoreboard') scoreBoardComponent: ScoreboardComponent;
@ -43,9 +46,7 @@ export class WarHeaderComponent implements OnInit {
playerChart: any[] = []; playerChart: any[] = [];
colorScheme = { colorScheme;
domain: [Fraction.COLOR_OPFOR, Fraction.COLOR_BLUFOR]
};
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private warService: WarService, private warService: WarService,
@ -64,8 +65,18 @@ export class WarHeaderComponent implements OnInit {
this.fractionStatsInitialized = false; this.fractionStatsInitialized = false;
this.fractionFilterSelected = undefined; this.fractionFilterSelected = undefined;
this.colorScheme = {
domain: [
FractionHelpers.getFractionColor('OPFOR', war),
FractionHelpers.getFractionColor('BLUFOR', war)
]
};
this.playerChart = this.playerChart =
ChartUtils.getSingleDataArray(Fraction.OPFOR, war.playersOpfor, Fraction.BLUFOR, war.playersBlufor); ChartUtils.getSingleDataArray(
FractionHelpers.getFractionName(war, 'OPFOR'), war.playersOpfor,
FractionHelpers.getFractionName(war, 'BLUFOR'), war.playersBlufor
);
Object.assign(this, [this.playerChart]); Object.assign(this, [this.playerChart]);
}); });

View File

@ -25,6 +25,33 @@
</select> </select>
</div> </div>
<div class="form-group">
<label for="fractionMappingBlufor">{{'stats.war.submit.mapping.blufor' | translate}}</label>
<select id="fractionMappingBlufor" name="fractionMappingBlufor" class="form-control btn dropdown-toggle"
required
[(ngModel)]="war.fractionMappingBlufor">
<option value="{{fraction.ARF}}">{{fraction.ARF}}</option>
<option value="{{fraction.SWORD}}">{{fraction.SWORD}}</option>
<option value="OPFOR">{{fraction.OPFOR}}</option>
<option value="BLUFOR">{{fraction.BLUFOR}}</option>
</select>
<show-error displayName="{{'stats.war.submit.mapping.blufor' | translate}}" controlPath="fraction"></show-error>
</div>
<div class="form-group">
<label for="fractionMappingOpfor">{{'stats.war.submit.mapping.opfor' | translate}}</label>
<select id="fractionMappingOpfor" name="fractionMappingOpfor" class="form-control btn dropdown-toggle"
required
[(ngModel)]="war.fractionMappingOpfor">
<option value="{{fraction.ARF}}">{{fraction.ARF}}</option>
<option value="{{fraction.SWORD}}">{{fraction.SWORD}}</option>
<option value="OPFOR">{{fraction.OPFOR}}</option>
<option value="BLUFOR">{{fraction.BLUFOR}}</option>
</select>
<show-error displayName="{{'stats.war.submit.mapping.opfor' | translate}}" controlPath="fraction"></show-error>
</div>
<div class="form-group" *ngIf="!war._id"> <div class="form-group" *ngIf="!war._id">
<label for="log">{{'stats.war.submit.logfile' | translate}}</label> <label for="log">{{'stats.war.submit.logfile' | translate}}</label>
<input id="log" name="log" class="ui-button form-control" type="file" <input id="log" name="log" class="ui-button form-control" type="file"
@ -35,24 +62,24 @@
</div> </div>
<div class="form-group" *ngIf="war._id"> <div class="form-group" *ngIf="war._id">
<label for="ptBlufor">{{'stats.war.submit.points' | translate}} {{fraction.BLUFOR}}</label> <label for="ptBlufor">{{'stats.war.submit.points' | translate}} {{fractionHelpers.getFractionName(war, "BLUFOR")}}</label>
<input type="number" class="form-control" <input type="number" class="form-control"
[(ngModel)]="war.ptBlufor" [(ngModel)]="war.ptBlufor"
name="ptBlufor" name="ptBlufor"
id="ptBlufor" id="ptBlufor"
required min="0"/> required min="0"/>
<show-error displayName="{{'stats.war.submit.points' | translate}} {{fraction.BLUFOR}}" <show-error displayName="{{'stats.war.submit.points' | translate}}"
controlPath="ptBlufor"></show-error> controlPath="ptBlufor"></show-error>
</div> </div>
<div class="form-group" *ngIf="war._id"> <div class="form-group" *ngIf="war._id">
<label for="ptOpfor">{{'stats.war.submit.points' | translate}} {{fraction.OPFOR}}</label> <label for="ptOpfor">{{'stats.war.submit.points' | translate}} {{fractionHelpers.getFractionName(war, "OPFOR")}}</label>
<input type="number" class="form-control" <input type="number" class="form-control"
[(ngModel)]="war.ptOpfor" [(ngModel)]="war.ptOpfor"
name="ptOpfor" name="ptOpfor"
id="ptOpfor" id="ptOpfor"
required min="0"/> required min="0"/>
<show-error displayName="{{'stats.war.submit.points' | translate}} {{fraction.OPFOR}}" <show-error displayName="{{'stats.war.submit.points' | translate}}"
controlPath="ptOpfor"></show-error> controlPath="ptOpfor"></show-error>
</div> </div>

View File

@ -9,6 +9,7 @@ import {SpinnerService} from '../../../services/user-interface/spinner/spinner.s
import {Subscription} from 'rxjs'; import {Subscription} from 'rxjs';
import {Fraction} from '../../../utils/fraction.enum'; import {Fraction} from '../../../utils/fraction.enum';
import {TranslateService} from '@ngx-translate/core'; import {TranslateService} from '@ngx-translate/core';
import {FractionHelpers} from '../../../utils/global.helpers';
@Component({ @Component({
@ -28,6 +29,8 @@ export class WarSubmitComponent {
readonly fraction = Fraction; readonly fraction = Fraction;
readonly fractionHelpers = FractionHelpers;
showFileError = false; showFileError = false;
loading = false; loading = false;

View File

@ -1,17 +1,23 @@
export enum Fraction { export enum Fraction {
COLOR_NEUTRAL = '#222222',
ARF = 'ARF', ARF = 'ARF',
COLOR_ARF = '#336699', COLOR_ARF = '#336699',
COLOR_ARF_LIGHT = '#6666dd',
COLOR_ARF_DARK = '#0C0CA6',
COLOR_ARF_GREY = '#515179',
SWORD = 'SWORD', SWORD = 'SWORD',
COLOR_SWORD = '#8b8b8b', COLOR_SWORD = '#8b8b8b',
COLOR_SWORD_GREY = '#282828',
COLOR_SWORD_DARK = '#101010',
COLOR_SWORD_LIGHT = '#b8b8b8',
BLUFOR = 'NATO', BLUFOR = 'NATO',
OPFOR = 'CSAT',
COLOR_BLUFOR = '#3c5fa1', COLOR_BLUFOR = '#3c5fa1',
COLOR_BLUFOR_LIGHT = '#6666dd', COLOR_BLUFOR_LIGHT = '#6666dd',
COLOR_BLUFOR_DARK = '#0C0CA6', COLOR_BLUFOR_DARK = '#0C0CA6',
COLOR_BLUFOR_GREY = '#515179', COLOR_BLUFOR_GREY = '#515179',
OPFOR = 'CSAT',
COLOR_OPFOR = '#a90100', COLOR_OPFOR = '#a90100',
COLOR_OPFOR_DARK = '#890F0F', COLOR_OPFOR_DARK = '#890F0F',
COLOR_OPFOR_LIGHT = '#fb5555', COLOR_OPFOR_LIGHT = '#fb5555',
COLOR_OPFOR_GREY = '#955c5f', COLOR_OPFOR_GREY = '#955c5f',
COLOR_NEUTRAL = '#222222',
} }

View File

@ -1,4 +1,6 @@
import {MatButtonToggleGroup} from '@angular/material'; import {MatButtonToggleGroup} from '@angular/material';
import {War} from '../models/model-interfaces';
import {Fraction} from './fraction.enum';
export const CSSHelpers = { export const CSSHelpers = {
getBackgroundCSS: (imageUrl) => { getBackgroundCSS: (imageUrl) => {
@ -10,6 +12,90 @@ export const CSSHelpers = {
} }
}; };
export const FractionHelpers = {
getFractionColor: (fraction, war?: War, style?) => {
let switchInput;
if (war) {
switchInput = (fraction === 'BLUFOR' ? war.fractionMappingBlufor : war.fractionMappingOpfor);
} else {
switchInput = fraction;
}
switch (switchInput) {
case Fraction.ARF:
switch (style) {
case 'LIGHT':
return Fraction.COLOR_ARF_LIGHT;
case 'DARK':
return Fraction.COLOR_ARF_DARK;
case 'GREY':
return Fraction.COLOR_ARF_GREY;
default:
return Fraction.COLOR_ARF;
}
case 'BLUFOR':
switch (style) {
case 'LIGHT':
return Fraction.COLOR_BLUFOR_LIGHT;
case 'DARK':
return Fraction.COLOR_BLUFOR_DARK;
case 'GREY':
return Fraction.COLOR_BLUFOR_GREY;
default:
return Fraction.COLOR_BLUFOR;
}
case 'OPFOR':
switch (style) {
case 'LIGHT':
return Fraction.COLOR_OPFOR_LIGHT;
case 'DARK':
return Fraction.COLOR_OPFOR_DARK;
case 'GREY':
return Fraction.COLOR_OPFOR_GREY;
default:
return Fraction.COLOR_OPFOR;
}
case Fraction.SWORD:
switch (style) {
case 'LIGHT':
return Fraction.COLOR_SWORD_LIGHT;
case 'DARK':
return Fraction.COLOR_SWORD_DARK;
case 'GREY':
return Fraction.COLOR_SWORD_GREY;
default:
return Fraction.COLOR_SWORD;
}
}
},
getFractionColors: (war: War, fraction) => {
switch (fraction === 'BLUFOR' ? war.fractionMappingBlufor : war.fractionMappingOpfor) {
case Fraction.ARF:
return Fraction.COLOR_ARF;
case 'BLUFOR':
return Fraction.COLOR_BLUFOR;
case 'OPFOR':
return Fraction.COLOR_OPFOR;
case Fraction.SWORD:
return Fraction.COLOR_SWORD;
}
},
getFractionName: (war: War, fraction) => {
switch (fraction === 'BLUFOR' ? war.fractionMappingBlufor : war.fractionMappingOpfor) {
case Fraction.ARF:
return Fraction.ARF;
case 'BLUFOR':
return Fraction.BLUFOR;
case 'OPFOR':
return Fraction.OPFOR;
case Fraction.SWORD:
return Fraction.SWORD;
}
}
};
export const UIHelpers = { export const UIHelpers = {
toggleReleaseButton: (currentVal, group?: MatButtonToggleGroup) => { toggleReleaseButton: (currentVal, group?: MatButtonToggleGroup) => {
if (group) { if (group) {

View File

@ -88,6 +88,8 @@
"stats.war.submit.button.submit": "Bestätigen", "stats.war.submit.button.submit": "Bestätigen",
"stats.war.submit.button.cancel": "Abbrechen", "stats.war.submit.button.cancel": "Abbrechen",
"stats.war.submit.error.file.format": "Logfile muss im Format RPT, LOG oder TXT vorliegen", "stats.war.submit.error.file.format": "Logfile muss im Format RPT, LOG oder TXT vorliegen",
"stats.war.submit.mapping.blufor": "Fraktion Zuordnung NATO",
"stats.war.submit.mapping.opfor": "Fraktion Zuordnung CSAT",
"stats.campaign.submit.headline.new": "Neue Kampagne hinzufügen", "stats.campaign.submit.headline.new": "Neue Kampagne hinzufügen",
"stats.campaign.submit.headline.edit": "Kampagne editieren", "stats.campaign.submit.headline.edit": "Kampagne editieren",

View File

@ -95,6 +95,8 @@
"stats.war.submit.button.submit": "Submit", "stats.war.submit.button.submit": "Submit",
"stats.war.submit.button.cancel": "Cancel", "stats.war.submit.button.cancel": "Cancel",
"stats.war.submit.error.file.format": "Logfile requires RPT, LOG or TXT format", "stats.war.submit.error.file.format": "Logfile requires RPT, LOG or TXT format",
"stats.war.submit.mapping.blufor": "Fraction Mapping NATO",
"stats.war.submit.mapping.opfor": "Fraction Mapping CSAT",
"stats.campaign.submit.headline.new": "Add new campaign", "stats.campaign.submit.headline.new": "Add new campaign",
"stats.campaign.submit.headline.edit": "Edit campaign", "stats.campaign.submit.headline.edit": "Edit campaign",