diff --git a/README.md b/README.md index 319797424d8d896998f03c67b3f9789366061706..4b93c03438e22e6bf8999418eef7e56393f49e3c 100644 --- a/README.md +++ b/README.md @@ -267,8 +267,9 @@ Custom Material SVG Icons will only show up when the application is deployed on On peut soit composer la classe concrète directement avec ces classes, soient dériver ces dernières et composer avec. 3. _src/locale/messages.<langue>.json_ : - Ajouter un champ pour le titre du module de calcul. Par exemple : - _"INFO_MACALC_TITRE": "Ma calculette"_ + Ajouter deux champs pour le titre et le titre court du module de calcul. Par exemple : + _"INFO_MACALC_TITRE": "Ma calculette"_, + _"INFO_MACALC_TITRE_COURT": "Ma calc."_ 4. Dans le constructeur de _FormulaireService_, ajouter une entrée dans `this.calculatorPaths` pour fournir le préfixe des fichiers de configuration/internationalisation. diff --git a/e2e/session/session-bad-syntax.json b/e2e/session/session-bad-syntax.json index c2de57a8d6403616c6bb93689e04071bcf8c7c86..bd9de9b5f9d0cf7e93c94a125c491d9185dd0367 100644 --- a/e2e/session/session-bad-syntax.json +++ b/e2e/session/session-bad-syntax.json @@ -1,7 +1,7 @@ { "header": { "source": "jalhyd", - "format_version": "1.1", + "format_version": "1.2", "created": "2019-08-21T13:20:54.284Z" }, "session": [ diff --git a/e2e/session/session-empty-modules-list.json b/e2e/session/session-empty-modules-list.json index 3a5bbefdd2755d876d8ced09b810cec6cf97dcdd..9fe699c785ece4ea9d3b24d7ec49a42b65e8dbd8 100644 --- a/e2e/session/session-empty-modules-list.json +++ b/e2e/session/session-empty-modules-list.json @@ -1,7 +1,7 @@ { "header": { "source": "jalhyd", - "format_version": "1.1", + "format_version": "1.2", "created": "2019-08-21T13:20:54.284Z" }, "session": [ diff --git a/e2e/session/session-missing-info.json b/e2e/session/session-missing-info.json index fa6003940308ae3f895ccd38db076c13cf6cb1d3..dadfcf9c240eba8fd002bf426d151e9bc1850fd5 100644 --- a/e2e/session/session-missing-info.json +++ b/e2e/session/session-missing-info.json @@ -1,7 +1,7 @@ { "header": { "source": "jalhyd", - "format_version": "1.1", + "format_version": "1.2", "created": "2019-08-21T13:20:54.284Z" }, "session": [ diff --git a/jalhyd_branch b/jalhyd_branch index 1f7391f92b6a3792204e07e99f71f643cc35e7e1..924865eab8ae980d10f69b74dcb1565556b44867 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -master +112-ajout-du-module-devalaison-trajectoire-des-poissons diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 22f1e48af327c8001cb6d4acff880669fc0c1eca..1cbc72c0fcd2f6a46d282e0075722732cc2e660f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -90,6 +90,8 @@ import { QuicknavComponent } from "./components/quicknav/quicknav.component"; import { ModulesDiagramComponent } from "./components/modules-diagram/modules-diagram.component"; import { MacrorugoCompoundResultsTableComponent } from "./components/macrorugo-compound-results/macrorugo-compound-results-table.component"; import { MacrorugoCompoundResultsComponent } from "./components/macrorugo-compound-results/macrorugo-compound-results.component"; +import { JetResultsComponent } from "./components/jet-results/jet-results.component"; +import { JetTrajectoryGraphComponent } from "./components/jet-trajectory-graph/jet-trajectory-graph.component"; import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-close-calc/dialog-confirm-close-calc.component"; @@ -193,6 +195,8 @@ const appRoutes: Routes = [ JalhydModelValidationMinDirective, JalhydModelValidationMaxDirective, JalhydModelValidationStepDirective, + JetResultsComponent, + JetTrajectoryGraphComponent, LogComponent, LogEntryComponent, ModulesDiagramComponent, diff --git a/src/app/calculators/jet/jet.config.json b/src/app/calculators/jet/jet.config.json new file mode 100644 index 0000000000000000000000000000000000000000..857c2018e253f13ac9f4fbe9dca012a2c9e06bbb --- /dev/null +++ b/src/app/calculators/jet/jet.config.json @@ -0,0 +1,12 @@ +[ + { + "id": "fs_jet", + "type": "fieldset", + "fields": [ "V0", "S", "D", "H" ] + }, + { + "type": "options", + "__idCal": "D", + "help": "devalaison/jet" + } +] \ No newline at end of file diff --git a/src/app/calculators/jet/jet.en.json b/src/app/calculators/jet/jet.en.json new file mode 100644 index 0000000000000000000000000000000000000000..4b7b42f433dc6b57f0d427e7a17c0f65193a705e --- /dev/null +++ b/src/app/calculators/jet/jet.en.json @@ -0,0 +1,21 @@ +{ + "fs_jet": "Jet and impact parameters", + + "V0": "Initial speed", + "S": "Initial slope", + "D": "Impact abscissa", + "H": "Fall height", + "t": "Flight time", + "Vx": "Horizontal speed at impact", + "Vz": "Vertical speed at impact", + "Vt": "Speed at impact", + + "UNIT_V0": "m/s", + "UNIT_S": "m/m", + "UNIT_D": "m", + "UNIT_H": "m", + "UNIT_T": "s", + "UNIT_VX": "m/s", + "UNIT_VZ": "m/s", + "UNIT_VT": "m/s" +} \ No newline at end of file diff --git a/src/app/calculators/jet/jet.fr.json b/src/app/calculators/jet/jet.fr.json new file mode 100644 index 0000000000000000000000000000000000000000..022826344675c1bacd92de1083b98c4da3fdaf69 --- /dev/null +++ b/src/app/calculators/jet/jet.fr.json @@ -0,0 +1,21 @@ +{ + "fs_jet": "Paramètres du jet et de l'impact", + + "V0": "Vitesse initiale", + "S": "Pente initiale", + "D": "Abscisse de l'impact", + "H": "Hauteur de chute", + "t": "Temps de vol", + "Vx": "Vitesse horizontale à l'impact", + "Vz": "Vitesse verticale à l'impact", + "Vt": "Vitesse à l'impact", + + "UNIT_V0": "m/s", + "UNIT_S": "m/m", + "UNIT_D": "m", + "UNIT_H": "m", + "UNIT_T": "s", + "UNIT_VX": "m/s", + "UNIT_VZ": "m/s", + "UNIT_VT": "m/s" +} \ No newline at end of file diff --git a/src/app/components/calculator-results/calculator-results.component.html b/src/app/components/calculator-results/calculator-results.component.html index 93748fe047535181136b937a26c71df1c2b1f8b8..e15f90423460d877543169dc7b5081eb4446e809 100644 --- a/src/app/components/calculator-results/calculator-results.component.html +++ b/src/app/components/calculator-results/calculator-results.component.html @@ -3,5 +3,6 @@ <remous-results></remous-results> <pab-results></pab-results> <macrorugo-compound-results></macrorugo-compound-results> + <jet-results></jet-results> <fixedvar-results></fixedvar-results> </div> diff --git a/src/app/components/calculator-results/calculator-results.component.ts b/src/app/components/calculator-results/calculator-results.component.ts index 9dd4576c506802ce8fd390a5168ae6068d550cb9..dcc7e97fb7bff94990d95bd7d1cf607e95278993 100644 --- a/src/app/components/calculator-results/calculator-results.component.ts +++ b/src/app/components/calculator-results/calculator-results.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, Output, EventEmitter, AfterViewChecked } from "@angular/core"; +import { Component, ViewChild, Output, EventEmitter, AfterViewChecked, Inject, forwardRef } from "@angular/core"; import { FixedVarResultsComponent } from "../../components/fixedvar-results/fixedvar-results.component"; import { SectionResultsComponent } from "../../components/section-results/section-results.component"; @@ -6,12 +6,15 @@ import { RemousResultsComponent } from "../../components/remous-results/remous-r import { PabResultsComponent } from "../../components/pab-results/pab-results.component"; import { MacrorugoCompoundResultsComponent } from "../macrorugo-compound-results/macrorugo-compound-results.component"; import { FormulaireDefinition } from "../../formulaire/definition/form-definition"; +import { JetResultsComponent } from "../jet-results/jet-results.component"; +import { GenericCalculatorComponent } from "../generic-calculator/calculator.component"; @Component({ selector: "calc-results", templateUrl: "./calculator-results.component.html", }) export class CalculatorResultsComponent implements AfterViewChecked { + private _formulaire: FormulaireDefinition; /** @@ -42,7 +45,13 @@ export class CalculatorResultsComponent implements AfterViewChecked { * composant d'affichage des résultats des passes à macrorugosités complexes */ @ViewChild(MacrorugoCompoundResultsComponent, { static: true }) - private mrcResultsComponent: PabResultsComponent; + private mrcResultsComponent: MacrorugoCompoundResultsComponent; + + /** + * composant d'affichage des résultats des impacts de jet + */ + @ViewChild(JetResultsComponent, { static: true }) + private jetResultsComponent: JetResultsComponent; /** * événement émis à la fin du dessin de la vue @@ -50,6 +59,10 @@ export class CalculatorResultsComponent implements AfterViewChecked { @Output() private afterViewChecked = new EventEmitter(); + public constructor( + @Inject(forwardRef(() => GenericCalculatorComponent)) private calculatorComponent: GenericCalculatorComponent + ) { } + public set formulaire(f: FormulaireDefinition) { this._formulaire = f; if (this._formulaire === undefined) { @@ -58,12 +71,18 @@ export class CalculatorResultsComponent implements AfterViewChecked { this.remousResultsComponent.results = undefined; this.pabResultsComponent.results = undefined; this.mrcResultsComponent.results = undefined; + this.jetResultsComponent.results = undefined; } else { - this.fixedVarResultsComponent.results = f.results; this.sectionResultsComponent.results = f.results; this.remousResultsComponent.results = f.results; this.pabResultsComponent.results = f.results; this.mrcResultsComponent.results = f.results; + // FixedVar and Jet are mutually incompatible (the 2nd extend the 1st) + if (this.isJet) { + this.jetResultsComponent.results = f.results; + } else { + this.fixedVarResultsComponent.results = f.results; + } } } @@ -73,9 +92,14 @@ export class CalculatorResultsComponent implements AfterViewChecked { this.remousResultsComponent.updateView(); this.pabResultsComponent.updateView(); this.mrcResultsComponent.updateView(); + this.jetResultsComponent.updateView(); } public ngAfterViewChecked() { this.afterViewChecked.emit(); } + + public get isJet() { + return this.calculatorComponent.isJet; + } } diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts index db97318390a3d125168c87cd489316826ab72fde..58a9afd15c54dc5a0e5335e6845a9880a6e26ed6 100644 --- a/src/app/components/fixedvar-results/fixedvar-results.component.ts +++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts @@ -22,13 +22,13 @@ export class FixedVarResultsComponent extends ResultsComponent implements DoChec /** * résultats non mis en forme */ - private _fixedResults: FixedResults; - private _varResults: VarResults; + protected _fixedResults: FixedResults; + protected _varResults: VarResults; /** * true si les résultats doiventt être remis à jour */ - private _doUpdate = false; + protected _doUpdate = false; @ViewChild(FixedResultsComponent, { static: false }) private fixedResultsComponent: FixedResultsComponent; @@ -119,7 +119,7 @@ export class FixedVarResultsComponent extends ResultsComponent implements DoChec * met à jour l'affichage des résultats * @returns true si les résultats ont pu être mis à jour */ - private updateResults() { + protected updateResults() { const fixedUpdated = this._fixedResults !== undefined && this.fixedResultsComponent !== undefined; if (fixedUpdated) { this.fixedResultsComponent.results = this._fixedResults; diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index 84f141806c65175548622e0522802ce5b8164f19..3fb26fbf1b646e5b67a0dfa421309513bf4f6dcb 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -500,6 +500,15 @@ export class GenericCalculatorComponent implements OnInit, DoCheck, AfterViewChe ); } + // true if current Nub is Jet + public get isJet() { + return ( + this._formulaire + && this._formulaire.currentNub + && this._formulaire.currentNub.calcType === CalculatorType.Jet + ); + } + // for "generate PAB" button public get isPABCloisons() { return ( diff --git a/src/app/components/jet-results/jet-results.component.html b/src/app/components/jet-results/jet-results.component.html new file mode 100644 index 0000000000000000000000000000000000000000..5b726da9770d5c6630bc867189ae8155f91ad364 --- /dev/null +++ b/src/app/components/jet-results/jet-results.component.html @@ -0,0 +1,18 @@ +<div class="container"> + <!-- journal --> + <log></log> + + <results-graph *ngIf="showVarResults"></results-graph> + + <jet-trajectory-graph *ngIf="hasResults"></jet-trajectory-graph> + + <div> + <!-- table des résultats fixés --> + <fixed-results [results]=fixedResults></fixed-results> + + <!-- table des résultats variés --> + <div *ngIf="showVarResults"> + <var-results [results]=varResults></var-results> + </div> + </div> +</div> diff --git a/src/app/components/jet-results/jet-results.component.scss b/src/app/components/jet-results/jet-results.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..6f5eb10d525664ef64b09c7c5eda9a8a074218b1 --- /dev/null +++ b/src/app/components/jet-results/jet-results.component.scss @@ -0,0 +1,4 @@ +results-graph { + margin-left: 1em; + margin-right: 1em; +} diff --git a/src/app/components/jet-results/jet-results.component.ts b/src/app/components/jet-results/jet-results.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8703b78e7f7f3528e8294e9def0553e95c24a948 --- /dev/null +++ b/src/app/components/jet-results/jet-results.component.ts @@ -0,0 +1,57 @@ +import { Component, ViewChild } from "@angular/core"; + +import { FixedVarResultsComponent } from "../fixedvar-results/fixedvar-results.component"; +import { JetTrajectoryGraphComponent } from "../jet-trajectory-graph/jet-trajectory-graph.component"; + +@Component({ + selector: "jet-results", + templateUrl: "./jet-results.component.html", + styleUrls: [ + "./jet-results.component.scss" + ] +}) +export class JetResultsComponent extends FixedVarResultsComponent { + + /** graphique de trajectoire */ + @ViewChild(JetTrajectoryGraphComponent, { static: false }) + private jetTrajectoryGraphComponent: JetTrajectoryGraphComponent; + + public get hasResults(): boolean { + return ( + (this._fixedResults !== undefined && this._fixedResults.hasResults) + || + (this._varResults !== undefined && this._varResults.hasResults) + ); + } + + public updateView() { + if (this.jetTrajectoryGraphComponent) { + this.jetTrajectoryGraphComponent.results = undefined; + } + super.updateView(); + } + + /** + * met à jour l'affichage des résultats + * @returns true si les résultats ont pu être mis à jour + */ + protected updateResults() { + const superUpdated = super.updateResults(); + + let trajectoryGraphUpdated: boolean; + trajectoryGraphUpdated = this.jetTrajectoryGraphComponent !== undefined; + + if (trajectoryGraphUpdated) { + // draw chart whether params are variating or not, + // hence different Results object for each case + if (this._varResults && this._varResults.hasResults) { + this.jetTrajectoryGraphComponent.results = this._varResults; + } else { + this.jetTrajectoryGraphComponent.results = this._fixedResults; + } + this.jetTrajectoryGraphComponent.updateView(); + } + + return superUpdated && trajectoryGraphUpdated; + } +} diff --git a/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.html b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.html new file mode 100644 index 0000000000000000000000000000000000000000..6ef01d5045c3b0203bb619d213b5a1357261885e --- /dev/null +++ b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.html @@ -0,0 +1,22 @@ +<div class="graph-results-container" #graphProfile fxLayout="row wrap" fxLayoutAlign="center center"> + <div fxFlex="1 1 100%"> + <div class="graph-profile-buttons"> + <button mat-icon-button (click)="resetZoom()" [disabled]="! zoomWasChanged" [title]="uitextResetZoomTitle"> + <mat-icon color="primary">replay</mat-icon> + </button> + <button mat-icon-button (click)="exportAsImage(graphProfile)" [title]="uitextExportImageTitle"> + <mat-icon color="primary">image</mat-icon> + </button> + <button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)" [title]="uitextEnterFSTitle"> + <mat-icon color="primary" class="scaled12">fullscreen</mat-icon> + </button> + <button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()" [title]="uitextExitFSTitle"> + <mat-icon color="primary" class="scaled12">fullscreen_exit</mat-icon> + </button> + </div> + + <div *ngIf="! displayChart" class="fake-chart"></div><!-- trick to avoid blinking effect due to forceRebuild --> + <chart *ngIf="displayChart" type="scatter" [data]="graph_data" [options]="graph_options" #graphChart> + </chart> + </div> +</div> \ No newline at end of file diff --git a/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.scss b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..19266623bd9da70c907c1db956b30eeecb2c443a --- /dev/null +++ b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.scss @@ -0,0 +1,34 @@ +.graph-results-container{ + display: block; + background-color: white; +} + +.graph-profile-buttons { + padding-right: 10px; + padding-top: 4px; + margin-bottom: -30px; + text-align: right; + background-color: white; + + button { + margin-left: 3px; + width: auto; + + mat-icon { + &.scaled12 { + transform: scale(1.2); + } + } + + &:disabled { + mat-icon { + color: #bfbfbf; + } + } + } +} + +.fake-chart { + width: 100%; + padding-top: 50%; +} diff --git a/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.ts b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..079e3fcc8c7c075ce763bc446f020812ecd9ddd9 --- /dev/null +++ b/src/app/components/jet-trajectory-graph/jet-trajectory-graph.component.ts @@ -0,0 +1,267 @@ +import { Component, ViewChild, ChangeDetectorRef } from "@angular/core"; + +import { ChartComponent } from "angular2-chartjs"; + +import { I18nService } from "../../services/internationalisation.service"; +import { ResultsComponent } from "../fixedvar-results/results.component"; +import { IYSeries } from "../../results/y-series"; +import { FixedResults } from "../../results/fixed-results"; +import { VarResults } from "../../results/var-results"; +import { fv } from "../../util"; + +import { Jet } from "jalhyd"; + +@Component({ + selector: "jet-trajectory-graph", + templateUrl: "./jet-trajectory-graph.component.html", + styleUrls: [ + "./jet-trajectory-graph.component.scss" + ] +}) +export class JetTrajectoryGraphComponent extends ResultsComponent { + + @ViewChild(ChartComponent, { static: false }) + private chartComponent; + + private _results: FixedResults | VarResults; + + private _zoomWasChanged = false; + + private _varValuesLists: any = {}; + + /** used to briefly destroy/rebuild the chart component, to refresh axis labels (@see bug #137) */ + public displayChart = true; + + /* + * config du graphe + */ + public graph_data: { datasets: any[] }; + public graph_options: any = { + responsive: true, + maintainAspectRatio: true, + aspectRatio: 1.5, + animation: { + duration: 0 + }, + legend: { + display: true, + position: "bottom", + reverse: false + }, + title: { + display: true, + text: this.intlService.localizeText("INFO_JET_TITRE_TRAJECTOIRE") + }, + elements: { + line: { + tension: 0 + } + } + }; + + public constructor( + private intlService: I18nService, + private cd: ChangeDetectorRef + ) { + super(); + // do not move following block out of constructor or scale labels won't be rendered + this.graph_options["scales"] = { + xAxes: [{ + type: "linear", + position: "bottom", + ticks: { + precision: ResultsComponent.CHARTS_AXIS_PRECISION + }, + scaleLabel: { + display: true, + labelString: this.intlService.localizeText("INFO_LIB_ABSCISSE") + } + }], + yAxes: [{ + type: "linear", + position: "left", + ticks: { + precision: ResultsComponent.CHARTS_AXIS_PRECISION + }, + scaleLabel: { + display: true, + labelString: this.intlService.localizeText("INFO_LIB_ALTITUDE") + } + }] + }; + // enable zoom and pan (using "chartjs-plugin-zoom" package) + const that = this; + this.graph_options["plugins"] = { + zoom: { + pan: { + enabled: false, // conflicts with drag zoom + mode: "xy", + }, + zoom: { + enabled: true, + drag: { // conflicts with pan; set to false to enable mouse wheel zoom, + borderColor: "rgba(225,225,225,0.3)", + borderWidth: 1, + backgroundColor: "rgba(0,0,0,0.25)" + }, + mode: "xy", + // percentage of zoom on a wheel event + // speed: 0.1, + onZoomComplete: function(t: any) { return function() { t.zoomComplete(); }; }(that) + } + } + }; + // format numbers in tooltips + this.graph_options.tooltips = { + displayColors: false, + callbacks: { + label: (tooltipItem, data) => { + return "(" + fv(Number(tooltipItem.xLabel)) + ", " + fv(Number(tooltipItem.yLabel)) + ")"; + } + } + }; + } + + /** forces Angular to rebuild the chart @see bug #137 */ + private forceRebuild() { + this.displayChart = false; + const that = this; + setTimeout(() => { // trick + that.displayChart = true; + }, 10); + } + + public set results(r: FixedResults | VarResults) { + this.forceRebuild(); // used for (de)activating legend in generateScatterGraph() + this._results = r; + + if (this._results) { + const nub = this._results.result.sourceNub as Jet; + const length = nub.variatingLength(); + // extract variable values list for legend + if (nub.resultHasMultipleValues()) { + for (const p of nub.parameterIterator) { + if (p.hasMultipleValues) { + this._varValuesLists[p.symbol] = []; + if (nub.calculatedParam === p) { // calculated + for (let i = 0; i < length; i++) { + this._varValuesLists[p.symbol].push(nub.result.resultElements[i].vCalc); + } + } else { // variating + const iter = p.getExtendedValuesIterator(length); + while (iter.hasNext) { + const nv = iter.next(); + this._varValuesLists[p.symbol].push(nv.value); + } + } + } + } + } + } + } + + public zoomComplete() { + this._zoomWasChanged = true; + this.cd.detectChanges(); + } + + public get zoomWasChanged(): boolean { + return this._zoomWasChanged; + } + + public updateView() { + this.generateScatterGraph(); + } + + /** + * génère les données d'un graphe de type "scatter" + */ + private generateScatterGraph() { + const ySeries = this.getYSeries(); + + // hide legend when there is only 1 series + this.graph_options.legend.display = (ySeries.length > 1); + + this.graph_data = { + datasets: [] + }; + + // build Y data series + for (const ys of ySeries) { + if (ys.data.length > 0) { + // push series config + this.graph_data.datasets.push({ + label: ys.label, + data: ys.data, + borderColor: ys.color, // couleur de la ligne + backgroundColor: "rgba(0,0,0,0)", // couleur de remplissage sous la courbe : transparent + showLine: "true" + }); + } + } + } + + public exportAsImage(element: HTMLDivElement) { + const canvas: HTMLCanvasElement = element.querySelector("canvas"); + canvas.toBlob((blob) => { + saveAs(blob, "chart.png"); + }); // defaults to image/png + } + + public resetZoom() { + this.chartComponent.chart.resetZoom(); + this._zoomWasChanged = false; + } + + public get uitextResetZoomTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_RESET_ZOOM"); + } + + public get uitextExportImageTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXPORT_IMAGE"); + } + + public get uitextEnterFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_ENTER_FS"); + } + + public get uitextExitFSTitle() { + return this.intlService.localizeText("INFO_GRAPH_BUTTON_TITLE_EXIT_FS"); + } + + private getYSeries(): IYSeries[] { + const ret: IYSeries[] = []; + const palette = ResultsComponent.distinctColors; + const nub = (this._results.result.sourceNub as Jet); + const trajectories = nub.generateTrajectories(); + + for (let i = 0; i < trajectories.length; i++) { + const traj = trajectories[i]; + ret.push({ + label: trajectories.length === 0 ? "" /* legend is hidden */ : this.getLegendForSeries(i), + color: palette[i % palette.length], + // map to IYSeries format + data: traj.map((t) => { + return { + x: t[0], + y: t[1] + }; + }) + }); + } + return ret; + } + + /** + * Returns a label showing the boundary conditions values for + * the given iteration + * @param n index of the variating parameter(s) iteration + */ + private getLegendForSeries(n: number): string { + return Object.keys(this._varValuesLists).map((symbol) => { + const values = this._varValuesLists[symbol]; + const val = fv(values[n]); + return `${symbol} = ${val}`; + }).join(", "); + } +} diff --git a/src/app/config.json b/src/app/config.json index c2ec2a974ab5fd1f39b32fbfee0e7cde04f6bf2a..41449c8e1e284cd6e2f3aa105182823d1f78eb70 100644 --- a/src/app/config.json +++ b/src/app/config.json @@ -14,7 +14,7 @@ "path": "passe-bassin.jpg", "credits": "S. Richard / AFB" }, - "calculators": [ 12, 13, 6, 5, 10, 15, 9 ] + "calculators": [ 12, 13, 6, 5, 10, 15 ] }, { "name": "PASSE_NATURELLE", @@ -24,6 +24,14 @@ }, "calculators": [ 11, 17 ] }, + { + "name": "DEVALAISON", + "image": { + "path": "surface-libre.jpg", + "credits": "PENSER À CHANGER CETTE IMAGE" + }, + "calculators": [ 18, 3, 9 ] + }, { "name": "HYDRAULIQUE_A_SURFACE_LIBRE", "image": { diff --git a/src/app/formulaire/form-iterator/deep-node-iterator.ts b/src/app/formulaire/form-iterator/deep-node-iterator.ts deleted file mode 100644 index cca6046a1a48ef715c5685ab5b89f7710dbb1501..0000000000000000000000000000000000000000 --- a/src/app/formulaire/form-iterator/deep-node-iterator.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { AbstractFormulaireNodeIterator } from "./abstract-node-iterator"; -import { FormulaireNode } from "../formulaire-node"; - -export class DeepFormulaireNodeIterator extends AbstractFormulaireNodeIterator<FormulaireNode> implements IterableIterator<FormulaireNode> { - // interface IterableIterator - - [Symbol.iterator](): IterableIterator<FormulaireNode> { - return this; - } -} diff --git a/src/app/results/multidimension-results.ts b/src/app/results/multidimension-results.ts index 5475c6c603a43f15b974e5bffc10d5d9dc6193d2..b0ecbca0e0ac8e011740abbd1509cf810d7fe7a8 100644 --- a/src/app/results/multidimension-results.ts +++ b/src/app/results/multidimension-results.ts @@ -2,7 +2,7 @@ import { CalculatedParamResults } from "./param-calc-results"; import { NgParameter } from "../formulaire/ngparam"; -export class MultiDimensionResults extends CalculatedParamResults/* implements PlottableData */ { +export class MultiDimensionResults extends CalculatedParamResults { /** paramètres variés */ public variatedParameters: NgParameter[]; diff --git a/src/app/services/formulaire.service.ts b/src/app/services/formulaire.service.ts index d880cb7d369c2fad3b556107309af2dda66ff241..9dc42709448f856e7651565605c6bd39fbac08bb 100644 --- a/src/app/services/formulaire.service.ts +++ b/src/app/services/formulaire.service.ts @@ -77,6 +77,7 @@ export class FormulaireService extends Observable { this.calculatorPaths[CalculatorType.MacroRugo] = "macrorugo"; this.calculatorPaths[CalculatorType.Pab] = "pab"; this.calculatorPaths[CalculatorType.MacroRugoCompound] = "macrorugo-compound"; + this.calculatorPaths[CalculatorType.Jet] = "jet"; } private get _intlService(): I18nService { diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index f274b57d0bae8e5c903936fd5cec78b6b67145e8..557e53d36f6cdf4bab586d9ec02f38d022f9f8d5 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -147,6 +147,8 @@ "INFO_FIELDSET_MOVE_DOWN": "Move down", "INFO_FIELDSET_MOVE_LEFT": "Move left", "INFO_FIELDSET_MOVE_RIGHT": "Move right", + "INFO_JET_TITRE_COURT": "Jet", + "INFO_JET_TITRE": "Jet impact", "INFO_WALL_ADDED": "1 wall added", "INFO_WALL_ADDED_N_TIMES": "%s walls added", "INFO_WALL_COPIED": "Wall #%s copied", @@ -155,8 +157,11 @@ "INFO_WALL_REMOVED": "Wall #%s removed", "INFO_WALLS_AND_DEVICES_REMOVED": "%s wall(s) and %s device(s) removed", "INFO_WALLS_REMOVED": "%s wall(s) removed", + "INFO_JET_TITRE_TRAJECTOIRE": "Trajectory", "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.", "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon", + "INFO_LIB_ABSCISSE": "Abscissa (m)", + "INFO_LIB_ALTITUDE": "Altitude (m)", "INFO_LIB_LENGTHS": "Every length", "INFO_LIB_WIDTHS": "Every width", "INFO_LIB_SLOPES": "Every slope", @@ -409,6 +414,8 @@ "INFO_SNACKBAR_RESULTS_INVALIDATED": "Results invalidated for", "INFO_SNACKBAR_SETTINGS_SAVED": "Settings saved on this device", "INFO_THEME_CREDITS": "Credit", + "INFO_THEME_DEVALAISON_TITRE": "Downstream migration", + "INFO_THEME_DEVALAISON_DESCRIPTION": "", "INFO_THEME_HYDRAULIQUE_A_SURFACE_LIBRE_DESCRIPTION": "Calculation modules for flows in channels and rivers", "INFO_THEME_HYDRAULIQUE_A_SURFACE_LIBRE_TITRE": "Open-channel flow", "INFO_THEME_HYDRAULIQUE_EN_CHARGE_DESCRIPTION": "Modules for calculating head losses in pressure pipes", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 4b72d9007e4655cea1aeba3a16ce8c30aac8cb72..871a868f19df47e98b024cf7ace60cfe8b5b2e3c 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -147,6 +147,8 @@ "INFO_FIELDSET_MOVE_DOWN": "Déplacer vers le bas", "INFO_FIELDSET_MOVE_LEFT": "Déplacer vers la gauche", "INFO_FIELDSET_MOVE_RIGHT": "Déplacer vers la droite", + "INFO_JET_TITRE_COURT": "Jet", + "INFO_JET_TITRE": "Impact de jet", "INFO_WALL_ADDED": "1 cloison ajoutée", "INFO_WALL_ADDED_N_TIMES": "%s cloisons ajoutées", "INFO_WALL_COPIED": "Cloison n°%s copiée", @@ -157,6 +159,9 @@ "INFO_WALLS_REMOVED": "%s cloison(s) supprimée(s)", "INFO_LECHAPTCALMON_TITRE_COURT": "Lechapt-C.", "INFO_LECHAPTCALMON_TITRE": "Lechapt-Calmon", + "INFO_JET_TITRE_TRAJECTOIRE": "Trajectoire", + "INFO_LIB_ABSCISSE": "Abscisse (m)", + "INFO_LIB_ALTITUDE": "Altitude (m)", "INFO_LIB_LENGTHS": "Toutes les longueurs", "INFO_LIB_WIDTHS": "Toutes les largeurs", "INFO_LIB_SLOPES": "Toutes les pentes", @@ -408,6 +413,8 @@ "INFO_SNACKBAR_RESULTS_INVALIDATED": "Résultats invalidés pour", "INFO_SNACKBAR_SETTINGS_SAVED": "Paramètres enregistrés sur cet appareil", "INFO_THEME_CREDITS": "Crédit", + "INFO_THEME_DEVALAISON_TITRE": "Dévalaison", + "INFO_THEME_DEVALAISON_DESCRIPTION": "PENSER À METTRE UNE DESCRIPTION ICI", "INFO_THEME_HYDRAULIQUE_A_SURFACE_LIBRE_DESCRIPTION": "Modules de calcul pour les écoulements en canaux et rivières", "INFO_THEME_HYDRAULIQUE_A_SURFACE_LIBRE_TITRE": "Hydraulique à surface libre", "INFO_THEME_HYDRAULIQUE_EN_CHARGE_DESCRIPTION": "Modules de calcul de perte de charge dans les conduites sous pression",