An error occurred while loading the file. Please try again.
-
Mathias Chouet authoreda857a563
import { Component, OnInit, DoCheck, OnDestroy, ViewChild, ViewChildren,
QueryList, AfterViewChecked, ElementRef, Inject, forwardRef } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { Observer, Session, Cloisons, Pab, ParamValueMode, CalculatorType, Bief, SectionParametree, acSection, round, SessionSettings } from "jalhyd";
import { AppComponent } from "../../app.component";
import { FormulaireService } from "../../services/formulaire.service";
import { I18nService } from "../../services/internationalisation.service";
import { FieldSet } from "../../formulaire/fieldset";
import { FormulaireDefinition } from "../../formulaire/definition/form-definition";
import { CalculatorResultsComponent } from "../../components/calculator-results/calculator-results.component";
import { Subscription } from "rxjs";
import { FieldSetComponent } from "../field-set/field-set.component";
import { CalculatorNameComponent } from "./calc-name.component";
import { FormulaireElement } from "../../formulaire/formulaire-element";
import { FieldsetContainer } from "../../formulaire/fieldset-container";
import { FieldsetContainerComponent } from "../fieldset-container/fieldset-container.component";
import { PabTableComponent } from "../pab-table/pab-table.component";
import { ServiceFactory } from "../../services/service-factory";
import { MatDialog } from "@angular/material";
import { DialogConfirmCloseCalcComponent } from "../dialog-confirm-close-calc/dialog-confirm-close-calc.component";
import { DialogGeneratePABComponent } from "../dialog-generate-pab/dialog-generate-pab.component";
import { PabTable } from "../../formulaire/pab-table";
import { HotkeysService, Hotkey } from "angular2-hotkeys";
@Component({
selector: "hydrocalc",
templateUrl: "./calculator.component.html",
styleUrls: ["./calculator.component.scss"]
})
export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChecked, OnDestroy, Observer {
/**
* liste des FieldSetComponent
*/
@ViewChildren(FieldSetComponent)
private _fieldsetComponents: QueryList<FieldSetComponent>;
/**
* liste des FieldsetContainerComponent
*/
@ViewChildren(FieldsetContainerComponent)
private _fieldsetContainerComponents: QueryList<FieldsetContainerComponent>;
/**
* PabTableComponent if any
*/
@ViewChild(PabTableComponent, { static: false })
private _pabTableComponent: PabTableComponent;
/**
* composant d'affichage des résultats
*/
@ViewChild(CalculatorResultsComponent, { static: true })
private resultsComponent: CalculatorResultsComponent;
/**
* composant "nom du module de calcul"
*/
@ViewChild(CalculatorNameComponent, { static: true })
private _calculatorNameComponent: CalculatorNameComponent;
/**
* formulaire affiché
*/
private _formulaire: FormulaireDefinition;
private _subscription: Subscription; // pour souscrire aux changements d'URL envoyés par le routeur
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
/**
* true si on a cliqué sur le bouton de lancement de calcul
*/
private _computeClicked: boolean;
/**
* flag de validité gloable de la saisie
* NB : la validité du bouton "calculer" dépend de la validité de la saisie dans l'UI et de celle indiquée par le formulaire.
* La validité de l'UI comprend la forme (pas de chaîne alpha dans les champs numériques, etc..).
* La validité formulaire comprend le domaine de définition des valeurs saisies.
*/
private _isUIValid = false;
/**
* flag disabled du bouton "calculer"
*/
public isCalculateDisabled = true;
/**
* flag (+info) indiquant un événement radio à traiter
* nécessaire avec l'introduction du mode de valeur LINK des paramètres car quand on modifie le mode à LINK, les possibles
* paramètres liables ne sont pas encore connus
*/
private _pendingRadioClick = false;
private _pendingRadioClickInfo: any;
// services
private intlService: I18nService;
private formulaireService: FormulaireService;
public get ID() {
if (this._formulaire) {
return this._formulaire.uid;
} else {
return "calculator_1";
}
}
constructor(
@Inject(forwardRef(() => AppComponent)) private appComponent: AppComponent,
private route: ActivatedRoute,
private router: Router,
private confirmCloseCalcDialog: MatDialog,
private generatePABDialog: MatDialog,
private _elementRef: ElementRef,
private hotkeysService: HotkeysService
) {
this.intlService = ServiceFactory.instance.i18nService;
this.formulaireService = ServiceFactory.instance.formulaireService;
// hotkeys listeners
this.hotkeysService.add(new Hotkey("alt+w", AppComponent.onHotkey(this.closeCalculator, this)));
this.hotkeysService.add(new Hotkey("alt+d", AppComponent.onHotkey(this.cloneCalculator, this)));
this.hotkeysService.add(new Hotkey("alt+enter", AppComponent.onHotkey(this.doCompute, this)));
this.hotkeysService.add(new Hotkey("alt+1", AppComponent.onHotkey(() => {
this.appComponent.scrollToQuicknav("input");
}, this)));
this.hotkeysService.add(new Hotkey("alt+2", AppComponent.onHotkey(() => {
this.appComponent.scrollToQuicknav("results");
}, this)));
this.hotkeysService.add(new Hotkey("alt+3", AppComponent.onHotkey(() => {
this.appComponent.scrollToQuicknav("charts");
}, this)));
}
public get formElements(): FormulaireElement[] {
if (this._formulaire === undefined) {
return [];
}
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
return this._formulaire.kids as FormulaireElement[];
}
/**
* détermine si un FormulaireElement est du type FieldSet
*/
public isFieldset(fe: any): boolean {
return fe instanceof FieldSet;
}
/**
* détermine si un FormulaireElement est du type FieldsetContainer
*/
public isFieldsetContainer(fe: any): boolean {
return fe instanceof FieldsetContainer;
}
/**
* détermine si un FormulaireElement est du type PabTable
*/
public isPabTable(fe: any): boolean {
return fe instanceof PabTable;
}
public get hasForm() {
return this._formulaire !== undefined;
}
public get hasResults(): boolean {
if (this.hasForm) {
return this._formulaire.hasResults;
}
return false;
}
public get uitextTitre() {
if (this.hasForm) {
return this.formulaireService.getLocalisedTitleFromCalculatorType(this._formulaire.calculatorType);
}
}
public get uitextCalculer() {
return this.intlService.localizeText("INFO_CALCULATOR_CALCULER");
}
public get uitextCalculatorName() {
return this.intlService.localizeText("INFO_CALCULATOR_CALC_NAME");
}
public get uitextResultsTitle() {
return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_TITLE");
}
public get uitextGeneratePAB() {
return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_PAB");
}
public get uitextGenerateSPAmont() {
return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_SP_AMONT");
}
public get uitextGenerateSPAval() {
return this.intlService.localizeText("INFO_CALCULATOR_RESULTS_GENERATE_SP_AVAL");
}
public get uitextOpenHelp() {
return this.intlService.localizeText("INFO_CALCULATOR_OPEN_HELP");
}
public get uitextCloneCalculator() {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
return this.intlService.localizeText("INFO_CALCULATOR_CLONE");
}
public get uitextSaveCalculator() {
return this.intlService.localizeText("INFO_CALCULATOR_SAVE");
}
public get uitextCloseCalculator() {
return this.intlService.localizeText("INFO_CALCULATOR_CLOSE");
}
public get uitextUsedBy() {
return this.intlService.localizeText("INFO_CALCULATOR_USED_BY");
}
public get quicknavItems() {
const elts = [ "input", "results" ];
if (this.isWide && this.hasResults) {
elts.push("charts");
}
return elts;
}
/**
* Triggered at calculator instanciation
*/
ngOnInit() {
this.formulaireService.addObserver(this);
this.subscribeRouter();
}
ngDoCheck() {
this.isCalculateDisabled = ! this._isUIValid;
}
ngOnDestroy() {
this.unsubscribeRouter();
this.formulaireService.removeObserver(this);
this.intlService.removeObserver(this);
}
private subscribeRouter() {
// récupération des paramètres passés avec la route (URL)
this._subscription = this.route.params.subscribe(params => {
const uid: string = params["uid"];
this.formulaireService.setCurrentForm(uid);
});
}
private unsubscribeRouter() {
if (this._subscription) {
this._subscription.unsubscribe();
}
}
/*
* gestion des événements clic sur les radios
*/
public onRadioClick(info: any) {
if (info.param.valueMode === ParamValueMode.LINK) {
this.updateLinkedParameters(); // only when switching to LINK mode
}
this._pendingRadioClick = true;
this._pendingRadioClickInfo = info;
}
public ngAfterViewChecked() {
if (this._pendingRadioClick) {
this._pendingRadioClick = false;
this._formulaire.onRadioClick(this._pendingRadioClickInfo);
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
this._pendingRadioClickInfo = undefined;
}
}
public onCloseForm() {
this.formulaireService.requestCloseForm(this._formulaire.uid);
}
/**
* met à jour les paramètres liés
*/
private updateLinkedParameters() {
this._fieldsetComponents.forEach(fsc => fsc.updateLinkedParameters());
this._fieldsetContainerComponents.forEach(fscc => fscc.updateLinkedParameters());
}
public doCompute() {
this._formulaire.resetResults([]);
this.appComponent.showProgressBar = true;
this._computeClicked = true;
setTimeout(() => {
this._formulaire.doCompute();
this.appComponent.showProgressBar = false;
}, 100); // 100ms is important, a lower value may make the progress bar never appear :/
}
public onCalcResultsViewChecked() {
if (this._computeClicked) {
this._computeClicked = false;
this.scrollToResults();
}
}
/** open calculator identified by given UID */
public toCalc(id: string) {
this.appComponent.toCalc(id);
}
/** list of calculators having a link pointing to the current calculator */
public get calculatorsUsingThisOne(): any {
const sources = Session.getInstance().getDependingNubs(this._formulaire.currentNub.uid, undefined, true);
return sources.map((s) => {
return {
label: this.formulaireService.getFormulaireFromNubId(s.uid).calculatorName,
uid: s.uid
};
});
}
/**
* Moves the view to the start of the "Results" section
*/
private scrollToResults() {
// try to scroll to quicknav "results" first
try {
this.appComponent.scrollToQuicknav("results");
} catch (e) {
const element = document.getElementById ("fake-results-anchor");
if (element) {
element.scrollIntoView();
}
}
}
private setForm(f: FormulaireDefinition) {
if (this._formulaire !== undefined) {
this._formulaire.removeObserver(this);
}
this._formulaire = f;
if (this._formulaire !== undefined) {
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
this._formulaire.addObserver(this);
}
}
private updateFormulaireResults(uid: string) {
if (this._formulaire.uid === uid) {
this.resultsComponent.updateView();
}
}
// interface Observer
update(sender: any, data: any): void {
if (sender instanceof FormulaireService) {
switch (data["action"]) {
case "currentFormChanged":
const uid: string = data["formId"];
this.setForm(this.formulaireService.getFormulaireFromId(uid));
this.resultsComponent.formulaire = this._formulaire;
this._calculatorNameComponent.model = this._formulaire;
// reload localisation in all cases
this.formulaireService.loadUpdateFormulaireLocalisation(this._formulaire);
break;
}
} else if (sender instanceof FormulaireDefinition) {
let f: FormulaireDefinition;
switch (data["action"]) {
case "resetForm": // réinitialisation du formulaire
case "resultsUpdated":
f = sender as FormulaireDefinition;
this.updateFormulaireResults(f.uid);
break;
}
}
}
/**
* appelé après le 1er affichage du composant
*/
protected afterFirstViewChecked() {
this.updateUIValidity();
}
/**
* calcul de la validité globale de la vue
*/
private updateUIValidity() {
this._isUIValid = false;
if (this._fieldsetComponents !== undefined) {
this._isUIValid = this._fieldsetComponents.reduce(
// callback
(
// accumulator (valeur précédente du résultat)
acc,
// currentValue (élément courant dans le tableau)
fieldset,
// currentIndex (indice courant dans le tableau)
currIndex,
// array (tableau parcouru)
array
) => {
return acc && fieldset.isValid;
}
// valeur initiale
, this._fieldsetComponents.length > 0);
}
if (this._fieldsetContainerComponents !== undefined) {
this._isUIValid = this._isUIValid && this._fieldsetContainerComponents.reduce<boolean>(
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
// callback
(
// accumulator (valeur précédente du résultat)
acc,
// currentValue (élément courant dans le tableau)
fieldsetContainer,
// currentIndex (indice courant dans le tableau)
currIndex,
// array (tableau parcouru)
array
): boolean => {
return acc && fieldsetContainer.isValid;
}
// valeur initiale
, true);
}
if (this._pabTableComponent !== undefined) {
this._isUIValid = this._isUIValid && this._pabTableComponent.isValid;
}
}
public getElementStyleDisplay(id: string) {
const isDisplayed: boolean = this._formulaire.isDisplayed(id);
return isDisplayed ? "block" : "none";
}
/**
* réception d'un événement de validité d'un FormElement
*/
public onElementValid() {
this.updateUIValidity();
}
/**
* réception d'un événement de changement de valeur d'un input
*/
public onInputChange(event: any) {
this._formulaire.resetResults([], (event ? event.symbol : undefined));
// to refresh log components, that are fed manually (!)
this.resultsComponent.updateView();
}
/**
* Passe d'un champ de saisie à l'autre lors de l'appui sur
* TAB, sans passer par les autres éléments d'interface
*/
public onTabPressed(event: any) {
// event source input id
const srcId = event.originalEvent.target.id;
// find all available inputs
const qs = "ngparam-input input.form-control";
let inputs: Node[] = Array.from(this._elementRef.nativeElement.querySelectorAll(qs));
// find calculated symbol if any, to exclude it from inputs list
let calcSymbol = "";
if (this._formulaire.currentNub.calculatedParam) {
calcSymbol = this._formulaire.currentNub.calculatedParam.symbol;
}
inputs = inputs.filter((i: any) => {
return i.id !== calcSymbol;
});
// find position among inputs list
const currentIndex = inputs.findIndex((i: any) => {
return i.id === srcId;
});
// focus previous / next input
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
let newIndex = currentIndex;
if (event.shift) {
newIndex = (newIndex === 0) ? (inputs.length - 1) : (newIndex - 1);
} else {
newIndex = (newIndex + 1) % inputs.length;
}
const elt = (inputs[newIndex] as HTMLInputElement);
elt.focus();
elt.select();
}
public openHelp() {
window.open("assets/docs-fr/calculators/" + this._formulaire.helpLink, "_blank");
}
/**
* flag d'affichage du bouton d'aide
*/
public get enableHelpButton() {
return this._formulaire && this._formulaire.helpLink;
}
/** return true if current Nub type is ct */
public is(ct: CalculatorType): boolean {
return (
this._formulaire
&& this._formulaire.currentNub
&& this._formulaire.currentNub.calcType === ct
);
}
// for "one wide column" layout
public get isWide() {
return (this.isPAB || this.isMRC);
}
// true if current Nub is PAB
public get isPAB() {
return this.is(CalculatorType.Pab);
}
// true if current Nub is MacroRugoCompound
public get isMRC() {
return this.is(CalculatorType.MacroRugoCompound);
}
// true if current Nub is Jet
public get isJet() {
return this.is(CalculatorType.Jet);
}
// for "generate PAB" button
public get isPABCloisons() {
return this.is(CalculatorType.Cloisons);
}
// true if current Nub is Bief
public get isBief() {
return this.is(CalculatorType.Bief);
}
/**
* Returns true if no parameter is varying
*/
private allParamsAreFixed() {
let ret = true;
for (const p of this._formulaire.currentNub.parameterIterator) {
if (p.valueMode === ParamValueMode.LINK) {
ret = ret && (! p.hasMultipleValues);
} else {
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
// avoid calling hasMultipleValues here, because changing parameter mode in GUI
// switches valueMode before setting min/max/step or valuesList, and iterator
// checker fails to count values that do not exist yet
ret = ret && (! [ ParamValueMode.LISTE, ParamValueMode.MINMAX ].includes(p.valueMode));
}
}
return ret;
}
// PAB generation is enabled only if :
// - no parameter is varying
// - Cloisons is calculated first
public get generatePABEnabled(): boolean {
return this.allParamsAreFixed() && this.hasResults;
}
public get uitextGeneratePabTitle() {
if (! this.hasResults) {
return this.intlService.localizeText("INFO_CALCULER_D_ABORD");
}
if (! this.allParamsAreFixed) {
return this.intlService.localizeText("INFO_PAB_PARAMETRES_FIXES");
}
return "";
}
/**
* Génère une passe à bassins à partir du modèle de cloisons en cours
*/
public generatePAB() {
// création du dialogue de génération d'une passe à bassin
const cloisons = (this._formulaire.currentNub as Cloisons);
const dialogRef = this.generatePABDialog.open(
DialogGeneratePABComponent,
{
data: {
chute: cloisons.prms.DH.V,
debit: cloisons.prms.Q.V,
coteAmont: cloisons.prms.Z1.V
},
disableClose: false
}
);
dialogRef.afterClosed().subscribe(result => {
if (result) {
if (result.generate) {
this.formulaireService.createFormulaire(CalculatorType.Pab).then((f: FormulaireDefinition) => {
const pab = (f.currentNub as Pab);
const params = pab.prms;
// paramètres hydrauliques
params.Q.singleValue = result.debit;
params.Z1.singleValue = result.coteAmont;
params.Z2.singleValue = result.coteAval;
// création des bassins
pab.deleteChild(0);
pab.addCloisonsFromModel(this._formulaire.currentNub as Cloisons, result.nbBassins);
// go to new PAB
this.router.navigate(["/calculator", f.uid]);
});
}
}
});
}
/**
* Génère une SectionParametree à partir des cotes amont du module Bief en cours
*/
public generateSPAmont() {
const bief = (this._formulaire.currentNub as Bief);
this.generateSP(round(bief.prms.Z1.singleValue - bief.prms.ZF1.singleValue, 3));
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
}
/**
* Génère une SectionParametree à partir des cotes aval du module Bief en cours
*/
public generateSPAval() {
const bief = (this._formulaire.currentNub as Bief);
this.generateSP(round(bief.prms.Z2.singleValue - bief.prms.ZF2.singleValue, 3));
}
/**
* Génère une SectionParametree à partir du module Bief en cours
* @param Y tirant d'eau
*/
private generateSP(Y: number) {
const bief = (this._formulaire.currentNub as Bief);
const pente = round(
(bief.prms.ZF1.singleValue - bief.prms.ZF2.singleValue) / bief.prms.Long.singleValue,
5 // ça ou autre chose…
);
const serialisedSection = bief.section.serialise();
const sectionCopy = Session.getInstance().unserialiseSingleNub(serialisedSection, false).nub;
const secParam = new SectionParametree(sectionCopy as acSection);
Session.getInstance().registerNub(secParam);
this.formulaireService.createFormulaire(CalculatorType.SectionParametree, secParam)
.then((f: FormulaireDefinition) => {
const sp = (f.currentNub as SectionParametree);
sp.section.prms.Y.singleValue = Y;
sp.section.prms.If.singleValue = pente;
// calculate
f.doCompute();
// go to new SP
this.router.navigate(["/calculator", f.uid]).then();
}
);
}
public saveCalculator() {
this.formulaireService.saveForm(this._formulaire);
}
public closeCalculator() {
const dialogRef = this.confirmCloseCalcDialog.open(
DialogConfirmCloseCalcComponent,
{
data: {
uid: this._formulaire.currentNub.uid
},
disableClose: true
}
);
dialogRef.afterClosed().subscribe(result => {
if (result) {
this.onCloseForm();
}
});
}
/**
* Duplicates the current calculator form
*/
public cloneCalculator() {
const serialisedNub: string = this._formulaire.currentNub.serialise({ title: this._formulaire.calculatorName });
const nubPointer = Session.getInstance().unserialiseSingleNub(serialisedNub);
this.formulaireService.createFormulaire(nubPointer.nub.calcType, nubPointer.nub, nubPointer.meta.title).then((f) => {
this.router.navigate(["/calculator", f.uid]);
});
}
}
701