
En este proyecto utilizamos ng2-chartjs para generar gráficas en Angular, nos apoyamos de Bootstrap para la maquetación, utilizamos MySQL como base de datos, y como backend Node.Js con Express. Tantos los datos de las graficas como sus colores van a ser parametrizables. El resultado que se obtendrá de este proyecto es el siguiente.


Tabla de Contenido
Requerimientos
- Conocimientos básicos de SQL
- Conocimientos básicos de Node.js
- Conocimientos intermedios de Angular
- Conocimientos básicos de Bootstrap
- Servidor Mysql
Configuración de la Base de Datos
Creamos una base de datos con el nombre graficas.
A continuación dejo el script de la base de datos, únicamente es una tabla, para ahorrar tiempo.
CREATE TABLE `graf_categoria` ( `PK_CATE` int(11) NOT NULL, `NOMBRE_CATE` varchar(255) NOT NULL, `COLOR_CATE` varchar(255) NOT NULL, `DATOS_CATE` varchar(255) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `graf_categoria` (`PK_CATE`, `NOMBRE_CATE`, `COLOR_CATE`, `DATOS_CATE`) VALUES (1, 'Hombres', '#1449a9', '1,2,3,4,5,4,10'), (3, 'Mujeres', '#8221e2', '1,4,5,6,8'), (4, 'Aliens', '#21d585', '1,2,3,4,5'); ALTER TABLE `graf_categoria` ADD PRIMARY KEY (`PK_CATE`); ALTER TABLE `graf_categoria` MODIFY `PK_CATE` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13; COMMIT;
Instalación del Backend
Para no alargar tanto este proyecto ya que lo que nos interesa es ver la parte Angular, vamos a partir primero instalando lo necesario, clonamos el backend que esta en Node.js, es un proyecto muy básico para efectos de pruebas.
git clone https://github.com/VManuelPM/GraficasAngularBack
Entramos a la carpeta del proyecto GraficasAngularBack e instalamos las dependencias.
npm install
Iniciamos el proyecto back con el comando nodemon
Creación del proyecto Angular
ng new GraficasAngular add routes = yes styles = scss
Instalación de dependencias
Las siguientes dependencias son las necesarias para realizar gráficas en Angular
npm install --save ng2-charts npm install --save chart.js npm install chartjs-plugin-annotation --save
Para utilizar el color picker el cual nos permite seleccionar colores de una paleta
npm install ngx-color-picker --save

Importación módulos a app.module.ts
import { HttpClientModule } from '@angular/common/http'; import { ReactiveFormsModule } from '@angular/forms'; import { ChartsModule } from 'ng2-charts'; import { ColorPickerModule } from 'ngx-color-picker'; imports: [ BrowserModule, AppRoutingModule, HttpClientModule, ReactiveFormsModule, ColorPickerModule, ChartsModule ]
Configuración rápida de Bootstrap
En el archivo index.htlm en la parte de <head></head> colocamos el cnd de Bootstrap
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
Creación de componentes menú, grafica y categoría
Creamos tres componentes uno para el menú de la aplicación, categoría es donde se listan las categorías y se crea el formulario para agregarlas y editarlas, y finalmente grafica donde vamos a pintar nuestro diagrama.
ng g c components/categoria ng g c components/graficas ng g c components/menu
Configuración de rutas
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { CategoriaComponent } from './components/categoria/categoria.component'; import { GraficasComponent } from './components/graficas/graficas.component'; const routes: Routes = [ { path: 'categoria', component: CategoriaComponent }, { path: 'categoria/:idCategoria', component: CategoriaComponent }, { path: 'graficas', component: GraficasComponent }, { path: '', component: CategoriaComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
Creación y configuración del Servicio
Creamos un servicio para hacer nuestras peticiones http a nuestro backend
ng g s services/categoria
Luego de la creación del servicio debemos tener un archivo llamado categoria.service.ts
Por costumbre y buenas practicas alojo la url base de mis servicios en el archivo enviroment.ts
export const environment = { baseUrl: 'http://localhost:3050', production: false };
Luego en el categoria.service.ts creamos los servicios necesarios para nuestra aplicación
import { Injectable } from '@angular/core'; import { environment } from '../../environments/environment'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class CategoriaService { baseUrl = environment.baseUrl; constructor(protected http: HttpClient) { } getCategorias() { return this.http.get(`${this.baseUrl}/categorias`); } getCategoria(idCategoria: string){ return this.http.get(`${this.baseUrl}/categorias/${idCategoria}`); } guardarCategoria(categoria: any) { return this.http.post(`${this.baseUrl}/addCategoria`, categoria); } borrarCategoria(idCategoria: number){ return this.http.delete(`${this.baseUrl}/deleteCategoria/${idCategoria}`); } actualizarCategoria(categoria: any){ return this.http.put(`${this.baseUrl}/updateCategoria/${categoria['idCategoria']}`, categoria); } }
Creación del menú
En el archivo menu.component.html utilizamos las clases de Bootstrap para agilizar la maquetación del front
<nav id="menu" class="navbar navbar-expand-lg navbar-light bg-light"> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <a class="nav-link" [routerLink]="['/categoria']" [routerLinkActive]="['active']">Categoria</a> </li> <li class="nav-item"> <a class="nav-link" [routerLink]="['/graficas']" [routerLinkActive]="['active']">Gráficas</a> </li> </ul> </div> </nav>
#menu{ margin-bottom: 15px; } .active{ border-top: 2px solid orange; background-color: gray; }
Creación de la categoría
<!-- Creación del formulario --> <div class="row"> <div class="card col-3"> <div class="card-body"> <form [formGroup] = "categoriaForm" (ngSubmit)="agregarCategoria()"> <div class="form-group"> <label for="categoria">Nombre de la categoria</label> <input type="text" class="form-control" id="categoria" formControlName="nombreCategoria"> </div> <div class="form-group"> <label for="categoria">Datos</label> <input type="text" class="form-control" id="categoria" formControlName="datosCategoria" required> <small id="emailHelp" class="form-text text-muted">Datos separados por una , ejem: 1,2,3</small> </div> <div class="form-group"> <label for="categoria">Color de la gráfica</label> <!-- Input que permite seleccionar el color de la paleta --> <input class="form-control" [(colorPicker)]="color" [style.background]="color" formControlName="colorCategoria" readonly/> </div> <div class="form-group"> <button class="btn btn-success" [disabled]="!categoriaForm.valid">{{textButton}}</button> </div> </form> </div> </div> <!-- Creación de la tabla --> <div class="col-9"> <table class="table"> <thead class="thead-dark text-center"> <tr> <th scope="col">NOMBRE_CATE</th> <th scope="col">DATOS_CATE</th> <th scope="col">COLOR_CATE</th> <th scope="col">OPCION</th> </tr> </thead> <tbody> <tr *ngFor="let categoria of categorias"> <td>{{categoria.NOMBRE_CATE}}</td> <td>{{categoria.DATOS_CATE}}</td> <td> <input class="form-control" [(colorPicker)]="categoria.COLOR_CATE" [style.background]="categoria.COLOR_CATE" readonly disabled/> </td> <td> <button class="btn btn-success" [routerLink]="['/categoria', categoria.PK_CATE]">Editar</button> <button class="btn btn-danger" (click)="borrarCategoria(categoria.PK_CATE)">Borrar</button> </td> </tr> </tbody> </table> </div> </div>
import { Component, OnInit } from '@angular/core'; import { CategoriaService } from '../../services/categoria.service'; import { FormGroup, FormBuilder } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-categoria', templateUrl: './categoria.component.html', styleUrls: ['./categoria.component.scss'] }) export class CategoriaComponent implements OnInit { categorias: any = []; color = "black"; categoriaForm: FormGroup; categoria: any; nombreCat: string; datosCat: string; idCategoria: string; textButton: string; constructor(protected categoriaService: CategoriaService, public fb: FormBuilder, private route: ActivatedRoute) { this.textButton = "Agregar"; this.obtenerParametroUrl(); this.categoriaForm = this.fb.group({ idCategoria: [''], nombreCategoria: ['', Validators.required], datosCategoria: ['', Validators.required], colorCategoria: [''] }); } ngOnInit(): void { this.getCategorias(); } obtenerParametroUrl() { this.route.paramMap.subscribe(params => { this.idCategoria = params.get('idCategoria'); if (this.idCategoria) { this.categoriaService.getCategoria(this.idCategoria).subscribe(res => { this.color = res[0].COLOR_CATE; this.datosCat = res[0].DATOS_CATE; this.nombreCat = res[0].NOMBRE_CATE; this.categoriaForm.patchValue({ idCategoria: [this.idCategoria], nombreCategoria: [this.nombreCat], datosCategoria: [this.datosCat], colorCategoria: [this.color] }); this.textButton = "Actualizar"; }); } }); } getCategorias() { this.categoriaService.getCategorias().subscribe(res => { this.categorias = res; }); } agregarCategoria() { this.categoriaForm.controls['colorCategoria'].setValue(this.color); this.categoria = this.categoriaForm.value; if (!this.idCategoria) { this.categoriaService.guardarCategoria(this.categoria).subscribe(res => { console.log(res); this.getCategorias(); }); } else { this.categoriaService.actualizarCategoria(this.categoria).subscribe(res =>{ console.log(res); this.getCategorias(); }); } } borrarCategoria(idCategoria) { this.categoriaService.borrarCategoria(idCategoria).subscribe(res => { console.log(res); this.getCategorias(); }) } }
Creación de gráficos con ng2-charts
La ventaja de utilizar ng2-charts es que aprovecha al máximo las directivas, se parte de una directiva base la cual es baseChart, hay 8 tipos de gráficas line, bar, radar, pie, polarArea, doughnut, bubble and scatter. Si quieres mas información de cada gráfica la puedes encontrar en la documentación oficial.
<div> <div> <div style="display: block" *ngIf="barChartData"> <canvas baseChart [datasets]="barChartData" [labels]="barChartLabels" [options]="barChartOptions" [plugins]="barChartPlugins" [legend]="barChartLegend" [chartType]="barChartType" [colors]="chartColors"> </canvas> </div> </div> </div>
- [datasets]=”barChartData” –> Con esta directiva se le indica los datos que vamos a graficar, barCharData es un arreglo el cual recibe dos datos
- { data: datos, label: nombreCategoria}
- [labels]=”barChartLabels” –> Ejes x, se utilizan para gráficas line, bar and radar
- [chartType]=”barChartType” –> Indica el tipo de gráfica que queremos, barChartType es una variable que almacena el tipo de grafica. Ejm;
- public barChartType: ChartType = ‘bar‘;
- [colors]=”chartColors” –> Directiva con la cual le indicamos los colores de las graficas, charColors es un arreglo el cual recibe la siguiente estructura de datos:
- {backgroundColor: colores}
En la parte de TypeScript tenemos el siguiente codigo:
import { Component, OnInit } from '@angular/core'; import { ChartOptions, ChartType, ChartDataSets } from 'chart.js'; import * as pluginDataLabels from 'chartjs-plugin-annotation'; import { Label } from 'ng2-charts'; import { CategoriaService } from '../../services/categoria.service'; @Component({ selector: 'app-graficas', templateUrl: './graficas.component.html', styleUrls: ['./graficas.component.scss'] }) export class GraficasComponent implements OnInit { public barChartOptions: ChartOptions = { responsive: true, // We use these empty structures as placeholders for dynamic theming. scales: { xAxes: [{}], yAxes: [{}] }, plugins: { datalabels: { anchor: 'end', align: 'end', } } }; public barChartLabels: Label[] = ['2010', '2011', '2012', '2013', '2014', '2015', '2016']; //Tipo de grafico que queremos: ejem: line, bar, radar public barChartType: ChartType = 'bar'; public barChartLegend = true; public barChartPlugins = [pluginDataLabels]; //Datos que vamos a cargar en las graficas public barChartData: ChartDataSets[]; public chartColors; private categoria; private dato: string; //Arreglo de los datos que vamos a pasar private datos = []; //Arreglo de las categorias que vamos a pasar private nombreCategoria = []; //Arreglo de los colores que vamos a pasar private colores = []; constructor(protected categoriaService: CategoriaService) { this.getCategoria(); } ngOnInit() { } getCategoria() { this.categoriaService.getCategorias().subscribe(res => { this.categoria = res; //Obtenemos las categorias y recorremos almacenando //en cada arreglo lo necesario for (const cate of this.categoria) { this.dato = cate.DATOS_CATE.split(','); this.datos.push(this.dato); this.nombreCategoria.push(cate.NOMBRE_CATE); this.colores.push(cate.COLOR_CATE); } //Llamado a función this.cargarDatos(this.datos, this.nombreCategoria, this.colores); }); } //Función que carga los datos en la grafica, asi como los colores cargarDatos(datos, nombreCategoria, colores) { this.barChartData = []; this.chartColors = []; for (const index in datos) { this.barChartData.push({ data: datos[index], label: nombreCategoria[index] }); this.chartColors.push({backgroundColor: colores[index]}); } } }
Corriendo el proyecto
Para correr el proyecto lo primero que hacemos es encender nuestro servicio de MySQL que contiene nuestra base de datos, luego nos ubicamos en nuestro proyecto back y ejecutamos el comando nodemon.
En el proyecto front iniciamos el servidor de angular con ng serve, nos dirigimos a http://localhost:4200/

Repositorios del proyecto
El proyecto de Back en Node.js lo encuentras dando clic aquí.
El proyecto de Front en Angular lo encuentras dando clic aquí.
Cualquier duda déjala en los comentarios, con mucho gusto la responderé.
Hola. Para los que usan: angular 11.2.0, npm 6.14.11 & node v15.13.0 o superior, para evitar problemas de compatibilidad usar las siguientes dependencias:
npm install chart.js@2.9.3 –save
npm install ng2-charts@2.2.3 –save
Saludos.
Buenas tardes. Necesito tu ayuda pues el archivo graficas.component.ts me genera los siguientes errores y no he podido corregir:
Error: node_modules/chartjs-plugin-annotation/types/label.d.ts:1:10 – error TS2305: Module ‘”../../@types/chart.js”‘ has no exported member ‘Color’.
1 import { Color, FontSpec } from ‘chart.js’;
~~~~~
node_modules/chartjs-plugin-annotation/types/label.d.ts:1:17 – error TS2305: Module ‘”../../@types/chart.js”‘ has no exported member ‘FontSpec’.
1 import { Color, FontSpec } from ‘chart.js’;
~~~~~~~~
node_modules/chartjs-plugin-annotation/types/options.d.ts:1:10 – error TS2305: Module ‘”../../@types/chart.js”‘ has no exported member ‘Color’.
1 import { Color } from ‘chart.js’;
~~~~~
node_modules/chartjs-plugin-annotation/types/index.d.ts:1:10 – error TS2305: Module ‘”../../@types/chart.js”‘ has no exported member ‘Plugin’.
1 import { Plugin, ChartType } from ‘chart.js’;
~~~~~~
Hola la importación de {color} realízala de esta modulo:
import { Label, Color } from “ng2-charts”;
Adicionalmente la ultima versión de ng2 charts esta poniendo problemas, te recomiendo utilizar estas versiones:
npm install chart.js@2.9.3 –save
npm install ng2-charts@2.2.3 –save
Saludos.