gradien chart js

This commit is contained in:
Ryan Ariana 2024-05-16 23:20:59 +07:00
parent 754c6aaeb0
commit af5fb0ad01
23 changed files with 336 additions and 77 deletions

View File

@ -10,6 +10,7 @@ android {
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-app')
implementation project(':capacitor-device')
implementation project(':capacitor-haptics')
implementation project(':capacitor-keyboard')
implementation project(':capacitor-status-bar')

View File

@ -5,6 +5,9 @@ project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
include ':capacitor-device'
project(':capacitor-device').projectDir = new File('../node_modules/@capacitor/device/android')
include ':capacitor-haptics'
project(':capacitor-haptics').projectDir = new File('../node_modules/@capacitor/haptics/android')

View File

@ -24,6 +24,7 @@
"@capacitor/android": "^6.0.0",
"@capacitor/app": "6.0.0",
"@capacitor/core": "6.0.0",
"@capacitor/device": "^6.0.0",
"@capacitor/haptics": "6.0.0",
"@capacitor/keyboard": "6.0.0",
"@capacitor/status-bar": "6.0.0",
@ -31,7 +32,9 @@
"@ionic/storage-angular": "^4.0.0",
"@swimlane/ngx-charts": "^20.5.0",
"@swimlane/ngx-datatable": "^20.1.0",
"chart.js": "^4.4.2",
"ionicons": "^7.0.0",
"ng2-charts": "^6.0.1",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.2"

View File

@ -39,6 +39,10 @@ const routes: Routes = [
path: 'tabel',
loadComponent: () => import('./tabel/tabel.page').then((m) => m.TabelPage),
},
{
path: 'get-identitas',
loadChildren: () => import('./get-identitas/get-identitas.module').then( m => m.GetIdentitasPageModule)
},
];
@NgModule({

View File

@ -2,7 +2,6 @@
[view]="view"
[scheme]="'neons'"
[legend]="legend"
[legendPosition]="legendPosition"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxis]="xAxis"

View File

@ -1,5 +1,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { LegendPosition, NgxChartsModule } from '@swimlane/ngx-charts';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { PengukuranService } from '../../services/pengukuran.service';
import { Storage } from '@ionic/storage-angular';
@Component({
selector: 'app-line-chart',
@ -19,43 +21,55 @@ export class LineChartComponent implements OnInit {
showYAxisLabel: boolean = true;
showXAxisLabel: boolean = true;
xAxisLabel: string = 'INDIKATOR KESEHATAN INDIVIDU';
yAxisLabel: string = 'Grafik';
yAxisLabel: string = 'Berat Badan';
timeline: boolean = true;
multi: any[] = [];
@Input() view: any;
@Input() legendPosition = LegendPosition.Right;
colorScheme: any = {
domain: ['#5AA454', '#E44D25', '#CFC0BB', '#7aa3e5', '#a8385d', '#aae3f5']
};
constructor() { }
constructor(
private pengukuranService: PengukuranService,
private storage: Storage,) { }
ngOnInit() {
this.generateData();
async ngOnInit() {
await this.storage.create();
this.getDataGraph()
// this.generateData();
}
async getDataGraph() {
const id_identitas = await this.storage.get('id_identitas');
this.pengukuranService.getGraphByIdentitas(id_identitas).subscribe(
async (response: any[]) => {
console.log(response);
generateData() {
this.multi = [
{
"name": "Ryan",
"series": []
// Filter the response to include only the segment with the name "Berat Badan"
const filteredResponse = response.filter(series => series.series_name === "Berat Badan");
// Transform the filtered response into the desired format
this.multi = filteredResponse.map(series => ({
name: series.series_name,
series: series.series_data.map((value: any, index: number) => ({
name: (index + 1).toString(), // Use index + 1 as the name
value: value
}))
}));
},
error => {
console.error('Error fetching data:', error);
}
];
// Generating data for each day of January 2024
for (let day = 1; day <= 31; day++) {
let formattedDay = day < 10 ? `0${day}` : `${day}`;
this.multi[0].series.push({
"name": `${formattedDay}-01-2024`,
"value": this.getRandomValue(1, 50)
});
}
);
}
private getDateByIndex(index: number): string {
// Define a method to generate date strings based on index
// For demonstration, we use a fixed start date and increment it by one day for each index
const startDate = new Date('2024-01-01');
const date = new Date(startDate);
date.setDate(startDate.getDate() + index);
getRandomValue(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
return date.toISOString().split('T')[0]; // Format date as 'YYYY-MM-DD'
}
onSelect(data: any): void {
console.log('Item clicked', JSON.parse(JSON.stringify(data)));
}

View File

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GetIdentitasPage } from './get-identitas.page';
const routes: Routes = [
{
path: '',
component: GetIdentitasPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class GetIdentitasPageRoutingModule {}

View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { GetIdentitasPageRoutingModule } from './get-identitas-routing.module';
import { GetIdentitasPage } from './get-identitas.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
GetIdentitasPageRoutingModule
],
declarations: [GetIdentitasPage]
})
export class GetIdentitasPageModule {}

View File

@ -0,0 +1,24 @@
<ion-header [translucent]="true">
<ion-toolbar color="primary">
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Ambil Identitas</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Ambil Identitas</ion-title>
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
<ion-list>
<ion-item>
<ion-label position="stacked">ID</ion-label>
<ion-input type="number" [(ngModel)]="userData.id" placeholder="Masukkan ID"></ion-input>
</ion-item>
<ion-button expand="block" color="primary" (click)="simpanData()">Simpan</ion-button>
</ion-list>
</ion-content>

View File

@ -0,0 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GetIdentitasPage } from './get-identitas.page';
describe('GetIdentitasPage', () => {
let component: GetIdentitasPage;
let fixture: ComponentFixture<GetIdentitasPage>;
beforeEach(() => {
fixture = TestBed.createComponent(GetIdentitasPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,60 @@
import { Component, OnInit } from '@angular/core';
import { Storage } from '@ionic/storage-angular';
import { ToastController } from '@ionic/angular';
import { IdentitasServiceService } from '../services/identitas-service.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-get-identitas',
templateUrl: './get-identitas.page.html',
styleUrls: ['./get-identitas.page.scss'],
})
export class GetIdentitasPage implements OnInit {
public userData = {
id: 0,
}
private idIdentitas: number | null = null;
constructor(
private storage: Storage,
private toastController: ToastController,
private identitasService: IdentitasServiceService,
private router: Router
) { }
async ngOnInit() {
await this.storage.create();
const id_identitas = await this.storage.get('id_identitas');
}
async showToast(message: string, position: 'top' | 'middle' | 'bottom', color: string) {
const toast = await this.toastController.create({
message: message,
duration: 2000,
position: position,
color: color
});
toast.present();
}
async simpanData() {
this.identitasService.getIdentitasById(this.userData.id).subscribe(
async (response) => {
console.log(response.data);
await this.storage.set('id_identitas', response.id || response.data.id);
this.idIdentitas = response.id || response.data.id;
this.handleResponse(response);
this.router.navigate(['/identitas']);
},
error => this.handleError(error)
);
}
handleResponse(response: any) {
this.showToast('Data Identitas Ditemukan!', 'top', 'success');
}
handleError(error: { message: any; }) {
this.showToast(`Data Identitas Tidak Ditemukan!`, 'top', 'danger');
}
// this.router.navigate(['/identitas']);
}

View File

@ -8,11 +8,7 @@
</ion-header>
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Identitas</ion-title>
</ion-toolbar>
</ion-header>
<ion-button expand="block" color="primary" (click)="getIdentitas()">Ambil Identitas</ion-button>
<ion-list>
<ion-item>
<ion-label position="stacked">Nama</ion-label>

View File

@ -2,6 +2,8 @@ import { Component, OnInit } from '@angular/core';
import { Storage } from '@ionic/storage-angular';
import { ToastController } from '@ionic/angular';
import { IdentitasServiceService } from '../services/identitas-service.service';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-identitas',
@ -30,12 +32,27 @@ export class IdentitasPage implements OnInit {
constructor(
private storage: Storage,
private toastController: ToastController,
private identitasService: IdentitasServiceService
) {}
private identitasService: IdentitasServiceService,
private router: Router
) {
// Subscribe to router events and refresh data on NavigationEnd
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd)
).subscribe(event => {
// Check if the event's URL matches the current page's URL
if (event.urlAfterRedirects === '/identitas') {
this.refreshData();
}
});
}
async ngOnInit() {
await this.storage.create();
this.refreshData();
}
async refreshData() {
const id_identitas = await this.storage.get('id_identitas');
console.log(id_identitas, "id identitas")
this.idIdentitas = await this.storage.get('id_identitas');
this.isEdit = !!id_identitas;
if (id_identitas) {
@ -122,5 +139,8 @@ export class IdentitasPage implements OnInit {
handleError(error: { message: any; }) {
this.showToast(`Error saving data: ${error.message}`, 'top', 'danger');
}
getIdentitas(){
this.router.navigate(['/get-identitas']);
}
}

View File

@ -16,8 +16,11 @@
<ion-content>
<ion-card>
<ion-card-title class="ion-padding-start">Line Chart</ion-card-title>
<ion-card-content class="ion-margin-top" [ngClass]="{'cardContent' : below}">
<app-line-chart [view]="view" [legendPosition]="legendPosition"></app-line-chart>
<ion-card-content class="ion-margin-top">
<div style="display: block; width: 100%; height: 150px;">
<canvas id="myChart"></canvas>
</div>
</ion-card-content>
</ion-card>
</ion-content>

View File

@ -11,14 +11,12 @@ import {
IonButtons,
IonMenuButton,
} from '@ionic/angular/standalone';
import { LegendPosition } from '@swimlane/ngx-charts';
import { NgClass } from '@angular/common';
import { GroupedVerticalBarChartComponent } from '../components/grouped-vertical-bar-chart/grouped-vertical-bar-chart.component';
import { PieChartComponent } from '../components/pie-chart/pie-chart.component';
import { VerticalBarChartComponent } from '../components/vertical-bar-chart/vertical-bar-chart.component';
import { LineChartComponent } from '../components/line-chart/line-chart.component';
import { HorizontalBarChartComponent } from '../components/horizontal-bar-chart/horizontal-bar-chart.component';
import { Chart, registerables } from 'chart.js';
import { ChartConfiguration, ChartOptions, ChartType } from "chart.js";
import { BaseChartDirective } from 'ng2-charts';
Chart.register(...registerables);
@Component({
selector: 'app-indikator',
templateUrl: './indikator.page.html',
@ -35,44 +33,83 @@ import { HorizontalBarChartComponent } from '../components/horizontal-bar-chart/
IonCardTitle,
IonCardContent,
NgClass,
VerticalBarChartComponent,
GroupedVerticalBarChartComponent,
PieChartComponent,
LineChartComponent,
HorizontalBarChartComponent
BaseChartDirective
],
})
export class IndikatorPage implements OnInit {
view: any;
legendPosition!: LegendPosition;
below: boolean = false;
public below: boolean = false;
constructor(private platform: Platform) {}
constructor() {}
ngOnInit() {
// this.changeLegendPostion(false);
this.handleScreenSizeChange();
}
@HostListener('window:resize', ['$event'])
onResize(event: any) {
this.handleScreenSizeChange();
this.createChart();
}
changeLegendPostion(defaultValue = true) {
this.legendPosition = defaultValue ? LegendPosition.Right : LegendPosition.Below;
this.below = !defaultValue;
}
createChart() {
const canvas = document.getElementById('myChart') as HTMLCanvasElement;
const ctx = canvas.getContext('2d');
handleScreenSizeChange() {
const width = this.platform.width();
const height = this.platform.height();
console.log(width, height);
if (width > height) {
this.changeLegendPostion();
this.view = [0.9 * width, 0.9 * height];
} else {
this.changeLegendPostion(false);
this.view = [0.95 * width, 0.35 * height];
if (ctx) {
// Create a gradient for the chart background
const gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(0, 255, 0, 0.5)'); // Green area
gradient.addColorStop(0.33, 'rgba(255, 255, 0, 0.5)'); // Yellow area
gradient.addColorStop(0.66, 'rgba(255, 0, 0, 0.5)'); // Red area
// Apply the gradient to the chart background
new Chart(ctx, {
type: 'line',
data: {
labels: ['January', 'February', 'March'],
datasets: [{
label: 'Series A',
data: [0.5, 1.5, 2.5],
borderColor: 'black',
fill: true,
}]
},
options: {
responsive: true,
scales: {
y: {
min: 0,
max: 3,
beginAtZero: true,
ticks: {
stepSize: 1,
callback: function(value) {
return value;
}
}
}
}
},
plugins: [{
beforeDraw: function (chart) {
const ctx = chart.ctx;
const chartArea = chart.chartArea;
const chartHeight = chartArea.bottom - chartArea.top;
// Calculate gradient stops
const greenStop = chartHeight * 0.33;
const yellowStop = chartHeight * 0.66;
const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);
gradient.addColorStop(0, 'rgba(0, 255, 0, 0.5)');
gradient.addColorStop(greenStop / chartHeight, 'rgba(0, 255, 0, 0.5)');
gradient.addColorStop(greenStop / chartHeight, 'rgba(255, 255, 0, 0.5)');
gradient.addColorStop(yellowStop / chartHeight, 'rgba(255, 255, 0, 0.5)');
gradient.addColorStop(yellowStop / chartHeight, 'rgba(255, 0, 0, 0.5)');
gradient.addColorStop(1, 'rgba(255, 0, 0, 0.5)');
ctx.save();
ctx.fillStyle = gradient;
ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
ctx.restore();
},
id: ''
}]
});
}
}
}

View File

@ -24,11 +24,6 @@
<ion-input type="number" [(ngModel)]="payloadData.tinggi_badan" placeholder="Masukkan Tinggi Badan"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">IMT (Kg/m²)</ion-label>
<ion-input type="number" [(ngModel)]="payloadData.imt" placeholder="Masukkan IMT"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Tekanan Darah Diastole(mmHg)</ion-label>
<ion-input type="number" [(ngModel)]="payloadData.tekanan_darah_diastole" placeholder="Masukkan Tekanan Darah Diastole"></ion-input>
@ -88,6 +83,10 @@
<ion-label position="stacked">Trigliserida</ion-label>
<ion-input type="number" [(ngModel)]="payloadData.trigliserida" placeholder="Masukkan Trigliserida"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">HBA1C</ion-label>
<ion-input type="number" [(ngModel)]="payloadData.hba1c" placeholder="Masukkan HBA1C"></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Lingkar Perut</ion-label>
<ion-input type="number" [(ngModel)]="payloadData.lingkar_perut" placeholder="Masukkan Lingkar Perut"></ion-input>

View File

@ -15,7 +15,7 @@ export class PemeriksaanPage implements OnInit {
berat_badan: '',
frekuensi_nafas: '',
golongan_darah: "",
imt: '',
imt: 0,
kadar_asam_urat: '',
kadar_gula_darah: '',
kadar_hb: '',
@ -30,7 +30,8 @@ export class PemeriksaanPage implements OnInit {
tekanan_darah_sistole: 0,
tinggi_badan: '',
trigliserida: '',
waktu_pengambilan_gula_darah: ''
waktu_pengambilan_gula_darah: '',
hba1c: '',
};
private idIdentitas: number | null = null;

View File

@ -19,4 +19,8 @@ export class PengukuranService {
const url = `${this.apiUrl}?identitas_id=${identitasId}&take=30`;
return this.http.get(url);
}
getGraphByIdentitas(identitasId: number): Observable<any> {
const url = `${this.apiUrl}/graph?identitas_id=${identitasId}`;
return this.http.get(url);
}
}

View File

@ -0,0 +1,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomDatePipe } from './custom-date.pipe'; // Adjust the path as necessary
@NgModule({
declarations: [CustomDatePipe],
imports: [CommonModule],
exports: [CustomDatePipe]
})
export class CustomDateModule { }

View File

@ -0,0 +1,16 @@
import { Pipe, PipeTransform } from '@angular/core';
import { formatDate } from '@angular/common';
@Pipe({
name: 'customDate'
})
export class CustomDatePipe implements PipeTransform {
transform(value: string): string {
if (!value) return '';
const date = new Date(value);
return formatDate(date, 'dd-MM-yyyy HH:mm', 'en-US');
}
}

View File

@ -27,6 +27,15 @@
<span class="tableHeader">ID</span>
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column prop="created_at">
<ng-template let-column="column" ngx-datatable-header-template let-sort="sortFn">
<span class="tableHeader">Tanggal</span>
</ng-template>
<ng-template ngx-datatable-cell-template let-value="value">
{{ value | customDate }}
</ng-template>
</ngx-datatable-column>
<ngx-datatable-column prop="berat_badan">
<ng-template let-column="column" ngx-datatable-header-template let-sort="sortFn">

View File

@ -16,6 +16,7 @@ import {
import { ColumnMode, DatatableComponent, NgxDatatableModule } from '@swimlane/ngx-datatable';
import { PengukuranService } from '../services/pengukuran.service';
import { Storage } from '@ionic/storage-angular';
import { CustomDateModule } from './custom-date.module';
@Component({
selector: 'app-tabel',
@ -35,7 +36,8 @@ import { Storage } from '@ionic/storage-angular';
IonInput,
NgxDatatableModule,
IonButtons,
IonMenuButton
IonMenuButton,
CustomDateModule
],
})
export class TabelPage implements OnInit {