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

Fix #234 : profil en long de la passe

parent b673610d
No related branches found
No related tags found
1 merge request!49Resolve "Ajout du module de calcul d'une passe à bassins"
......@@ -79,6 +79,7 @@ import { VarResultsComponent } from "./components/fixedvar-results/var-results.c
import { LogEntryComponent } from "./components/log-entry/log-entry.component";
import { ParamLinkComponent } from "./components/param-link/param-link.component";
import { SelectModelFieldLineComponent } from "./components/select-model-field-line/select-model-field-line.component";
import { PabProfileGraphComponent } from "./components/pab-profile-graph/pab-profile-graph.component";
import { PabTableComponent } from "./components/pab-table/pab-table.component";
import { PabVariableResultsSelectorComponent } from "./components/pab-results/pab-variable-results-selector.component";
......@@ -183,6 +184,7 @@ const appRoutes: Routes = [
LogComponent,
LogEntryComponent,
NgParamInputComponent,
PabProfileGraphComponent,
PabResultsComponent,
PabResultsTableComponent,
PabTableComponent,
......
<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)="exportAsImage(graphProfile)">
<mat-icon color="primary">image</mat-icon>
</button>
<button mat-icon-button *ngIf="! isFullscreen" (click)="setFullscreen(graphProfile)">
<mat-icon color="primary" class="scaled12">fullscreen</mat-icon>
</button>
<button mat-icon-button *ngIf="isFullscreen" (click)="exitFullscreen()">
<mat-icon color="primary" class="scaled12">fullscreen_exit</mat-icon>
</button>
</div>
<chart type="scatter" [data]="graph_data" [options]="graph_options" #graphChart>
</chart>
</div>
</div>
.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);
}
}
}
}
import { Component } from "@angular/core";
import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
import { I18nService } from "../../services/internationalisation/internationalisation.service";
import { ResultsComponent } from "../fixedvar-results/results.component";
import { PabResults } from "../../results/pab-results";
@Component({
selector: "pab-profile-graph",
templateUrl: "./pab-profile-graph.component.html",
styleUrls: [
"./pab-profile-graph.component.scss"
]
})
export class PabProfileGraphComponent extends ResultsComponent {
private _results: PabResults;
/*
* config du graphe
*/
public graph_data: { datasets: any[] };
public graph_options = {
responsive: true,
maintainAspectRatio: true,
animation: {
duration: 0
},
legend: {
display: false
},
title: {
display: true,
text: "Profil en long de la passe"
},
elements: {
line: {
tension: 0
}
}
};
public constructor(
private appSetup: ApplicationSetupService,
private intlService: I18nService
) {
super();
}
public set results(r: PabResults) {
this._results = r;
}
public updateView() {
console.log("PPG => updateView() !");
this.generateScatterGraph();
}
/**
* génère les données d'un graphe de type "scatter"
*/
private generateScatterGraph() {
const nDigits = this.appSetup.displayDigits;
const ySeries = this.getYSeries();
this.graph_data = {
datasets: []
};
this.graph_options["scales"] = {
xAxes: [{
type: "linear",
position: "bottom",
ticks: {
precision: nDigits
},
scaleLabel: {
display: true,
labelString: "la super abscisse"
// labelString: this.axisLabelWithoutSymbol(this.chartX)
}
}],
yAxes: [{
type: "linear",
position: "left",
ticks: {
precision: nDigits
},
scaleLabel: {
display: true,
labelString: "la super ordonnée"
/// labelString: this.axisLabelWithoutSymbol(this.chartY)
}
}]
};
// build Y data series
for (const ys of ySeries) {
// 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"
});
}
/* const that = this;
this.graph_options["tooltips"] = {
displayColors: false,
callbacks: {
title: (tooltipItems, data) => {
return this.chartY + " = " + Number(tooltipItems[0].yLabel).toFixed(nDigits);
},
label: (tooltipItem, data) => {
const lines: string[] = [];
const nbLines = that._results.getVariatingParametersSymbols().length;
for (const v of that._results.getVariatingParametersSymbols()) {
const series = that._results.getValuesSeries(v);
const line = v + " = " + series[tooltipItem.index].toFixed(nDigits);
if (v === this.chartX) {
if (nbLines > 1) {
lines.unshift("");
}
lines.unshift(line);
} else {
lines.push(line);
}
}
return lines;
}
}
}; */
}
public exportAsImage(element: HTMLDivElement) {
const canvas: HTMLCanvasElement = element.querySelector("canvas");
canvas.toBlob((blob) => {
saveAs(blob, "chart.png");
}); // defaults to image/png
}
private getXSeries(): string[] {
const data: string[] = [];
const nDigits = this.appSetup.displayDigits;
// X is always wall abscissa
for (const cr of this._results.cloisonsResults) {
const x = cr.resultElement.getExtraResult("x"); // any resultElement will do
data.push(x.toFixed(nDigits));
}
const xdw = this._results.cloisonAvalResults.resultElement.getExtraResult("x");
data.push(xdw.toFixed(nDigits));
return data;
}
private getYSeries(): { data: { x: string, y: string }[], label: string, color: string }[] {
const ret: { data: { x: string, y: string }[], label: string, color: string }[] = [];
const xs = this.getXSeries(); // abscissae
const pabLength = Number(xs[xs.length - 1]) - Number(xs[0]);
const pabLength5Pct = (pabLength * 5) / 100;
// 1. fond du machin
const dataF: { x: string, y: string }[] = [];
const nDigits = this.appSetup.displayDigits;
// extend upstrem
dataF.push({
x: (Number(xs[0]) - pabLength5Pct).toFixed(nDigits),
y: this._results.cloisonsResults[0].resultElement.getExtraResult("ZRAM").toFixed(nDigits)
});
// regular walls
for (let i = 0; i < this._results.cloisonsResults.length; i++) {
const cr = this._results.cloisonsResults[i];
const ZRAM = cr.resultElement.getExtraResult("ZRAM"); // any ResultElement will do
dataF.push({
x: xs[i],
y: ZRAM.toFixed(nDigits)
});
}
// downwall
const ZRAMdw = this._results.cloisonAvalResults.resultElement.getExtraResult("ZRAM");
dataF.push({
x: xs[ xs.length - 1 ],
y: ZRAMdw.toFixed(nDigits)
});
// extend downstream
dataF.push({
x: (Number(xs[xs.length - 1]) + pabLength5Pct).toFixed(nDigits),
y: ZRAMdw.toFixed(nDigits)
});
// add series
ret.push({
data: dataF,
label: "fond du machin",
color: "#000000"
});
// 2. séries
const nbSeries = this._results.cloisonsResults[0].resultElements.length;
const palette = this.distinctColors;
for (let n = 0; n < nbSeries; n++) {
// --------- build nth series ---------
const dataN: { x: string, y: string }[] = [];
let i = 0; // abscissa index
// extend upstream
dataN.push({
x: (Number(xs[0]) - pabLength5Pct).toFixed(nDigits),
y: this._results.cloisonsResults[0].resultElements[n].vCalc.toFixed(nDigits)
});
// walls
for (const x of xs) {
let Z1: number;
let nextZ1: number;
if (i < xs.length - 2) {
// regular walls
Z1 = this._results.cloisonsResults[i].resultElements[n].vCalc;
nextZ1 = this._results.cloisonsResults[i + 1].resultElements[n].vCalc;
} else if (i === xs.length - 2) {
// last regular wall
Z1 = this._results.cloisonsResults[i].resultElements[n].vCalc;
nextZ1 = this._results.cloisonAvalResults.resultElements[n].vCalc;
} else {
// downwall
Z1 = this._results.cloisonAvalResults.resultElements[n].vCalc;
nextZ1 = this._results.Z2[n];
}
// 2 points for each abscissa
dataN.push({
x: x,
y: Z1.toFixed(nDigits)
});
dataN.push({
x: x,
y: nextZ1.toFixed(nDigits)
});
i++;
}
// extend downstream
dataN.push({
x: (Number(xs[xs.length - 1]) + pabLength5Pct).toFixed(nDigits),
y: this._results.Z2[n].toFixed(nDigits)
});
ret.push({
data: dataN,
label: "série " + n,
color: palette[ n % palette.length ]
});
}
return ret;
}
/**
* 14 distinct colors @see https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors
*/
private get distinctColors(): string[] {
return [
"#4363d8", // blue
"#f58231", // orange
"#3cb44b", // green
"#e6194B", // red
"#911eb4", // purple
"#ffe119", // yellow
"#f032e6", // magenta
"#9A6324", // brown
"#000075", // navy
"#808000", // olive
"#42d4f4", // cyan
"#a9a9a9", // grey
"#bfef45", // lime
"#469990", // teal
];
}
}
......@@ -12,6 +12,11 @@
<pab-results-table *ngIf="hasDisplayableResults" [results]="pabResults"></pab-results-table>
</div>
<results-graph *ngIf="hasDisplayableResults"></results-graph>
<div id="pab-graphs-container" class="container" fxLayout="row wrap" fxLayoutAlign="space-around start">
<pab-profile-graph *ngIf="hasDisplayableResults" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px">
</pab-profile-graph>
<results-graph *ngIf="hasDisplayableResults" fxFlex.gt-xs="1 0 400px" fxFlex.lt-sm="1 0 300px">
</results-graph>
</div>
</div>
results-graph {
margin-left: 1em;
margin-right: 1em;
}
import { Component, ViewChild, DoCheck } from "@angular/core";
import { Result, cLog, MessageSeverity, Message, MessageCode } from "jalhyd";
import { Result, cLog, Message, MessageCode } from "jalhyd";
import { LogComponent } from "../../components/log/log.component";
import { CalculatorResults } from "../../results/calculator-results";
......@@ -13,12 +13,13 @@ import { PlottableData } from "../../results/plottable-data";
import { PlottablePabResults } from "../../results/plottable-pab-results";
import { ResultsGraphComponent } from "../results-graph/results-graph.component";
import { I18nService } from "../../services/internationalisation/internationalisation.service";
import { PabProfileGraphComponent } from "../pab-profile-graph/pab-profile-graph.component";
@Component({
selector: "pab-results",
templateUrl: "./pab-results.component.html",
styleUrls: [
"../fixedvar-results/fixedvar-results.component.scss"
"./pab-results.component.scss"
]
})
export class PabResultsComponent implements DoCheck {
......@@ -26,7 +27,7 @@ export class PabResultsComponent implements DoCheck {
/** résultats non mis en forme */
private _pabResults: PabResults;
/** résultats mis en forme pour le graphique */
/** résultats mis en forme pour le graphique de données (classique) */
private _plottableResults: PlottablePabResults;
/** true si les résultats doiventt être remis à jour */
......@@ -47,6 +48,9 @@ export class PabResultsComponent implements DoCheck {
@ViewChild(ResultsGraphComponent)
private resultsGraphComponent: ResultsGraphComponent;
@ViewChild(PabProfileGraphComponent)
private profileGraphComponent: PabProfileGraphComponent;
constructor(
private appSetupService: ApplicationSetupService,
private i18nService: I18nService,
......@@ -83,6 +87,9 @@ export class PabResultsComponent implements DoCheck {
if (this.resultsGraphComponent) {
this.resultsGraphComponent.results = undefined;
}
if (this.profileGraphComponent) {
this.profileGraphComponent.results = undefined;
}
// set _doUpdate flag so that results are rebuilt on the next Angular display cycle
this._doUpdate = false;
if (this._pabResults !== undefined) {
......@@ -198,7 +205,8 @@ export class PabResultsComponent implements DoCheck {
*/
private updateResults() {
let pabUpdated: boolean;
let graphUpdated: boolean;
let resultsGraphUpdated: boolean;
let profileGraphUpdated: boolean;
let selectorUpdated: boolean;
// results or not, there might be a log
......@@ -218,18 +226,24 @@ export class PabResultsComponent implements DoCheck {
if (selectorUpdated) {
this.pabVariableResultsSelectorComponent.results = this._pabResults;
}
graphUpdated = this.resultsGraphComponent !== undefined;
if (graphUpdated) {
resultsGraphUpdated = this.resultsGraphComponent !== undefined;
if (resultsGraphUpdated) {
this.resultsGraphComponent.results = this.plottableResults;
this.resultsGraphComponent.updateView();
}
profileGraphUpdated = this.profileGraphComponent !== undefined;
if (profileGraphUpdated) {
this.profileGraphComponent.results = this._pabResults;
this.profileGraphComponent.updateView();
}
} else {
pabUpdated = true;
graphUpdated = true;
resultsGraphUpdated = true;
profileGraphUpdated = true;
selectorUpdated = true;
}
return pabUpdated && logUpdated && graphUpdated && selectorUpdated;
return pabUpdated && logUpdated && resultsGraphUpdated && profileGraphUpdated && selectorUpdated;
}
public get pabResults() {
......@@ -273,4 +287,5 @@ export class PabResultsComponent implements DoCheck {
this._plottableResults.setPabResults(this.pabResults);
return this._plottableResults;
}
}
......@@ -17,7 +17,7 @@ export class PlottablePabResults implements PlottableData {
}
// axes par défaut
this.chartX = this.chartX || "CLOISON";
this.chartY = this.chartY || "Z";
this.chartY = this.chartY || "YMOY";
}
/** reaffect pabResults, for ex. when objet was contructed with empty pabResults */
......
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