Partial Correct heatMap implementation
All checks were successful
Java CI with Maven / build-and-push-frontend (push) Successful in 14s
Java CI with Maven / build-and-push-backend (push) Successful in 10s

This commit is contained in:
Sebastian Böckelmann 2024-03-17 16:01:48 +01:00
parent e53a1797fe
commit 985aa5f83b
4 changed files with 160 additions and 145 deletions

View File

@ -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>

View File

@ -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();
} }
} }

View File

@ -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>

View File

@ -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() {