From c8e074ff4bfe9dc12452b2074cf37911be582db6 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 22 Dec 2022 18:20:56 -0800 Subject: [PATCH] added charts (#13) --- .../components/header/header.component.html | 3 + .../report-labs-observation.component.html | 43 +++-- .../report-labs-observation.component.ts | 175 ++++++++++++++++++ ...t-medical-history-condition.component.html | 11 +- frontend/src/app/components/shared.module.ts | 2 + .../medical-history.component.html | 2 +- .../report-labs/report-labs.component.html | 45 +++-- .../report-labs/report-labs.component.ts | 26 ++- 8 files changed, 269 insertions(+), 38 deletions(-) diff --git a/frontend/src/app/components/header/header.component.html b/frontend/src/app/components/header/header.component.html index fb57e02e..cce2a095 100644 --- a/frontend/src/app/components/header/header.component.html +++ b/frontend/src/app/components/header/header.component.html @@ -17,6 +17,9 @@ + diff --git a/frontend/src/app/components/report-labs-observation/report-labs-observation.component.html b/frontend/src/app/components/report-labs-observation/report-labs-observation.component.html index 412d0b74..d796d8f1 100644 --- a/frontend/src/app/components/report-labs-observation/report-labs-observation.component.html +++ b/frontend/src/app/components/report-labs-observation/report-labs-observation.component.html @@ -3,7 +3,7 @@
- {{observationTitle}} + {{observationTitle}}
{{observations[0] | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}} @@ -20,12 +20,27 @@

- Test Code (loinc): {{observationCode}}
+ Short Name: {{observations[0] | fhirPath: "Observation.code.text"}}
+ Result: {{observations[0] | fhirPath: "Observation.valueQuantity.value"}} {{observations[0] | fhirPath: "Observation.valueQuantity.unit"}}
+
Latest Test Date: {{observations[0] | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}
Ordered By: {{observations[0] | fhirPath: "Observation.encounter.display"}}
- Notes: + LOINC Code: {{observationCode}}
+ Notes: {{observations[0] | fhirPath: "Observation.note.text"}} + +
+
+ show all

+
+ +
    +
  • Observation: {{observation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}
  • +
+
+ +
@@ -33,20 +48,20 @@
-

- - Troponin I is a part of the troponin complex. It binds to actin in thin myofilaments to hold the actin-tropomyosin complex in place. Because of it myosin cannot bind actin in relaxed muscle. When calcium binds to the Troponin C it causes conformational changes which lead to dislocation of troponin I and finally tropomyosin leaves the binding site for myosin on actin leading to contraction of muscle. The letter I is given due to its inhibitory character. - -

+
+

+ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +

+
+ +
+ +
- -
- {{observation | fhirPath: "Observation.valueQuantity.value" }} -
- -
diff --git a/frontend/src/app/components/report-labs-observation/report-labs-observation.component.ts b/frontend/src/app/components/report-labs-observation/report-labs-observation.component.ts index 9718f304..c8f0eda8 100644 --- a/frontend/src/app/components/report-labs-observation/report-labs-observation.component.ts +++ b/frontend/src/app/components/report-labs-observation/report-labs-observation.component.ts @@ -1,5 +1,11 @@ import {Component, Input, OnInit} from '@angular/core'; import {ResourceFhir} from '../../models/fasten/resource_fhir'; +import {ChartOptions} from 'chart.js'; +// import { ChartConfiguration, ChartData, ChartEvent, ChartType } from 'chart.js'; +// import { BaseChartDirective } from 'ng2-charts'; +import * as fhirpath from 'fhirpath'; +import {formatDate} from '@angular/common'; + @Component({ selector: 'app-report-labs-observation', @@ -12,10 +18,179 @@ export class ReportLabsObservationComponent implements OnInit { @Input() observationCode: string @Input() observationTitle: string + // based on https://stackoverflow.com/questions/38889716/chartjs-2-stacked-bar-with-marker-on-top + // https://stackoverflow.com/questions/62711919/chart-js-horizontal-lines-per-bar + + + chartHeight = 45 + + barChartData =[ + // { + // label: "Current", + // backgroundColor: 'rgba(255, 0, 128, 1)', + // data: [], + // xAxisID: "x-axis-current" + // }, + // { + // label: "Reference", + // backgroundColor: 'rgba(99,189,50,0.2)', + // data: [], + // xAxisID: "x-axis-ref" + // }, + + + + { + label: "Reference", + data: [[55,102], [44,120]], + backgroundColor: "rgba(91, 71, 251,0.6)", + hoverBackgroundColor: "rgba(91, 71, 251,0.2)" + },{ + label: "Current", + data: [[80,81], [130,131]], + borderColor: "rgba(0,0,0,1)", + backgroundColor: "rgba(0,0,0,1)", + hoverBackgroundColor: "rgba(0,0,0,1)", + minBarLength: 3, + barPercentage: 1, + tooltip: { + + } + // id: "x-axis-current", + //important settings + + //set the width of the line ( or point ) + // pointRadius: 50, + // don´t show line betrween points + // showLine: false, + //change points of line chart to line style ( little bit confusin why it´s named point anyway ) + // pointStyle: 'line', + + //chart type + // type: "line", + } + ] + + barChartLabels = [] // ["2020", "2018"] //["1","2","3","4","5","6","7","8"] + + barChartOptions = { + legend:{ + display: false, + }, + //add padding to fix tooltip cutoff + layout: { + padding: { + left: 0, + right: 4, + top: 0, + bottom: 10 + } + }, + scales: { + yAxes: [{ + stacked: true, + ticks: { + beginAtZero: true, + fontSize: 10, + min: 0, + // max: 80 + }, + }], + xAxes: [{ + scaleLabel:{ + display: false, + labelString: "xaxis", + padding: 4, + }, + // stacked: true, + ticks: { + beginAtZero: true, + fontSize: 10, + min: 0, + // max: 80 + }, + + }], + } + // xAxes: [{ + // id: "x-axis-current", + // stacked: true, + // // barPercentage: 0.6, + // ticks: { + // beginAtZero:true, + // fontSize: 11 + // } + // },{ + // id: "x-axis-ref", + // stacked: true, + // ticks: { + // beginAtZero:true, + // fontSize: 11 + // } + // // offset: true, + // + // // display: false, + // // gridLines: { + // // offsetGridLines: true + // // } + // }] + // }, + // legend: { + // display: false + // }, + // elements: { + // point: { + // radius: 0 + // } + // } + } as ChartOptions + + barChartColors = [ + { + backgroundColor: 'white' + } + ]; + constructor() { } ngOnInit(): void { + + let currentValues = [] + + let referenceRanges = [] + + for(let observation of this.observations){ + //get label + this.barChartLabels.push( + formatDate(fhirpath.evaluate(observation.resource_raw, "Observation.effectiveDateTime")[0], "mediumDate", "en-US", undefined) + ) + + //get current value + currentValues.push(fhirpath.evaluate(observation.resource_raw, "Observation.valueQuantity.value")[0]) + + //set chart x-axis label + let units = fhirpath.evaluate(observation.resource_raw, "Observation.valueQuantity.unit")[0] + if(units){ + this.barChartOptions.scales.xAxes[0].scaleLabel.display = true + this.barChartOptions.scales.xAxes[0].scaleLabel.labelString = units + } + + + //add low/high ref value blocks + referenceRanges.push([ + fhirpath.evaluate(observation.resource_raw, "Observation.referenceRange.low.value")[0], + fhirpath.evaluate(observation.resource_raw, "Observation.referenceRange.high.value")[0] + ]) + } + + // @ts-ignore + this.barChartData[0].data = referenceRanges + this.barChartData[1].data = currentValues.map(v => [v, v]) + + if(currentValues.length > 1){ + this.chartHeight = 30 * currentValues.length + } } } diff --git a/frontend/src/app/components/report-medical-history-condition/report-medical-history-condition.component.html b/frontend/src/app/components/report-medical-history-condition/report-medical-history-condition.component.html index 02845e81..4f23e7fe 100644 --- a/frontend/src/app/components/report-medical-history-condition/report-medical-history-condition.component.html +++ b/frontend/src/app/components/report-medical-history-condition/report-medical-history-condition.component.html @@ -1,6 +1,6 @@
-
+
{{condition | fhirPath: "Condition.code.text.first()":"Condition.code.coding.display.first()"}} @@ -48,6 +48,15 @@
+ + show all +
+ +
    +
  • Resource: {{resource.source_resource_type}}/{{resource.source_resource_id}}
  • +
+
+
diff --git a/frontend/src/app/components/shared.module.ts b/frontend/src/app/components/shared.module.ts index 0cea7f5c..aae51468 100644 --- a/frontend/src/app/components/shared.module.ts +++ b/frontend/src/app/components/shared.module.ts @@ -41,6 +41,7 @@ import { TreeModule } from '@circlon/angular-tree-component'; import {FilterPipe} from '../pipes/filter.pipe'; import { ReportMedicalHistoryConditionComponent } from './report-medical-history-condition/report-medical-history-condition.component'; import { ReportLabsObservationComponent } from './report-labs-observation/report-labs-observation.component'; +import { ChartsModule } from 'ng2-charts'; @NgModule({ imports: [ @@ -50,6 +51,7 @@ import { ReportLabsObservationComponent } from './report-labs-observation/report NgbModule, MomentModule, TreeModule, + ChartsModule ], declarations: [ ComponentsSidebarComponent, diff --git a/frontend/src/app/pages/medical-history/medical-history.component.html b/frontend/src/app/pages/medical-history/medical-history.component.html index 97a6f8bb..bf7c6c51 100644 --- a/frontend/src/app/pages/medical-history/medical-history.component.html +++ b/frontend/src/app/pages/medical-history/medical-history.component.html @@ -3,7 +3,7 @@
- + diff --git a/frontend/src/app/pages/report-labs/report-labs.component.html b/frontend/src/app/pages/report-labs/report-labs.component.html index eb4df820..b9e5e9d9 100644 --- a/frontend/src/app/pages/report-labs/report-labs.component.html +++ b/frontend/src/app/pages/report-labs/report-labs.component.html @@ -3,23 +3,42 @@
- + - - -
-
-

Observations

+ + +
+
+

Observations

+
-
- - + + + + + + + + +
+ +
+
diff --git a/frontend/src/app/pages/report-labs/report-labs.component.ts b/frontend/src/app/pages/report-labs/report-labs.component.ts index c8a7b517..7b576bdb 100644 --- a/frontend/src/app/pages/report-labs/report-labs.component.ts +++ b/frontend/src/app/pages/report-labs/report-labs.component.ts @@ -14,12 +14,17 @@ export class ReportLabsComponent implements OnInit { observationGroups: {[key: string]: ResourceFhir[]} = {} observationGroupTitles: {[key: string]: string} = {} + loading = true + isEmptyReport = false + constructor( private fastenApi: FastenApiService, ) { } ngOnInit(): void { this.fastenApi.getResources("Observation").subscribe(results => { + this.loading = false + results = results || [] console.log("ALL OBSERVATIONS", results) //loop though all observations, group by "code.system": "http://loinc.org" @@ -31,18 +36,21 @@ export class ReportLabsComponent implements OnInit { if(!this.observationGroupTitles[observationGroup]){ this.observationGroupTitles[observationGroup] = fhirpath.evaluate(observation.resource_raw, "Observation.code.coding.where(system='http://loinc.org').first().display")[0] } - } - //TODO: sort observation groups - - // this.observationGroups = results - // - // //populate a lookup table with all resources - // for (let condition of this.conditions) { - // this.recPopulateResourceLookup(condition) - // } + this.isEmptyReport = !!!results.length + }, error => { + this.loading = false + this.isEmptyReport = true }) } + + + + isEmpty(obj: any) { + return Object.keys(obj).length === 0; + } + + }