diff --git a/src/main/webapp/app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component.html b/src/main/webapp/app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component.html index 7390a72a5907..02a0bccffc96 100644 --- a/src/main/webapp/app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component.html +++ b/src/main/webapp/app/overview/visualizations/exercise-scores-chart/exercise-scores-chart.component.html @@ -46,12 +46,12 @@

{{ 'artemisApp.exercise-scores-chart.title' | artemisTranslate > {{ model.name }}
- {{ model.series }}: {{ Math.max(model.value - 1, 0) }} % + {{ model.series }}: {{ Math.max(model.value, 0) }} %
{{ model[0].name }}
-
{{ entry.series }}: {{ Math.max(entry.value - 1, 0) }}%
+
{{ entry.series }}: {{ Math.max(entry.value, 0) }}%
{{ 'artemisApp.exercise-scores-chart.exerciseType' | artemisTranslate }} {{ 'artemisApp.exercise-scores-chart.' + model[0].exerciseType.toLowerCase() | artemisTranslate }} { const extraInformation = { - exerciseId: exerciseScoreDTO.exerciseId, + exerciseId: exerciseScoreDTO.exerciseId!, exerciseType: exerciseScoreDTO.exerciseType, }; // adapt the y-axis max @@ -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 }; @@ -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); } /** @@ -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); } } diff --git a/src/test/javascript/spec/component/overview/course-statistics/visualizations/exercise-scores-chart.component.spec.ts b/src/test/javascript/spec/component/overview/course-statistics/visualizations/exercise-scores-chart.component.spec.ts index 4cac347eb88d..76416a42e4f9 100644 --- a/src/test/javascript/spec/component/overview/course-statistics/visualizations/exercise-scores-chart.component.spec.ts +++ b/src/test/javascript/spec/component/overview/course-statistics/visualizations/exercise-scores-chart.component.spec.ts @@ -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'; @@ -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', () => { @@ -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); @@ -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); }