From 2c95c44b79fcaf1ec039c5e0c7aad7c9ac40bdc0 Mon Sep 17 00:00:00 2001
From: "mathias.chouet" <mathias.chouet@irstea.fr>
Date: Mon, 11 Mar 2019 11:09:54 +0100
Subject: [PATCH] =?UTF-8?q?Fix=20#109=20choisir=20l'abscisse=20et=20l'ordo?=
 =?UTF-8?q?nn=C3=A9e=20des=20graphiques=20de=20r=C3=A9sultats=20vari=C3=A9?=
 =?UTF-8?q?s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../results-graph/graph-type.component.scss   |   5 +-
 .../results-graph.component.html              |  20 ++++
 .../results-graph.component.scss              |  11 ++
 .../results-graph/results-graph.component.ts  | 111 ++++++++++++++----
 .../definition/form-compute-fixedvar.ts       |   1 -
 .../form-compute-section-parametree.ts        |   1 -
 .../definition/form-result-fixedvar.ts        |   4 -
 src/app/results/var-results.ts                |  84 +++++++++++--
 src/locale/messages.en.json                   |   2 +
 src/locale/messages.fr.json                   |   2 +
 10 files changed, 199 insertions(+), 42 deletions(-)

diff --git a/src/app/components/results-graph/graph-type.component.scss b/src/app/components/results-graph/graph-type.component.scss
index 46070b5e3..1d8503e20 100644
--- a/src/app/components/results-graph/graph-type.component.scss
+++ b/src/app/components/results-graph/graph-type.component.scss
@@ -1,7 +1,10 @@
 :host {
     display: block;
     margin-top: 5px;
-    text-align: center;
+}
+
+mat-form-field {
+    width: 100%;
 }
 
 mat-select {
diff --git a/src/app/components/results-graph/results-graph.component.html b/src/app/components/results-graph/results-graph.component.html
index 61ff43cc4..3d1b41a31 100644
--- a/src/app/components/results-graph/results-graph.component.html
+++ b/src/app/components/results-graph/results-graph.component.html
@@ -18,3 +18,23 @@
 </div>
 
 <graph-type></graph-type>
+
+<div class="select-x-y-axis" fxLayout="row wrap" fxLayoutAlign="space-between start">
+    <mat-form-field fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
+        <mat-select id="selectX" [placeholder]="uitextSelectX" [(value)]="chartX">
+            <mat-option *ngFor="let x of availableChartAxis" [value]="x">
+                {{ getChartAxisLabel(x) }}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+
+    <div fxHide.xs fxFlex.gt-xs="0 0 16px"></div>
+
+    <mat-form-field fxFlex.gt-xs="1 0 auto" fxFlex.lt-sm="1 0 100%">
+        <mat-select id="selectY" [placeholder]="uitextSelectY" [(value)]="chartY">
+            <mat-option *ngFor="let y of availableChartAxis" [value]="y">
+                {{ getChartAxisLabel(y) }}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+</div>
diff --git a/src/app/components/results-graph/results-graph.component.scss b/src/app/components/results-graph/results-graph.component.scss
index 7a13a42ec..b0c7e8451 100644
--- a/src/app/components/results-graph/results-graph.component.scss
+++ b/src/app/components/results-graph/results-graph.component.scss
@@ -21,3 +21,14 @@
         }
     }
 }
+
+mat-select {
+
+    ::ng-deep .mat-select-value {
+        > span {
+            > span {
+                line-height: 1.3em;
+            }
+        }
+    }
+}
diff --git a/src/app/components/results-graph/results-graph.component.ts b/src/app/components/results-graph/results-graph.component.ts
index 9603b0a1a..ec43b3499 100644
--- a/src/app/components/results-graph/results-graph.component.ts
+++ b/src/app/components/results-graph/results-graph.component.ts
@@ -5,6 +5,7 @@ import { Observer } from "jalhyd";
 import { VarResults, GraphType } from "../../results/var-results";
 import { GraphTypeSelectComponent } from "./graph-type.component";
 import { ApplicationSetupService } from "../../services/app-setup/app-setup.service";
+import { I18nService } from "../../services/internationalisation/internationalisation.service";
 
 @Component({
     selector: "results-graph",
@@ -45,7 +46,8 @@ export class ResultsGraphComponent implements AfterContentInit, Observer {
     }
 
     public constructor(
-        private appSetup: ApplicationSetupService
+        private appSetup: ApplicationSetupService,
+        private intlService: I18nService
     ) {
         // limit display precision according to app preferences
         const nDigits = this.appSetup.displayDigits;
@@ -58,7 +60,67 @@ export class ResultsGraphComponent implements AfterContentInit, Observer {
         }
     }
 
+    public get availableChartAxis() {
+        if (this._results) {
+            return this._results.getAvailableChartAxis();
+        }
+    }
+
+    public get chartX() {
+        if (this._results) {
+            return this._results.chartX;
+        }
+    }
+
+    public set chartX(X) {
+        if (X !== this.chartX) {
+            this._results.chartX = X;
+            // refresh chart
+            this.updateView();
+        }
+    }
+
+    public get chartY() {
+        if (this._results) {
+            return this._results.chartY;
+        }
+    }
+
+    public set chartY(Y) {
+        if (Y !== this.chartY) {
+            this._results.chartY = Y;
+            // refresh chart
+            this.updateView();
+        }
+    }
+
+    /**
+     * Returns a human readable description of any param / result symbol
+     */
+    public getChartAxisLabel(symbol: string) {
+        // 1. calculated param ?
+        if (this._results.calculatedParameter.symbol === symbol) {
+            return this._results.calculatedParameterHeader;
+        } else
+        // 2. variated param ?
+        if (this._results.variatedParameter.symbol === symbol) {
+            return this._results.variableParamHeader;
+        } else {
+            // 3. Result element ?
+            return this.intlService.getExtraResLabel(symbol);
+        }
+    }
+
+    public get uitextSelectX() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_GRAPH_SELECT_X_AXIS");
+    }
+
+    public get uitextSelectY() {
+        return this.intlService.localizeText("INFO_PARAMFIELD_GRAPH_SELECT_Y_AXIS");
+    }
+
     public updateView() {
+        // (re)generate chart
         switch (this._graphTypeComponent.selectedValue) {
             case GraphType.Histogram:
                 this.graph_type = "bar";
@@ -87,15 +149,16 @@ export class ResultsGraphComponent implements AfterContentInit, Observer {
     private generateLineGraph() {
         const labs = [];
         const dat = [];
-        let i = 0;
-        for (const x of this._results.variatedParameter.valuesIterator) {
-            labs.push(x);
-            const y = this._results.yValues[i];
-            dat.push(y);
-            i++;
+        const xSeries = this._results.getValuesSeries(this.chartX);
+        const ySeries = this._results.getValuesSeries(this.chartY);
+        // both series are supposed to be the same length
+        for (let i = 0; i < xSeries.length; i++) {
+            labs.push(xSeries[i]);
+            dat.push(ySeries[i]);
         }
 
-        this.graph_options.title.text = this._results.graphTitle;
+        // @see bug #137
+        this.graph_options.title.text = this.chartY + " = f ( " + this.chartX + " )";
 
         this.graph_data = {
             labels: labs,
@@ -112,15 +175,17 @@ export class ResultsGraphComponent implements AfterContentInit, Observer {
     private generateBarGraph() {
         const labs = [];
         const dat = [];
-        let i = 0;
-        for (const x of this._results.variatedParameter.valuesIterator) {
-            labs.push(x);
-            const y = this._results.yValues[i];
-            dat.push(y);
-            i++;
+        const xSeries = this._results.getValuesSeries(this.chartX);
+        const ySeries = this._results.getValuesSeries(this.chartY);
+        // both series are supposed to be the same length
+        for (let i = 0; i < xSeries.length; i++) {
+            labs.push(xSeries[i]);
+            dat.push(ySeries[i]);
         }
 
-        this.graph_options.title.text = this._results.graphTitle;
+        // @see bug #137
+        this.graph_options.title.text = this.chartY + " = f ( " + this.chartX + " )";
+
         const nDigits = this.appSetup.displayDigits;
         this.graph_options["scales"] = {
             xAxes: [{
@@ -157,17 +222,19 @@ export class ResultsGraphComponent implements AfterContentInit, Observer {
      */
     private generateScatterGraph() {
         const dat = [];
-        let i = 0;
-        for (const x of this._results.variatedParameter.valuesIterator) {
-            const y = this._results.yValues[i];
+        const xSeries = this._results.getValuesSeries(this.chartX);
+        const ySeries = this._results.getValuesSeries(this.chartY);
+        // both series are supposed to be the same length
+        for (let i = 0; i < xSeries.length; i++) {
             dat.push({
-                x: x,
-                y: y
+                x: xSeries[i],
+                y: ySeries[i]
             });
-            i++;
         }
 
-        this.graph_options.title.text = this._results.graphTitle;
+        // @see bug #137
+        this.graph_options.title.text = this.chartY + " = f ( " + this.chartX + " )";
+
         const nDigits = this.appSetup.displayDigits;
         this.graph_options["scales"] = {
             xAxes: [{
diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts
index 300703a6d..151b875bf 100644
--- a/src/app/formulaire/definition/form-compute-fixedvar.ts
+++ b/src/app/formulaire/definition/form-compute-fixedvar.ts
@@ -61,7 +61,6 @@ export class FormComputeFixedVar extends FormCompute {
             this.formResult.varResults.calculatedParameter = computedParam;
 
             this.formResult.varResults.result = res;
-            this.formResult.graphTitle = computedParam.symbol + " = f( " + varParam.symbol + " )";
             this.formResult.varResults.update(false);
         }
     }
diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts
index 1da49fa7e..fc41974d9 100644
--- a/src/app/formulaire/definition/form-compute-section-parametree.ts
+++ b/src/app/formulaire/definition/form-compute-section-parametree.ts
@@ -50,7 +50,6 @@ export class FormComputeSectionParametree extends FormCompute {
         this._varResults.calculatedParameter = computedParam;
 
         this._varResults.result = this.runNubCalc(sectNub, computedParam);
-        this._varResults.graphTitle = computedParamInfo.symbol + " = f( " + varParam.symbol + " )";
         this._varResults.update(false);
     }
 
diff --git a/src/app/formulaire/definition/form-result-fixedvar.ts b/src/app/formulaire/definition/form-result-fixedvar.ts
index 04b248a83..291a6373a 100644
--- a/src/app/formulaire/definition/form-result-fixedvar.ts
+++ b/src/app/formulaire/definition/form-result-fixedvar.ts
@@ -54,10 +54,6 @@ export class FormResultFixedVar extends FormResult {
         this._varResults.graphType = t;
     }
 
-    public set graphTitle(t: string) {
-        this._varResults.graphTitle = t;
-    }
-
     public get hasResults(): boolean {
         return this._fixedResults.hasResults || this._varResults.hasResults;
     }
diff --git a/src/app/results/var-results.ts b/src/app/results/var-results.ts
index 177f36a60..752664fcb 100644
--- a/src/app/results/var-results.ts
+++ b/src/app/results/var-results.ts
@@ -47,14 +47,18 @@ export class VarResults extends CalculatedParamResults {
     private _extraResultHeaders: string[];
 
     /**
-     * titre du graphe des résultats variés
+     * type de graphe
      */
-    private _graphTitle: string;
+    public graphType: GraphType = GraphType.Scatter;
 
     /**
-     * type de graphe
+     * variated parameter or result displayed as chart's X-axis
      */
-    public graphType: GraphType = GraphType.Scatter;
+    public chartX: string;
+    /**
+     * variated parameter or result displayed as chart's Y-axis
+     */
+    public chartY: string;
 
     /**
      * tableau des ordonnées du graphe des résultats variés
@@ -72,7 +76,6 @@ export class VarResults extends CalculatedParamResults {
         this._extraResultHeaders = [];
         this._extraResultKeys = [];
         this._yValues = [];
-        this._graphTitle = undefined;
     }
 
     public get variatedParameter(): NgParameter {
@@ -96,14 +99,6 @@ export class VarResults extends CalculatedParamResults {
         return this.result.resultElements;
     }
 
-    public get graphTitle() {
-        return this._graphTitle;
-    }
-
-    public set graphTitle(t: string) {
-        this._graphTitle = t;
-    }
-
     public get extraResultHeaders() {
         return this._extraResultHeaders;
     }
@@ -116,11 +111,64 @@ export class VarResults extends CalculatedParamResults {
         this._extraResultKeys = k;
     }
 
+    /**
+     * Returns the series of values for the required variated parameter / result element
+     * @param symbol parameter / result symbol (ex: "Q")
+     */
+    public getValuesSeries(symbol: string) {
+        // console.log("GVS for symbol", symbol);
+        const series = [];
+        // 1. calculated param ?
+        if (this._calculatedParam.symbol === symbol) {
+            if (this.result) {
+                for (const r of this.result.resultElements) {
+                    series.push(r.vCalc);
+                }
+            }
+        } else
+        // 2. variated param ?
+        if (this.variatedParameter.symbol === symbol) {
+            for (const v of this.variatedParameter.valuesIterator) {
+                series.push(v);
+            }
+        } else {
+            // 3. Result element ?
+            for (const r of this.result.resultElements) { // re:ResultElement
+                for (const k in r.extraResults) {
+                    if (k === symbol) {
+                        series.push(r.extraResults[k]);
+                    }
+                }
+            }
+        }
+
+        return series;
+    }
+
+    /**
+     * Returns a list of plottable parameters / result elements, that can be defined
+     * as X or Y chart axis
+     * @param except exclude this symbol from the list
+     */
+    public getAvailableChartAxis() {
+        const res = [];
+        res.push(this.calculatedParameter.symbol);
+        res.push(this.variatedParameter.symbol);
+        for (const erk of this.extraResultKeys) {
+            res.push(erk);
+        }
+        return res;
+    }
+
     public update(displaySymbol: boolean) {
         if (this._variableParamHeader === undefined) {
             this._variableParamHeader = CalculatorResults.paramLabel(this.variatedParameter, displaySymbol);
         }
 
+        // set axis selectors values the first time
+        this.chartX = this.chartX || this.variatedParameter.symbol;
+        this.chartY = this.chartY || this.calculatedParameter.symbol;
+
         // valeurs du paramètre à calculer
         for (const r of this.result.resultElements) {
             this._yValues.push(r.vCalc);
@@ -144,5 +192,15 @@ export class VarResults extends CalculatedParamResults {
         for (const k of this._extraResultKeys) {
             this._extraResultHeaders.push(intlService.getExtraResLabel(k));
         }
+
+        // when variable parameter changes, ensure the X / Y current values are still availble
+        // (might be the previous variated parameter, that is not accessible anymore)
+        const aca = this.getAvailableChartAxis();
+        if (! aca.includes(this.chartX)) {
+            this.chartX = this.variatedParameter.symbol;
+        }
+        if (! aca.includes(this.chartY)) {
+            this.chartY = this.variatedParameter.symbol;
+        }
     }
 }
diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json
index 0fbca2261..bed80e332 100644
--- a/src/locale/messages.en.json
+++ b/src/locale/messages.en.json
@@ -154,6 +154,8 @@
     "INFO_PARALLELSTRUCTURE_TITRE_COURT": "// structures",
     "INFO_PARAMFIELD_GRAPH_TYPE": "Graph type",
     "INFO_PARAMFIELD_GRAPH_TYPE_HISTOGRAM": "Histogram",
+    "INFO_PARAMFIELD_GRAPH_SELECT_X_AXIS": "Variable for X axis",
+    "INFO_PARAMFIELD_GRAPH_SELECT_Y_AXIS": "Variable for Y axis",
     "INFO_PARAMFIELD_IN_CALCULATION": "In calculation",
     "INFO_PARAMFIELD_IN_CALCULATION_INITIAL_VALUE": "initial value",
     "INFO_PARAMFIELD_PARAMCALCULER": "Calculate",
diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json
index fc557bf8c..ea0bae031 100644
--- a/src/locale/messages.fr.json
+++ b/src/locale/messages.fr.json
@@ -154,6 +154,8 @@
     "INFO_PARALLELSTRUCTURE_TITRE_COURT": "Ouvrages",
     "INFO_PARAMFIELD_GRAPH_TYPE": "Type de graphe",
     "INFO_PARAMFIELD_GRAPH_TYPE_HISTOGRAM": "Histogramme",
+    "INFO_PARAMFIELD_GRAPH_SELECT_X_AXIS": "Variable en abscisse",
+    "INFO_PARAMFIELD_GRAPH_SELECT_Y_AXIS": "Variable en ordonnée",
     "INFO_PARAMFIELD_IN_CALCULATION": "En calcul",
     "INFO_PARAMFIELD_IN_CALCULATION_INITIAL_VALUE": "valeur initiale",
     "INFO_PARAMFIELD_PARAMCALCULER": "calculer",
-- 
GitLab