lib/components/plot-settings/plot-settings.component.ts
Angular material form fields for changing plot settings.
selector | nshmp-plot-settings |
imports |
MatLabel
MatFormField
MatInput
MatSlideToggle
MatHint
MatError
NshmpPlotSettingsAxisComponent
NshmpSectionComponent
MatSuffix
MatSelect
MatOption
MatDivider
ReactiveFormsModule
|
templateUrl | ./plot-settings.component.html |
styleUrl | ./plot-settings.component.scss |
Properties |
|
Methods |
|
Inputs |
Outputs |
showLabel | |
Default value : true
|
|
Whether to show plot label |
updatedPlot | |
Private updatePlotFromSettings | ||||||||
updatePlotFromSettings(plot: NshmpPlot)
|
||||||||
Update the Plotly config and layout from the application plot settings.
Parameters :
Returns :
NshmpPlot
|
configSettings |
Type : FormGroup<PlotlyConfigFormGroup>
|
Config settings form state |
Private destroyRef |
Default value : inject(DestroyRef)
|
exportFormat |
Type : []
|
Default value : ['png', 'svg', 'jpeg', 'webp']
|
Plotly export formats |
layoutSettings |
Type : FormGroup<NshmpPlotLayoutFormGroup>
|
Layout settings form state |
plotSettings |
Type : FormGroup<NshmpPlotSettingFormGroup>
|
Plot settings form state |
Readonly showLabel |
Default value : true
|
Whether to show plot label |
Readonly updatedPlot |
import {Component, DestroyRef, inject, input, output} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {FormGroup, ReactiveFormsModule} from '@angular/forms';
import {MatOption} from '@angular/material/core';
import {MatDivider} from '@angular/material/divider';
import {MatError, MatFormField, MatHint, MatLabel, MatSuffix} from '@angular/material/form-field';
import {MatInput} from '@angular/material/input';
import {MatSelect} from '@angular/material/select';
import {MatSlideToggle} from '@angular/material/slide-toggle';
import {NshmpSectionComponent} from '@ghsc/nshmp-lib-ng/nshmp';
import {PlotlyPlot} from '@ghsc/nshmp-utils-ts/libs/plotly';
import {DataTitle} from 'plotly.js';
import {
NshmpPlot,
NshmpPlotLayoutFormGroup,
NshmpPlotSettingFormGroup,
PlotlyConfigFormGroup,
} from '../../models/nshmp-plot.model';
import {NshmpPlotSettingsAxisComponent} from '../plot-settings-axis/plot-settings-axis.component';
/**
* Angular material form fields for changing plot settings.
*/
@Component({
imports: [
MatLabel,
MatFormField,
MatInput,
MatSlideToggle,
MatHint,
MatError,
NshmpPlotSettingsAxisComponent,
NshmpSectionComponent,
MatSuffix,
MatSelect,
MatOption,
MatDivider,
ReactiveFormsModule,
],
selector: 'nshmp-plot-settings',
styleUrl: './plot-settings.component.scss',
templateUrl: './plot-settings.component.html',
})
export class NshmpPlotSettingsComponent {
private destroyRef = inject(DestroyRef);
/** Plot settings form state */
plotSettings!: FormGroup<NshmpPlotSettingFormGroup>;
/** Layout settings form state */
layoutSettings!: FormGroup<NshmpPlotLayoutFormGroup>;
/** Config settings form state */
configSettings!: FormGroup<PlotlyConfigFormGroup>;
/** Plotly export formats */
exportFormat = ['png', 'svg', 'jpeg', 'webp'];
readonly updatedPlot = output<NshmpPlot>();
/**
* Sets the plot
*
* @param plot The NSHMP plot
*/
readonly plot = input.required<NshmpPlot, NshmpPlot>({
transform: plot => {
this.plotSettings = plot.settingsForm;
this.configSettings = plot.settingsForm.controls.config;
this.layoutSettings = plot.settingsForm.controls.layout;
this.plotSettings.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => {
this.updatedPlot.emit(this.updatePlotFromSettings(plot));
});
return plot;
},
});
/** Whether to show plot label */
readonly showLabel = input(true);
/**
* Update the Plotly config and layout from the application plot settings.
*
* @param plot The NSHMP plot
*/
private updatePlotFromSettings(plot: NshmpPlot): NshmpPlot {
const settings = plot.settingsForm.getRawValue();
const plotData: PlotlyPlot = {
...plot.plotData,
config: {
...plot.plotData.config,
...settings.config,
toImageButtonOptions: {
...plot.plotData.config.toImageButtonOptions,
...settings.config.toImageButtonOptions,
},
},
layout: {
...plot.plotData.layout,
...settings.layout,
legend: {
...plot.plotData.layout.legend,
x: settings.layout.legend.x,
y: settings.layout.legend.y,
},
showlegend: settings.layout.legend.showlegend,
title: {
...(plot.plotData.layout.title as DataTitle),
font: {
...(plot.plotData.layout.title as DataTitle).font,
size: settings.layout.title.size,
},
text: settings.layout.title.text,
},
xaxis: {
...plot.plotData.layout.xaxis,
nticks: settings.layout.xaxis.nticks,
title: {
...(plot.plotData?.layout?.xaxis?.title as DataTitle),
font: {
...(plot.plotData?.layout?.xaxis?.title as DataTitle).font,
size: settings.layout.xaxis.title.size,
},
text: settings.layout.xaxis.title.text,
},
type: settings.layout.xaxis.type,
},
yaxis: {
...plot.plotData.layout.yaxis,
nticks: settings.layout.yaxis.nticks,
title: {
...(plot.plotData?.layout?.yaxis?.title as DataTitle),
font: {
...(plot.plotData?.layout?.yaxis?.title as DataTitle).font,
size: settings.layout.yaxis.title.size,
},
text: settings.layout.yaxis.title.text,
},
type: settings.layout.yaxis.type,
},
},
};
return {
...plot,
plotData,
};
}
}
@if (plotSettings && layoutSettings) {
@let label = showLabel() ? plot().label : '';
<nshmp-section [label]="label">
<form class="padding-x-1" [formGroup]="plotSettings">
<!-- Plot Settings: title text -->
<mat-form-field class="grid-col-12 padding-top-2 title-input">
<mat-label>Title</mat-label>
<input type="text" matInput [formControl]="layoutSettings.controls.title.controls.text" />
</mat-form-field>
<!-- Plot Settings: title font size -->
<mat-form-field class="grid-col-12 title-font-size-input">
<mat-label>Title Font Size</mat-label>
<input matInput type="number" [formControl]="layoutSettings.controls.title.controls.size" />
</mat-form-field>
<!-- Plot Settings: aspect ratio -->
<mat-form-field class="grid-col-12 padding-bottom-2 plot-aspect-ratio-input">
<mat-label>Aspect Ratio</mat-label>
<input type="string" matInput [formControl]="layoutSettings.controls.aspectRatio" />
</mat-form-field>
@if (layoutSettings.controls.legend; as legend) {
<nshmp-section label="Legend">
<!-- Plot Settings: Legend -->
<!-- Legend: show legend -->
<div class="grid-row">
<mat-slide-toggle
class="show-legend-toggle grid-col-12"
[formControl]="legend.controls.showlegend"
>
Legend
</mat-slide-toggle>
</div>
<!-- Legend: location-->
<div class="grid-row padding-bottom-2">
<mat-form-field class="grid-col-6 legend-x-input">
<mat-label>Legend X Location</mat-label>
<input [formControl]="legend.controls.x" type="number" matInput max="3" min="-2" />
<mat-hint>[-2, 3] Normalized unts</mat-hint>
<mat-error>[-2, 3]</mat-error>
</mat-form-field>
<mat-form-field class="grid-col-6 legend-y-input">
<mat-label>Legend Y location</mat-label>
<input [formControl]="legend.controls.y" type="number" matInput max="3" min="-2" />
<mat-hint>[-2, 3] Normalized units</mat-hint>
<mat-error>[-2, 3]</mat-error>
</mat-form-field>
</div>
</nshmp-section>
}
<!-- X-Axis Settings-->
<nshmp-plot-settings-axis
class="x-axis-settings"
[settings]="layoutSettings.controls.xaxis"
label="X-Axis"
/>
<!-- Y-Axis Settings -->
<nshmp-plot-settings-axis
class="y-axis-settings"
[settings]="layoutSettings.controls.yaxis"
label="Y-Axis"
/>
<!-- Export Settings -->
@if (configSettings && configSettings.controls.toImageButtonOptions; as exportSettings) {
<nshmp-section label="Export Options">
<!-- Export Settings: Height -->
@if (exportSettings.controls.height) {
<mat-form-field class="grid-col-12 export-height-input">
<mat-label>Height</mat-label>
<input type="text" matInput [formControl]="exportSettings.controls.height" />
<span matTextSuffix>px</span>
</mat-form-field>
}
<!-- Export Settings: Width -->
@if (exportSettings.controls.width) {
<mat-form-field class="grid-col-12 export-width-input">
<mat-label>Width</mat-label>
<input type="text" matInput [formControl]="exportSettings.controls.width" />
<span matTextSuffix>px</span>
</mat-form-field>
}
<!-- Export Settings: Scale -->
@if (exportSettings.controls.scale) {
<mat-form-field class="grid-col-12 export-scale-input margin-bottom-2">
<mat-label>Scaling Factor</mat-label>
<input type="text" matInput [formControl]="exportSettings.controls.scale" />
<mat-hint>Scale canvas by this factor for better resolution</mat-hint>
</mat-form-field>
}
<!-- Export Settings: Format -->
@if (exportSettings.controls.format) {
<mat-form-field class="grid-col-12 export-format-select">
<mat-label>Format</mat-label>
<mat-select [formControl]="exportSettings.controls.format">
@for (format of exportFormat; track format) {
<mat-option [value]="format">
{{ format }}
</mat-option>
}
</mat-select>
</mat-form-field>
}
</nshmp-section>
}
<mat-divider class="padding-bottom-2" />
</form>
</nshmp-section>
}