| @@ -2679,6 +2679,11 @@ | |||
| "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", | |||
| "dev": true | |||
| }, | |||
| "claygl": { | |||
| "version": "1.3.0", | |||
| "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz", | |||
| "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==" | |||
| }, | |||
| "clean-stack": { | |||
| "version": "2.2.0", | |||
| "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", | |||
| @@ -3419,6 +3424,31 @@ | |||
| "domhandler": "^4.2.0" | |||
| } | |||
| }, | |||
| "echarts": { | |||
| "version": "5.3.0", | |||
| "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.3.0.tgz", | |||
| "integrity": "sha512-zENufmwFE6WjM+24tW3xQq4ICqQtI0CGj4bDVDNd3BK3LtaA/5wBp+64ykIyKy3QElz0cieKqSYP4FX9Lv9MwQ==", | |||
| "requires": { | |||
| "tslib": "2.3.0", | |||
| "zrender": "5.3.0" | |||
| }, | |||
| "dependencies": { | |||
| "tslib": { | |||
| "version": "2.3.0", | |||
| "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", | |||
| "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" | |||
| } | |||
| } | |||
| }, | |||
| "echarts-gl": { | |||
| "version": "2.0.8", | |||
| "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.8.tgz", | |||
| "integrity": "sha512-ayFmjLxdF9pRpnh1Lz5aOgjnLqL3WIGu0t4Bt+oFwXGsViU2XcjCkHZARsZdv05lySow8eMD9JYZGXfLpuqYng==", | |||
| "requires": { | |||
| "claygl": "^1.2.1", | |||
| "zrender": "^5.1.1" | |||
| } | |||
| }, | |||
| "ee-first": { | |||
| "version": "1.1.1", | |||
| "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", | |||
| @@ -5650,6 +5680,14 @@ | |||
| "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", | |||
| "dev": true | |||
| }, | |||
| "ngx-echarts": { | |||
| "version": "8.0.1", | |||
| "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-8.0.1.tgz", | |||
| "integrity": "sha512-CP+WnCcnMCNpCL9BVmDIZmhGSVPnkJhhFbQEKt0nrwV0L6d4QTAGZ+e4y6G1zTTFKkIMPHpaO0nhtDRgSXAW/w==", | |||
| "requires": { | |||
| "tslib": "^2.3.0" | |||
| } | |||
| }, | |||
| "nice-napi": { | |||
| "version": "1.0.2", | |||
| "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", | |||
| @@ -8229,6 +8267,21 @@ | |||
| "requires": { | |||
| "tslib": "^2.0.0" | |||
| } | |||
| }, | |||
| "zrender": { | |||
| "version": "5.3.0", | |||
| "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.3.0.tgz", | |||
| "integrity": "sha512-Ln2QB5uqI1ftNYMtCRxd+XDq6MOttLgam2tmhKAVA+j0ko47UT+VNlDvKTkqe4K2sJhBvB0EhYNLebqlCTjatQ==", | |||
| "requires": { | |||
| "tslib": "2.3.0" | |||
| }, | |||
| "dependencies": { | |||
| "tslib": { | |||
| "version": "2.3.0", | |||
| "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", | |||
| "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -18,6 +18,9 @@ | |||
| "@angular/platform-browser": "~13.1.0", | |||
| "@angular/platform-browser-dynamic": "~13.1.0", | |||
| "@angular/router": "~13.1.0", | |||
| "echarts": "^5.3.0", | |||
| "echarts-gl": "^2.0.8", | |||
| "ngx-echarts": "^8.0.1", | |||
| "rxjs": "~7.4.0", | |||
| "tslib": "^2.3.0", | |||
| "zone.js": "~0.11.4" | |||
| @@ -1,7 +1,8 @@ | |||
| import { NgModule } from '@angular/core'; | |||
| import { BrowserModule } from '@angular/platform-browser'; | |||
| import { NgxEchartsModule } from 'ngx-echarts'; | |||
| import { AppRoutingModule } from './app-routing.module'; | |||
| import { AppComponent } from './app.component'; | |||
| import { LoginComponent } from './login/login.component'; | |||
| import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | |||
| @@ -12,21 +13,24 @@ import { ReportComponent } from './dashboard/report/report.component'; | |||
| import { SettingsComponent } from './dashboard/settings/settings.component'; | |||
| @NgModule({ | |||
| declarations: [ | |||
| AppComponent, | |||
| LoginComponent, | |||
| DashboardComponent, | |||
| GraphComponent, | |||
| TableComponent, | |||
| ReportComponent, | |||
| SettingsComponent | |||
| ], | |||
| imports: [ | |||
| BrowserModule, | |||
| AppRoutingModule, | |||
| BrowserAnimationsModule | |||
| ], | |||
| providers: [], | |||
| bootstrap: [AppComponent] | |||
| declarations: [ | |||
| AppComponent, | |||
| LoginComponent, | |||
| DashboardComponent, | |||
| GraphComponent, | |||
| TableComponent, | |||
| ReportComponent, | |||
| SettingsComponent | |||
| ], | |||
| imports: [ | |||
| BrowserModule, | |||
| AppRoutingModule, | |||
| BrowserAnimationsModule, | |||
| NgxEchartsModule.forRoot({ | |||
| echarts: () => import('echarts'), | |||
| }), | |||
| ], | |||
| providers: [], | |||
| bootstrap: [AppComponent] | |||
| }) | |||
| export class AppModule { } | |||
| @@ -1,11 +1,27 @@ | |||
| <div class="subpage"> | |||
| <header> | |||
| <header class="main-header"> | |||
| <h2> Dashboard </h2> | |||
| </header> | |||
| <section class="analytics"> | |||
| <div class="card"> | |||
| <div class="line-chart"></div> | |||
| <div echarts [options]="chartOption"></div> | |||
| </div> | |||
| <div class="card"> | |||
| <div echarts [options]="chartOption1"></div> | |||
| </div> | |||
| <div class="card"> | |||
| <div echarts [options]="options"></div> | |||
| </div> | |||
| <div class="card"> | |||
| <div echarts [options]="chartOption4"></div> | |||
| </div> | |||
| <div class="card"> | |||
| <div echarts [options]="chartOption5"></div> | |||
| </div> | |||
| </section> | |||
| </div> | |||
| @@ -0,0 +1,18 @@ | |||
| .analytics { | |||
| display: grid; | |||
| grid-template-columns: 1fr 1fr 1fr; | |||
| grid-gap: 20px; | |||
| } | |||
| .card { | |||
| padding: 0; | |||
| height: 300px; | |||
| &:nth-child(3) { | |||
| height: 450px; | |||
| } | |||
| &:nth-child(4), &:nth-child(5) { | |||
| margin-top: -150px; | |||
| } | |||
| } | |||
| @@ -1,15 +1,184 @@ | |||
| import { Component, OnInit } from '@angular/core'; | |||
| import { EChartsOption } from 'echarts'; | |||
| @Component({ | |||
| selector: 'app-graph', | |||
| templateUrl: './graph.component.html', | |||
| styleUrls: ['./graph.component.scss'] | |||
| selector: 'app-graph', | |||
| templateUrl: './graph.component.html', | |||
| styleUrls: ['./graph.component.scss'] | |||
| }) | |||
| export class GraphComponent implements OnInit { | |||
| primaryColor = window.getComputedStyle(document.documentElement).getPropertyValue('--primary'); | |||
| secondaryColor = window.getComputedStyle(document.documentElement).getPropertyValue('--secondary'); | |||
| constructor() { } | |||
| chartOption: EChartsOption = { | |||
| title: { | |||
| text: 'Partners registered this week', | |||
| left: 'center', | |||
| top: 15, | |||
| textStyle: { | |||
| fontSize: 15, | |||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||
| }, | |||
| }, | |||
| height: 180, | |||
| offset: 0, | |||
| xAxis: { | |||
| type: 'category', | |||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||
| }, | |||
| yAxis: { | |||
| type: 'value', | |||
| }, | |||
| series: [ | |||
| { | |||
| data: [820, 932, 901, 934, 1290, 1330, 1320], | |||
| type: 'line', | |||
| color: this.primaryColor | |||
| }, | |||
| ], | |||
| }; | |||
| ngOnInit(): void { | |||
| } | |||
| chartOption4: EChartsOption = { | |||
| title: { | |||
| text: 'Goals completed', | |||
| left: 'center', | |||
| top: 15, | |||
| textStyle: { | |||
| fontSize: 15, | |||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||
| }, | |||
| }, | |||
| height: 180, | |||
| offset: 0, | |||
| xAxis: { | |||
| type: 'category', | |||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||
| }, | |||
| yAxis: { | |||
| type: 'value', | |||
| }, | |||
| series: [ | |||
| { | |||
| data: [11, 200, 300, 50, 0, 60, 0], | |||
| type: 'line', | |||
| color: this.primaryColor | |||
| }, | |||
| ], | |||
| }; | |||
| chartOption5: EChartsOption = { | |||
| title: { | |||
| text: 'Goals missed vs completed', | |||
| left: 'center', | |||
| top: 15, | |||
| textStyle: { | |||
| fontSize: 15, | |||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||
| }, | |||
| }, | |||
| height: 180, | |||
| offset: 0, | |||
| xAxis: { | |||
| type: 'category', | |||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||
| }, | |||
| yAxis: { | |||
| type: 'value', | |||
| }, | |||
| series: [ | |||
| { | |||
| data: [220, 0, 100, 20, 0, 290, 0], | |||
| type: 'line', | |||
| color: this.secondaryColor | |||
| }, | |||
| { | |||
| data: [11, 200, 300, 50, 0, 60, 0], | |||
| type: 'line', | |||
| color: this.primaryColor | |||
| } | |||
| ], | |||
| }; | |||
| chartOption1: EChartsOption = { | |||
| title: { | |||
| text: 'Relative registeration count', | |||
| left: 'center', | |||
| top: 15, | |||
| textStyle: { | |||
| fontSize: 15, | |||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||
| }, | |||
| }, | |||
| height: 180, | |||
| offset: 0, | |||
| xAxis: { | |||
| type: 'category', | |||
| data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], | |||
| }, | |||
| yAxis: { | |||
| type: 'value', | |||
| }, | |||
| series: [ | |||
| { | |||
| data: [820, 932, 901, 934, 1290, 1330, 1320], | |||
| type: 'bar', | |||
| color: this.primaryColor | |||
| }, | |||
| { | |||
| data: [1320, 901, 934, 932, 1290, 1330, 820], | |||
| type: 'bar', | |||
| color: this.secondaryColor | |||
| }, | |||
| ], | |||
| animationEasing: 'elasticOut', | |||
| animationDelayUpdate: (idx) => idx * 5, | |||
| }; | |||
| options: EChartsOption = { | |||
| title: { | |||
| text: 'Partners by category', | |||
| left: 'center', | |||
| top: 20, | |||
| textStyle: { | |||
| fontSize: 20, | |||
| color: window.getComputedStyle(document.documentElement).getPropertyValue('--secondary-text'), | |||
| }, | |||
| }, | |||
| height: 500, | |||
| visualMap: { | |||
| show: false, | |||
| min: 80, | |||
| max: 600, | |||
| inRange: { | |||
| colorLightness: [0, 1], | |||
| }, | |||
| }, | |||
| series: [ | |||
| { | |||
| name: 'Counters', | |||
| type: 'pie', | |||
| radius: '55%', | |||
| center: ['50%', '50%'], | |||
| color: this.primaryColor, | |||
| data: [ | |||
| { value: 335, name: 'C-1' }, | |||
| { value: 310, name: 'C-2' }, | |||
| { value: 274, name: 'C-3' }, | |||
| { value: 235, name: 'C-4' }, | |||
| { value: 400, name: 'C-5' }, | |||
| ].sort((a, b) => a.value - b.value), | |||
| roseType: 'radius', | |||
| animationType: 'scale', | |||
| animationEasing: 'elasticOut', | |||
| animationDelay: () => Math.random() * 200, | |||
| }, | |||
| ], | |||
| }; | |||
| constructor() { } | |||
| ngOnInit(): void { | |||
| } | |||
| } | |||
| @@ -102,4 +102,16 @@ | |||
| .subpage { | |||
| padding: 20px; | |||
| height: 100vh; | |||
| width: 100%; | |||
| overflow: auto; | |||
| .main-header { | |||
| margin-bottom: 20px; | |||
| h2 { | |||
| color: var(--secondary-text); | |||
| font-size: 30px; | |||
| } | |||
| } | |||
| } | |||