Skip to content
Snippets Groups Projects
Commit d469b73d authored by mathias.chouet's avatar mathias.chouet
Browse files

Fix #287 add jet type results

parent ce7ed5b7
No related branches found
No related tags found
1 merge request!60Resolve "Ajout du module "Impact de jet""
......@@ -91,6 +91,7 @@ import { ModulesDiagramComponent } from "./components/modules-diagram/modules-di
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";
......@@ -195,6 +196,7 @@ const appRoutes: Routes = [
JalhydModelValidationMaxDirective,
JalhydModelValidationStepDirective,
JetResultsComponent,
JetTrajectoryGraphComponent,
LogComponent,
LogEntryComponent,
ModulesDiagramComponent,
......
......@@ -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;
......@@ -116,7 +116,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;
......
......@@ -4,7 +4,7 @@
<results-graph *ngIf="showVarResults"></results-graph>
<trajectory-graph></trajectory-graph>
<jet-trajectory-graph *ngIf="hasResults"></jet-trajectory-graph>
<div>
<!-- table des résultats fixés -->
......
import { Component } from "@angular/core";
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",
......@@ -11,4 +12,46 @@ import { FixedVarResultsComponent } from "../fixedvar-results/fixedvar-results.c
})
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;
}
}
<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
.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%;
}
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]
};
})
});
}
console.log("Y series", ret.length, ret);
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(", ");
}
}
......@@ -327,7 +327,6 @@ export class FormulaireService extends Observable {
* @param calculatorName nom du module, à afficher dans l'interface
*/
public createFormulaire(ct: CalculatorType, nub?: Nub, calculatorName?: string): Promise<FormulaireDefinition> {
console.log(">> Create form !!", ct);
// Crée un formulaire du bon type
const f: FormulaireDefinition = this.newFormulaire(ct);
this._formulaires.push(f);
......
......@@ -156,8 +156,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",
......
......@@ -158,6 +158,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",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment