Building a Dynamic test performance Graph in Angular with Chart.js
Building a Dynamic test performance Graph in Angular with Chart.js

Building a Dynamic test performance Graph in Angular with Chart.js

In this blog post, we'll walk through the process of building a dynamic performance graph for an aptitude test application using Angular and Chart.js. This example will demonstrate how to visualize test results stored in the browser's local storage and present them in a bar chart along with a data table. We’ll cover the following steps:

  1. Setting up the Angular Component: Creating the component and importing necessary dependencies.
  2. Fetching Stored Quiz Results: Retrieving data from localStorage.
  3. Processing Data for Visualization: Preparing the data for the bar chart and table.
  4. Creating the Chart: Rendering the bar chart using Chart.js.
  5. Generating the Data Table: Displaying the data in a structured table format.

1. Setting up the Angular Component

First, let's create an Angular component named AptitudeTestGraphComponent. This component will be responsible for displaying the performance graph and the corresponding data table.

import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
import { Chart } from 'chart.js/auto';
import { ChartOptions, ChartConfiguration } from 'chart.js/auto';

@Component({
  selector: 'app-aptitude-test-graph',
  templateUrl: './aptitude-test-graph.component.html',
  styleUrls: ['./aptitude-test-graph.component.css']
})
export class AptitudeTestGraphComponent implements AfterViewInit {
  @ViewChild('barChart') barChart!: ElementRef;

  userAnswers: any[] = [];
  correctAnswers: any[] = [];
  performanceLevel!: string;
  attemptedQuestions: any[] = []; 
  testName: any;
  currentQuestionIndex: number = 0;
  showSubmitButton: boolean = false;

  constructor() { }

  ngOnInit(): void {
    this.getStoredResults();
  }

  ngAfterViewInit(): void {
    this.showCharts();
  }        

2. Fetching Stored data

The getStoredResults method retrieves the quiz results from localStorage and parses them into a usable format.

  getStoredResults() {
    const resultsString = localStorage.getItem('quizResults');
    if (resultsString) {
      const results = JSON.parse(resultsString);
      this.attemptedQuestions = results.attemptedQuestions;
      this.userAnswers = results.userAnswers;
      this.performanceLevel = results.performanceLevel;
      this.correctAnswers = results.correctAnswers;
      console.log('Stored Quiz Results:', results);
    } else {
      console.log('No quiz results found in localStorage.');
    }
  }        

3. Processing Data for Visualization

The getTopicData method processes the retrieved data to calculate the correct, incorrect, not attempted counts, and a formula value for each topic.

  getTopicData(): { topicName: string, correctCount: number, incorrectCount: number, notAttemptedCount: number, totalCount: number, formulaValue: number, notPerformed: boolean }[] {
    const topicCounts: { [key: string]: { correctCount: number, incorrectCount: number, notAttemptedCount: number, totalCount: number, formulaValue: number, notPerformed: boolean } } = {};

    for (const q of this.attemptedQuestions) {
        const topicName = q.topicName;
        if (topicName) {
            if (!topicCounts[topicName]) {
                topicCounts[topicName] = { correctCount: 0, incorrectCount: 0, notAttemptedCount: 0, totalCount: 0, formulaValue: 0, notPerformed: false };
            }

            if (q.userAnswer.answer === true) {
                topicCounts[topicName].correctCount++;
            } else if (q.userAnswer.answer === false) {
                topicCounts[topicName].incorrectCount++;
            } else {
                topicCounts[topicName].notAttemptedCount++;
            }
            topicCounts[topicName].totalCount++;
            topicCounts[topicName].formulaValue = topicCounts[topicName].correctCount / topicCounts[topicName].totalCount * 10;
            topicCounts[topicName].notPerformed = topicCounts[topicName].correctCount === 0 && topicCounts[topicName].totalCount !== 0;
        }
    }

    return Object.entries(topicCounts).map(([topicName, { correctCount, incorrectCount, notAttemptedCount, totalCount, formulaValue, notPerformed }]) => ({ topicName, correctCount, incorrectCount, notAttemptedCount, totalCount, formulaValue, notPerformed }));
}        

4. Creating the Chart

The showTopicChart method takes the processed data and renders a bar chart using Chart.js. It also appends a data table below the chart for a detailed view.

  showCharts() {
    if (!this.attemptedQuestions.length) return;

    const topicData = this.getTopicData();
    console.log('Topic Data:', topicData);
    this.showTopicChart(topicData);
  }

  showTopicChart(topicData: { topicName: string, correctCount: number, incorrectCount: number, notAttemptedCount: number, totalCount: number, formulaValue: number, notPerformed: boolean }[]) {
    const topicChartCtx = this.barChart.nativeElement.getContext('2d');
    const labels = topicData.map(entry => entry.topicName );
    const formulaValues = topicData.map(entry => entry.formulaValue);
    const notPerformedData = topicData.map(entry => entry.notPerformed ? 0.1 : 0);

    const chartData = {
        labels,
        datasets: [
            {
                label: 'Topic Score',
                data: formulaValues,
                backgroundColor: '#007bff'
            },
            {
                label: 'Topic Not Performed',
                data: notPerformedData,
                backgroundColor: '#C40013'
            }
        ]
    };

    const chartOptions: ChartOptions<'bar'> = {
        responsive: false,
        maintainAspectRatio: false,
        scales: {
            y: {
                beginAtZero: true
            }
        },
        plugins: {
            legend: {
                display: true,
                position: 'bottom'
            }
        }
    };

    const chartConfig: ChartConfiguration<'bar', number[], string> = {
        type: 'bar',
        data: chartData,
        options: chartOptions
    };

    const chart = new Chart(topicChartCtx, chartConfig);        

5. Generating the Data Table

Below the chart, we create a data table to provide a detailed view of the test results.

    // Create the data table
    const tableContainer = document.createElement('div');
    tableContainer.className = 'table-container';

    const table = document.createElement('table');
    table.className = 'table table-striped table-bordered';

    const thead = document.createElement('thead');
    const headerRow = document.createElement('tr');
    ['Topic', 'Correct', 'Incorrect', 'Not Attempted', 'Total', 'Formula Value'].forEach(header => {
        const th = document.createElement('th');
        th.textContent = header;
        headerRow.appendChild(th);
    });
    thead.appendChild(headerRow);
    table.appendChild(thead);

    const tbody = document.createElement('tbody');
    topicData.forEach(entry => {
        const row = document.createElement('tr');
        const topicCell = document.createElement('td');
        topicCell.textContent = entry.topicName;
        row.appendChild(topicCell);

        const correctCell = document.createElement('td');
        correctCell.textContent = entry.correctCount.toString();
        row.appendChild(correctCell);

        const incorrectCell = document.createElement('td');
        incorrectCell.textContent = entry.incorrectCount.toString();
        row.appendChild(incorrectCell);

        const notAttemptedCell = document.createElement('td');
        notAttemptedCell.textContent = entry.notAttemptedCount.toString();
        row.appendChild(notAttemptedCell);

        const totalCell = document.createElement('td');
        totalCell.textContent = entry.totalCount.toString();
        row.appendChild(totalCell);

        const formulaValueCell = document.createElement('td');
        formulaValueCell.textContent = entry.formulaValue.toFixed(2);
        row.appendChild(formulaValueCell);

        tbody.appendChild(row);
    });
    table.appendChild(tbody);
    tableContainer.appendChild(table);

    const chartContainer = this.barChart.nativeElement.parentElement;
    chartContainer.appendChild(tableContainer);
}        

6. HTML

<div class="chart-container">
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <canvas #barChart></canvas>
      </div>
    </div>
  </div>
</div>
        

Conclusion

In this post, we demonstrated how to create a dynamic aptitude test performance graph in Angular using Chart.js. By fetching data from localStorage, processing it for visualization, and rendering both a bar chart and a detailed data table, we can provide users with clear insights into their test performance. This approach can be extended to other types of data visualizations and applications, offering a robust solution for presenting analytical results in a user-friendly manner.

要查看或添加评论,请登录

Chandan Kumar的更多文章

社区洞察

其他会员也浏览了