fix-statistics #110
@ -1,8 +1,11 @@
|
|||||||
<div style="text-align:center">
|
<div style="text-align:center" *ngIf="selectedTaskgroupPath != undefined">
|
||||||
<apx-chart
|
<apx-chart
|
||||||
[series]="chartOptions.series!"
|
[series]="chartOptions!.series!"
|
||||||
[chart]="chartOptions.chart!"
|
[chart]="chartOptions!.chart!"
|
||||||
[xaxis]="chartOptions.xaxis!"
|
[title]="chartOptions!.title!"
|
||||||
[title]="chartOptions.title!"
|
[plotOptions]="chartOptions!.plotOptions!"
|
||||||
|
[xaxis]="chartOptions!.xAxis!"
|
||||||
|
[yaxis]="chartOptions!.yAxis!"
|
||||||
|
[tooltip]="chartOptions!.tooltip!"
|
||||||
></apx-chart>
|
></apx-chart>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,168 +1,180 @@
|
|||||||
import {Component, Input, OnInit, ViewChild} from '@angular/core';
|
import {Component, Input, OnChanges, ViewChild} from '@angular/core';
|
||||||
import {ApexAxisChartSeries, ChartComponent, ChartType} from "ng-apexcharts";
|
|
||||||
import {ChartOptions} from "../taskgroup-activity.component";
|
import {
|
||||||
|
ApexAxisChartSeries,
|
||||||
|
ApexTitleSubtitle,
|
||||||
|
ApexDataLabels,
|
||||||
|
ApexChart,
|
||||||
|
ApexPlotOptions, ChartComponent, ApexXAxis, ApexYAxis, ApexTooltip
|
||||||
|
} from "ng-apexcharts";
|
||||||
|
import {generate} from "rxjs";
|
||||||
import * as moment from "moment";
|
import * as moment from "moment";
|
||||||
import {HistoryService, TaskgroupActivityInfo, TaskgroupPathInfo} from "../../../../api";
|
import {HistoryService, TaskgroupActivityInfo, TaskgroupPathInfo} from "../../../../api";
|
||||||
|
|
||||||
|
export type ChartOptions = {
|
||||||
interface XYData {
|
series: ApexAxisChartSeries;
|
||||||
x: any,
|
chart: ApexChart;
|
||||||
y: any
|
dataLabels: ApexDataLabels;
|
||||||
}
|
title: ApexTitleSubtitle;
|
||||||
|
plotOptions: ApexPlotOptions;
|
||||||
|
xAxis: ApexXAxis,
|
||||||
|
yAxis: ApexYAxis,
|
||||||
|
tooltip: ApexTooltip
|
||||||
|
};
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-heatmap-activity',
|
selector: 'app-heatmap-activity',
|
||||||
templateUrl: './heatmap-activity.component.html',
|
templateUrl: './heatmap-activity.component.html',
|
||||||
styleUrls: ['./heatmap-activity.component.css']
|
styleUrls: ['./heatmap-activity.component.css']
|
||||||
})
|
})
|
||||||
export class HeatmapActivityComponent implements OnInit{
|
export class HeatmapActivityComponent implements OnChanges{
|
||||||
|
|
||||||
@ViewChild("chart") chart?: ChartComponent;
|
@ViewChild("chart") chart: ChartComponent | undefined;
|
||||||
public chartOptions: Partial<ChartOptions> = this.generateChartOptions()
|
@Input() selectedTaskgroupPath: TaskgroupPathInfo | undefined
|
||||||
|
public chartOptions: Partial<ChartOptions> | undefined;
|
||||||
|
|
||||||
@Input() selectedTaskgroupPath?: TaskgroupPathInfo
|
maxValue = 120
|
||||||
|
|
||||||
constructor(private historyService: HistoryService) {
|
constructor(private historyService: HistoryService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnChanges() {
|
||||||
this.chartOptions = this.generateChartOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
generateChartOptions(): Partial<ChartOptions> {
|
|
||||||
return {
|
|
||||||
series: this.generateSeries(),
|
|
||||||
chart: {
|
|
||||||
height: 350,
|
|
||||||
type: 'heatmap',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: ""
|
|
||||||
},
|
|
||||||
dataLabels: {
|
|
||||||
enabled: false
|
|
||||||
},
|
|
||||||
colors: ["#008FFB"],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSeries() : ApexAxisChartSeries {
|
|
||||||
const series: ApexAxisChartSeries = []
|
|
||||||
|
|
||||||
if(this.selectedTaskgroupPath != undefined) {
|
if(this.selectedTaskgroupPath != undefined) {
|
||||||
const startingDate = new Date(2023, 4, 9);
|
|
||||||
const endDate = new Date(2023, 11, 20);
|
|
||||||
let activityInfos: TaskgroupActivityInfo[];
|
|
||||||
this.historyService.statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(
|
this.historyService.statisticsTaskgroupActivityTaskgroupIDStartingDateEndingDateIncludeSubTaskgroupsGet(
|
||||||
this.selectedTaskgroupPath.rootTasktroup.taskgroupID,
|
this.selectedTaskgroupPath!.rootTasktroup.taskgroupID,
|
||||||
moment().subtract(6, "months").format("YYYY-MM-DD"),
|
moment().startOf('year').format("YYYY-MM-DD"),
|
||||||
moment().add(2, 'days').format("YYYY-MM-DD"),
|
moment().endOf("year").format("YYYY-MM-DD"),
|
||||||
true
|
false
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: resp => {
|
next: resp => {
|
||||||
activityInfos = resp;
|
const taskgroupActivityInfo = resp;
|
||||||
const data: XYData[][] = [];
|
console.log("Chat Options")
|
||||||
let currentDate: moment.Moment = moment(activityInfos[0].date).subtract(moment(activityInfos[0].date).day(), 'days');
|
this.chartOptions = {
|
||||||
|
series: [
|
||||||
//Offset until data starts
|
{
|
||||||
let index = currentDate.day();
|
name: "Monday",
|
||||||
while(currentDate < moment(activityInfos[0].date)) {
|
data: this.generateData(moment().startOf('year'),taskgroupActivityInfo)
|
||||||
if(data[currentDate.day()] == undefined) {
|
},
|
||||||
data[currentDate.day()] = [];
|
{
|
||||||
|
name: "Tuesday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(1, "days"),taskgroupActivityInfo)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wednesday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(2, "days"), taskgroupActivityInfo)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Thursday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(3, "days"), taskgroupActivityInfo)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Friday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(4, "days"), taskgroupActivityInfo)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Saturday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(5, "days"), taskgroupActivityInfo)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sunday",
|
||||||
|
data: this.generateData(moment().startOf('year').add(6, "days"), taskgroupActivityInfo)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
chart: {
|
||||||
|
height: 350,
|
||||||
|
type: "heatmap"
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
heatmap: {
|
||||||
|
shadeIntensity: 0.5,
|
||||||
|
colorScale: {
|
||||||
|
ranges: [
|
||||||
|
{
|
||||||
|
from: 0,
|
||||||
|
to: 5,
|
||||||
|
name: "low",
|
||||||
|
color: "#00A100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 6,
|
||||||
|
to: 20,
|
||||||
|
name: "medium",
|
||||||
|
color: "#128FD9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 21,
|
||||||
|
to: 45,
|
||||||
|
name: "high",
|
||||||
|
color: "#FFB200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: 46,
|
||||||
|
to: this.maxValue,
|
||||||
|
name: "extreme",
|
||||||
|
color: "#FF0000"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: true,
|
||||||
|
style: {
|
||||||
|
fontSize: "12px"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: "HeatMap Chart with Color Range"
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
enabled: true,
|
||||||
|
y: {
|
||||||
|
formatter: function (value, { seriesIndex, dataPointIndex, w }) {
|
||||||
|
return "<span style='font-weight: normal'>Spent </span>" + value + " <span style='font-weight: normal'>Minutes on <br>" + w.config.series[seriesIndex].data[dataPointIndex].extraInfo.format("dddd, MMMM D, YYYY") + "</span>"
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
formatter: seriesName => ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
data[currentDate.day()][index] = {
|
|
||||||
x: moment(currentDate).toDate(),
|
|
||||||
y: 0
|
|
||||||
}
|
|
||||||
currentDate.add(1, 'days');
|
|
||||||
}
|
|
||||||
|
|
||||||
//inside data
|
|
||||||
activityInfos.forEach(activityInfo => {
|
|
||||||
const momentDate: moment.Moment = moment(activityInfo.date);
|
|
||||||
const seriesIndex = momentDate.day();
|
|
||||||
|
|
||||||
if(data[seriesIndex] == undefined) {
|
|
||||||
data[seriesIndex] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
data[seriesIndex][index] = {
|
|
||||||
x: activityInfo.date,
|
|
||||||
y: activityInfo.activeMinutes
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(seriesIndex == 6) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
currentDate = moment(activityInfos[activityInfos.length-1].date);
|
|
||||||
currentDate = currentDate.add(1, "days");
|
|
||||||
//offset outside data
|
|
||||||
for(let i=moment(activityInfos[activityInfos.length-1].date).day(); i<7; i++) {
|
|
||||||
data[i][index] = {
|
|
||||||
x: moment(currentDate).toDate(),
|
|
||||||
y: 0
|
|
||||||
}
|
|
||||||
console.log(currentDate)
|
|
||||||
currentDate = currentDate.add(1, "days");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
series.push({
|
|
||||||
name: "Saturday",
|
|
||||||
data: data[6]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Friday",
|
|
||||||
data: data[5]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Thursday",
|
|
||||||
data: data[4]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Wednesday",
|
|
||||||
data: data[3]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Tuesday",
|
|
||||||
data: data[2]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Monday",
|
|
||||||
data: data[1]
|
|
||||||
});
|
|
||||||
series.push({
|
|
||||||
name: "Sunday",
|
|
||||||
data: data[0]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return series;
|
|
||||||
} else {
|
|
||||||
return series;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generateData(start: moment.Moment, end: moment.Moment) {
|
private generateData(startingDate: moment.Moment, data: TaskgroupActivityInfo[]) {
|
||||||
const data: TaskgroupActivityInfo[] = [];
|
let currentDate = startingDate;
|
||||||
let currentDate: moment.Moment = moment(start);
|
|
||||||
while(currentDate <= end) {
|
let series = []
|
||||||
data.push({
|
let endingDate = startingDate.clone().endOf('year');
|
||||||
date: currentDate.format("YYYY-MM-DD"),
|
|
||||||
activeMinutes: Math.floor(Math.random() * (100 + 1))
|
while(currentDate.isBefore(endingDate)) {
|
||||||
|
let x = "w" + currentDate.isoWeek();
|
||||||
|
let y = this.findTaskgroupActivityInfoByDate(currentDate, data)
|
||||||
|
let extraInfo = currentDate.clone()
|
||||||
|
|
||||||
|
series.push({
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
extraInfo: extraInfo
|
||||||
})
|
})
|
||||||
currentDate = currentDate.add(1, 'days');
|
currentDate = currentDate.add(7, "days");
|
||||||
}
|
}
|
||||||
return data;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedTaskgroupPath(taskgroupPath: TaskgroupPathInfo) {
|
private findTaskgroupActivityInfoByDate(date: moment.Moment, data: TaskgroupActivityInfo[]) {
|
||||||
this.selectedTaskgroupPath = taskgroupPath;
|
return data.find(taskActivity => moment(taskActivity.date).isSame(date))
|
||||||
this.chartOptions = this.generateChartOptions();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,5 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<app-simple-activity-diagram *ngIf="selectedChartype !== 'heatmap'" #simpleActivityDiagram [selectedChartype]="selectedChartype" [selectedTaskgroupPath]="selectedTaskgroupPath"></app-simple-activity-diagram>
|
<app-simple-activity-diagram *ngIf="selectedChartype !== 'heatmap'" #simpleActivityDiagram [selectedChartype]="selectedChartype" [selectedTaskgroupPath]="selectedTaskgroupPath"></app-simple-activity-diagram>
|
||||||
<app-heatmap-activity *ngIf="selectedChartype === 'heatmap'" #heatMap></app-heatmap-activity>
|
<app-heatmap-activity *ngIf="selectedChartype === 'heatmap'" #heatMap [selectedTaskgroupPath]="selectedTaskgroupPath!"></app-heatmap-activity>
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,7 +70,7 @@ export class TaskgroupActivityComponent implements OnInit{
|
|||||||
this.simpleActivityDiagram.setSelectedTaskgroupPath(this.selectedTaskgroupPath!);
|
this.simpleActivityDiagram.setSelectedTaskgroupPath(this.selectedTaskgroupPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.heatMap?.setSelectedTaskgroupPath(this.selectedTaskgroupPath!);
|
//this.heatMap?.setSelectedTaskgroupPath(this.selectedTaskgroupPath!);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectChartType() {
|
onSelectChartType() {
|
||||||
|
Loading…
Reference in New Issue
Block a user