import { Canvas, Meta } from '@storybook/blocks';
import * as RCPCHChartStories from './RCPCHChart.stories.tsx';
An RCPCHChart
instance is a wrapper component that receives user props and uses these to create either a CentileChart or an SDSChart.
The prop to define which chart type is rendered is: chartType?: 'centile' | 'sds'
Other props are:
title: string;
the title of the chart : could include patient name and identifiersmeasurementMethod: 'height' | 'weight' | 'ofc' | 'bmi';
must be one of the options providedreference: 'uk-who' | 'turner' | 'trisomy-21' | 'cdc';
must be one of the options providedsex: 'male' | 'female';
must be one of the options providedmeasurements: { measurementMethod: Measurement[]};
array of measurements returned from RCPCH Growth API. This should not be edited or manipulated. NOTE this has changed in v7.0.0midParentalHeightData?: MidParentalHeightObject | undefined;
an RCPCH object returned from the RCPCH Growth API. Should not be edited or manipulatedenableZoom?: boolean;
Allows the user to zoom and pan the charts if set to true. If disabled, hides the buttons associated with this.chartType?: 'centile' | 'sds';
These are addressed belowenableExport?: boolean | undefined;
Cut/Paste button. Returns an SVG snapshot of the chart (without title) if set to true. If false, the buttons associated with this are hidden.exportChartCallback(svg?: any): any;
Names the function within the client to return the exported SVG to.clinicianFocus?: boolean | undefined | null;
Toggles tooltip advice between those aimed at clinicians and those more appropriate for patients/lay people.theme?: 'monochrome' | 'traditional' | 'tanner1' | 'tanner2' | 'tanner3' | 'custom'
height?: number
: defaults to 800pxwidth?: number
: defaults to 1000pxcustomThemeStyles?
: discussed below
Note in v7.0.0 this prop has changed. Formerly measurementsArray
, the structure has changed to conform to the following structure:
{
height?: Measurement[]
weight?: Measurment[]
bmi?: Measurement[]
ofc?: Measurement[]
}
Measurements should be passed to the component through the measurements
prop using this structure.
This aligns the SDS and centile charts to accept the same structure. SDS and centile charts differ, in that SDS charts multiple measurement methods on a single chart, whereas centile charts must have one instance for each measurement method.
An array of height measurements for a girl returned from the RCPCH Growth API:
<RCPCHChart
reference={'uk-who'}
measurementMethod={'height'}
sex={'female'}
title={"Arthur Scargill - 12345678A"}
measurements={
height: [
{
birth_data: {
...
},
bone_age: {
...
},
child_observation_value: {
...
},
events_data: {
...
},
measurement_calculated_values: {
...
},
measurement_dates: {
...
},
plottable_data: {
...
}
},
...
]
} // this is the plottable child data
midParentalHeightData={[]} // this is the optional plottable midparental height data from the RCPCH API
theme={'traditional'}
enableZoom
chartType={'centile'}
enableExport={false}
exportChartCallback={()=>{}} // this is a callback for the export chart function if true
clinicianFocus={false}
/>
In the same way, an implementation for the sds charts would be:
<RCPCHChart
reference={'uk-who'}
measurementMethod={'height'}
sex={'female'}
title={"Arthur Scargill - 12345678A"}
measurements={
height: [
{
birth_data: {
...
},
bone_age: {
...
},
child_observation_value: {
...
},
events_data: {
...
},
measurement_calculated_values: {
...
},
measurement_dates: {
...
},
plottable_data: {
...
}
},
...
],
weight: [
{
birth_data: {
...
},
bone_age: {
...
},
child_observation_value: {
...
},
events_data: {
...
},
measurement_calculated_values: {
...
},
measurement_dates: {
...
},
plottable_data: {
...
}
},
...
],
ofc: [],
bmi: []
} // this is the plottable child data
midParentalHeightData={[]} // this is the optional plottable midparental height data from the RCPCH API
theme={'traditional'}
enableZoom
chartType={'sds'}
enableExport={false}
exportChartCallback={()=>{}} // this is a callback for the export chart function if true
clinicianFocus={false}
/>
For information the structure of the Measurement interface is provided here. This matches the response object from the RCPCH Growth API, therefore implementers should not need to use this interface:
export interface Measurement {
birth_data: {
birth_date: string;
estimated_date_delivery: string;
estimated_date_delivery_string: string;
gestation_weeks: number;
gestation_days: number;
sex: 'male' | 'female';
};
child_observation_value: {
measurement_method: 'height' | 'weight' | 'bmi' | 'ofc';
observation_value: number;
observation_value_error?: string;
};
measurement_dates: {
chronological_calendar_age: string;
chronological_decimal_age: number;
corrected_calendar_age: string;
corrected_decimal_age: number;
corrected_gestational_age?: {
corrected_gestation_weeks?: number;
corrected_gestation_days?: number;
};
comments?:{
clinician_corrected_decimal_age_comment?: string;
lay_corrected_decimal_age_comment?: string;
clinician_chronological_decimal_age_comment: string;
lay_chronological_decimal_age_comment: string;
}
observation_date: string;
corrected_decimal_age_error?: string;
chronological_decimal_age_error?: string;
};
measurement_calculated_values: {
chronological_centile: number;
chronological_centile_band: string;
chronological_measurement_error?: string;
chronological_sds: number;
corrected_centile: number;
corrected_centile_band: string;
corrected_measurement_error?: string;
corrected_percentage_median_bmi?: number
chronological_percentage_median_bmi?: number
corrected_sds: number;
};
plottable_data: {
centile_data: {
chronological_decimal_age_data: {
age_error?: string;
age_type: 'chronological_age' | 'corrected_age';
calendar_age: string;
centile_band: string;
clinician_comment: string;
lay_comment: string;
observation_error?: string;
observation_value_error?: string;
x: number;
y: number;
b?: number;
centile?: number;
sds?: number;
bone_age_label?: string;
events_text?: string[];
bone_age_type?: string;
bone_age_sds?: number;
bone_age_centile?: number;
};
corrected_decimal_age_data: {
age_error?: string;
age_type: 'chronological_age' | 'corrected_age';
calendar_age: string;
centile_band: string;
clinician_comment: string;
lay_comment: string;
observation_error?: string;
observation_value_error?: string;
x: number;
y: number;
b?: number;
centile?: number;
sds?: number;
bone_age_label?: string;
events_text?: string[];
bone_age_type?: string;
bone_age_sds?: number;
bone_age_centile?: number;
corrected_gestational_age?: string;
};
};
sds_data: {
chronological_decimal_age_data: {
age_error?: string;
age_type: 'chronological_age' | 'corrected_age';
calendar_age: string;
centile_band: string;
clinician_comment: string;
lay_comment: string;
observation_error?: string;
observation_value_error?: string;
x: number;
y: number;
b?: number;
centile: number;
sds: number;
bone_age_label?: string;
events_text?: string[];
bone_age_sds?: number;
bone_age_type?: string;
bone_age_centile?: number;
};
corrected_decimal_age_data: {
age_error?: string;
age_type: 'chronological_age' | 'corrected_age';
calendar_age: string;
centile_band: string;
clinician_comment: string;
lay_comment: string;
observation_error?: string;
observation_value_error?: string;
x: number;
y: number;
b?: number;
centile: number;
sds: number;
bone_age_label?: string;
bone_age_type?: string;
events_text?: string[];
bone_age_sds?: number;
bone_age_centile?: number;
corrected_gestational_age?: string;
};
};
};
bone_age: {
bone_age?: number;
bone_age_type?: string;
bone_age_centile?: number;
bone_age_sds?: number;
bone_age_text?: string;
};
events_data: {
events_text?: string[];
};
}
Themes are collections of styles. The RCPCH have created some suggested themes:
- Monochrome (default)
- Traditional: this uses the preexisting pink and blue colours present on the paper charts
- Tanner 1: Purple and yellow
- Tanner 2: Orange and blue
- Tanner 3: Red and yellow
- Custom
These themes all have predefined attributes for fontFamily
, color
, size
, weight
, stroke
and strokeWidth
for different aspects of the charts.
If these attributes are too prescriptive and users would like either to build their own theme,
or override styles within an existing theme, this can be done by passing in custom styles through the customThemeStyles
prop.
All attributes are optional, therefore only those attributes where changes are requested need be passed in. The keys for the customThemeStyles
object are as follows:
chartStyle?: ChartStyle;
axisStyle?: AxisStyle;
gridlineStyle?: GridlineStyle;
centileStyle?: CentileStyle;
sdsStyle?: SDSStyle;
measurementStyle?: MeasurementStyle;
referenceStyle?: ReferenceStyle;
The attributes of each of these are below:
backgroundColour?: string;
//background colour of charttitleStyle?: TextStyle
; // style of text in title: includes fontFamily, fontSize, colour, style, weightsubTitleStyle?: TextStyle
; // style of text in subtitle: includes fontFamily, fontSize, colour, style, weighttooltipBackgroundColour?: string;
//background colour of tooltiptooltipStroke?: string;
//border colour of tooltiptooltipTextStyle?: TextStyle
; // tooltip text: includes fontFamily, fontSize, colour, style, weighttermFill?: string;
// background colour of weight term areatermStroke?: string;
// border colour of weight term areatoggleButtonInactiveColour?: string;
// buttons - inactive colourtoggleButtonActiveColour?: string;
// buttons - active colourtoggleButtonTextStyle?: TextStyle | undefined;
// buttons text: includes fontFamily, fontSize, colour, style, weight
measurementFill?: string;
// measurement point fill colour - only apply to SDS chartshighlightedMeasurementFill?: string;
// measurement point fill colour when hightlighted (SDS charts)eventTextStyle?: TextStyle;
// styles for text of events: includes fontFamily, fontSize, colour, style, weight
sdsStroke?: string;
// sds line colourcentileStroke?: string;
// centile line colournondisjunctionThresholdLabel ?: string;
// label for nondisjunctionThresholdLabelnondisjunctionThresholdLine ?: string;
// colour of nondisjunctionThresholdLinedelayedPubertyAreaFill?: string;
// delayed puberty area colourmidParentalCentileStroke?: string;
// Midparental height centile line colourmidParentalAreaFill?: string;
// Midparental height area colourcentileTextStyle?: Pick<TextStyle, 'name' | 'size' | 'weight'>;
// centile text style : includes name, size, weight
heightStroke?: string;
// sds line colourweightStroke?: string;
// sds line colourofcStroke?: string;
// sds line colourbmiStroke?: string;
// sds line colour
gridlines?: boolean;
// show or hide gridlinesstroke?: string;
// gridline colourstrokeWidth?: number;
// gridline widthdashed?: boolean;
// dashed vs continuous gridlines
axisStroke?: string;
// Axis colouraxisThresholdLabelTextStyle?: TextStyle;
// Axis label text: : includes fontFamily, fontSize, colour, style, weightaxisThresholdLineStyle?: AxisThresholdLineStyle;
// Axis line: includes colouraxisLabelTextStyle?: TextStyle;
// Axis label text: : includes fontFamily, fontSize, colour, style, weighttickLabelTextStyle?: TickLabelTextStyle;
// Tick label text : includes fontFamily, fontSize, colour, style, weight and padding
name?: string;
colour?: string;
size?: number;
style?: 'italic' | 'normal';
weight?: number | string;
For example, if a user wished to override the background colour of the existing 'monochrome' theme:
const customChartStyle: ChartStyle = {
backgroundColour: "tomato"
}
const customStyles = {
chartStyle: customChartStyle
}
And in the JSX:
<RCPCHChart
reference={'uk-who'}
measurementMethod={'height'}
sex={'female'}
title={'Arthur Scargill - 12345678A'}
measurements={[]} // this is the plottable child data
midParentalHeightData={[]} // this is the optional plottable midparental height data from the RCPCH API
theme={'monochrome'}
customThemeStyles={customStyles} <---- override styles here
enableZoom
chartType={'centile'}
enableExport={false}
exportChartCallback={() => {}} // this is a callback for the export chart function if true
clinicianFocus={false}
/>
yields:
Or even build a whole new theme to match a custom Design System
const customStyles = {
chartStyle: {
backgroundColour: '#FAF8F5',
titleStyle: {
weight: 800,
colour: '#706A80',
name: 'sans-serif',
size: 16,
},
subTitleStyle: {
weight: 400,
colour: '#706A80',
name: 'sans-serif',
size: 13,
},
tooltipStroke: '#5a526b',
tooltipBorderRadius: 4,
tooltipBackgroundColour: '#5a526b',
tooltipTextStyle: {
colour: '#fffdfd',
name: 'sans-serif',
size: 14,
},
toggleButtonActiveColour: '#B89F81',
toggleButtonInactiveColour: '#e8dbcc',
toggleButtonTextStyle: {
colour: 'white',
name: 'sans-serif',
size: 16,
weight: 400,
},
toggleButtonTooltipStyle: {
backgroundColour: '#5a526b',
borderRadius: 4,
colour: 'white',
size: 14,
name: 'sans-serif',
weight: 400,
}
},
axisStyle: {
axisStroke: '#EDE7DD',
tickLabelTextStyle: {
colour: '#706A80',
size: 12,
weight: 400,
name: 'sans-serif',
},
axisLabelTextStyle: {
weight: 500,
colour: '#706A80',
name: 'sans-serif',
size: 15,
},
axisThresholdLabelTextStyle: {
weight: 500,
colour: '#706A80',
name: 'sans-serif',
size: 12.5,
},
axisThresholdLineStyle: {
colour: '#706A80',
},
},
gridlineStyle: {
dashed: true,
stroke: '#EDE7DD',
strokeWidth: 1,
gridlines: true,
},
centileStyle: {
centileTextStyle: {
name: 'sans-serif',
size: 12.5,
weight: 400,
},
centileStroke: '#B89F81',
midParentalAreaFill: '#B89F81',
midParentalCentileStroke: '#B89F81',
delayedPubertyAreaFill: '#B89F81',
sdsStroke: '#B89F81',
},
measurementStyle: {
eventTextStyle: {
size: 14,
name: 'sans-serif',
weight: 400,
colour: '#760050',
},
highlightedMeasurementFill: '#B89F81',
measurementFill: '#760050',
},
referenceStyle: {
weight: 500,
colour: '#706A80',
name: 'sans-serif',
size: 13,
},
},
yields: