Skip to content

Commit

Permalink
Grading: Fix course statistics to show correct numbers in tooltips (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
rstief authored Oct 3, 2023
1 parent d2ff084 commit a0e3758
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ <h2 class="col-9">{{ 'artemisApp.exercise-scores-chart.title' | artemisTranslate
>
<ng-template #tooltipTemplate let-model="model">
<b>{{ model.name }}</b> <br />
<span>{{ model.series }}: {{ Math.max(model.value - 1, 0) }} %</span>
<span>{{ model.series }}: {{ Math.max(model.value, 0) }} %</span>
</ng-template>
<ng-template #seriesTooltipTemplate let-model="model">
<ng-container *ngIf="model.length">
<h6>{{ model[0].name }}</h6>
<div *ngFor="let entry of model">{{ entry.series }}: {{ Math.max(entry.value - 1, 0) }}%</div>
<div *ngFor="let entry of model">{{ entry.series }}: {{ Math.max(entry.value, 0) }}%</div>
<b>
{{ 'artemisApp.exercise-scores-chart.exerciseType' | artemisTranslate }}
{{ 'artemisApp.exercise-scores-chart.' + model[0].exerciseType.toLowerCase() | artemisTranslate }}</b
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ import { ChartExerciseTypeFilter } from 'app/shared/chart/chart-exercise-type-fi
import { GraphColors } from 'app/entities/statistics.model';
import { ArtemisNavigationUtilService } from 'app/utils/navigation.utils';

type ChartSeries = {
name: string;
series: SeriesDatapoint[];
};

export type ChartNode = SeriesDatapoint & {
series: string;
};

type SeriesDatapoint = {
name: string;
value: number;
exerciseId: number;
exerciseType: string;
};

@Component({
selector: 'jhi-exercise-scores-chart',
templateUrl: './exercise-scores-chart.component.html',
Expand All @@ -37,8 +53,8 @@ export class ExerciseScoresChartComponent implements AfterViewInit, OnChanges {
faFilter = faFilter;

// ngx
ngxData: any[] = [];
backUpData: any[] = [];
ngxData: ChartSeries[] = [];
backUpData: ChartSeries[] = [];
xAxisLabel: string;
yAxisLabel: string;
ngxColor = {
Expand Down Expand Up @@ -117,12 +133,12 @@ export class ExerciseScoresChartComponent implements AfterViewInit, OnChanges {
*/
private addData(exerciseScoresDTOs: ExerciseScoresDTO[]): void {
this.ngxData = [];
const scoreSeries: any[] = [];
const averageSeries: any[] = [];
const bestScoreSeries: any[] = [];
const scoreSeries: SeriesDatapoint[] = [];
const averageSeries: SeriesDatapoint[] = [];
const bestScoreSeries: SeriesDatapoint[] = [];
exerciseScoresDTOs.forEach((exerciseScoreDTO) => {
const extraInformation = {
exerciseId: exerciseScoreDTO.exerciseId,
exerciseId: exerciseScoreDTO.exerciseId!,
exerciseType: exerciseScoreDTO.exerciseType,
};
// adapt the y-axis max
Expand All @@ -132,9 +148,9 @@ export class ExerciseScoresChartComponent implements AfterViewInit, OnChanges {
round(exerciseScoreDTO.maxScoreAchieved!),
this.maxScale,
);
scoreSeries.push({ name: exerciseScoreDTO.exerciseTitle, value: round(exerciseScoreDTO.scoreOfStudent!) + 1, ...extraInformation });
averageSeries.push({ name: exerciseScoreDTO.exerciseTitle, value: round(exerciseScoreDTO.averageScoreAchieved!) + 1, ...extraInformation });
bestScoreSeries.push({ name: exerciseScoreDTO.exerciseTitle, value: round(exerciseScoreDTO.maxScoreAchieved!) + 1, ...extraInformation });
scoreSeries.push({ name: exerciseScoreDTO.exerciseTitle!, value: round(exerciseScoreDTO.scoreOfStudent!), ...extraInformation });
averageSeries.push({ name: exerciseScoreDTO.exerciseTitle!, value: round(exerciseScoreDTO.averageScoreAchieved!), ...extraInformation });
bestScoreSeries.push({ name: exerciseScoreDTO.exerciseTitle!, value: round(exerciseScoreDTO.maxScoreAchieved!), ...extraInformation });
});

const studentScore = { name: this.yourScoreLabel, series: scoreSeries };
Expand All @@ -144,7 +160,7 @@ export class ExerciseScoresChartComponent implements AfterViewInit, OnChanges {
this.ngxData.push(averageScore);
this.ngxData.push(bestScore);
this.ngxData = [...this.ngxData];
this.backUpData = [...this.ngxData];
this.backUpData = cloneDeep(this.ngxData);
}

/**
Expand All @@ -153,34 +169,29 @@ export class ExerciseScoresChartComponent implements AfterViewInit, OnChanges {
* If the users click on an entry in the legend, the corresponding line disappears or reappears depending on its previous state
* @param data the event sent by the framework
*/
onSelect(data: any): void {
// delegate to the corresponding exercise if chart node is clicked
if (data.exerciseId) {
this.navigateToExercise(data.exerciseId);
} else {
// if a legend label is clicked, the corresponding line has to disappear or reappear
const name = JSON.parse(JSON.stringify(data)) as string;
onSelect(data: ChartNode | string): void {
if (typeof data === 'string') {
// if a legend label is clicked, the visibility of the corresponding line is toggled
const name: string = data;
// find the affected line in the dataset
const index = this.ngxData.findIndex((dataPack: any) => {
const dataName = dataPack.name as string;
return dataName === name;
});
// check whether the line is currently displayed
if (this.ngxColor.domain[index] !== 'rgba(255,255,255,0)') {
const placeHolder = cloneDeep(this.ngxData[index]);
placeHolder.series.forEach((piece: any) => {
piece.value = 0;
});
// exchange actual line with all-zero line and make color transparent
this.ngxData[index] = placeHolder;
//if the line is displayed, remove its values and make it transparent
this.ngxData[index].series = [];
this.ngxColor.domain[index] = 'rgba(255,255,255,0)';
} else {
// if the line is currently hidden, the color and the values are reset
// if the line is currently hidden, the values and the color are reset
this.ngxData[index].series = cloneDeep(this.backUpData[index].series);
this.ngxColor.domain[index] = this.colorBase[index];
this.ngxData[index] = this.backUpData[index];
}
// trigger a chart update
this.ngxData = [...this.ngxData];
} else {
// if a chart node is clicked, navigate to the corresponding exercise
this.navigateToExercise(data.exerciseId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateService } from '@ngx-translate/core';
import { AlertService } from 'app/core/util/alert.service';
import { MockDirective, MockModule, MockPipe, MockProvider } from 'ng-mocks';
import { ExerciseScoresChartComponent } from 'app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component';
import { ChartNode, ExerciseScoresChartComponent } from 'app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component';
import { ArtemisTranslatePipe } from 'app/shared/pipes/artemis-translate.pipe';
import { of } from 'rxjs';
import { ActivatedRoute } from '@angular/router';
Expand Down Expand Up @@ -136,11 +136,11 @@ describe('ExerciseScoresChartComponent', () => {
component.onSelect(legendClickEvent);

expect(component.ngxColor.domain[2]).toBe('rgba(255,255,255,0)');
expect(component.ngxData[2].series.map((exercise: any) => exercise.value)).toEqual([0, 0]);
expect(component.ngxData[2].series).toEqual([]);

component.onSelect(legendClickEvent);
expect(component.ngxColor.domain[2]).toBe(GraphColors.GREEN);
expect(component.ngxData[2].series.map((exercise: any) => exercise.value)).toEqual([61, 71]);
expect(component.ngxData[2].series.map((exercise: any) => exercise.value)).toEqual([60, 70]);
});

it('should react correct if chart point is clicked', () => {
Expand All @@ -150,7 +150,7 @@ describe('ExerciseScoresChartComponent', () => {
setUpServiceAndStartComponent([firstExercise, secondExercise]);
const routingService = TestBed.inject(ArtemisNavigationUtilService);
const routingStub = jest.spyOn(routingService, 'routeInNewTab');
const pointClickEvent = { exerciseId: 2 };
const pointClickEvent: ChartNode = { exerciseType: '', name: '', series: '', value: 0, exerciseId: 2 };

component.onSelect(pointClickEvent);

Expand All @@ -177,7 +177,7 @@ describe('ExerciseScoresChartComponent', () => {
});

function validateStructureOfDataPoint(dataPoint: any, exerciseScoresDTO: ExerciseScoresDTO, score: number) {
const expectedStructure = { name: exerciseScoresDTO.exerciseTitle, value: score + 1, exerciseId: exerciseScoresDTO.exerciseId, exerciseType: exerciseScoresDTO.exerciseType };
const expectedStructure = { name: exerciseScoresDTO.exerciseTitle, value: score, exerciseId: exerciseScoresDTO.exerciseId, exerciseType: exerciseScoresDTO.exerciseType };
expect(dataPoint).toEqual(expectedStructure);
}

Expand Down

0 comments on commit a0e3758

Please sign in to comment.